[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] cvs2svn.py multipath addition

From: Kim Lester <kim_at_dfusion.com.au>
Date: 2003-09-29 14:03:05 CEST

Enclosed are the patches for multipath support in cvs2svn.py.
Around half the changes are actually debugging lines that I used to help
me figure out how the tool worked and I think they might as well stay
for
future use (use -d to turn them on).
The existing couple of debug lines were converted to use -d too.

key new command line options:

--root=a/b --subroot=x/y --suppress-parents

=> /a/b/BBB/x/y where BBB is (by default) trunk | branches | tags
I guess the --root can be simulated with svnadmin load --parent-dir=a/b
  but this is self contained.

Here are my two sample use scripts to give you an idea. Note that the
--suppress-parents
was needed because we need to run cvs2svn multiple times (I could alter
the program
to do mulitple loops but the "long" way is actually more convenient.)
Because of this we must not output the common base dirs (essentially
--root, trunk|branches|tags, --subroot)
since svnadmin load will barf if it gets given an existing directory.
[Aside: Although load/dump is really a whole-of-repository command,
what about a -merge option to
not complain about existing DIRs !?]

So I independently create (by hand/script) the half a dozen or so base
dirs (a/b/trunk/x/y etc).
In this case I put them in a dump file import.basedirs in the sample
script.
If you ahve only ONE dumpfile then just drop the --suppress-parents and
your life will be simpler.

I have not fully tested this in terms of checking versions/revisions
properly, but I have done a couple
of simple consistency checks.

BTW this is my first attempt at reading/writing python so go easy on
code comments :-)

regards
        Kim

======= CVS DUMP SCRIPT=========
#!/bin/sh
#set -x

rm -f import.log
projs=`cd $CVSROOT/src; ls -d pkg/*/*`

for path in $projs
do
     # echo $path
     file=`basename $path`
     test.py --dump-only --dumpfile=import.dump.$file --suppress-parents
  --subroot=$path $CVSROOT/src/$path >> import.log
done
=======================

==== SAMPLE LOAD SCRIPT======
svnadmin load /usr/local/repository/svn < import.basedirs > log
svnadmin load /usr/local/repository/svn < import.dump.PkgA >> log
svnadmin load /usr/local/repository/svn < import.dump.PkgB >> log
...
========================

=====CVS2SVN DIFFS============
--- ../cvs2svn.py Mon Sep 29 21:24:58 2003
+++ cvs2svn_new.py Mon Sep 29 16:39:07 2003
@@ -97,6 +97,7 @@
      """Record that REVISION is the branch number for BRANCH_NAME.
      REVISION is an RCS branch number with an odd number of components,
      for example '1.7.2' (never '1.7.0.2')."""
