2009-07-03 2 views
3

Ich habe einen regulären Python-Ausdruck, der mit einer Reihe von Dateinamen übereinstimmt. Wie kann ich es ändern, damit ich es in Mercurials .hgignore-Datei verwenden kann, um Dateien zu ignorieren, die nicht entsprechen den Ausdruck?Wie wird der Sprachenkomplement-Operator in .hgignore emuliert?

Ganzer Geschichte: Ich habe einen großen Quellbaum mit *.ml Dateien überall verstreut. Ich möchte sie in ein neues Repository legen. Es gibt andere, weniger wichtige Dateien, die zu schwer sind, um in das Repository aufgenommen zu werden. Ich versuche den entsprechenden Ausdruck für .hgignore Datei zu finden.

1. Beobachtung: Python hat keinen regulären Sprachkomplement-Operator (AFAIK kann nur eine Menge von Zeichen ergänzen). (BTW, warum?)

2. Beobachtung: Die folgende Regex in Python:

re.compile("^.*(?<!\.ml)$") 

funktioniert wie erwartet:

abcabc - match 
abc.ml - no match 
x/abcabc - match 
x/abc.ml - no match 

Allerdings, wenn ich lege genau den gleichen Ausdruck in den .hgignore Datei, bekomme ich diese:

$ hg st --all 
? abc.ml 
I .hgignore 
I abcabc 
I x/xabc 
I x/xabc.ml 

Nach .hgignore Manpage verwendet Mercurial nur normale reguläre Python-Ausdrücke. Wie kommt es, dass ich dann andere Ergebnisse bekomme? Wie ist es möglich, dass Mercurial eine Übereinstimmung für die x/xabc.ml gefunden hat?

Kennt jemand weniger hässlichen Weg um den Mangel an regulären Sprache Komplement-Operator?

+0

Sie sollten gehen und diesen Fehlerbericht abonnieren: http://mercurial.selenic.com/bts/issue712 –

Antwort

1

Die Regexs werden der Reihe nach auf jede Unterverzeichniskomponente angewendet, genauso wie der Dateiname, nicht der gesamte relative Pfad auf einmal. Wenn ich also ein/b/c/d in meinem Repo habe, wird jeder Regex auf a, a/b, a/b/c sowie a/b/c/d angewendet. Wenn eine Komponente übereinstimmt, wird die Datei ignoriert. (Können Sie sagen, dass dies das Verhalten, indem Sie versuchen ^bar$ mit Bar/foo ist - Sie, dass Bar/foo ignoriert sehen werden.)

^.*(?<!\.ml)$ ignoriert x/xabc.ml weil die Musterübereinstimmungen x (dh das Unterverzeichnis.)

Dies bedeutet, dass es keine Regex gibt, die Ihnen helfen wird, da Ihre Muster mit der ersten Unterverzeichniskomponente übereinstimmen müssen.

+0

Aber in meiner Antwort oben, "x/abcabc" und "x/abc.ml "werden unterschiedlich behandelt: der erste wird (richtig) abgeglichen, der zweite nicht (auch korrekt). –

+0

Sie wenden den ignore-func auf den gesamten relativen Pfad an, nicht auf die Unterpfade. Wenn Sie die Quelle betrachten, Sehen Sie sich _dirignore in mercurial/dirstate.py an. Ich bin mir ziemlich sicher, dass das ist, wo dieses Verhalten herkommt. " – hwiechers

+0

Ah, ich dachte auch, dass es mit dem gesamten relativen Pfad übereinstimmte. Und dieser Mann sagte, dass es so war, aber beim nochmaligen Lesen gibt es etwas anderes an. –

0

Durch einige Tests gefunden zwei Lösungen, die zu funktionieren scheinen. Die ersten Wurzeln in ein Unterverzeichnis, und das ist offensichtlich von Bedeutung. Die zweite ist spröde, da nur ein Suffix verwendet werden kann. Ich führe diese Tests auf Windows XP (angepasst, um etwas unixy arbeiten) mit Mercurial 1.2.1.

