def _configure(self): """ Parse configuration from git config """ sc = StackedConfig(StackedConfig.default_backends()) self.config = {} # Get top level directory of project proc = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.config['top_dir'] = proc.communicate()[0] if proc.returncode != 0: exit_code = 20 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) sys.exit(exit_code) self.config['deploy_file'] = self.config['top_dir'] + '/.git' try: self.config['hook_dir'] = sc.get('deploy', 'hook-dir') except KeyError: exit_code = 21 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) sys.exit(exit_code) try: self.config['repo_name'] = sc.get('deploy', 'tag-prefix') except KeyError: exit_code = 22 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) sys.exit(exit_code) self.config['sync_dir'] = '{0}/sync'.format(self.config['hook_dir'])
def create(self, title="tessera title goes here"): """ create a new tessera with title {title}. @returns Tessera object of the new Tessera """ uuid = uuid1() tessera_path = os.path.join(Tessera._tesserae, str(uuid)) tessera_file = "%s/tessera" % tessera_path os.mkdir(tessera_path) fin = open(os.path.join(Tessera._tesserae, "template"), "r") fout = open(tessera_file, "w") for line in fin.readlines(): if line == "@title@\n": line = "# %s\n" % title fout.write(line) fin.close() fout.close() tessera_info = "%s/info" % tessera_path fout = open(tessera_info, "w") c = StackedConfig(StackedConfig.default_backends()) fout.write("author: %s\n"%c.get("user", "name")) fout.write("email: %s\n"%c.get("user", "email")) fout.write("updated: %d\n"%int(time())) fout.close() return Tessera(tessera_path, self._config)
def create(self, title="tessera title goes here"): """ create a new tessera with title {title}. @returns Tessera object of the new Tessera """ uuid = uuid1() tessera_path = os.path.join(Tessera._tesserae, str(uuid)) tessera_file = "%s/tessera" % tessera_path os.mkdir(tessera_path) fin = open(os.path.join(Tessera._tesserae, "template"), "r") fout = open(tessera_file, "w") for line in fin.readlines(): if line == "@title@\n": line = "# %s\n" % title fout.write(line) fin.close() fout.close() tessera_info = "%s/info" % tessera_path fout = open(tessera_info, "w") c = StackedConfig(StackedConfig.default_backends()) fout.write("author: %s\n" % c.get("user", "name")) fout.write("email: %s\n" % c.get("user", "email")) fout.write("updated: %d\n" % int(time())) fout.close() return Tessera(tessera_path, self._config)
def get_config_stack(self): from dulwich.config import StackedConfig backends = [] p = self.get_config() if p is not None: backends.append(p) writable = p else: writable = None backends.extend(StackedConfig.default_backends()) return StackedConfig(backends, writable=writable)
def get_config_stack(self): """Return a config stack for this repository. This stack accesses the configuration for both this repository itself (.git/config) and the global configuration, which usually lives in ~/.gitconfig. :return: `Config` instance for this repository """ from dulwich.config import StackedConfig backends = [self.get_config()] + StackedConfig.default_backends() return StackedConfig(backends, writable=backends[0])
def configure(**kwargs): """ Parse configuration from git config """ sc = StackedConfig(StackedConfig.default_backends()) config = {} # Get top level directory of project proc = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) config['top_dir'] = proc.communicate()[0].strip() if proc.returncode != 0: exit_code = 20 log.error("{0} :: {1}".format(__name__, exit_codes[exit_code])) sys.exit(exit_code) config['deploy_file'] = config['top_dir'] + '/.git/.deploy' # Define the key names, git config names, and error codes config_elements = { 'hook_dir': ('deploy', 'hook-dir', 21), 'path': ('deploy', 'path', 23), 'user': ('deploy', 'user', 24), 'target': ('deploy', 'target', 25), 'repo_name': ('deploy', 'tag-prefix', 22), 'remote': ('deploy', 'remote', 26), 'branch': ('deploy', 'branch', 27), 'client_path': ('deploy', 'client-path', 19), 'user.name': ('user', 'name', 28), 'user.email': ('user', 'email', 29), 'deploy.key_path': ('deploy', 'key-path', 37), 'deploy.test_repo': ('deploy', 'test-repo-path', 38), } # Assign the values of each git config element for key, value in config_elements.iteritems(): try: # Override with kwargs if the attribute exists if key in kwargs: config[key] = kwargs[key] else: config[key] = sc.get(value[0], value[1]) except KeyError: exit_code = value[2] log.error("{0} :: {1}".format(__name__, exit_codes[exit_code])) sys.exit(exit_code) config['sync_dir'] = '{0}/sync'.format(config['hook_dir']) return config
def sync(self, no_deps=False, force=False): """ * add a sync tag * write a .deploy file with the tag information * call a sync hook with the prefix (repo) and tag info """ # TODO: do git calls in dulwich, rather than shelling out # TODO: get all configuration via a function, and get it during main if "lock" not in os.listdir(".git/deploy"): exit_code = 20 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) return exit_code sc = StackedConfig(StackedConfig.default_backends()) try: hook_dir = sc.get("deploy", "hook-dir") except KeyError: exit_code = 21 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) return exit_code try: repo_name = sc.get("deploy", "tag-prefix") except KeyError: exit_code = 22 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) return exit_code sync_dir = "{0}/sync".format(hook_dir) sync_script = "{0}/{1}.sync".format(sync_dir, repo_name) _tag = "{0}-sync-{1}".format(repo_name, datetime.now().strftime(DATE_TIME_TAG_FORMAT)) proc = subprocess.Popen(["/usr/bin/git tag", "-a", _tag]) if proc.returncode != 0: exit_code = 23 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) return exit_code # TODO: use a pluggable sync system rather than shelling out if os.path.exists(sync_script): proc = subprocess.Popen( [ sync_script, '--repo="{0}"'.format(repo_name), '--tag="{0}"'.format(_tag), '--force="{0}"'.format(force), ] ) log.info(proc.stdout.read()) if proc.returncode != 0: exit_code = 24 log.error("{0}::{1}".format(__name__, exit_codes[exit_code])) return exit_code
def ls_remote(remote): """List the refs in a remote. :param remote: Remote repository location :return: Dictionary with remote refs """ config = StackedConfig.default() client, host_path = get_transport_and_path(remote, config=config) return client.get_refs(host_path)
def ls_remote(remote, config=None, **kwargs): """List the refs in a remote. :param remote: Remote repository location :param config: Configuration to use :return: Dictionary with remote refs """ if config is None: config = StackedConfig.default() client, host_path = get_transport_and_path(remote, config=config, **kwargs) return client.get_refs(host_path)
def create(cls, basepath, title): t_id = str(generate_uniq_id()) t_path = os.path.join(basepath, t_id) t_file = os.path.join(t_path, Tessera.TESSERA_FILENAME) t_info = os.path.join(t_path, Tessera.INFO_FILENAME) os.makedirs(t_path) with open(Tessera.NEW_TESSERA_TEMPLATE, "r") as fin: with open(t_file, "w+") as fout: for l in fin.readlines(): if l == "@title@\n": l = "# %s\n" % title fout.write(l) with open(t_info, "w+") as f: c = StackedConfig(StackedConfig.default_backends()) f.write("author: %s\n" % c.get("user", "name")) f.write("email: %s\n" % c.get("user", "email")) f.write("updated: %s\n" % datetime.now().strftime("%Y-%m-%dT%H:%M:%S")) t = Tessera(t_id, t_path) return t
def test_default_backends(self): StackedConfig.default_backends()
def test_default_backends(self): self.makeSafeEnv() StackedConfig.default_backends()
def clone(source, target=None, bare=False, checkout=None, errstream=default_bytes_err_stream, outstream=None, origin=b"origin", **kwargs): """Clone a local or remote git repository. :param source: Path or URL for source repository :param target: Path to target repository (optional) :param bare: Whether or not to create a bare repository :param checkout: Whether or not to check-out HEAD after cloning :param errstream: Optional stream to write progress to :param outstream: Optional stream to write progress to (deprecated) :param origin: Name of remote from the repository used to clone :return: The new repository """ # TODO(jelmer): This code overlaps quite a bit with Repo.clone if outstream is not None: import warnings warnings.warn( "outstream= has been deprecated in favour of errstream=.", DeprecationWarning, stacklevel=3) errstream = outstream if checkout is None: checkout = (not bare) if checkout and bare: raise ValueError("checkout and bare are incompatible") config = StackedConfig.default() client, host_path = get_transport_and_path(source, config=config, **kwargs) if target is None: target = host_path.split("/")[-1] if not os.path.exists(target): os.mkdir(target) if bare: r = Repo.init_bare(target) else: r = Repo.init(target) reflog_message = b'clone: from ' + source.encode('utf-8') try: fetch_result = fetch(r, host_path, origin, message=reflog_message) target_config = r.get_config() if not isinstance(source, bytes): source = source.encode(DEFAULT_ENCODING) target_config.set((b'remote', origin), b'url', source) target_config.set((b'remote', origin), b'fetch', b'+refs/heads/*:refs/remotes/' + origin + b'/*') target_config.write_to_path() # TODO(jelmer): Support symref capability, # https://github.com/jelmer/dulwich/issues/485 try: head = r[fetch_result[b'HEAD']] except KeyError: head = None else: r[b'HEAD'] = head.id if checkout and not bare and head is not None: errstream.write(b'Checking out ' + head.id + b'\n') r.reset_index(head.tree) except BaseException: r.close() raise return r
def clone(source, target=None, bare=False, checkout=None, errstream=default_bytes_err_stream, outstream=None, origin=b"origin", **kwargs): """Clone a local or remote git repository. :param source: Path or URL for source repository :param target: Path to target repository (optional) :param bare: Whether or not to create a bare repository :param checkout: Whether or not to check-out HEAD after cloning :param errstream: Optional stream to write progress to :param outstream: Optional stream to write progress to (deprecated) :param origin: Name of remote from the repository used to clone :return: The new repository """ # TODO(jelmer): This code overlaps quite a bit with Repo.clone if outstream is not None: import warnings warnings.warn( "outstream= has been deprecated in favour of errstream=.", DeprecationWarning, stacklevel=3) errstream = outstream if checkout is None: checkout = (not bare) if checkout and bare: raise ValueError("checkout and bare are incompatible") config = StackedConfig.default() client, host_path = get_transport_and_path(source, config=config, **kwargs) if target is None: target = host_path.split("/")[-1] if not os.path.exists(target): os.mkdir(target) if bare: r = Repo.init_bare(target) else: r = Repo.init(target) reflog_message = b'clone: from ' + source.encode('utf-8') try: fetch_result = fetch(r, host_path, origin, message=reflog_message) target_config = r.get_config() if not isinstance(source, bytes): source = source.encode(DEFAULT_ENCODING) target_config.set((b'remote', origin), b'url', source) target_config.set( (b'remote', origin), b'fetch', b'+refs/heads/*:refs/remotes/' + origin + b'/*') target_config.write_to_path() # TODO(jelmer): Support symref capability, # https://github.com/jelmer/dulwich/issues/485 try: head = r[fetch_result[b'HEAD']] except KeyError: head = None else: r[b'HEAD'] = head.id if checkout and not bare and head is not None: errstream.write(b'Checking out ' + head.id + b'\n') r.reset_index(head.tree) except BaseException: r.close() raise return r
def clone(source, target=None, bare=False, checkout=None, errstream=default_bytes_err_stream, outstream=None, origin=b"origin"): """Clone a local or remote git repository. :param source: Path or URL for source repository :param target: Path to target repository (optional) :param bare: Whether or not to create a bare repository :param checkout: Whether or not to check-out HEAD after cloning :param errstream: Optional stream to write progress to :param outstream: Optional stream to write progress to (deprecated) :param origin: Name of remote from the repository used to clone :return: The new repository """ if outstream is not None: import warnings warnings.warn( "outstream= has been deprecated in favour of errstream=.", DeprecationWarning, stacklevel=3) errstream = outstream if checkout is None: checkout = (not bare) if checkout and bare: raise ValueError("checkout and bare are incompatible") config = StackedConfig.default() client, host_path = get_transport_and_path(source, config=config) if target is None: target = host_path.split("/")[-1] if not os.path.exists(target): os.mkdir(target) if bare: r = Repo.init_bare(target) else: r = Repo.init(target) try: remote_refs = client.fetch( host_path, r, determine_wants=r.object_store.determine_wants_all, progress=errstream.write) r.refs.import_refs( b'refs/remotes/' + origin, { n[len(b'refs/heads/'):]: v for (n, v) in remote_refs.items() if n.startswith(b'refs/heads/') }) r.refs.import_refs( b'refs/tags', { n[len(b'refs/tags/'):]: v for (n, v) in remote_refs.items() if n.startswith(b'refs/tags/') and not n.endswith(ANNOTATED_TAG_SUFFIX) }) target_config = r.get_config() if not isinstance(source, bytes): source = source.encode(DEFAULT_ENCODING) target_config.set((b'remote', origin), b'url', source) target_config.set((b'remote', origin), b'fetch', b'+refs/heads/*:refs/remotes/' + origin + b'/*') target_config.write_to_path() if checkout and not bare: # TODO(jelmer): Support symref capability, # https://github.com/jelmer/dulwich/issues/485 try: head = r[remote_refs[b"HEAD"]] except KeyError: pass else: r[b'HEAD'] = head.id errstream.write(b'Checking out ' + head.id + b'\n') r.reset_index(head.tree) except BaseException: r.close() raise return r
def test_default_backends(self): self.addCleanup(os.environ.__setitem__, "HOME", os.environ["HOME"]) os.environ["HOME"] = "/nonexistant" StackedConfig.default_backends()