On Fri February 23 2007 10:33, Tailor wrote:
> #97: Monotone to SVN fails
> ----------------------+------------------------------------------
>----------- Reporter: stelios | Owner: lele
> Type: defect | Status: new
> Priority: major | Milestone: VersionOne
> Component: tailor | Version: 0.9
> Resolution: | Keywords:
> ----------------------+------------------------------------------
>----------- Comment (by stelios):
>
> Has anyone been able to look into this ?
I see this as well, it is apparently triggered by a "Revisions: ..."
string in a ChangeLog body.
The patch below seems to fix this precise problem but I am not a regular
monotone user so it might break something else I am not aware of.
Robin
-------------------------------------------------------------------
monotone: restrict order of headers in revision logs
Since monotone does not indent the user provided log message that
follows a ChangeLog header, collisions can happen between a monotone
header and a line in the log message.
According to monotone's sources, the last two headers in a revision
log are, in order, ChangeLog and Comments. Hence, while parsing the
log message, we can consider any line not starting with Comments: as
part of the log message.
diff --git a/vcpx/repository/monotone.py b/vcpx/repository/monotone.py
--- a/vcpx/repository/monotone.py
+++ b/vcpx/repository/monotone.py
@@ -251,12 +251,9 @@ class MonotoneLogParser:
# 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
- LOG = 5 # in changelog listing
- CMT = 6 # in comment listing
+ MOD = 1 # in modification file/dir listing
+ LOG = 2 # in changelog listing
+ CMT = 3 # in comment listing
def __init__(self, repository, working_dir):
self.working_dir = working_dir
@@ -304,65 +301,61 @@ class MonotoneLogParser:
state = self.SINGLE
loglines = outstr[0].getvalue().splitlines()
for curline in loglines:
-
+ if state == self.MOD:
+ # skip dir/file add/remove/rename information
+ if curline[:1].isspace():
+ continue
+ state = self.SINGLE
pr = self.PrefixRemover(curline)
+ if state == self.LOG:
+ # only a Comment section can follow a ChangeLog section
+ if pr("Comments:"):
+ comments = comments + "Note:\n"
+ state = self.CMT
+ else:
+ # log line, accumulate string
+ logs = logs + curline + "\n"
+ continue
+ if state == self.CMT:
+ # comment line, accumulate string
+ comments = comments + curline + "\n"
+ continue
+ # state == self.SINGLE
if pr("Revision:"):
if pr.value != revision:
raise GetUpstreamChangesetsFailure(
- "Revision doesn't match. Expected %s, found %s" %
(revision, pr.value))
- state = self.SINGLE
+ "Revision doesn't match. Expected %s, found %s" %
+ (revision, pr.value))
elif pr("Ancestor:"):
if pr.value:
- self.ancestors.append(pr.value) # cset could be a merge
and have multiple ancestors
- state = self.SINGLE
+ # cset could be a merge and have multiple ancestors
+ self.ancestors.append(pr.value)
elif pr("Author:"):
self.authors.append(pr.value)
- state = self.SINGLE
elif pr("Date:"):
- # monotone dates are expressed in ISO8601, always UTC
- dateparts = pr.value.split('T')
- assert len(dateparts) >= 2, `dateparts`
- day = dateparts[0]
- time = dateparts[1]
- y,m,d = map(int, day.split(day[4]))
- hh,mm,ss = map(int, time.split(':'))
- date = datetime(y,m,d,hh,mm,ss,0,UTC)
- self.dates.append(date)
- state = self.SINGLE
+ # monotone dates are expressed in ISO8601, always UTC
+ dateparts = pr.value.split('T')
+ assert len(dateparts) >= 2, `dateparts`
+ day = dateparts[0]
+ time = dateparts[1]
+ y,m,d = map(int, day.split(day[4]))
+ hh,mm,ss = map(int, time.split(':'))
+ date = datetime(y,m,d,hh,mm,ss,0,UTC)
+ self.dates.append(date)
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("Added files:") or pr("Added directories:") or \
+ pr("Deleted files:") or pr("Deleted directories:") or \
+ pr("Deleted entries:") or pr("Renamed files:") or \
+ pr("Renamed directories:") or pr("Renamed entries:") or \
+ pr("Modified files:"):
+ state = self.MOD
elif pr("ChangeLog:"):
- state=self.LOG
+ 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"
- else:
- # parse_cset_entry(mode, chset, curline.strip()) # cset
entry, handle
- pass # we ignore cset info
+ comments = comments + "Note:\n"
+ state = self.CMT
# parsing terminated, verify the data
if len(self.authors)<1 or len(self.dates)<1 or revision=="":
_______________________________________________
Tailor mailing list
[email protected]
http://lists.zooko.com/mailman/listinfo/tailor