| 1 | # -*- mode: python; coding: utf-8 -*- |
|---|
| 2 | # :Progetto: vcpx -- Git target (using git-core) |
|---|
| 3 | # :Creato: Thu 1 Sep 2005 04:01:37 EDT |
|---|
| 4 | # :Autore: Todd Mokros <tmokros@tmokros.net> |
|---|
| 5 | # Brendan Cully <brendan@kublai.com> |
|---|
| 6 | # Yann Dirson <ydirson@altern.org> |
|---|
| 7 | # :Licenza: GNU General Public License |
|---|
| 8 | # |
|---|
| 9 | |
|---|
| 10 | """ |
|---|
| 11 | This module implements the parts of the backend for Git using git-core, |
|---|
| 12 | common to source and target modules. |
|---|
| 13 | """ |
|---|
| 14 | |
|---|
| 15 | __docformat__ = 'reStructuredText' |
|---|
| 16 | |
|---|
| 17 | from vcpx.repository import Repository |
|---|
| 18 | from vcpx.shwrap import ExternalCommand, PIPE |
|---|
| 19 | from vcpx.config import ConfigurationError |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | class GitRepository(Repository): |
|---|
| 23 | METADIR = '.git' |
|---|
| 24 | |
|---|
| 25 | def _load(self, project): |
|---|
| 26 | Repository._load(self, project) |
|---|
| 27 | self.EXECUTABLE = project.config.get(self.name, 'git-command', 'git') |
|---|
| 28 | self.parent_repo = project.config.get(self.name, 'parent-repo') |
|---|
| 29 | self.branch_point = project.config.get(self.name, 'branchpoint', 'HEAD') |
|---|
| 30 | self.branch_name = project.config.get(self.name, 'branch') |
|---|
| 31 | if self.branch_name: |
|---|
| 32 | self.branch_name = 'refs/heads/' + self.branch_name |
|---|
| 33 | |
|---|
| 34 | if self.repository and self.parent_repo: |
|---|
| 35 | self.log.critical('Cannot make sense of both "repository" and "parent-repo" parameters') |
|---|
| 36 | raise ConfigurationError ('Must specify only one of "repository" and "parent-repo"') |
|---|
| 37 | |
|---|
| 38 | if self.branch_name and not self.repository: |
|---|
| 39 | self.log.critical('Cannot make sense of "branch" if "repository" is not set') |
|---|
| 40 | raise ConfigurationError ('Missing "repository" to make use o "branch"') |
|---|
| 41 | |
|---|
| 42 | self.env = {} |
|---|
| 43 | |
|---|
| 44 | if self.repository: |
|---|
| 45 | self.storagedir = self.repository |
|---|
| 46 | self.env['GIT_DIR'] = self.storagedir |
|---|
| 47 | self.env['GIT_INDEX_FILE'] = self.METADIR + '/index' |
|---|
| 48 | else: |
|---|
| 49 | self.storagedir = self.METADIR |
|---|
| 50 | |
|---|
| 51 | def runCommand(self, cmd, exception=Exception, pipe=True): |
|---|
| 52 | """ |
|---|
| 53 | Facility to run a git command in a controlled context. |
|---|
| 54 | """ |
|---|
| 55 | |
|---|
| 56 | c = GitExternalCommand(self, |
|---|
| 57 | command = self.command(*cmd), cwd = self.basedir) |
|---|
| 58 | if pipe: |
|---|
| 59 | output = c.execute(stdout=PIPE)[0] |
|---|
| 60 | else: |
|---|
| 61 | c.execute() |
|---|
| 62 | if c.exit_status: |
|---|
| 63 | raise exception(str(c) + ' failed') |
|---|
| 64 | if pipe: |
|---|
| 65 | return output.read().split('\n') |
|---|
| 66 | |
|---|
| 67 | def create(self): |
|---|
| 68 | """ |
|---|
| 69 | Initialize .git through ``git init-db`` or ``git-clone``. |
|---|
| 70 | """ |
|---|
| 71 | |
|---|
| 72 | from os import renames, mkdir |
|---|
| 73 | from os.path import join, exists |
|---|
| 74 | |
|---|
| 75 | if exists(join(self.basedir, self.METADIR)): |
|---|
| 76 | return |
|---|
| 77 | |
|---|
| 78 | if self.parent_repo: |
|---|
| 79 | cmd = self.command("clone", "--shared", "-n", self.parent_repo, 'tmp') |
|---|
| 80 | clone = GitExternalCommand(self, cwd=self.basedir, command=cmd) |
|---|
| 81 | clone.execute() |
|---|
| 82 | if clone.exit_status: |
|---|
| 83 | raise TargetInitializationFailure( |
|---|
| 84 | "%s returned status %s" % (str(clone), clone.exit_status)) |
|---|
| 85 | |
|---|
| 86 | renames(join(self.basedir, 'tmp', '.git'), join(self.basedir, '.git')) |
|---|
| 87 | |
|---|
| 88 | cmd = self.command("reset", "--soft", self.branch_point) |
|---|
| 89 | reset = GitExternalCommand(self, cwd=self.basedir, command=cmd) |
|---|
| 90 | reset.execute() |
|---|
| 91 | if reset.exit_status: |
|---|
| 92 | raise TargetInitializationFailure( |
|---|
| 93 | "%s returned status %s" % (str(reset), reset.exit_status)) |
|---|
| 94 | |
|---|
| 95 | elif self.repository and self.branch_name: |
|---|
| 96 | # ...and exists(self.storagedir) ? |
|---|
| 97 | |
|---|
| 98 | # initialization of a new branch in single-repository mode |
|---|
| 99 | mkdir(join(self.basedir, self.METADIR)) |
|---|
| 100 | |
|---|
| 101 | bp = self.runCommand(['rev-parse', self.branch_point])[0] |
|---|
| 102 | self.runCommand(['read-tree', bp]) |
|---|
| 103 | self.runCommand(['update-ref', self.branch_name, bp]) |
|---|
| 104 | #self.runCommand(['checkout-index']) |
|---|
| 105 | |
|---|
| 106 | else: |
|---|
| 107 | if exists(join(self.basedir, self.storagedir)): |
|---|
| 108 | raise TargetInitializationFailure( |
|---|
| 109 | "Repository %s already exists - " |
|---|
| 110 | "did you forget to set \"branch\" parameter ?" % self.storagedir) |
|---|
| 111 | |
|---|
| 112 | self.runCommand(['init-db']) |
|---|
| 113 | if self.repository: |
|---|
| 114 | # in this mode, the db is not stored in working dir, so we |
|---|
| 115 | # have to create .git ourselves |
|---|
| 116 | mkdir(join(self.basedir, self.METADIR)) |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | class GitExternalCommand(ExternalCommand): |
|---|
| 120 | def __init__(self, repo, command=None, cwd=None): |
|---|
| 121 | """ |
|---|
| 122 | Initialize an ExternalCommand instance tied to a GitRepository |
|---|
| 123 | from which it inherits a set of environment variables to use |
|---|
| 124 | for each execute(). |
|---|
| 125 | """ |
|---|
| 126 | |
|---|
| 127 | self.repo = repo |
|---|
| 128 | return ExternalCommand.__init__(self, command, cwd) |
|---|
| 129 | |
|---|
| 130 | def execute(self, *args, **kwargs): |
|---|
| 131 | """Execute the command, with controlled environment.""" |
|---|
| 132 | |
|---|
| 133 | if not kwargs.has_key('env'): |
|---|
| 134 | kwargs['env'] = {} |
|---|
| 135 | |
|---|
| 136 | kwargs['env'].update(self.repo.env) |
|---|
| 137 | |
|---|
| 138 | return ExternalCommand.execute(self, *args, **kwargs) |
|---|