[PATCH] convert: support glob patterns in filemap directives

Tessa Starkey testarkey at gmail.com
Sat Apr 3 12:07:40 CDT 2010


This is a patch that I have submitted previously to the mailing list,
then made some changes to it per the feedback I got. Any feedback on
this version of the patch would be much appriciated.

Thanks,
Tessa Starkey

On Wed, Mar 24, 2010 at 9:52 PM, Tessa Starkey <testarkey at gmail.com> wrote:
> # HG changeset patch
> # User Tessa Starkey <testarkey at gmail.com>
> # Date 1269481039 14400
> # Node ID f428cd7661d07c6dd379760ccb99f51dcd359abb
> # Parent  d9aa5b368e36c10d2c29411772fef9fd339c2e9f
> convert: support glob patterns in exclude and include filemap directives
>
> This is implemented using the matcher from the mercurial core, in order to
> make the it more consistant and avoid rewriting the matching code.
>
> diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py
> --- a/hgext/convert/__init__.py
> +++ b/hgext/convert/__init__.py
> @@ -90,9 +90,10 @@
>     directory, to be included in the destination repository, and the
>     exclusion of all other files and directories not explicitly
>     included. The 'exclude' directive causes files or directories to
> -    be omitted. The 'rename' directive renames a file or directory. To
> -    rename from a subdirectory into the root of the repository, use
> -    '.' as the path to rename to.
> +    be omitted. In the arguments to 'include' and 'exclude' directives,
> +    glob patterns can be used, but not regular expressions. The 'rename'
> +    directive renames a file or directory. To rename from a subdirectory
> +    into the root of the repository, use '.' as the path to rename to.
>
>     The splicemap is a file that allows insertion of synthetic
>     history, letting you specify the parents of a revision. This is
> diff --git a/hgext/convert/filemap.py b/hgext/convert/filemap.py
> --- a/hgext/convert/filemap.py
> +++ b/hgext/convert/filemap.py
> @@ -1,3 +1,4 @@
> +
>  # Copyright 2007 Bryan O'Sullivan <bos at serpentine.com>
>  # Copyright 2007 Alexis S. L. Carvalho <alexis at cecm.usp.br>
>  #
> @@ -6,7 +7,7 @@
>
>  import shlex
>  from mercurial.i18n import _
> -from mercurial import util
> +from mercurial import util, match
>  from common import SKIPREV, converter_source
>
>  def rpairs(name):
> @@ -21,17 +22,20 @@
>     A name can be mapped to itself, a new name, or None (omit from new
>     repository).'''
>
> -    def __init__(self, ui, path=None):
> +    def __init__(self, ui, root,  path=None):
>         self.ui = ui
> -        self.include = {}
> -        self.exclude = {}
> +        self.root = root
>         self.rename = {}
> +        self.includematch = None
> +        self.excludematch = None
>         if path:
>             if self.parse(path):
>                 raise util.Abort(_('errors in filemap'))
>
>     def parse(self, path):
>         errs = 0
> +        include = []
> +        exclude = []
>         def check(name, mapping, listname):
>             if name in mapping:
>                 self.ui.warn(_('%s:%d: %r already in %s list\n') %
> @@ -44,17 +48,17 @@
>         while cmd:
>             if cmd == 'include':
>                 name = lex.get_token()
> -                errs += check(name, self.exclude, 'exclude')
> -                self.include[name] = name
> +                errs += check(name, exclude, 'exclude')
> +                include.append(name)
>             elif cmd == 'exclude':
>                 name = lex.get_token()
> -                errs += check(name, self.include, 'include')
> +                errs += check(name, include, 'include')
>                 errs += check(name, self.rename, 'rename')
> -                self.exclude[name] = name
> +                exclude.append(name)
>             elif cmd == 'rename':
>                 src = lex.get_token()
>                 dest = lex.get_token()
> -                errs += check(src, self.exclude, 'exclude')
> +                errs += check(src, exclude, 'exclude')
>                 self.rename[src] = dest
>             elif cmd == 'source':
>                 errs += self.parse(lex.get_token())
> @@ -63,6 +67,13 @@
>                              (lex.infile, lex.lineno, cmd))
>                 errs += 1
>             cmd = lex.get_token()
> +        #deal with svn urls for files
> +        if self.root.startswith("file://"):
> +            self.root = self.root[7:]
> +        if include:
> +            self.includematch = match.match(self.root, '', include)
> +        if exclude:
> +            self.excludematch = match.match(self.root, '', exclude)
>         return errs
>
>     def lookup(self, name, mapping):
> @@ -73,16 +84,22 @@
>                 pass
>         return '', name, ''
>
> +    def matchlookup(self, name, matcher):
> +        for pre, suf in rpairs(name):
> +             if matcher(pre):
> +                 return pre, pre, suf
> +        return '', name, ''
> +
>     def __call__(self, name):
> -        if self.include:
> -            inc = self.lookup(name, self.include)[0]
> +        if self.includematch:
> +            inc = self.matchlookup(name, self.includematch)[0]
>         else:
>             inc = name
> -        if self.exclude:
> -            exc = self.lookup(name, self.exclude)[0]
> +        if self.excludematch:
> +            exc = self.matchlookup(name, self.excludematch)[0]
>         else:
>             exc = ''
> -        if (not self.include and exc) or (len(inc) <= len(exc)):
> +        if (not self.includematch and exc) or (len(inc) <= len(exc)):
>             return None
>         newpre, pre, suf = self.lookup(name, self.rename)
>         if newpre:
> @@ -115,7 +132,7 @@
>     def __init__(self, ui, baseconverter, filemap):
>         super(filemap_source, self).__init__(ui)
>         self.base = baseconverter
> -        self.filemapper = filemapper(ui, filemap)
> +        self.filemapper = filemapper(ui, self.base.path, filemap)
>         self.commits = {}
>         # if a revision rev has parent p in the original revision graph, then
>         # rev will have parent self.parentmap[p] in the restricted graph.
> diff --git a/tests/test-convert-filemap b/tests/test-convert-filemap
> --- a/tests/test-convert-filemap
> +++ b/tests/test-convert-filemap
> @@ -21,6 +21,8 @@
>  echo dir/file2 >> dir/file2
>  echo dir/subdir/file3 >> dir/subdir/file3
>  echo dir/subdir/file4 >> dir/subdir/file4
> +echo dir/fi.bin >> dir/fi.bin
> +echo dir/file5.bin >> dir/file5.bin
>  hg ci -d '0 0' -qAm '0: add foo baz dir/'
>
>  echo bar > bar
> @@ -128,3 +130,17 @@
>  hg --cwd source cat copied
>  echo 'copied2:'
>  hg --cwd renames.repo cat copied2
> +
> +echo % convert with glob exclude patterns in filemap
> +cat > globs.fmap <<EOF
> +exclude dir/file2
> +exclude b*
> +rename dir dir2
> +rename foo foo2
> +exclude */f?.bin
> +EOF
> +hg -q convert --filemap globs.fmap --datesort source globs.repo
> +hg up -q -R globs.repo
> +glog -R globs.repo
> +hg -R globs.repo manifest --debug
> +
> diff --git a/tests/test-convert-filemap.out b/tests/test-convert-filemap.out
> --- a/tests/test-convert-filemap.out
> +++ b/tests/test-convert-filemap.out
> @@ -16,14 +16,16 @@
>  |/
>  o  1 "1: add bar quux; copy foo to copied" files: bar copied quux
>  |
> -o  0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/subdir/file3 dir/subdir/file4 foo
> +o  0 "0: add foo baz dir/" files: baz dir/fi.bin dir/file dir/file2 dir/file5.bin dir/subdir/file3 dir/subdir/file4 foo
>
>  % final file versions in this repo:
>  9463f52fe115e377cf2878d4fc548117211063f2 644   bar
>  94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644   baz
>  6ca237634e1f6bee1b6db94292fb44f092a25842 644   copied
> +6617e5e33028b1dd4bc5a15ddfe1657fc0f9bb34 644   dir/fi.bin
>  3e20847584beff41d7cd16136b7331ab3d754be0 644   dir/file
>  75e6d3f8328f5f6ace6bf10b98df793416a09dca 644   dir/file2
> +18b2e207d8149c85a4f4e9baf4a9d8d8d8bbd22d 644   dir/file5.bin
>  5fe139720576e18e34bcc9f79174db8897c8afe9 644   dir/subdir/file3
>  57a1c1511590f3de52874adfa04effe8a77d64af 644   dir/subdir/file4
>  9a7b52012991e4873687192c3e17e61ba3e837a3 644   foo
> @@ -146,10 +148,12 @@
>  |
>  o  1 "1: add bar quux; copy foo to copied" files: copied2
>  |
> -o  0 "0: add foo baz dir/" files: dir2/file dir2/subdir/file3 foo2
> +o  0 "0: add foo baz dir/" files: dir2/fi.bin dir2/file dir2/file5.bin dir2/subdir/file3 foo2
>
>  e5e3d520be9be45937d0b06b004fadcd6c221fa2 644   copied2
> +6617e5e33028b1dd4bc5a15ddfe1657fc0f9bb34 644   dir2/fi.bin
>  3e20847584beff41d7cd16136b7331ab3d754be0 644   dir2/file
> +18b2e207d8149c85a4f4e9baf4a9d8d8d8bbd22d 644   dir2/file5.bin
>  5fe139720576e18e34bcc9f79174db8897c8afe9 644   dir2/subdir/file3
>  9a7b52012991e4873687192c3e17e61ba3e837a3 644   foo2
>  copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd
> @@ -157,3 +161,29 @@
>  foo
>  copied2:
>  foo
> +% convert with glob exclude patterns in filemap
> +@  8 "8: change foo" files: foo2
> +|
> +o    7 "7: second merge; change bar" files:
> +|\
> +| o  6 "6: change foo baz" files: foo2
> +| |
> +o |  5 "5: change bar baz quux" files: quux
> +|/
> +o    4 "4: first merge; change bar baz" files:
> +|\
> +| o  3 "3: change bar quux" files: quux
> +| |
> +o |  2 "2: change foo" files: foo2
> +|/
> +o  1 "1: add bar quux; copy foo to copied" files: copied quux
> +|
> +o  0 "0: add foo baz dir/" files: dir2/file dir2/file5.bin dir2/subdir/file3 dir2/subdir/file4 foo2
> +
> +e5e3d520be9be45937d0b06b004fadcd6c221fa2 644   copied
> +3e20847584beff41d7cd16136b7331ab3d754be0 644   dir2/file
> +18b2e207d8149c85a4f4e9baf4a9d8d8d8bbd22d 644   dir2/file5.bin
> +5fe139720576e18e34bcc9f79174db8897c8afe9 644   dir2/subdir/file3
> +57a1c1511590f3de52874adfa04effe8a77d64af 644   dir2/subdir/file4
> +9a7b52012991e4873687192c3e17e61ba3e837a3 644   foo2
> +bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644   quux
> diff --git a/tests/test-convert.out b/tests/test-convert.out
> --- a/tests/test-convert.out
> +++ b/tests/test-convert.out
> @@ -69,9 +69,11 @@
>     The 'include' directive causes a file, or all files under a directory, to
>     be included in the destination repository, and the exclusion of all other
>     files and directories not explicitly included. The 'exclude' directive
> -    causes files or directories to be omitted. The 'rename' directive renames
> -    a file or directory. To rename from a subdirectory into the root of the
> -    repository, use '.' as the path to rename to.
> +    causes files or directories to be omitted. In the arguments to 'include'
> +    and 'exclude' directives, glob patterns can be used, but not regular
> +    expressions. The 'rename' directive renames a file or directory. To rename
> +    from a subdirectory into the root of the repository, use '.' as the path
> +    to rename to.
>
>     The splicemap is a file that allows insertion of synthetic history,
>     letting you specify the parents of a revision. This is useful if you want
>


More information about the Mercurial-devel mailing list