+
      if self.branch_names.has_key(revision):
        sys.stderr.write("Error while parsing '%s':\n"
                         " branch %s already has name '%s',\n"
@@ -110,6 +111,7 @@
      """Return the name of the branch on which REVISION lies.
      REVISION is a non-branch evision number with an even number of,
      components, for example '1.7.2.1' (never '1.7.2' nor '1.7.0.2')."""
+
      return self.branch_names.get(revision[:revision.rindex(".")])

    def add_branch_point(self, revision, branch_name):
@@ -116,6 +118,7 @@
      """Record that BRANCH_NAME sprouts from REVISION.
      REVISION is a non-branch revision number with an even number of
      components, for example '1.7' (never '1.7.2' nor '1.7.0.2')."""
+
      if not self.branchlist.has_key(revision):
        self.branchlist[revision] = []
      self.branchlist[revision].append(branch_name)
@@ -289,6 +292,8 @@
    #
    # and the surrounding thread, for why what people really want is a
    # way of specifying an in-repository prefix path, not interpolation.
+ #
+ # Now supports various prefix and infixes - Kim Lester, Sept 03

    if branch_name and tag_name:
      sys.stderr.write('make_path() miscalled: both branch and tag
given.\n')
@@ -295,22 +300,28 @@
      sys.exit(1)

    if branch_name:
- if path:
- return ctx.branches_base + '/' + branch_name + '/' + path
- else:
- return ctx.branches_base + '/' + branch_name
+ base = ctx.branches_base
+ name = branch_name
    elif tag_name:
- if path:
- return ctx.tags_base + '/' + tag_name + '/' + path
- else:
- return ctx.tags_base + '/' + tag_name
+ base = ctx.tags_base
+ name = tag_name
    else:
- if path:
- return ctx.trunk_base + '/' + path
- else:
- return ctx.trunk_base
+ base = ctx.trunk_base
+ name = ""

+ if (path and path != ""):
+ p = os.path.join(ctx.root, base, ctx.subroot, name, path)
+ else:
+ p = os.path.join(ctx.root, base, ctx.subroot, name)

+ p = string.lstrip(p) # annoying os.path "bug", leading space
+
+ if ctx.debug:
+ print "MP: name:%s, path:%s, return:%s" %(name, path, p)
+
+ return p
+
+
  def relative_name(cvsroot, fname):
    l = len(cvsroot)
    if fname[:l] == cvsroot:
@@ -420,6 +431,7 @@
         The actual revision from which the path was copied, which
         may be one less than the requested revision when the path
         was deleted in the requested revision, or None."""
+
    def __init__(self, op, closed_tags, closed_branches,
                 deleted_entries=None, copyfrom_rev=None):
      self.op = op
@@ -475,6 +487,12 @@
      self.revs_db[str(self.youngest)] = gen_key()
      self.nodes_db[self.revs_db[str(self.youngest)]] = marshal.dumps({})

+ # Debug flag
+ self.debug = 0
+
+ def set_debug(self, debug):
+ self.debug = debug
+
    def new_revision(self):
      """Stabilize the current revision, then start the next one.
      (Increments youngest.)"""
@@ -498,7 +516,7 @@
      root_key = self.revs_db[str(self.youngest)]
      self._stabilize_directory(root_key)

- def probe_path(self, path, revision=-1, debugging=None):
+ def probe_path(self, path, revision=-1):
      """If PATH exists in REVISION of the svn repository mirror,
      return its leaf value, else return None.
      If DEBUGGING is true, then print trace output to stdout.
@@ -507,8 +525,8 @@
      if revision == -1:
        revision = self.youngest

- if debugging:
- print "PROBING path: '%s' in %d" % (path, revision)
+ if self.debug:
+ print "RM.probe_path: '%s' in %d" % (path, revision)

      parent_key = self.revs_db[str(revision)]
      parent = marshal.loads(self.nodes_db[parent_key])
@@ -517,14 +535,14 @@
      i = 1
      for component in components:

- if debugging:
+ if self.debug:
          print " " * i,
          print "'%s' key: %s, val:" % (previous_component, parent_key),
parent

        if not parent.has_key(component):
- if debugging:
- print " PROBE ABANDONED: '%s' does not contain '%s'" \
- % (previous_component, component)
+ if self.debug:
+ print " Probing path: Failed: '%s' does not contain '%s'" \
+ % (previous_component, component)
          return None

        this_entry_key = parent[component]
@@ -534,7 +552,7 @@
        previous_component = component
        i = i + 1

- if debugging:
+ if self.debug:
        print " " * i,
        print "parent_key: %s, val:" % parent_key, parent

@@ -541,8 +559,8 @@
      # It's not actually a parent at this point, it's the leaf node.
      return parent

- def change_path(self, path, tags, branches,
- intermediate_dir_func=None,
+ def change_path(self, path, tags, branches,
+ intermediate_dir_func=None, dir_suppress_thresh=0,
                    copyfrom_path=None, copyfrom_rev=None,
                    expected_entries=None):
      """Record a change to PATH. PATH may not have a leading slash.
@@ -575,6 +593,10 @@
      No action is taken for keys in EXPECTED_ENTRIES but not in the
      dst; it is assumed that the caller will compensate for these by
      calling change_path again with other arguments."""
+
+ if self.debug:
+ print "RM.change_path: path=", path
+
      if ((copyfrom_rev and not copyfrom_path) or
          (copyfrom_path and not copyfrom_rev)):
        sys.stderr.write("error: change_path() called with one copyfrom "
@@ -592,6 +614,7 @@
        self.nodes_db[parent_key] = marshal.dumps(parent)
        self.revs_db[str(self.youngest)] = parent_key

+ i = 1
      for component in components[:-1]:
        # parent is always mutable at the top of the loop

@@ -600,6 +623,9 @@
        else:
          path_so_far = component

+ if self.debug:
+ print " checking path: %s" % path_so_far
+
        # Ensure that the parent has an entry for this component.
        if not parent.has_key(component):
          new_child_key = gen_key()
@@ -606,9 +632,23 @@
          parent[component] = new_child_key
          self.nodes_db[new_child_key] =
marshal.dumps(self.empty_mutable_thang)
          self.nodes_db[parent_key] = marshal.dumps(parent)
+
          if intermediate_dir_func:
- intermediate_dir_func(path_so_far)
+ # if we are generating many dump files we need to prevent
+ # clashes on adding intermediate dirs more than once.
+ # since path_so_far is absolute and we know that all intermediate
+ # dirs are num_root_components + 1 (trunk/bra etc) +
num_subroot_comp - 1
+ if (i > dir_suppress_thresh):
+ if self.debug:
+ print " creating dir: %s" % path_so_far
+ intermediate_dir_func(path_so_far)
+ else:
+ if self.debug:
+ print " NOT creating dir (th:%d) %s" % \
+ (dir_suppress_thresh, path_so_far)

+ i = i + 1
+
        # One way or another, parent dir now has an entry for component,
        # so grab it, see if it's mutable, and DTRT if it's not. (Note
        # it's important to reread the entry value from the db, even
@@ -847,6 +887,8 @@
      self.revision = 0
      self.dumpfile = open(dumpfile_path, 'wb')
      self.repos_mirror = RepositoryMirror()
+ self.dir_suppress_thresh = 0
+ self.debug = 0

      # Initialize the dumpfile with the standard headers:
      #
@@ -855,7 +897,15 @@
      # the dumpfile, we'll tell svnadmin to ignore the UUID below.
      self.dumpfile.write('SVN-fs-dump-format-version: 2\n'
                          '\n')
+ def set_debug(self, debug):
+ self.debug = debug
+ self.repos_mirror.set_debug(debug)

+
+ def set_dir_suppress_threshold(self, thresh):
+ self.dir_suppress_thresh = thresh
+
+
    def start_revision(self, props):
      """Write the next revision, with properties, to the dumpfile.
      Return the newly started revision."""
@@ -925,6 +975,8 @@
      return self.revision

    def add_dir(self, path):
+ if self.debug:
+ print "add_dir: %s" % path
      self.dumpfile.write("Node-path: %s\n"
                          "Node-kind: dir\n"
                          "Node-action: add\n"
@@ -938,6 +990,10 @@
    def probe_path(self, path):
      """Return true if PATH exists in the youngest tree of the svn
      repository, else return None. PATH does not start with '/'."""
+
+ if self.debug:
+ print "dumper.probe_path: %s " % path
+
      if self.repos_mirror.probe_path(path) is None:
        return None
      else:
@@ -953,14 +1009,20 @@
      No action is taken for keys in ENTRIES but not in the dst; it is
      assumed that the caller will compensate for these by calling
      copy_path again with other arguments."""
+
      change = self.repos_mirror.change_path(svn_dst_path,
                                             [], [],
                                             self.add_dir,
+ self.dir_suppress_thresh,
                                             svn_src_path, svn_src_rev,
                                             entries)
      if change.op == 'A':
        # We don't need to include "Node-kind:" for copies; the loader
        # ignores it anyway and just uses the source kind instead.
+ if self.debug:
+ print "copy_path Add: %s (%d) -> %s" % \
+ (svn_src_path, change.copyfrom_rev, svn_dst_path)
+
        self.dumpfile.write('Node-path: %s\n'
                            'Node-action: add\n'
                            'Node-copyfrom-rev: %d\n'
@@ -969,6 +1031,9 @@
                            % (svn_dst_path, change.copyfrom_rev,
svn_src_path))

        for ent in change.deleted_entries:
+ if self.debug:
+ print "copy_path Delete: %s" % (svn_dst_path + '|' + ent)
+
          self.dumpfile.write('Node-path: %s\n'
                              'Node-action: delete\n'
                              '\n' % (svn_dst_path + '/' + ent))
@@ -980,6 +1045,7 @@
      change = self.repos_mirror.change_path(path,
                                             [], [],
                                             self.add_dir,
+ self.dir_suppress_thresh,
                                             None, None,
                                             expected)
      for ent in change.deleted_entries:
@@ -1022,7 +1088,8 @@
      # be perfectly reliable, both because of 'cvs commit -r', and also
      # the possibility of file resurrection.
      change = self.repos_mirror.change_path(svn_path, tags, branches,
- self.add_dir)
+ self.add_dir,
+ self.dir_suppress_thresh)

      if change.op == OP_ADD:
        action = 'add'
@@ -1029,6 +1096,9 @@
      else:
        action = 'change'

+ if self.debug:
+ print "add/change path: %s : %s" % (action, svn_path)
+
      self.dumpfile.write('Node-path: %s\n'
                          'Node-kind: file\n'
                          'Node-action: %s\n'
@@ -1220,18 +1290,18 @@
      self.tags_copyfrom_rev_key = "/tags-copyfrom-rev"
      self.br_copyfrom_rev_key = "/br-copyfrom-rev"

- def probe_path(self, symbolic_name, path, debugging=None):
+ def probe_path(self, symbolic_name, path):
      """If 'SYMBOLIC_NAME/PATH' exists in the symbolic name tree,
      return the value of its last component, else return None.
- PATH may be None, but may not start with '/'.
- If DEBUGGING is true, then print trace output to stdout."""
+ PATH may be None, but may not start with '/'."""
+
      if path:
        components = [symbolic_name] + string.split(path, '/')
      else:
        components = [symbolic_name]

- if debugging:
- print "PROBING SYMBOLIC NAME:\n", components
+ if self.debug:
+ print "SNT.probe_path:\n", components

      parent_key = self.root_key
      parent = marshal.loads(self.db[parent_key])
@@ -1238,7 +1308,7 @@
      last_component = "/"
      i = 1
      for component in components:
- if debugging:
+ if self.debug:
          print " " * i,
          print "'%s' key: %s, val:" % (last_component, parent_key),
parent

@@ -1254,7 +1324,7 @@
        last_component = component
        i = i + 1

- if debugging:
+ if self.debug:
        print " " * i,
        print "parent_key: %s, val:" % parent_key, parent

@@ -1261,6 +1331,7 @@
      # It's not actually a parent at this point, it's the leaf node.
      return parent

+
    def bump_rev_count(self, item_key, rev, revlist_key):
      """Increment REV's count in opening or closing list under KEY.
      REVLIST_KEY is self.*_opening_revs_key or self.*_closing_revs_key,
@@ -1471,6 +1542,11 @@
      symbolic name anywhere in this descent.

      ('JIT' == 'Just In Time'.)"""
+
+ if self.debug:
+ print "copy/descend: nm:%s en:%s pr:%d\n\tsp:%s, dp:%s
it:%s\n\tpa:
%s" % \
+ (name, entry_name, parent_rev, src_path, dst_path, is_tag, parent)
+
      ### Hmmm, is passing [1] instead of 1 an idiomatic way of passing
      ### a side-effectable boolean in Python? That's how the
      ### JIT_NEW_REV parameter works here and elsewhere, but maybe
@@ -1489,6 +1565,9 @@
        copyfrom_rev_key = self.br_copyfrom_rev_key

      if not val.has_key(copyfrom_rev_key):
+ #if self.debug:
+ # print " copy/descend: get best rev"
+
        # If not already copied this subdir, calculate its "best rev"
        # and see if it differs from parent's best rev.
        scores = self.score_revisions(val.get(opening_key),
val.get(closing_key))
@@ -1495,9 +1574,13 @@
        rev = self.best_rev(scores)

        if rev == SVN_INVALID_REVNUM:
+ # print " CD invalid rev num - END"
          return # name is a branch, but we're doing a tag, or vice
versa

        else:
+ if self.debug:
+ print " copy/descend: valid rev num %d" % rev
+
          if is_tag:
            copy_dst = make_path(ctx, dst_path, None, name)
          else:
@@ -1508,6 +1591,7 @@
            if jit_new_rev and jit_new_rev[0]:
              dumper.start_revision(make_revision_props(name, is_tag))
              jit_new_rev[0] = None
+
            dumper.copy_path(src_path, parent_rev, copy_dst, val)
            # Record that this copy is done:
            val[copyfrom_rev_key] = parent_rev
@@ -1522,6 +1606,9 @@
            # anything that's not part of the symbolic name.
            dumper.prune_entries(copy_dst, val)

+ if self.debug:
+ print " copy/descend: iterate over entries"
+
      for ent in val.keys():
        if not ent[0] == '/':
          if src_path:
@@ -1532,6 +1619,10 @@
            next_dst = dst_path + '/' + ent
          else:
            next_dst = ent
+
+ if self.debug:
+ print " copy/descend: ns:%s nd:%s" % (next_src, next_dst)
+
          self.copy_descend(dumper, ctx, name, val, ent, parent_rev,
                            next_src, next_dst, is_tag, jit_new_rev)

@@ -1567,6 +1658,9 @@
      # revisions 6028 and 6347). If it changes again, the logic here
      # must be adjusted to match.

+ if self.debug:
+ print "fill_name: create non-existant paths %s" % name
+
      parent_key = self.root_key
      parent = marshal.loads(self.db[parent_key])

@@ -1577,9 +1671,22 @@
          sys.stderr.write("No origin records for branch '%s'.\n" % name)
        sys.exit(1)

+ # gets child of name (ie skip trunk/branches/foo etc)
      parent_key = parent[name]
      parent = marshal.loads(self.db[parent_key])

+ comp_sp = []
+ if (ctx.root != ""):
+ comp_sp = string.split(ctx.root, '/')
+
+ # need to chain through ctx.root, not just take ctx.trunk_base
+ for comp in comp_sp:
+ if self.debug:
+ print " fill_name: getting child of %s" % comp
+ k = parent[comp]
+ parent = marshal.loads(self.db[k]) # contains the children of
parent k
+
+
      # All Subversion source paths under the branch start with one of
      # three things:
      #
@@ -1610,13 +1717,65 @@
      # overwrite one with the other as anything else -- anyway, isn't
      # that what CVS would do if you checked out the branch? <shrug>

+ if self.debug:
+ print " fill_name: nm: %s pk:%s\n\tpa:%s", name, parent_key,
parent
+
      if parent.has_key(ctx.trunk_base):
- self.copy_descend(dumper, ctx, name, parent, ctx.trunk_base,
- SVN_INVALID_REVNUM, ctx.trunk_base, "",
- is_tag, jit_new_rev)
+ if self.debug:
+ print " fill_name: trunk_base have_key(%s)" % ctx.trunk_base
+
+ rp = os.path.join(ctx.trunk_base, ctx.subroot)
+ ap = os.path.join(ctx.root, rp)
+
+ comp_rp = string.split(rp, '/')
+ head = comp_rp[-1]
+
+ if self.debug:
+ print " fill_name: trunk: ap:%s, head:%s" % (ap, head)
+
+ if (ctx.subroot != ""):
+ # need to chain through ctx.subroot, not just take ctx.trunk_base
+ for comp in comp_rp[:-1]:
+ if self.debug:
+ print " fill_name: trunk: sr: getting child of %s" % comp
+ print " fill_name: pa:%s" % (parent)
+
+ k = parent[comp]
+ parent = marshal.loads(self.db[k])
+
+ if self.debug:
+ print " fill_name: CD: en:%s, pa:%s" % (head, parent)
+
+ self.copy_descend(dumper, ctx, name, parent, head,
+ SVN_INVALID_REVNUM, ap, "", is_tag, jit_new_rev)
+
+ if self.debug:
+ print " fill_name: trunk_base END"
+
+ # NOTE: prev block changes parent. Can both parent.has_key(trunk,
branches)
+ # be called one after the other. If so does it matter if parent has
been
+ # changed or must I restore... - Kim
+
      if parent.has_key(ctx.branches_base):
+ if self.debug:
+ print " fill_name: branches_base have_key(%s)" %
ctx.branches_base
+
+ # skip "branches" child !? :
        branch_base_key = parent[ctx.branches_base]
        branch_base = marshal.loads(self.db[branch_base_key])
+
+ comp_sr = string.split(ctx.subroot, '/')
+
+ if (ctx.subroot != ""):
+ # need to chain through ctx.subroot [1:] is just subroot
+ for comp in comp_sr:
+ if self.debug:
+ print " fill_name branches: getting child of: %s" % comp
+ print " fill_name: pa:%s" % (branch_base)
+
+ k = branch_base[comp]
+ branch_base = marshal.loads(self.db[k])
+
        for this_source in branch_base.keys():
          # We skip special names beginning with '/' for the usual
          # reason. We skip cases where (this_source == name) for a
@@ -1625,11 +1784,19 @@
          # different branches in an RCS file, which CVS doesn't
          # permit. So while it wouldn't hurt to descend, it would be a
          # waste of time.
+
+ if self.debug:
+ print " fill_name: branch keys iterator: this_source: %s" %
this_source
+
          if (this_source[0] != '/') and (this_source != name):
- src_path = ctx.branches_base + '/' + this_source
+ src_path = os.path.join(ctx.root, ctx.branches_base,
ctx.subroot,
this_source)
+ if self.debug:
+ print " fill_name: branches: ", src_path
            self.copy_descend(dumper, ctx, name, branch_base,
this_source,
                              SVN_INVALID_REVNUM, src_path, "",
                              is_tag, jit_new_rev)
+ if self.debug:
+ print " fill_name: END"

    def fill_tag(self, dumper, ctx, tag, jit_new_rev=None):
      """Use DUMPER to create all currently available parts of TAG that
@@ -1705,7 +1872,11 @@
      self.deletes = [ ]
      self.t_min = 1<<30
      self.t_max = 0
+ self.debug = 0

+ def set_debug(self, debug):
+ self.debug = debug
+
    def has_file(self, fname):
      return self.files.has_key(fname)

@@ -1753,7 +1924,7 @@
    def commit(self, dumper, ctx, sym_tracker):
      # commit this transaction
      seconds = self.t_max - self.t_min
- print 'committing: %s, over %d seconds' % (time.ctime(self.t_min),
seconds)
+ print '\ncommitting: %s, over %d seconds' %
(time.ctime(self.t_min),
seconds)
      if seconds > COMMIT_THRESHOLD:
        print 'WARNING: commit spans more than %d seconds' %
COMMIT_THRESHOLD

@@ -1798,6 +1969,9 @@
        # compute a repository path, dropping the ,v from the file name
        cvs_path = relative_name(ctx.cvsroot, rcs_file[:-2])
        svn_path = make_path(ctx, cvs_path, br)
+
+ if self.debug:
+ print "\nchanges: (cvs_path:%s, br:%s, brs:%s)" % (cvs_path,
br,
branches)
        if svn_rev == SVN_INVALID_REVNUM:
          svn_rev = dumper.start_revision(props)
        sym_tracker.enroot_tags(svn_path, svn_rev, tags)
@@ -1812,6 +1986,7 @@
          ### constant time query.
          if not dumper.probe_path(svn_path):
            sym_tracker.fill_branch(dumper, ctx, br)
+
        # The first revision on a vendor branch is always the same as
        # the revision from which the branch sprouts, e.g., 1.1.1.1 is
        # always the same as 1.1, so there's no need to further modify
@@ -1829,6 +2004,9 @@

      for rcs_file, cvs_rev, br, tags, branches in self.deletes:
        # compute a repository path, dropping the ,v from the file name
+ if self.debug:
+ print "\ndeletes:"
+
        cvs_path = relative_name(ctx.cvsroot, rcs_file[:-2])
        svn_path = make_path(ctx, cvs_path, br)
        print ' deleting %s : %s' % (cvs_rev, svn_path)
@@ -1864,7 +2042,10 @@
      else:
        print ' no new revision created, as nothing to do'

+ if self.debug:
+ print "end: commit"

+
  def read_resync(fname):
    "Read the .resync file into memory."

@@ -2002,6 +2183,7 @@

  def pass4(ctx):
    sym_tracker = SymbolicNameTracker()
+ sym_tracker.debug = ctx.debug

    # A dictionary of Commit objects, keyed by digest. Each object
    # represents one logical commit, which may involve multiple files.
@@ -2020,6 +2202,8 @@

    # Start the dumpfile object.
    dumper = Dumper(ctx.dumpfile)
+ dumper.set_debug(ctx.debug)
+ dumper.set_dir_suppress_threshold(ctx.dir_suppress_threshold)

    # process the logfiles, creating the target
    for line in fileinput.FileInput(ctx.log_fname_base +
SORTED_REVS_SUFFIX):
@@ -2059,6 +2243,7 @@
        c = commits[id]
      else:
        c = commits[id] = Commit()
+ c.set_debug(ctx.debug)
      c.add(timestamp, op, fname, rev, branch_name, tags, branches)

    # End of the sorted revs file. Flush any remaining commits:
@@ -2126,10 +2311,11 @@

  def usage(ctx):
- print 'USAGE: %s [-n] [-v] [-s svn-repos-path] [-p pass]
cvs-repos-path'
\
+ print 'USAGE: %s [-n] [-v] [-d] [-s svn-repos-path] [-p pass]
cvs-repos-path' \
          % os.path.basename(sys.argv[0])
    print ' -n dry run; parse CVS repos, but do not
construct
SVN repos'
    print ' -v verbose'
+ print ' -d debug'
    print ' -s PATH path for SVN repos'
    print ' -p NUM start at pass NUM of %d' % len(_passes)
    print ' --create create a new SVN repository'
@@ -2136,15 +2322,18 @@
    print ' --dumpfile=PATH name of intermediate svn dumpfile'
    print ' --svnadmin=PATH path to the svnadmin program'
    print ' --trunk-only convert only trunk commits, not tags nor
branches'
- print ' --trunk=PATH path for trunk (default: %s)' \
+ print ' --trunk=DIR directory name for trunk (default: %s)'
\
          % ctx.trunk_base
- print ' --branches=PATH path for branches (default: %s)' \
+ print ' --branches=DIR directory name for branches (default: %s)'
\
          % ctx.branches_base
- print ' --tags=PATH path for tags (default: %s)' \
+ print ' --tags=DIR directory name for tags (default: %s)'
\
          % ctx.tags_base
    print ' --no-prune don\'t prune empty directories'
    print ' --dump-only just produce a dumpfile, don\'t commit to a
repos'
    print ' --encoding=ENC encoding of log messages in CVS repos
(default:
%s)' % ctx.encoding
+ print ' --root=PATH svn prefix path before trunk/branches/tags
(default: %s)' % ctx.root
+ print ' --subroot=PATH svn path after trunk/branches/tags
(default:
%s)' % ctx.subroot
+ print ' --suppress-parents suppresses output of parent dirs to
dumpfile (default: disabled)'
    sys.exit(1)

@@ -2155,6 +2344,7 @@
    ctx.target = None
    ctx.log_fname_base = DATAFILE
    ctx.dumpfile = DUMPFILE
+ ctx.debug = 0
    ctx.verbose = 0
    ctx.dry_run = 0
    ctx.prune = 1
@@ -2166,10 +2356,15 @@
    ctx.branches_base = "branches"
    ctx.encoding = "ascii"
    ctx.svnadmin = "svnadmin"
+ ctx.root = ""
+ ctx.subroot = ""
+ ctx.dir_suppress_threshold = 0

    try:
- opts, args = getopt.getopt(sys.argv[1:], 'p:s:vn',
- [ "create", "trunk=",
+ opts, args = getopt.getopt(sys.argv[1:], 'p:s:vnd',
+ [ "create", "dumpfile=", "svnadmin=",
+ "trunk=", "root=", "subroot=",
+ "suppress-parents",
                                   "branches=", "tags=", "encoding=",
                                   "trunk-only", "no-prune",
"dump-only"])
    except getopt.GetoptError:
@@ -2179,6 +2374,7 @@

    ctx.cvsroot = args[0]
    start_pass = 1
+ enable_suppress = 0

    for opt, value in opts:
      if opt == '-p':
@@ -2187,6 +2383,8 @@
          print 'ERROR: illegal value (%d) for starting pass. ' \
                'must be 1 through %d.' % (start_pass, len(_passes))
          sys.exit(1)
+ elif opt == '-d':
+ ctx.debug = 1
      elif opt == '-v':
        ctx.verbose = 1
      elif opt == '-n':
@@ -2213,7 +2411,28 @@
        ctx.dump_only = 1
      elif opt == '--encoding':
        ctx.encoding = value
+ elif opt == '--root':
+ ctx.root = value
+ elif opt == '--subroot':
+ ctx.subroot = value
+ elif opt == '--suppress-parents':
+ enable_suppress = 1

+
+ if enable_suppress:
+ thresh = 0
+ if (ctx.root != ""):
+ list = string.split(ctx.root, '/')
+ thresh = thresh + len(list)
+
+ if (ctx.subroot != ""):
+ list = string.split(ctx.subroot, '/')
+ thresh = thresh + len(list)
+ if ctx.debug:
+ print "Thresh level = ", thresh
+
+ ctx.dir_suppress_threshold = thresh
+
    # Consistency check for options.
    if (not ctx.target) and (not ctx.dump_only):
      sys.stderr.write("Error: must pass one of '-s' or
'--dump-only'.\n")
@@ -2230,11 +2449,7 @@
    if ((string.find(ctx.trunk_base, '/') > -1)
        or (string.find(ctx.tags_base, '/') > -1)
        or (string.find(ctx.branches_base, '/') > -1)):
- sys.stderr.write("Error: cannot pass multicomponent path to ")
- sys.stderr.write("--trunk, --tags, or --branches yet.\n")
- sys.stderr.write(" See
http://subversion.tigris.org/issues/show_bug.cgi?")
- sys.stderr.write("id=1409 ")
- sys.stderr.write("for details.\n")
+ sys.stderr.write("Error: --trunk, --tags, --branches must not
contain
'/'")
      sys.exit(1)

    convert(ctx, start_pass=start_pass)

==================================

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Mon Sep 29 14:04:18 2003

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.