From: "James Youngman" <jay@gnu.org>
To: git@vger.kernel.org
Subject: [PATCH] fast importer for SCCS files
Date: Sun, 20 Jan 2008 11:12:47 +0000 [thread overview]
Message-ID: <c5df85930801200312o7cd5d307v1a39fb35179249a9@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 366 bytes --]
The attached patch implements an importer for SCCS files using
git-fastimport. It's unidirectional SCCS->git. This is my first git
patch, so apologies if I have done something the wrong way with regard
to how one shoudl submit a patch. I've attached the patch because
my mail client would probably screw the formatting up if I just pasted
it :(
Thanks,
James.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-a-fast-importer-for-SCCS.patch --]
[-- Type: text/x-patch; name=0001-Add-a-fast-importer-for-SCCS.patch, Size: 21698 bytes --]
From 64c49a2ee864d50280df06b0f04d17d718f187c2 Mon Sep 17 00:00:00 2001
From: James Youngman <jay@gnu.org>
Date: Sun, 20 Jan 2008 11:02:10 +0000
Subject: [PATCH] Add a fast importer for SCCS.
---
contrib/fast-import/git-sccsimport.py | 733 +++++++++++++++++++++++++++++++++
1 files changed, 733 insertions(+), 0 deletions(-)
create mode 100755 contrib/fast-import/git-sccsimport.py
diff --git a/contrib/fast-import/git-sccsimport.py b/contrib/fast-import/git-sccsimport.py
new file mode 100755
index 0000000..06980d8
--- /dev/null
+++ b/contrib/fast-import/git-sccsimport.py
@@ -0,1 +1,733 @@
+#!/usr/bin/env python
+#
+# git-sccsimport.py -- Imports SCCS files into git
+#
+# Author: James Youngman <jay@gnu.org>
+# Copyright: 2008 James Youngman <jay@gnu.org>
+# License: GNU GPL version 2 or later <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
+#
+"""
+A fast git importer for SCCS files.
+
+How to use this program:
+
+Let's assume you have some SCCS files in $PROJECTDIR and want to
+convert them to a git repository in the directory $NEWGIT.
+
+First, make sure the SCCS (or CSSC) binaries are on your $PATH. Then
+do this:
+
+ cd "$PROJECTDIR"
+ python git-sccsimport.py --init --git-dir="$NEWGIT" --dirs .
+
+Notice that git-sccsimport is being run with its working
+directory as the root of the tree of SCCS files. This is
+becaue the relative path from your working directory to the
+SCCS file is also used as the name of the file in the resulting
+git repository.
+
+I tried this on a 32M code repository in SCCS and it produced a
+36M git repository.
+"""
+import datetime
+import errno
+import optparse
+import os
+import os.path
+import re
+import stat
+import subprocess
+import sys
+import time
+
+GET = "get"
+PRS = "prs"
+SCCS_ESCAPE = chr(1)
+TIMEZONE = None
+MAIL_DOMAIN = None
+UNIX_EPOCH = time.mktime(datetime.datetime(1970, 1, 1,
+ 0, 0, 0, 0,
+ None).timetuple())
+IMPORT_REF = None
+
+
+# Two checkins separated by more than FUZZY_WINDOW
+# will never be considered part of the same commit.
+FUZZY_WINDOW = 300.0
+
+
+verbose = False
+
+
+class ImportFailure(Exception):
+ pass
+
+class UsageError(Exception):
+ pass
+
+class AbstractClassError(Exception):
+ pass
+
+def Usage(who, retval, f, e):
+ if e:
+ print >>f, e
+ print >>f, ("usage: %s sccs-file [sccs-file...]"
+ % (who,))
+ if retval:
+ sys.exit(retval)
+ return retval
+
+
+def NotImporting(file, sid, reason):
+ if sid:
+ msg = ("%s: not importing SID %s: %s"
+ % (file, sid, reason))
+ else:
+ msg = ("%s: not importing this file: %s"
+ % (file, reason))
+ print >> sys.stderr, msg
+
+
+def DiagnoseCommandFailure(command, returncode, errors):
+ if not errors:
+ errors = ""
+ if returncode < 0:
+ msg = ("%s %s killed by signal %s" % command, -(returncode))
+ else:
+ msg = ("%s %s returned exit status %s" % command, returncode)
+ raise ImportFailure, "%s\n%s" % (errors, msg)
+
+
+def RunCommand(commandline):
+ try:
+ if verbose:
+ msg = ("Running command: %s\n"
+ % (" ".join(commandline),))
+ sys.stderr.write(msg)
+ child = subprocess.Popen(commandline,
+ close_fds = True,
+ stdin =subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ output, errors = child.communicate(None)
+ if child.returncode != 0:
+ # Some stderr output is normal (warnings, etc.)
+ DiagnoseCommandFailure(commandline[0], child.returncode, errors)
+ else:
+ return output
+ except OSError, oe:
+ msg = ("Failed to run '%s': %s (%s)"
+ % (commandline[0], oe,
+ errno.errorcode[oe.errno]))
+ raise ImportFailure, msg
+
+
+
+
+def GetBody(sfile, seqno, expand_keywords):
+ options = [GET, "-p", "-s", ("-a%d" % seqno)]
+ if not expand_keywords:
+ options.append("-k")
+ options.append(sfile)
+ return RunCommand(options)
+
+
+def FileMode(filename):
+ return stat.S_IMODE(os.stat(filename).st_mode)
+
+
+class SccsFileQueryBase(object):
+ @staticmethod
+ def HeaderLines(filename):
+ header_end = "^%cT" % (SCCS_ESCAPE,)
+ result = []
+ try:
+ f = open(filename, "rb")
+ for line in f.readlines():
+ if line.startswith(header_end):
+ break
+ else:
+ result.append(line)
+ return result
+ finally:
+ f.close()
+
+
+
+#class SccsFileQuerySlow(SccsFileQueryBase):
+# """Extract information from SCCS files by running prs."""
+# @staticmethod
+# def RunPrs(options):
+# commandline = [PRS]
+# commandline.extend(options)
+# return RunCommand(commandline)
+#
+# @staticmethod
+# def FetchDeltaProperties(sid, filename):
+# fmt = (":Dy:/:Dm:/:Dd:%(esc)c" # 0 delta creation date
+# ":Th:::Tm:::Ts:%(esc)c" # 1 delta creation time (24h)
+# ":C:%(esc)c" # 2 checkin comments
+# ":DS:%(esc)c" # 3 seqno
+# ":DP:%(esc)c" # 4 parent seqno
+# ":DT:%(esc)c" # 5 delta type (R or D)
+# ":I:%(esc)c" # 6 SID
+# ":MR:%(esc)c" # 7 MR numbers
+# ":P:%(esc)c" # 8 Perpetrator (committer)
+# % { 'esc': SCCS_ESCAPE })
+# cmdline = [("-d%s" % fmt), ("-r%s" % sid), filename]
+# propdata = SccsFileQuerySlow.RunPrs(cmdline)
+# return propdata.split(SCCS_ESCAPE)
+#
+# @staticmethod
+# def IsValidSccsFile(filename):
+# try:
+# output = SccsFileQuerySlow.RunPrs(["-d:F: ", filename])
+# return True
+# except ImportFailure:
+# return False
+#
+# @staticmethod
+# def GetRevisionList(filename):
+# revisions = SccsFileQuerySlow.RunPrs(["-d:I: ", "-e", filename])
+# return revisions.split()
+
+
+class SccsFileQueryFast(SccsFileQueryBase):
+ """Extract information from SCCS files by parsing them directly."""
+ DELTA_RE = re.compile("^%cd D ([.0-9]*)" % (SCCS_ESCAPE,))
+
+ @staticmethod
+ def IsValidSccsFile(filename):
+ try:
+ f = open(filename, "rb")
+ header = f.read(2)
+ return header[0] == SCCS_ESCAPE and header[1] == 'h'
+ finally:
+ f.close()
+
+ @staticmethod
+ def GetRevisionList(filename):
+ result = []
+ header_end = "^%cT" % (SCCS_ESCAPE,)
+ for line in SccsFileQueryBase.HeaderLines(filename):
+ m = SccsFileQueryFast.DELTA_RE.match(line)
+ if m:
+ result.append(m.group(1))
+ return result
+
+ @staticmethod
+ def FetchDeltaProperties(sid, filename):
+ found = False
+ props = []
+ comments = []
+ comment_leader = "%cc" % (SCCS_ESCAPE,)
+ for line in SccsFileQueryBase.HeaderLines(filename):
+ if not found:
+ m = SccsFileQueryFast.DELTA_RE.match(line)
+ if m and (sid == m.group(1)):
+ found = True
+ fields = line.split()
+ props = [ fields[3],
+ fields[4],
+ None, # checkin comment
+ fields[6],
+ fields[7],
+ 'D',
+ fields[2],
+ "", # MR list
+ fields[5],
+ "yodel"
+ ]
+ continue
+ else:
+ if found:
+ if line.startswith(comment_leader):
+ comments.append(line[3:])
+ else:
+ break
+ if found:
+ props[2] = "\n".join(comments)
+ # print >> sys.stderr, "props: %s" % (props,)
+ return props
+ else:
+ return None
+
+
+def SccsFileQuery():
+ """Factory method for objects that query SccsFileQuery objects"""
+ return SccsFileQueryFast()
+
+
+class Delta(object):
+ """Represents the properties of an SCCS delta that we
+ import into git."""
+ def __init__(self, sccsfile, sid, qif, *args, **kwargs):
+ super(Delta, self).__init__(*args, **kwargs)
+ self._sccsfile = sccsfile
+ self._sid = sid
+ self._qif = qif
+ self.FetchDeltaProperties()
+
+ def __repr__(self):
+ return 'Delta(%s, "%s")' % (repr(self._sccsfile), self._sid)
+
+ def FetchDeltaProperties(self):
+ """Query the properties of this delta from the SCCS file."""
+ props = self._qif.FetchDeltaProperties(self._sid,
+ self._sccsfile._filename)
+ assert len(props)>1, "%s %s %s" % (self._sccsfile._filename, self._sid, props)
+ self.SetTimestamp(props[0], props[1])
+ (self._comment, self._seqno, self._parent_seqno, self._type,
+ sidcheck, mrlist, self._comitter, _) = props[2:]
+
+ self._seqno = int(self._seqno)
+ self._parent_seqno = int(self._parent_seqno)
+ if self._comment == "\n":
+ self._comment = None
+ assert sidcheck==self._sid
+ self._mrs = mrlist.split()
+
+ def SameFuzzyCommit(self, other):
+ #print >>sys.stderr, ("SameFuzzyCommit: comparing\n1: %s with\n2: %s"
+ # % (self, other))
+ if self._comment != other._comment:
+ return False
+ elif self._comitter != other._comitter:
+ return False
+ elif self._mrs != other._mrs:
+ return False
+ else:
+ delta = abs(other._timestamp - self._timestamp)
+ if delta > FUZZY_WINDOW:
+ return False
+ else:
+ return True
+
+ def SetTimestamp(self, checkin_date, checkin_time):
+ try:
+ year, month, monthday = [int(f) for f in checkin_date.split("/")]
+ except ValueError:
+ raise ImportFailure, ("Unexpected date format: %s"
+ % (checkin_date,))
+ try:
+ h,m,s = [int(f) for f in checkin_time.split(":")]
+ except ValueError:
+ raise ImportFailure, ("Unexpected time format: %s"
+ % (checkin_time,))
+ microsec = 0
+
+ if year < 100:
+ # Apply the y2k rule (see the "Year 2000 Issues" section
+ # of the CSSC documentation).
+ if year < 69:
+ year += 2000
+ else:
+ year += 1900
+
+ dt = datetime.datetime(year, month, monthday,
+ h, m, s,
+ microsec, TIMEZONE)
+ epoch_offset = time.mktime(dt.timetuple())
+ # We subtract UNIX_EPOCH to take account of the fact
+ # that the system epoch may in fact not be the same as the Unix
+ # epoch. git fast-import requires the timestamp to be measured in
+ # seconds since the Unix epoch.
+ self._timestamp = epoch_offset - UNIX_EPOCH
+
+ def GitTimestamp(self):
+ n = int(self._timestamp)
+ return "%d +0000" % (n,)
+
+
+class SccsFile(object):
+ def __init__(self, name, *args, **kwargs):
+ super(SccsFile, self).__init__(*args, **kwargs)
+ self._filename = name
+ qif = SccsFileQuery()
+ revisions = filter(self.GoodRevision, qif.GetRevisionList(name))
+ self._deltas = [Delta(self, sid, qif) for sid in revisions]
+ self._gitname = self.GitFriendlyName(self._GottenName())
+ if FileMode(self._filename) & 0111:
+ self._gitmode = "755"
+ else:
+ self._gitmode = "644"
+
+ gitname = property(lambda self: self._gitname)
+ gitmode = property(lambda self: self._gitmode)
+ filename = property(lambda self: self._filename)
+
+ @staticmethod
+ def IsValidSccsFile(filename):
+ qif = SccsFileQuery()
+ return qif.IsValidSccsFile(filename)
+
+ def __repr__(self):
+ return "SccsFile(r'%s')" % self._filename
+
+ @staticmethod
+ def GitFriendlyName(name):
+ """git-fastimport does not like leading or trailing slashes,
+ or . or .. in file names. This method removes such things."""
+ if os.path.isabs(name):
+ raise ImportFailure, "%s is an absolute path name" % (name,)
+ drive, path = os.path.splitdrive(name)
+ return os.path.normpath(path)
+
+ def _GottenName(self):
+ """Convert the name of an SCCS file to the name of the
+ working file as would be assumed by make. Specifically,
+ the s. prefix is stipped, and if the s.file is in a directory
+ called SCCS, that directory is stripped out of the path also.
+ """
+ head, tail = os.path.split(self._filename)
+ if tail.startswith("s."):
+ tail = tail[2:]
+ dirhead, dirtail = os.path.split(head)
+ if dirtail == "SCCS":
+ head = dirhead
+ return os.path.join(head, tail)
+
+
+ def GoodRevision(self, sid):
+ comps = sid.split(".")
+ if len(comps) > 1:
+ return True
+ else:
+ NotImporting(self._filename, sid,
+ "SID contains no level component")
+ return False
+
+
+
+
+class GitImporter(object):
+ """Handles communications with git-fast-import."""
+
+ def __init__(self, *args, **kwargs):
+ super(GitImporter, self).__init__(*args, **kwargs)
+ self._next_mark = 1
+ self._command = None
+ self._importer = None
+ self._write_to_stdout = False
+
+ def StartImporter(self):
+ args = ["git","fast-import"]
+ self._command = " ".join(args)
+ self._importer = subprocess.Popen(args,
+ close_fds=True,
+ stdin=subprocess.PIPE)
+
+ def SendToStdout(self):
+ self._command = None
+ self._importer = None
+ self._write_to_stdout = True
+
+ def GetNextMark(self):
+ """Get the next unused idnum for a mark statement."""
+ result = self._next_mark
+ self._next_mark += 1
+ return result
+
+ def Write(self, s):
+ """Write some data to the importer."""
+ if self._write_to_stdout:
+ sys.stdout.write(s)
+ else:
+ assert self._importer
+ self._importer.stdin.write(s)
+
+ def Done(self):
+ if self._importer:
+ self._importer.stdin.close()
+ returncode = self._importer.wait()
+ if returncode != 0:
+ DiagnoseCommandFailure(self._command, returncode, None)
+ else:
+ print >>sys.stderr, ("%s completed successfully"
+ % (self._command,))
+
+ def ProgressMsg(self, msg):
+ """Emit a progress message for the user."""
+ sys.stderr.write(msg)
+
+ def Progress(self, done, items):
+ """Inform the user of our current progress."""
+ percent = (100.0 * float(done)) / float(items)
+ if done == items:
+ tail = " done\n"
+ else:
+ tail = ""
+ msg = "\r %3.0f%% (%d/%d)%s" % (percent, done, items, tail)
+ self.ProgressMsg(msg)
+
+ def GetUserEmailAddress(self, login_name):
+ """Get an email address corresponding to the given login name."""
+ if MAIL_DOMAIN:
+ return "%s@$s" % (login_name,MAIL_DOMAIN)
+ else:
+ return login_name
+
+ def WriteData(self, data):
+ """Emit a data command followd by a blob of data."""
+ self.Write("data %d\n" % (len(data),))
+ self.Write(data)
+ self.Write("\n")
+
+ def BeginCommit(self, delta, parent):
+ """Start a new commit (having the indicated parent)."""
+ mark = self.GetNextMark()
+ self.Write("commit %s\nmark :%d\n" % (IMPORT_REF, mark))
+ ts = delta.GitTimestamp()
+ self.Write("committer %s <%s> %s\n"
+ % (delta._comitter,
+ self.GetUserEmailAddress(delta._comitter),
+ ts))
+ if delta._comment:
+ self.WriteData(delta._comment)
+ else:
+ self.WriteData("") # commit comment is mandatory
+ if parent:
+ self.Write("from :%d\n" % (parent,))
+ return mark
+
+ def Filemodify(self, sfile, body):
+ """Write a filemodify section of a commit."""
+ self.Write("M %s inline %s\n" % (sfile.gitmode, sfile.gitname))
+ self.WriteData(body)
+
+ def CompleteCommit(self):
+ """Write the final part of a commit."""
+ self.Write("\n")
+
+# TODO: if the fuzzy commit logic puts subsequent deltas into the same
+# commit, the timestamp of the commit is that of the first delta. One
+# could argue that the timestamp of the last one would be a better
+# choice.
+
+def ImportDeltas(imp, deltas):
+ if not deltas:
+ raise ImportFailure, "No deltas to import"
+ first_delta_in_commit = None
+ done = 0
+ imp.ProgressMsg("Creating commits...\n")
+ parent = None
+ commit_count = 0
+ for d in deltas:
+ imp.Progress(done, len(deltas))
+ done += 1
+ # Figure out if we need to start a new commit.
+ if first_delta_in_commit:
+ if not first_delta_in_commit.SameFuzzyCommit(d):
+ imp.CompleteCommit()
+ first_delta_in_commit = None
+ if first_delta_in_commit is None:
+ first_delta_in_commit = d
+ current = imp.BeginCommit(d, parent)
+ commit_count += 1
+ parent = current
+ # We're now in a commit. Emit the body for this delta.
+ body = GetBody(d._sccsfile._filename, d._seqno, False)
+ imp.Filemodify(d._sccsfile, body)
+ # Finished looping over deltas
+ if parent:
+ imp.CompleteCommit()
+ imp.Progress(done, len(deltas))
+ print >>sys.stderr, ("%d SCCS deltas in %d git commits"
+ % (len(deltas), commit_count))
+
+
+def Import(filenames, stdout):
+ """Import the indicated SCCS files into git."""
+ for filename in filenames:
+ if not os.access(filename, os.R_OK):
+ msg = "%s is not readable" % (filename,)
+ raise ImportFailure, msg
+ if not os.path.isfile(filename):
+ msg = "%s is not a file" % (filename,)
+ raise ImportFailure, msg
+ sccsfiles = []
+ done = 0
+ imp = GitImporter()
+ imp.ProgressMsg("Reading metadata from SCCS files...\n")
+ for filename in filenames:
+ try:
+ imp.Progress(done, len(filenames))
+ if SccsFile.IsValidSccsFile(filename):
+ sf = SccsFile(filename)
+ sccsfiles.append(sf)
+ else:
+ NotImporting(filename, None, "not a valid SCCS file")
+ done += 1
+ except ImportFailure:
+ msg = ("\nAn import failure occurred while processing %s"
+ % (filename,))
+ print >> sys.stderr, msg
+ raise
+ imp.Progress(done, len(filenames))
+ # Now we have all the metadata; sort the deltas by timestamp
+ # and import the deltas in time order.
+ delta_list = []
+ for sfile in sccsfiles:
+ for delta in sfile._deltas:
+ ts = "%15f" % (delta._timestamp,)
+ t = (ts, delta)
+ delta_list.append(t)
+ delta_list.sort()
+
+ if stdout:
+ imp.SendToStdout()
+ else:
+ imp.StartImporter()
+ try:
+ ImportDeltas(imp, [d[1] for d in delta_list])
+ finally:
+ imp.Done()
+
+
+def IsValidGitDir(path):
+ """Returns True IFF path is a valid git repo.
+
+ Copied from git-p4.
+ """
+ if (os.path.exists(path + "/HEAD")
+ and os.path.exists(path + "/refs")
+ and os.path.exists(path + "/objects")):
+ return True;
+ return False
+
+
+def FindGitDir(gitdir, init):
+ """Locate the git repository."""
+ if not gitdir:
+ gitdir = RunCommand(["git", "rev-parse", "--git-dir"])
+ if gitdir:
+ gitdir = gitdir.strip()
+ else:
+ cdup = RunCommand(["git", "rev-parse", "--show-cdup"])
+ if cdup:
+ gitdir = os.path.abspath(cdup.strip())
+ else:
+ gitdir = "."
+ if init:
+ # Do a sanity check that we're not about to create /.git.
+ assert gitdir
+ if not gitdir.endswith("/.git"):
+ gitdir += "/.git"
+ if IsValidGitDir(gitdir):
+ raise ImportFailure, ("Git repository %s was already initialised"
+ % (gitdir,))
+ else:
+ RunCommand(["git", "--git-dir=%s" % (gitdir,), "init"])
+
+ if not IsValidGitDir(gitdir):
+ gitdir += "/.git"
+ if not IsValidGitDir(gitdir):
+ raise ImportFailure, ("cannot locate git repository at %s" %
+ (gitdir,))
+ print >> sys.stderr, "git repository is at", gitdir
+ return gitdir
+
+
+def MakeDirWorklist(dirs):
+ result = []
+ for dirname in dirs:
+ for root, subdirs, files in os.walk(dirname):
+ for f in files:
+ if f.startswith("s."):
+ physpath = os.path.join(root, f)
+ if os.access(physpath, os.R_OK):
+ result.append(physpath)
+ if not result:
+ print >>sys.stderr, ("Warning: No SCCS files were found in %s"
+ % (" ".join(dirs)))
+ return result
+
+
+def ParseOptions(argv):
+ global IMPORT_REF
+ global MAIL_DOMAIN
+ global FUZZY_WINDOW
+ global verbose
+ parser = optparse.OptionParser()
+ parser.add_option("--branch",
+ help="branch to populate",
+ default="master")
+ parser.add_option("--maildomain",
+ help="Mail domain for usernames taken from SCCS files")
+ parser.add_option("--fuzzy-commit-window",
+ default=FUZZY_WINDOW,
+ help=("Deltas more than this many seconds apart "
+ "are always considered to be in different commits"))
+ parser.add_option("--git-dir",
+ help="Directory containing the git repository")
+ parser.add_option("--init", default=False, action="store_true",
+ help="Initialise the git repository first")
+ parser.add_option("--verbose", default=False, action="store_true",
+ help="Print verbose status messages")
+ parser.add_option("--stdout", default=False, action="store_true",
+ help=("Send git-fast-import data to stdout "
+ "rather than to git-fast-import"))
+ parser.add_option("--dirs",
+ action="store_true",
+ help=("Command-line arguments are a list "
+ "of directories to automatically search "
+ "rather than a list of SCCS files"))
+ (options, args) = parser.parse_args(argv)
+ verbose = options.verbose
+ if options.maildomain:
+ MAIL_DOMAIN = options.maildomain
+ try:
+ FUZZY_WINDOW = float(options.fuzzy_commit_window)
+ except ValueError:
+ raise UsageError("The argument for the --fuzzy-commit-window option "
+ "should be a number, but you specified '%s'"
+ % (options.fuzzy_commit_window,))
+ IMPORT_REF = "refs/heads/%s" % (options.branch,)
+ return options, args
+
+
+def main(argv):
+ progname = argv[0] or "git-sccsimport"
+ try:
+ options, args = ParseOptions(argv)
+ print >>sys.stderr, "Positional args:", " ".join(args)
+ args = args[1:]
+
+ if not args:
+ if options.dirs:
+ raise UsageError("You did not specify any directories to import from")
+ else:
+ raise UsageError("You did not specify any SCCS files to import")
+
+ if options.stdout and options.init:
+ raise UsageError("The --init option is incompatible "
+ "with the --stdout option")
+
+ if not options.stdout:
+ try:
+ os.environ["GIT_DIR"] = FindGitDir(options.git_dir, options.init)
+ except ImportFailure, init_failure:
+ if options.init:
+ action = "initialise"
+ else:
+ action = "locate"
+ print >>sys.stderr, ("Failed to %s the git repository: %s"
+ % (action, init_failure))
+ return 1
+
+ if options.dirs:
+ items = MakeDirWorklist(args)
+ else:
+ items = args
+ print >>sys.stderr, "Importing items:", " ".join(items)
+ return Import(items, options.stdout)
+
+ except UsageError, usage_err:
+ return Usage(progname, 1, sys.stderr, usage_err)
+ except ImportFailure, imp_failure:
+ print >> sys.stderr, "Import failed: %s" % (imp_failure,)
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
--
1.5.3.8
next reply other threads:[~2008-01-20 11:13 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-01-20 11:12 James Youngman [this message]
2008-01-21 0:50 ` [PATCH] fast importer for SCCS files Junio C Hamano
2008-01-21 5:53 ` Miles Bader
2008-01-21 6:27 ` Junio C Hamano
2008-01-21 8:01 ` Miles Bader
2008-01-22 4:10 ` Sam Vilain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c5df85930801200312o7cd5d307v1a39fb35179249a9@mail.gmail.com \
--to=jay@gnu.org \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).