deps: repository dependencies extension

Aleix Conchillo Flaqué aleix at member.fsf.org
Thu Feb 14 02:49:55 CST 2008


Hi,

comming from baz/tla I was missing config files. With config files you  
could add repository dependencies (normally external libraries which  
resided in other arch repos), then using the build-config command one  
could get the dependencies in an easy way.

I have created this extension to have a similar feature in Mercurial.

This is a first approach, so any comments will be welcome.

Aleix


# HG changeset patch
# User Aleix Conchillo Flaque <aleix at member.fsf.org>
# Date 1202978727 -3600
# Node ID 9bcc3fdbd5197ffd3419731342799dbb9a57ab89
# Parent  e85deb6dcf9d9265a2a35b5ec6fac36dfed28aee
deps: initial repository dependencies extension

diff -r e85deb6dcf9d -r 9bcc3fdbd519 hgext/deps.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/deps.py	Thu Feb 14 09:45:27 2008 +0100
@@ -0,0 +1,188 @@
+# repository dependencies extension
+
+import os
+import re
+
+from mercurial.i18n import _
+from mercurial import cmdutil, commands, hg, util
+
+def deps(ui, repo, tag = None, **opts):
+    '''create and manage repository dependencies
+
+    Dependencies are useful when a repository might depend on some
+    external repositories. This extension helps you manage these
+    dependencies in an easy manner.
+
+    To enable this extension, add this to your .hgrc file:
+
+    [extensions]
+    deps =
+
+    Repository dependencies are defined by a dependency list that has
+    an associated name that normally corresponds to a tag, but can be
+    any other thing that identifies the list. So, version 1.0 of a
+    'foo' application might depend on version 0.5 of an external
+    library 'libfoo' and on version 0.8 of another external library
+    'libfoo'.
+
+    A dependency is defined by a revision, an alias for an external
+    repository and the destination directory where the dependency will
+    be copied.
+
+    Repository aliases are defined in section [deps] of your .hgrc
+    file, and must be edited by hand.
+
+    [deps]
+    aliases = libfoo, libbar...
+    alias.libfoo = SOURCE
+    alias.libbar = SOURCE
+    ...
+
+    To facilitate version control, distribution, and merging of
+    dependencies, they are stored as a file named ".hgdeps" which is
+    managed similarly to other project files and can be hand-edited if
+    necessary. This is an example of a dependencies file:
+
+    [1.0]
+    f24139319bdb    libfoo    lib/foo
+    e296e11a9bc5    libbar    lib/bar
+
+    [0.9.1]
+    3a9b061bada1    libfoo    lib/foo
+    89b6ae79bc88    libbar    lib/bar
+
+    If no name is given, a list of all dependencies will be shown. A
+    given name will only display the dependencies for that name.
+
+    To add a dependency for a given name, the external repository
+    alias, a revision of that repository and a future destination path
+    must be provided. The destination path will be used by the
+    'depsclone' command.
+    '''
+    aliases = ui.configlist('deps', 'aliases')
+    config = deps_config('.hgdeps')
+
+    if not tag and not config.tags:
+        return
+
+    if not tag and config.tags:
+        ui.status('\n')
+        for t in config.tags:
+            ui.status('[%s]\n' % t)
+            deps = config.tags[t]
+            for d in deps:
+                ui.status('%-25s %-25s %s\n' % (d.rev, d.alias,  
d.dest))
+            ui.status('\n')
+    else:
+        alias = opts['alias']
+        rev = opts['rev']
+        dest = opts['dest']
+        if not alias in aliases:
+            raise util.Abort(_("alias '%s' is not registered" % alias))
+        dep = dependency(rev, alias, dest)
+        if not config.tags.has_key(tag):
+            config.tags[tag] = []
+        ui.status(_("adding dependency (revision = %s, alias = %s,  
path = %s)"
+                    " for %s\n" % (rev, alias, dest, tag)))
+        config.tags[tag].append(dep)
+        config.save()
+
+def deps_clone(ui, repo, tag, **opts):
+    '''make a copy of repository dependencies
+
+    Create a copy of a given repository dependency list.
+
+    This command will clone all the dependencies of the given name
+    into the destination directories previously registered with the
+    'deps' command.
+
+    Dependencies are normally used with tags, thus a correct use of
+    this command would be to obtain external dependencies for a given
+    tag first and then update the repository files to the given tag
+    using the 'update' command. The dependencies must be obtained
+    first as the .hgdeps could be created after the tag and the file
+    might not exist in that tag.
+    '''
+    aliases = ui.configlist('deps', 'aliases')
+    repos = {}
+    for alias in aliases:
+        repo = ui.config('deps', 'alias.%s' % alias)
+        repos[alias] = repo
+    config = deps_config('.hgdeps')
+    deps = config.tags[tag]
+    cmdutil.setremoteconfig(ui, opts)
+    for d in deps:
+        if not repos.has_key(d.alias):
+            raise util.Abort(_("alias '%s' is not registered" %  
d.alias))
+        ui.status(_('obtaining revision %s from %s to %s\n'
+                    % (d.rev, repos[d.alias], d.dest)))
+        # create all intermediate directories
+        os.makedirs(d.dest)
+        os.rmdir(d.dest)
+        hg.clone(ui, repos[d.alias], d.dest,
+                 pull = opts['pull'],
+                 stream = opts['uncompressed'],
+                 rev = [d.rev],
+                 update = True)
+
+class dependency:
+    def __init__(self, rev, alias, dest):
+        self.rev = rev
+        self.alias = alias
+        self.dest = dest
+
+    def write(self, f):
+        f.write('%-25s %-25s %s\n' % (self.rev, self.alias, self.dest))
+
+class deps_config:
+    def __init__(self, config_file):
+        self.tags = {}
+        self._config_file = config_file
+        try:
+            self._readconfig()
+        except IOError:
+            True
+
+    def save(self):
+        f = open(self._config_file, 'wb')
+        for t in self.tags:
+            f.write('[%s]\n' % t)
+            for dep in self.tags[t]:
+                dep.write(f)
+            f.write('\n')
+        f.close()
+
+    def _readconfig(self):
+        p_tag = re.compile(r'\[(\S+)\]')
+        p_dep = re.compile(r'(\S+)\s+(\S+)\s+(\S+)')
+        f = open(self._config_file, 'rb')
+        tag = None
+        for line in f.readlines():
+            m = p_tag.search(line)
+            if m:
+                tag = m.group(1).strip()
+                self.tags[tag] = []
+            else:
+                m = p_dep.search(line)
+                if m:
+                    rev = m.group(1).strip()
+                    alias = m.group(2).strip()
+                    dest = m.group(3).strip()
+                    dep = dependency(rev, alias, dest)
+                    self.tags[tag].append(dep)
+        f.close()
+
+cmdtable = {
+    "deps": (deps,
+            [('a', 'alias', '', 'alias of the repository dependency'),
+             ('r', 'rev', '', 'revision of the repository dependency'),
+             ('', 'remove', '', "remove name's dependencies"),
+             ('d', 'dest', '', 'destination directory for the  
dependency')],
+            "hg deps [-a ALIAS -r REV -d DEST] [NAME]"),
+    "depsclone": (deps_clone,
+                  [('', 'pull', None, _('use pull protocol to copy  
metadata')),
+                   ('', 'uncompressed', None,
+                    _('use uncompressed transfer (fast over LAN)')),
+                   ] + commands.remoteopts,
+                  "hg depsclone NAME")
+}



More information about the Mercurial-devel mailing list