Replace the MonotoneLogParser with a MonotoneCertsParser
Is more robust and gets all informations about the revision.
Remove the deal with supportsLogRevision and supportsLogNoGraph.
Added "Tag" and "Testresult" to changelog.
Complete patch with more fixups can found on:
http://www.henrynestler.com/tailor/monotone-complete-20070603.patch
--
Henry N.
# Replace the MonotoneLogParser with a MonotoneCertsParser
# Is more robust and gets all informations about the revision.
# Remove the deal with supportsLogRevision and supportsLogNoGraph.
# Added "Tag" and "Testresult" to changelog.
#
# Warning: Monotone 'log' and 'list certs' depens with tokens
# on LANG setting.
#
# 2007-06-03 Henry(at)Bigfoot.de
#
--- tailor-snapshot/vcpx/repository/monotone.py
+++ tailor-20070603/vcpx/repository/monotone.py
@@ -51,66 +51,6 @@
cget(self.name, '%s-keygenid' % self.which)
self.custom_lua = cget(self.name, 'custom_lua') or \
cget(self.name, '%s-custom_lua' % self.which)
- self._supportsLogRevision = Unknown
- self._supportsLogNoGraph = Unknown
-
- def supportsLogRevision(self, working_dir, revision):
- """
- In Monotone 0.32, ``mtn log --revision`` was changed to ``mtn
- log --from``. This function returns True if ``--revision``
- is supported or False otherwise.
-
- FIXME: To call this method, you have to actually pass working_dir
- and a revision to it. Ideally, this is unnecessary and it is
- really just a hack. Perhaps a better way to do this is to have a
- ``log`` method on the MonotoneRepository class.
- """
-
- # Lazily (upon first request) attempt to determine the value
- # of this variable:
- if self._supportsLogRevision is Unknown:
- cmd = self.command("log",
- "--db", self.repository,
- "--last", "1",
- "--revision", revision)
- mtl = ExternalCommand(cwd=working_dir, command=cmd)
- outstr = mtl.execute(stdout=PIPE, stderr=PIPE)
- if mtl.exit_status:
- self._supportsLogRevision = False
- else:
- self._supportsLogRevision = True
-
- return self._supportsLogRevision
-
- def supportsLogNoGraph(self, working_dir, revision):
- """
- In Monotone 0.33, the log message format was changed and the
- ``mtn log --no-graph`` option was added to revert to the prior log
- format. Since this new format is intended for pretty-printing,
- it is not very helpful when screen-scraping.
-
- FIXME: (see the FIXME in supportsLogRevision)
- """
-
- # Lazily (upon first request) attempt to determine the value
- # of this variable:
- if self._supportsLogNoGraph is Unknown:
- if not self.supportsLogRevision(working_dir, revision):
- cmd = self.command("log",
- "--db", self.repository,
- "--last", "1",
- "--from", revision,
- "--no-graph") # <- we're testing for this!
- mtl = ExternalCommand(cwd=working_dir, command=cmd)
- outstr = mtl.execute(stdout=PIPE, stderr=PIPE)
- if mtl.exit_status:
- self._supportsLogNoGraph = False
- else:
- self._supportsLogNoGraph = True
- else:
- self._supportsLogNoGraph = False
-
- return self._supportsLogNoGraph
def create(self):
"""
@@ -228,9 +168,9 @@
self.branches = branches
-class MonotoneLogParser:
+class MonotoneCertsParser:
"""
- Obtain and parse a *single* "mtn log" output, reconstructing
+ Obtain and parse a "mtn list certs" output, reconstructing
the revision information
"""
@@ -240,23 +180,27 @@
"""
def __init__(self, str):
self.str = str
- self.value=""
+ pos = str.find(': ')
+ if pos > 5:
+ self.value = self.str[pos+2:]
+ else:
+ self.value = ""
def __call__(self, prefix):
if self.str.startswith(prefix):
- self.value = self.str[len(prefix):].strip()
return True
else:
return False
- # logfile states
- SINGLE = 0 # single line state
- ADD = 1 # in add file/dir listing
- MOD = 2 # in mod file/dir listing
- DEL = 3 # in delete file/dir listing
- REN = 4 # in renamed file/dir listing
+ # certs states
+ DUMMY = 0 # Nothing or unknown
+ AUTHOR = 1 # Author, multiple
+ BRANCH = 2 # Branch
+ DATE = 3 # Date, multiple
+ TAG = 4 # in tags listing
LOG = 5 # in changelog listing
CMT = 6 # in comment listing
+ TESTRESULT = 7 # in tags listing
def __init__(self, repository, working_dir):
self.working_dir = working_dir
@@ -272,53 +216,62 @@
self.changelog=""
self.branches=[]
- cmd = None
-
- logRevision = self.repository.supportsLogRevision(self.working_dir,
- revision)
- logNoGraph = self.repository.supportsLogNoGraph(self.working_dir,
- revision)
- if logRevision: # <= Montone-0.31
- cmd = self.repository.command("log",
- "--db", self.repository.repository,
- "--last", "1",
- "--revision", revision)
- elif not logRevision and not logNoGraph: # Monotone-0.32
- cmd = self.repository.command("log",
- "--db", self.repository.repository,
- "--last", "1",
- "--from", revision)
- elif not logRevision and logNoGraph: # Monotone-0.33
- cmd = self.repository.command("log",
- "--db", self.repository.repository,
- "--last", "1",
- "--from", revision,
- "--no-graph")
+ # Get ancestors from automate parents
+ cmd = self.repository.command("automate", "parents", revision,
+ "--db", self.repository.repository)
mtl = ExternalCommand(cwd=self.working_dir, command=cmd)
outstr = mtl.execute(stdout=PIPE, stderr=PIPE)
if mtl.exit_status:
- raise GetUpstreamChangesetsFailure("mtn log returned status %d" % mtl.exit_status)
+ raise GetUpstreamChangesetsFailure("mtn automate parents returned "
+ "status %d" % mtl.exit_status)
+ self.ancestors = outstr[0].getvalue().splitlines()
+
+ # Get informations about revision from list certs
+ cmd = self.repository.command("list", "certs", revision,
+ "--db", self.repository.repository)
+ mtl = ExternalCommand(cwd=self.working_dir, command=cmd)
+ outstr = mtl.execute(stdout=PIPE, stderr=PIPE)
+ if mtl.exit_status:
+ raise GetUpstreamChangesetsFailure("mtn list certs returned "
+ "status %d" % mtl.exit_status)
+ tags = ""
logs = ""
comments = ""
- state = self.SINGLE
+ state = self.DUMMY
loglines = outstr[0].getvalue().splitlines()
for curline in loglines:
+ if curline.startswith("---") or len(curline) < 6:
+ state = self.DUMMY
+ continue
+
pr = self.PrefixRemover(curline)
- if pr("Revision:"):
- if pr.value != revision:
- raise GetUpstreamChangesetsFailure(
- "Revision doesn't match. Expected %s, found %s" % (revision, pr.value))
- state = self.SINGLE
- elif pr("Ancestor:"):
- if pr.value:
- self.ancestors.append(pr.value) # cset could be a merge and have multiple ancestors
- state = self.SINGLE
- elif pr("Author:"):
- self.authors.append(pr.value)
- state = self.SINGLE
- elif pr("Date:"):
+ if pr("Name"):
+ if pr.value == "author":
+ state = self.AUTHOR
+ elif pr.value == "branch":
+ state = self.BRANCH
+ elif pr.value == "date":
+ state = self.DATE
+ elif pr.value == "changelog":
+ state = self.LOG
+ elif pr.value == "comment":
+ comments = comments + "\nNote:\n"
+ state = self.CMT
+ elif pr.value == "tag":
+ state = self.TAG
+ elif pr.value == "testresult":
+ state = self.TESTRESULT
+ else:
+ state = self.DUMMY
+ elif pr("Value") or pr(" "):
+ if state == self.AUTHOR:
+ self.authors.append(pr.value)
+ elif state == self.BRANCH:
+ # branch data
+ self.branches.append(pr.value)
+ elif state == self.DATE:
# monotone dates are expressed in ISO8601, always UTC
dateparts = pr.value.split('T')
assert len(dateparts) >= 2, `dateparts`
@@ -328,46 +281,29 @@
hh,mm,ss = map(int, time.split(':'))
date = datetime(y,m,d,hh,mm,ss,0,UTC)
self.dates.append(date)
- state = self.SINGLE
- elif pr("Branch:"):
- # branch data
- self.branches.append(pr.value)
- state = self.SINGLE
- elif pr("Tag"):
- # unused data, just resetting state
- state = self.SINGLE
- elif pr("Deleted files:") or pr("Deleted directories:") or pr("Deleted entries"):
- state=self.DEL
- elif pr("Renamed files:") or pr("Renamed directories:") or pr("Renamed entries"):
- state=self.REN
- elif pr("Added files:") or pr("Added directories:"):
- state=self.ADD
- elif pr("Modified files:"):
- state=self.ADD
- elif pr("ChangeLog:"):
- state=self.LOG
- elif pr("Comments:"):
- comments=comments + "Note:\n"
- state=self.CMT
- else:
- # otherwise, it must be a log/comment/changeset entry, or an unknown cert line
- if state == self.SINGLE:
- # line coming from an unknown cert
- pass
- elif state == self.LOG:
- # log line, accumulate string
- logs = logs + curline + "\n"
elif state == self.CMT:
# comment line, accumulate string
- comments = comments + curline + "\n"
+ comments = comments + pr.value + "\n"
+ elif state == self.LOG:
+ # log line, accumulate string
+ logs = logs + pr.value + "\n"
+ elif state == self.TAG:
+ # Tag print into ChangeLog
+ tags = tags + "Tag: " + pr.value + "\n"
+ elif state == self.TESTRESULT:
+ # Testresult print into ChangeLog
+ tags = tags + "Testresult: " + pr.value + "\n"
else:
- # parse_cset_entry(mode, chset, curline.strip()) # cset entry, handle
pass # we ignore cset info
+ elif pr("Key") or pr("Sig"):
+ pass # we ignore cset info
+ else:
+ raise GetUpstreamChangesetsFailure("Unexpected certs token: '%s' " % curline)
# parsing terminated, verify the data
if len(self.authors)<1 or len(self.dates)<1 or revision=="":
- raise GetUpstreamChangesetsFailure("Error parsing log of revision %s. Missing data" % revision)
- self.changelog = logs + comments
+ raise GetUpstreamChangesetsFailure("Error parsing certs of revision %s. Missing data" % revision)
+ self.changelog = tags + logs + comments
def convertLog(self, chset):
self.parse(chset.revision)
@@ -571,8 +507,8 @@
The revision itself is real, only its ancestors (and all changes
between) are faked.
- To properly do this, changeset are created by a mixture of 'log'
- and 'diff' output. Log gives the revision data, diff the
+ To properly do this, changeset are created by a mixture of 'list
+ certs' and 'diff' output. Certs gives the revision data, diff the
differences beetween revisions.
Monotone also supports multiple authors/tags/comments for each
@@ -595,13 +531,13 @@
"Note:" line
tag
- not used by tailor. Ignored
+ all tags are appended to the changelog string, prefixed by a "Tag:"
branch
used to restrict source revs (tailor follows only a single branch)
testresult
- ignored
+ appedned to changelog string, ptrfixed by a "Testresult:"
other certs
ignored
@@ -623,7 +559,7 @@
self.working_dir = working_dir
self.repository = repository
self.branch = branch
- self.logparser = MonotoneLogParser(repository=repository,
+ self.logparser = MonotoneCertsParser(repository=repository,
working_dir=working_dir)
self.diffparser = MonotoneDiffParser(repository=repository,
working_dir=working_dir)
_______________________________________________
Tailor mailing list
[email protected]
http://lists.zooko.com/mailman/listinfo/tailor