Python 如何在.hgignore中模拟语言补码运算符?
我有一个与一组文件名匹配的Python正则表达式。如何更改它,以便在Mercurial的.hgignore文件中使用它来忽略与表达式不匹配的文件 完整故事: 我有一个很大的源代码树,其中的Python 如何在.hgignore中模拟语言补码运算符?,python,regex,mercurial,Python,Regex,Mercurial,我有一个与一组文件名匹配的Python正则表达式。如何更改它,以便在Mercurial的.hgignore文件中使用它来忽略与表达式不匹配的文件 完整故事: 我有一个很大的源代码树,其中的*.ml文件散布在各处。我想把它们放到一个新的存储库中。还有其他不太重要的文件,它们太重,无法包含在存储库中。我试图找到.hgignore文件的对应表达式 第一个观察:Python没有常规的语言补码操作符(AFAIK,它只能补码一组字符)。(顺便说一句,为什么?) 第二项观察: Python中的以下正则表达式:
*.ml
文件散布在各处。我想把它们放到一个新的存储库中。还有其他不太重要的文件,它们太重,无法包含在存储库中。我试图找到.hgignore
文件的对应表达式
第一个观察:Python没有常规的语言补码操作符(AFAIK,它只能补码一组字符)。(顺便说一句,为什么?)
第二项观察:
Python中的以下正则表达式:
re.compile("^.*(?<!\.ml)$")
但是,当我在.hgignore
文件中放入完全相同的表达式时,我得到以下结果:
$ hg st --all
? abc.ml
I .hgignore
I abcabc
I x/xabc
I x/xabc.ml
根据.hgignore
手册页,Mercurial只使用普通的Python正则表达式。那我怎么会得到不同的结果呢?
Mercurial怎么可能找到与x/xabc.ml
匹配的文件
有人知道缺少常规语言补码运算符的不那么难看的方法吗?通过一些测试,找到了两种似乎有效的解决方案。第一个根指向一个子目录,显然这很重要。第二个是脆弱的,因为它只允许使用一个后缀。我正在使用Mercurial 1.2.1在Windows XP(定制为更加unixy)上运行这些测试 (我用
#消息添加了评论。)
$hg--版本
Mercurial分布式SCM(版本1.2.1)
$cat.hg忽略
语法:regexp
^x/+(?)?
第二点:
$ cat .hgignore
syntax: regexp
#^x/.+(?<!\.ml)$
^.+[^.][^m][^l]$ # brittle, can only use one suffix
$ hg status --all
? abc.ml # versioned, is *.ml
? x\saveme.ml # versioned, is *.ml
I .hgignore # ignored, is not *.ml
I abcabc # ignored, is not *.ml
I x\abcabc # ignored, is not *.ml
I x\ignoreme.txt # ignored, is not *.ml
$cat.hg忽略
语法:regexp
#^x/+(?)?
根据我对OP的理解,第二个具有完全预期的行为。第一个仅在子目录中具有预期的行为,但更灵活。问题在于子目录中的匹配项与根目录中的匹配项不同。请注意以下几点:
$ hg --version
Mercurial Distributed SCM (version 1.1.2)
它是旧版本,但其行为方式相同。我的项目包含以下文件:
$ find . -name 'abc*' -print
./x/abcabc
./x/abc.ml
./abcabc
./abc.ml
这是我的.hgignore:
$ cat .hgignore
^.*(?<!\.ml)$
因此,hg
无法拾取x/abc.ml
。但这真的是正则表达式的问题吗?也许不是:
$ python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mercurial.ignore
>>> import os
>>> root = os.getcwd()
>>> ignorefunc = mercurial.ignore.ignore(root, ['.hgignore'], lambda msg: None)
>>>
>>> ignorefunc("abc.ml") # No match - this is correct
>>> ignorefunc("abcabc") # Match - this is correct, we want to ignore this
<_sre.SRE_Match object at 0xb7c765d0>
>>> ignorefunc("abcabc").span()
(0, 6)
>>> ignorefunc("x/abcabc").span() # Match - this is correct, we want to ignore this
(0, 8)
>>> ignorefunc("x/abc.ml") # No match - this is correct!
>>>
$python
Python 2.6.2(Release26Maint,2009年4月19日,01:56:41)
[GCC 4.3.3]关于linux2
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>导入mercurial.ignore
>>>导入操作系统
>>>root=os.getcwd()
>>>ignorefunc=mercurial.ignore.ignore(根,['.hgignore'],lambda msg:None)
>>>
>>>ignorefunc(“abc.ml”)#不匹配-这是正确的
>>>ignorefunc(“abcabc”)#匹配-这是正确的,我们希望忽略这一点
>>>ignorefunc(“abcabc”).span()
(0, 6)
>>>ignorefunc(“x/abcabc”).span()#匹配-这是正确的,我们希望忽略这一点
(0, 8)
>>>ignorefunc(“x/abc.ml”)#不匹配-这是正确的!
>>>
请注意,ignorefunc
treatedabcabc
和x/abcabc
是相同的(匹配-即忽略),而abc.ml
和x/abc.ml
也是相同的(不匹配-即不忽略)
因此,也许逻辑错误在Mercurial中的其他地方,或者我看到的Mercurial的错误部分(如果是这样的话,我会感到惊讶)。除非我遗漏了什么,可能是一个bug(而不是Martin Geisler指出的RFE)需要针对Mercurial进行归档。正则表达式依次应用于每个子目录组件以及文件名,而不是一次应用于整个相对路径。因此,如果我的回购协议中有a/b/c/d,则每个正则表达式将应用于a、a/b、a/b/c以及a/b/c/d。如果任何组件匹配,则将忽略该文件。(您可以通过使用bar/foo尝试^bar$
来判断这是一种行为-您将看到bar/foo被忽略。)
^.*(*忽略x/xabc.ml,因为模式匹配x(即子目录)
这意味着没有正则表达式可以帮助您,因为您的模式必须与第一个子目录组件匹配。您应该去订阅此错误报告:如果您对我的第一个答案做出响应,当我从^re/+更改为^re.+(如问题所示)时,我能够重现该问题。(因此我删除了该答案。)显然,这与指定的目录有关,这导致我提出了当前的建议。我没有查看hg的源代码,但是,根据这个外部测试,问题确实存在。呃-是的,我是在评论你的第一个(现在已删除)回答。无论如何,我的测试似乎没有指出正则表达式是问题的根源。不幸的是,如果我在.hgignore中尝试您的模式,我会看到以下内容显示为“?”:.hgignore(不应该存在)、abc.ml(应该存在)、abcabc(不应该存在)、x/abc.ml(应该存在)、y/abc.ml(应该存在)、y/abcabc.ml(不应该存在)。对于OP的正则表达式,它正确地忽略了所有内容,但也错误地忽略了x/abc.ml和y/abc.ml。因此,我不确定这是否是一种解决方法。哪种模式?以子目录为根的模式(第一种)当然不会影响不在该子目录中的文件。除了一个警告,它在所有情况下都会正常工作,第二个也会正常工作。我现在就更新我的帖子。我指的是第一个,因为它没有被注释掉。然而,不幸的是,你上面的脆弱re也不能用于文件名,这也是为什么会这样的另一个原因脆性。:)感谢您找到了这个额外的错误。第一个解决方案需要在.hgignore中指定所有目录。这归结为使用手工工具对源代码树进行爬网(然后我们可以显式选择每个文件,并且不需要.hgignore)。第二个正则表达式导致包含名为“shame”的文件(不匹配)。这太不准确了。但在我上面的回答中,“x/abcabc”和“x/abc.ml”被区别对待:第一个匹配(正确),而第二个不匹配(也正确)。您正在应用
$ cat .hgignore
^.*(?<!\.ml)$
$ hg stat
? abc.ml
$ python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mercurial.ignore
>>> import os
>>> root = os.getcwd()
>>> ignorefunc = mercurial.ignore.ignore(root, ['.hgignore'], lambda msg: None)
>>>
>>> ignorefunc("abc.ml") # No match - this is correct
>>> ignorefunc("abcabc") # Match - this is correct, we want to ignore this
<_sre.SRE_Match object at 0xb7c765d0>
>>> ignorefunc("abcabc").span()
(0, 6)
>>> ignorefunc("x/abcabc").span() # Match - this is correct, we want to ignore this
(0, 8)
>>> ignorefunc("x/abc.ml") # No match - this is correct!
>>>