(Kommentare mit # message von mir hinzugefügt.)

 
$ hg --version 
Mercurial Distributed SCM (version 1.2.1) 

$ cat .hgignore 
syntax: regexp 
^x/.+(?<!\.ml)$  # rooted to x/ subdir 
#^.+[^.][^m][^l]$ 

$ hg status --all 
? .hgignore   # not affected by x/ regex 
? abc.ml    # not affected by x/ regex 
? abcabc    # not affected by x/ regex 
? x\saveme.ml   # versioned, is *.ml 
I x\abcabc   # ignored, is not *.ml 
I x\ignoreme.txt  # ignored, is not *.ml 

Und die zweite:

 
$ 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 

Das zweite Verhalten vollständig zu erwarten hat, als ich die OP verstehen. Die erste hat nur das Verhalten im Unterverzeichnis erwartet, ist aber flexibler.

+0

Leider, wenn ich Ihr Muster in. Hgignore versuchen, bekomme ich Folgendes als "?":. hgignore (sollte nicht da sein), abc.ml (sollte sein), abcabc (sollte nicht sein), x/abc.ml (sollte sein), y/abc.ml (sollte sein), y/abcabc (sollte nicht sein) bin nicht). Mit der Regex des OP ignoriert es alles korrekt, ignoriert aber auch falsch x/abc.ml und y/abc.ml. Also ich bin mir nicht sicher, dass dies eine Problemumgehung ist. –

+0

Welches Muster? Derjenige, der im Unterverzeichnis (dem ersten) verwurzelt ist, wirkt sich natürlich nicht auf Dateien aus, die sich nicht in diesem Unterverzeichnis befinden. Abgesehen von dieser einen Einschränkung funktioniert es so, wie es sollte, und die zweite funktioniert in allen Fällen so, wie es sollte. Ich werde meinen Beitrag jetzt aktualisieren. –

+0

Ich meinte die erste, da sie nicht auskommentiert war. Allerdings versagt Ihre spröde re oben leider auch bei Dateinamen die <= 3 Zeichen lang sind - zB "a", "ab" und "abc" werden nicht ignoriert. "abcd" ist gefangen. –

0

Das Problem scheint speziell zu sein, dass Übereinstimmungen in Unterverzeichnissen sich vom Stamm unterscheiden. Beachten Sie Folgendes:

$ hg --version 
Mercurial Distributed SCM (version 1.1.2) 

Es ist eine ältere Version, aber es verhält sich in der gleichen Weise. Mein Projekt hat folgende Dateien:

$ find . -name 'abc*' -print 
./x/abcabc 
./x/abc.ml 
./abcabc 
./abc.ml 

Hier ist meine.hgignore:

$ cat .hgignore 
^.*(?<!\.ml)$ 

Nun, wenn ich stat laufen:

$ hg stat 
? abc.ml 

So hat hg gescheitert x/abc.ml abholen. Aber ist das wirklich ein Problem mit dem regulären Ausdruck? Vielleicht nicht:

$ 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! 
>>> 

Beachten Sie, dass ignorefunc behandelt abcabc und x/abcabc die gleiche (angepasst - das heißt ignorieren), während abc.ml und x/abc.ml auch die gleiche (keine Übereinstimmung - das heißt nicht ignorieren) behandelt werden.

Also, vielleicht ist der logische Fehler woanders in Mercurial, oder vielleicht schaue ich auf das falsche Bit von Mercurial (obwohl ich überrascht sein würde, wenn das der Fall wäre). Wenn ich nicht etwas verpasst habe, muss vielleicht ein Bug (anstatt eines RFE, auf den Martin Geisler hingewiesen hat) gegen Mercurial eingereicht werden.

+0

Wenn Sie auf meine erste Antwort reagieren, als ich von^re /.+ zu ^. + Gewechselt habe (wie die Frage lautet), konnte ich das Problem reproduzieren. (Also habe ich diese Antwort gelöscht.) Anscheinend hat das etwas mit dem angegebenen Verzeichnis zu tun, was mich zum aktuellen Vorschlag geführt hat. Ich habe die Quelle von hg nicht angeschaut, aber aufgrund dieser externen Tests scheint es, dass das Problem irgendwo da ist. –

+0

Äh - ja, ich habe Ihre erste (jetzt gelöschte) Antwort kommentiert. Wie auch immer, meine Tests scheinen auf den regulären Ausdruck zu verweisen, der die Ursache des Problems ist. –

Verwandte Themen