From a3fac7c1f3bf8a5deadb600ea6d1d096e3be891f Mon Sep 17 00:00:00 2001 From: "Eric S. Raymond" Date: Fri, 12 Nov 2010 10:56:38 -0500 Subject: [PATCH] Checkpoint. 32% translated. --- rcs-fast-export | 788 ++++++++++++++++++++++++------------------------ 1 file changed, 392 insertions(+), 396 deletions(-) diff --git a/rcs-fast-export b/rcs-fast-export index 858bced..33c6133 100644 --- a/rcs-fast-export +++ b/rcs-fast-export @@ -8,11 +8,10 @@ TODO * Optimize memory usage by discarding unneeded text """ -import sys +import sys, os, stat import pprint # Functional equivalent of Ruby pp? def usage(): - print >>sys.stderr, """\ rcs-fast-export [options] file [file ...] @@ -78,16 +77,18 @@ class FatalException: self.msg = msg class RCS: + RCS.marks = {} + @staticmethod def clean(arg): - # strip an optional final ; + "Strip an optional final ;" if arg.endswith(";"): arg = arg[:-1] return arg @staticmethod def sanitize(arg): - # strip the first and last @, and de-double @@s + "Strip the first and last @, and de-double @@s" if type(arg) == type([]): if not arg[0].startswith("@@"): raise FatalException('malformed first line') @@ -109,375 +110,371 @@ class RCS: @staticmethod def at_clean(arg): - # clean and sanitize + "Clean and sanitize." return RCS.sanitize(RCS.clean(arg)) - def RCS.mark(key) - @@marks ||= {} - if @@marks.key? key - @@marks[key] - else - @@marks[key] = @@marks.length + 1 - end - end - - def RCS.blob(file, rev) - RCS.mark([file, rev]) - end - - def RCS.commit(commit) - RCS.mark(commit) - end + @staticmethod + def mark(key): + "Return a sequence mark for an object, which may be a blob or a commit." + if not key in RCS.marks: + RCS.marks[key] = len(RCS.marks)+1 + return RCS.marks[key] - class File - attr_accessor :head, :comment, :desc, :revision, :fname, :mode - def initialize(fname, executable) - @fname = fname.dup - @head = nil - @comment = nil - @desc = [] - @revision = Hash.new { |h, r| h[r] = Revision.new(self, r) } - @mode = executable ? '755' : '644' - end + @staticmethod + def blob(file, rev): + return RCS.mark([file, rev]) - def has_revision?(rev) - @revision.has_key?(rev) and not @revision[rev].author.nil? - end + @staticmethod + def commit(commit): + return RCS.mark(commit) + + class File: + def __init__(master): + self.fname = master + self.head = None + self.comment = None + self.desc = [] + self.revision = {} #Hash.new { |h, r| h[r] = Revision.new(self, r) } + executable = stat.S_IXUSER(os.stat(master)[stat.ST_MODE]) + self.mode = '755' if executable else '644' + + def has_revision(rev): + return rev in revision and self.revision[rev].author is not None + + def export_commits(opts): + counter = 0 + exported = [] + while self.revision: + counter += 1 + + # a string sort is a very good candidate for + # export order, getting a miss only for + # multi-digit revision components + keys = self.revision.keys() + keys.sort() + + print >>sys.stderr,"commit export loop %d" % counter + if exported: + print >>sys.stderr,"\t#%d commits exported so far: %s" % ", ".join(exported) + print >>sys.stderr,"\t#%d to export: %s" % (len(keys), ",".join(keys)) + for key in keys: + rev = self.revision[key] + # the parent commit is rev.next if we're on the + # master branch (rev.branch is None) or + # rev.diff_base otherwise + if rev.branch is None: + parent = rev.next + else: + parent = rev.diff_base + # A commit can only be exported if it has no + # parent, or if the parent has been exported + # already. Skip this commit otherwise + if parent and parent not in exported: + continue + + branch = rev.branch or 'master' + author = opts.authors[rev.author] or (rev.author + " ") + date = `rev.date.tv_sec` + " +0000" + log = "" + if opts.log_filename: + log += self.fname + ": " + log += rev.log.to_s + + print "commit refs/heads/" + branch + print "mark :" + RCS.commit(key) + print "committer %s %s" % (author, date) + print "data %d" % len(log) + if log: + print log + if rev.branch_point: + print "from :" + RCS.commit(parent) + print "M %s :%s %s" % (RCS.blob(self.fname, key), fname) + # TODO FIXME this *should* be safe, in + # that it should not unduly move + # branches back in time, but I'm not + # 100% sure ... + for sym in rev.branches: + print "reset refs/heads/" + sym + print "from :" + RCS.commit(key) + for sym in rev.symbols: + print "reset refs/tags/" + sym + print "from :" + RCS.commit(key) + if opts.tag_each_rev: + print "reset refs/tags/" + key + print "from :" + RCS.commit(key) + exported.append(key) + for k in exported: del self.revision[k] + + class Revision: + def __init__(fileobj, rev): + self.file = fileobj + self.rev = rev + self.author = None + self.date = None + self.state = None + self.next = None + self.branches = [] + self.branch = None + self.branch_point = None + self.diff_base = None + self.log = [] + self.text = [] + self.symbols = set([]) + def __hash__(self): + return hash(file, rev) + #def date=(str) + # @date = Time.rcs(str) + #end + def blob(self): + str = "".join(self.text) + return "blob\nmark :#%s\ndata %d\n%s\n" \ + (RCS.blob(self.file.fname, self.rev), len(str), str) - def export_commits(opts={}) - counter = 0 - exported = [] - until @revision.empty? - counter += 1 - - # a string sort is a very good candidate for - # export order, getting a miss only for - # multi-digit revision components - keys = @revision.keys.sort - - STDERR.puts "commit export loop ##{counter}" - STDERR.puts "\t#{exported.length} commits exported so far: #{exported.join(', ')}" unless exported.empty? - STDERR.puts "\t#{keys.size} to export: #{keys.join(', ')}" - - keys.each do |key| - rev = @revision[key] - # the parent commit is rev.next if we're on the - # master branch (rev.branch is nil) or - # rev.diff_base otherwise - from = rev.branch.nil? ? rev.next : rev.diff_base - # A commit can only be exported if it has no - # parent, or if the parent has been exported - # already. Skip this commit otherwise - if from and not exported.include? from - next - end - - branch = rev.branch || 'master' - author = opts[:authors][rev.author] || "#{rev.author} " - date = "#{rev.date.tv_sec} +0000" - log = String.new - if opts[:log_filename] - log << @fname << ": " - end - log << rev.log.to_s - - puts "commit refs/heads/#{branch}" - puts "mark :#{RCS.commit key}" - puts "committer #{author} #{date}" - puts "data #{log.length}" - puts log unless log.empty? - puts "from :#{RCS.commit from}" if rev.branch_point - puts "M #{@mode} :#{RCS.blob @fname, key} #{@fname}" - - # TODO FIXME this *should* be safe, in - # that it should not unduly move - # branches back in time, but I'm not - # 100% sure ... - rev.branches.each do |sym| - puts "reset refs/heads/#{sym}" - puts "from :#{RCS.commit key}" - end - rev.symbols.each do |sym| - puts "reset refs/tags/#{sym}" - puts "from :#{RCS.commit key}" - end - if opts[:tag_each_rev] - puts "reset refs/tags/#{key}" - puts "from :#{RCS.commit key}" - end - - exported.push key - end - exported.each { |k| @revision.delete(k) } + @staticmethod + def parse(rcsfile): + rcs = RCS.File(rcsfile) + status = ["basic"] + rev = None + lines = [] + difflines = [] + linebuffer = [] + with file(rcs.fname) as fp: + while True: + if linebuffer: + line = linebuffer.pop() + else: + line = fp.readline() + if not line: + break + if status[-1] == "basic": + m = re.match(r"^([a-z]+)\s+([^;]*);?", line) + if not m: + raise FatalException("failed to find command") + command = m.group(1) + args = m.group(2) + if not command: + if debug: + print >>sys.stderr,"Skipping empty command" + continue + if command == 'head': + rcs.head = RCS.clean(args) + continue + if command == 'symbols': + status.append('symbols') + if args: + linebuffer.append(args) + continue + if command == 'comment': + rcs.comment = RCS.at_clean(args) + continue + m = re.match("^[0-9.]+$", command) + if m: + rev = command + if rcs.has_revision(rev): + status.appand("revision_data") + else: + status.append("new_revision") + continue + if command == 'desc': + status.append("desc") + lines = [] + status.append("read_lines") + continue + if command in ('branch', 'access', 'locks', 'expand'): + if debug: + print >>sys.stderr,"Skipping unhandled command %s" % command + status.append("skipping_lines") + if args: + linebuffer.apppend(args) + continue + raise FatalException("Unknown command %s" % command) + elif status[-1] == "skipping_lines": + if line.strip.endswith(";"): + status.pop() + continue + elif status[-1] == "symbols": + # we can have multiple symbols per line + for pair in line.strip().split(";"): + if not pair: + status.pop() + else: + (sym, rev) = pair.strip().split(':') + if rev: + rcs.revision[rev].symbols.append(sym) + else: + status.pop() + when :desc + rcs.desc.replace lines.dup + status.pop + when :read_lines + # we sanitize lines as we read them + + actual_line = line.dup + + # the first line must begin with a @, which we strip + if lines.empty? + ats = line.match(/^@+/) + raise 'malformed line' unless ats + actual_line.replace line.sub(/^@/,'') + end + + # if the line ends with an ODD number of @, it's the + # last line -- we work on actual_line so that content + # such as @\n or @ work correctly (they would be + # encoded respectively as ['@@@\n','@\n'] and + # ['@@@@\n'] + ats = actual_line.chomp.match(/@+$/) + if nomore = (ats && Regexp.last_match(0).length.odd?) + actual_line.replace actual_line.chomp.sub(/@$/,'') + end + lines << actual_line.gsub('@@','@') + if nomore + status.pop + redo + end + when :new_revision + case line.chomp + when /^date\s+(\S+);\s+author\s+(\S+);\s+state\s+(\S+);$/ + rcs.revision[rev].date = $1 + rcs.revision[rev].author = $2 + rcs.revision[rev].state = $3 + when 'branches' + status.push :branches + when /branches\s*;/ + next + when /^next\s+(\S+)?;$/ + nxt = rcs.revision[rev].next = $1 + next unless nxt + raise "multiple diff_bases for #{nxt}" unless rcs.revision[nxt].diff_base.None? + rcs.revision[nxt].diff_base = rev + rcs.revision[nxt].branch = rcs.revision[rev].branch + else + status.pop + end + when :branches + candidate = line.split(';',2) + branch = candidate.first.strip + rcs.revision[rev].branches.push branch + raise "multiple diff_bases for #{branch}" unless rcs.revision[branch].diff_base.None? + rcs.revision[branch].diff_base = rev + # we drop the last number from the branch name + rcs.revision[branch].branch = branch.sub(/\.\d+$/,'.x') + rcs.revision[branch].branch_point = rev + status.pop if candidate.length > 1 + when :revision_data + case line.chomp + when 'log' + status.push :log + lines.clear + status.push :read_lines + when 'text' + if rev == rcs.head + status.push :head + else + status.push :diff + end + lines.clear + status.push :read_lines + else + status.pop + end + when :log + rcs.revision[rev].log.replace lines.dup + status.pop + when :head + rcs.revision[rev].text.replace lines.dup + print rcs.revision[rev].blob + status.pop + when :diff + difflines.replace lines.dup + difflines.pop if difflines.last.empty? + base = rcs.revision[rev].diff_base + unless rcs.revision[base].text + pp rcs + print rev, base + raise 'no diff base!' + end + # deep copy + buffer = [] + rcs.revision[base].text.each { |l| buffer << [l.dup] } + + adding = false + index = None + count = None + + while l = difflines.shift + if adding + raise 'negative index during insertion' if index < 0 + raise 'negative count during insertion' if count < 0 + adding << l + count -= 1 + # collected all the lines, put the before + unless count > 0 + unless buffer[index] + buffer[index] = [] + end + buffer[index].unshift(*adding) + adding = false + end + next + end + + l.chomp! + raise 'malformed diff' unless l =~ /^([ad])(\d+) (\d+)$/ + diff_cmd = $1.intern + index = $2.to_i + count = $3.to_i + case diff_cmd + when :d + # for deletion, index 1 is the first index, so the Ruby + # index is one less than the diff one + index -= 1 + # we replace them with empty string so that 'a' commands + # referring to the same line work properly + while count > 0 + buffer[index].clear + index += 1 + count -= 1 + end + when :a + # addition will prepend the appropriate lines + # to the given index, and in this case Ruby + # and diff indices are the same + adding = [] + end + end + + # turn the buffer into an array of lines, deleting the empty ones + buffer.delete_if { |l| l.empty? } + buffer.flatten! + + rcs.revision[rev].text = buffer + print rcs.revision[rev].blob + status.pop + else + raise "Unknown status #{status.last}" + end + end + end + + # clean up the symbols/branches: look for revisions that have + # one or more symbols but no dates, and make them into + # branches, pointing to the highest commit with that key + branches = [] + keys = rcs.revision.keys + rcs.revision.each do |key, rev| + if rev.date.None? and not rev.symbols.empty? + top = keys.select { |k| k.match(/^#{key}\./) }.sort.last + tr = rcs.revision[top] + raise "unhandled complex branch structure met: #{rev.inspect} refers #{tr.inspect}" if tr.date.None? + tr.branches |= rev.symbols + branches << key end end - end - - class Revision - attr_accessor :rev, :author, :state, :next - attr_accessor :branches, :log, :text, :symbols - attr_accessor :branch, :diff_base, :branch_point - attr_reader :date - def initialize(file, rev) - @file = file - @rev = rev - @author = nil - @date = nil - @state = nil - @next = nil - @branches = [] - @branch = nil - @branch_point = nil - @diff_base = nil - @log = [] - @text = [] - @symbols = Set.new - end - - def date=(str) - @date = Time.rcs(str) - end - - def blob - str = @text.join('') - ret = "blob\nmark :#{RCS.blob @file.fname, @rev}\ndata #{str.length}\n#{str}\n" - ret - end - end - - def RCS.parse(fname, rcsfile) - rcs = RCS::File.new(fname, ::File.executable?(rcsfile)) - - ::File.open(rcsfile, 'r') do |file| - status = [:basic] - rev = nil - lines = [] - difflines = [] - file.each_line do |line| - case status.last - when :basic - command, args = line.split($;,2) - next if command.empty? - - if command.chomp!(';') - STDERR.puts "Skipping empty command #{command.inspect}" if $DEBUG - next - end - - case command - when 'head' - rcs.head = RCS.clean(args.chomp) - when 'symbols' - status.push :symbols - next if args.empty? - line = args; redo - when 'comment' - rcs.comment = RCS.at_clean(args.chomp) - when /^[0-9.]+$/ - rev = command.dup - if rcs.has_revision?(rev) - status.push :revision_data - else - status.push :new_revision - end - when 'desc' - status.push :desc - lines.clear - status.push :read_lines - when 'branch', 'access', 'locks', 'expand' - STDERR.puts "Skipping unhandled command #{command.inspect}" if $DEBUG - status.push :skipping_lines - next if args.empty? - line = args; redo - else - raise "Unknown command #{command.inspect}" - end - when :skipping_lines - status.pop if line.strip.chomp!(';') - when :symbols - # we can have multiple symbols per line - pairs = line.strip.split($;) - pairs.each do |pair| - sym, rev = pair.strip.split(':',2); - if rev - status.pop if rev.chomp!(';') - rcs.revision[rev].symbols << sym - else - status.pop - end - end - when :desc - rcs.desc.replace lines.dup - status.pop - when :read_lines - # we sanitize lines as we read them - - actual_line = line.dup - - # the first line must begin with a @, which we strip - if lines.empty? - ats = line.match(/^@+/) - raise 'malformed line' unless ats - actual_line.replace line.sub(/^@/,'') - end - - # if the line ends with an ODD number of @, it's the - # last line -- we work on actual_line so that content - # such as @\n or @ work correctly (they would be - # encoded respectively as ['@@@\n','@\n'] and - # ['@@@@\n'] - ats = actual_line.chomp.match(/@+$/) - if nomore = (ats && Regexp.last_match(0).length.odd?) - actual_line.replace actual_line.chomp.sub(/@$/,'') - end - lines << actual_line.gsub('@@','@') - if nomore - status.pop - redo - end - when :new_revision - case line.chomp - when /^date\s+(\S+);\s+author\s+(\S+);\s+state\s+(\S+);$/ - rcs.revision[rev].date = $1 - rcs.revision[rev].author = $2 - rcs.revision[rev].state = $3 - when 'branches' - status.push :branches - when /branches\s*;/ - next - when /^next\s+(\S+)?;$/ - nxt = rcs.revision[rev].next = $1 - next unless nxt - raise "multiple diff_bases for #{nxt}" unless rcs.revision[nxt].diff_base.nil? - rcs.revision[nxt].diff_base = rev - rcs.revision[nxt].branch = rcs.revision[rev].branch - else - status.pop - end - when :branches - candidate = line.split(';',2) - branch = candidate.first.strip - rcs.revision[rev].branches.push branch - raise "multiple diff_bases for #{branch}" unless rcs.revision[branch].diff_base.nil? - rcs.revision[branch].diff_base = rev - # we drop the last number from the branch name - rcs.revision[branch].branch = branch.sub(/\.\d+$/,'.x') - rcs.revision[branch].branch_point = rev - status.pop if candidate.length > 1 - when :revision_data - case line.chomp - when 'log' - status.push :log - lines.clear - status.push :read_lines - when 'text' - if rev == rcs.head - status.push :head - else - status.push :diff - end - lines.clear - status.push :read_lines - else - status.pop - end - when :log - rcs.revision[rev].log.replace lines.dup - status.pop - when :head - rcs.revision[rev].text.replace lines.dup - puts rcs.revision[rev].blob - status.pop - when :diff - difflines.replace lines.dup - difflines.pop if difflines.last.empty? - base = rcs.revision[rev].diff_base - unless rcs.revision[base].text - pp rcs - puts rev, base - raise 'no diff base!' - end - # deep copy - buffer = [] - rcs.revision[base].text.each { |l| buffer << [l.dup] } - - adding = false - index = nil - count = nil - - while l = difflines.shift - if adding - raise 'negative index during insertion' if index < 0 - raise 'negative count during insertion' if count < 0 - adding << l - count -= 1 - # collected all the lines, put the before - unless count > 0 - unless buffer[index] - buffer[index] = [] - end - buffer[index].unshift(*adding) - adding = false - end - next - end - - l.chomp! - raise 'malformed diff' unless l =~ /^([ad])(\d+) (\d+)$/ - diff_cmd = $1.intern - index = $2.to_i - count = $3.to_i - case diff_cmd - when :d - # for deletion, index 1 is the first index, so the Ruby - # index is one less than the diff one - index -= 1 - # we replace them with empty string so that 'a' commands - # referring to the same line work properly - while count > 0 - buffer[index].clear - index += 1 - count -= 1 - end - when :a - # addition will prepend the appropriate lines - # to the given index, and in this case Ruby - # and diff indices are the same - adding = [] - end - end - - # turn the buffer into an array of lines, deleting the empty ones - buffer.delete_if { |l| l.empty? } - buffer.flatten! - - rcs.revision[rev].text = buffer - puts rcs.revision[rev].blob - status.pop - else - raise "Unknown status #{status.last}" - end - end - end - - # clean up the symbols/branches: look for revisions that have - # one or more symbols but no dates, and make them into - # branches, pointing to the highest commit with that key - branches = [] - keys = rcs.revision.keys - rcs.revision.each do |key, rev| - if rev.date.nil? and not rev.symbols.empty? - top = keys.select { |k| k.match(/^#{key}\./) }.sort.last - tr = rcs.revision[top] - raise "unhandled complex branch structure met: #{rev.inspect} refers #{tr.inspect}" if tr.date.nil? - tr.branches |= rev.symbols - branches << key - end - end - branches.each { |k| rcs.revision.delete k } + branches.each { |k| rcs.revision.delete k } - return rcs - end + return rcs + end class Tree def initialize(commit) @@ -581,24 +578,24 @@ class RCS: xdate = "#{numdate} +0000" key = numdate.to_s - puts "commit refs/heads/#{xbranch}" - puts "mark :#{RCS.commit key}" - puts "committer #{xauthor} #{xdate}" - puts "data #{xlog.length}" - puts xlog unless xlog.empty? + print "commit refs/heads/#{xbranch}" + print "mark :#{RCS.commit key}" + print "committer #{xauthor} #{xdate}" + print "data #{xlog.length}" + print xlog unless xlog.empty? # TODO branching support for multi-file export - # puts "from :#{RCS.commit from}" if self.branch_point - puts self.tree.to_s + # print "from :#{RCS.commit from}" if self.branch_point + print self.tree.to_s # TODO branching support for multi-file export # rev.branches.each do |sym| - # puts "reset refs/heads/#{sym}" - # puts "from :#{RCS.commit key}" + # print "reset refs/heads/#{sym}" + # print "from :#{RCS.commit key}" # end self.symbols.each do |sym| - puts "reset refs/tags/#{sym}" - puts "from :#{RCS.commit key}" + print "reset refs/tags/#{sym}" + print "from :#{RCS.commit key}" end end @@ -667,7 +664,7 @@ opts.each do |opt, arg| when '--authors-file' authors = load_authors_file(arg) redef = parse_options[:authors].keys & authors.keys - STDERR.puts "Authors file #{arg} redefines #{redef.join(', ')}" unless redef.empty? + print >>sys.stderr,"Authors file #{arg} redefines #{redef.join(', ')}" unless redef.empty? parse_options[:authors].merge!(authors) when '--rcs-suffixes' # TODO @@ -683,13 +680,13 @@ opts.each do |opt, arg| parse_options[:tag_each_rev] = true when '--no-tag-each-rev' # this is the default, which is fine since the missing key - # (default) returns nil which is false in Ruby + # (default) returns None which is false in Ruby parse_options[:tag_each_rev] = false when '--log-filename' parse_options[:log_filename] = true when '--no-log-filename' # this is the default, which is fine since the missing key - # (default) returns nil which is false in Ruby + # (default) returns None which is false in Ruby parse_options[:log_filename] = false when '' file_list << arg @@ -793,12 +790,12 @@ file_list.each do |arg| begin rcs << RCS.parse(filename, rcsfile) rescue Exception => e - STDERR.puts "Failed to parse #{filename} @ #{rcsfile}:#{$.}" + print >>sys.stderr,"Failed to parse #{filename} @ #{rcsfile}:#{$.}" raise e end end else - STDERR.puts "Cannot handle #{arg} of #{ftype} type" + print >>sys.stderr,"Cannot handle #{arg} of #{ftype} type" status |= 1 end end @@ -806,7 +803,7 @@ end if rcs.length == 1 rcs.first.export_commits(parse_options) else - STDERR.puts "Preparing commits" + print >>sys.stderr,"Preparing commits" commits = [] @@ -816,20 +813,20 @@ else end end - STDERR.puts "Sorting by date" + print >>sys.stderr,"Sorting by date" commits.sort! if $DEBUG - STDERR.puts "RAW commits (#{commits.length}):" + print >>sys.stderr,"RAW commits (#{commits.length}):" commits.each do |c| PP.pp c.to_a, $stderr end else - STDERR.puts "#{commits.length} single-file commits" + print >>sys.stderr,"#{commits.length} single-file commits" end - STDERR.puts "Coalescing [1] by date with fuzz #{parse_options[:commit_fuzz]}" + print >>sys.stderr,"Coalescing [1] by date with fuzz #{parse_options[:commit_fuzz]}" commits.reverse_each do |c| commits.reverse_each do |k| @@ -839,21 +836,21 @@ else next if k.date > c.date unless c.symbols.subset?(k.symbols) or k.symbols.subset?(c.symbols) if parse_options[:symbol_check] - STDERR.puts "Not coalescing #{c.log.inspect}\n\tfor (#{c.tree.filenames.join(', ')})\n\tand (#{k.tree.filenames.join(', ')})" - STDERR.puts "\tbecause their symbols disagree:\n\t#{c.symbols.to_a.inspect} and #{k.symbols.to_a.inspect} disagree on #{(c.symbols ^ k.symbols).to_a.inspect}" - STDERR.puts "\tretry with the --no-symbol-check option if you want to merge these commits anyway" + print >>sys.stderr,"Not coalescing #{c.log.inspect}\n\tfor (#{c.tree.filenames.join(', ')})\n\tand (#{k.tree.filenames.join(', ')})" + print >>sys.stderr,"\tbecause their symbols disagree:\n\t#{c.symbols.to_a.inspect} and #{k.symbols.to_a.inspect} disagree on #{(c.symbols ^ k.symbols).to_a.inspect}" + print >>sys.stderr,"\tretry with the --no-symbol-check option if you want to merge these commits anyway" next elsif $DEBUG - STDERR.puts "Coalescing #{c.log.inspect}\n\tfor (#{c.tree.filenames.join(', ')})\n\tand (#{k.tree.filenames.join(', ')})" - STDERR.puts "\twith disagreeing symbols:\n\t#{c.symbols.to_a.inspect} and #{k.symbols.to_a.inspect} disagree on #{(c.symbols ^ k.symbols).to_a.inspect}" + print >>sys.stderr,"Coalescing #{c.log.inspect}\n\tfor (#{c.tree.filenames.join(', ')})\n\tand (#{k.tree.filenames.join(', ')})" + print >>sys.stderr,"\twith disagreeing symbols:\n\t#{c.symbols.to_a.inspect} and #{k.symbols.to_a.inspect} disagree on #{(c.symbols ^ k.symbols).to_a.inspect}" end end begin c.merge! k rescue RuntimeError => err fuzz = c.date - k.date - STDERR.puts "Fuzzy commit coalescing failed: #{err}" - STDERR.puts "\tretry with commit fuzz < #{fuzz} if you don't want to see this message" + print >>sys.stderr,"Fuzzy commit coalescing failed: #{err}" + print >>sys.stderr,"\tretry with commit fuzz < #{fuzz} if you don't want to see this message" break end commits.delete k @@ -861,12 +858,12 @@ else end if $DEBUG - STDERR.puts "[1] commits (#{commits.length}):" + print >>sys.stderr,"[1] commits (#{commits.length}):" commits.each do |c| PP.pp c.to_a, $stderr end else - STDERR.puts "#{commits.length} coalesced commits" + print >>sys.stderr,"#{commits.length} coalesced commits" end commits.each { |c| c.export(parse_options) } @@ -874,6 +871,5 @@ else end exit status - -- 2.43.0