From: Scott Lamb <slamb@slamb.org>
To: git@vger.kernel.org, Junio C Hamano <junkio@cox.net>
Cc: Scott Lamb <slamb@slamb.org>
Subject: [PATCH 1/4] git-p4import: fix subcommand error handling
Date: Sat, 2 Jun 2007 20:58:43 -0700 [thread overview]
Message-ID: <1180843126948-git-send-email-slamb@slamb.org> (raw)
In-Reply-To: <4ACE2ABC-8D73-4097-87AC-F3B27EDA97DE@slamb.org>
Use the Python "subcommand" module to properly handle the subcommand
pipeline and raise exceptions on error.
Signed-off-by: Scott Lamb <slamb@slamb.org>
---
I folded the elimination of the shell pipelines into this patch - the error
handling couldn't work otherwise.
The difference between exceptions paths with "die" and ones with an exception
thrown to the top is somewhat arbitrary; I tried to use it to distinguish
between user error and bugs.
git-p4import.py | 166 +++++++++++++++++++++++++++++++++----------------------
1 files changed, 99 insertions(+), 67 deletions(-)
diff --git a/git-p4import.py b/git-p4import.py
index 60a758b..002f8d8 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -13,6 +13,9 @@ import os
import sys
import time
import getopt
+import subprocess
+import re
+import errno
from signal import signal, \
SIGPIPE, SIGINT, SIG_DFL, \
@@ -34,7 +37,7 @@ def usage():
sys.exit(1)
verbosity = 1
-logfile = "/dev/null"
+logfile = file("/dev/null", "a")
ignore_warnings = False
stitch = 0
tagall = True
@@ -44,59 +47,70 @@ def report(level, msg, *args):
global logfile
for a in args:
msg = "%s %s" % (msg, a)
- fd = open(logfile, "a")
- fd.writelines(msg)
- fd.close()
+ logfile.writelines(msg)
if level <= verbosity:
print msg
+class P4Exception(Exception):
+ def __init__(self, cmd, errmsg):
+ Exception.__init__(self, '%r: %s' % (cmd, errmsg))
+ self.cmd = cmd
+ self.errmsg = errmsg
+
class p4_command:
def __init__(self, _repopath):
- try:
- global logfile
- self.userlist = {}
- if _repopath[-1] == '/':
- self.repopath = _repopath[:-1]
- else:
- self.repopath = _repopath
- if self.repopath[-4:] != "/...":
- self.repopath= "%s/..." % self.repopath
- f=os.popen('p4 -V 2>>%s'%logfile, 'rb')
- a = f.readlines()
- if f.close():
- raise
- except:
- die("Could not find the \"p4\" command")
+ self.userlist = {}
+ if _repopath[-1] == '/':
+ self.repopath = _repopath[:-1]
+ else:
+ self.repopath = _repopath
+ if self.repopath[-4:] != "/...":
+ self.repopath= "%s/..." % self.repopath
+ p4 = subprocess.Popen(['p4', '-V'],
+ stdout=file('/dev/null', 'a'),
+ stderr=subprocess.PIPE)
+ err = p4.stderr.read()
+ if p4.wait() != 0:
+ die("Could not run the \"p4\" command: %r" % (err,))
def p4(self, cmd, *args):
global logfile
cmd = "%s %s" % (cmd, ' '.join(args))
+ cmdlist = ['p4', '-G'] + cmd.split(' ')
report(2, "P4:", cmd)
- f=os.popen('p4 -G %s 2>>%s' % (cmd,logfile), 'rb')
+ p4 = subprocess.Popen(cmdlist,
+ stdout=subprocess.PIPE,
+ stderr=logfile)
list = []
while 1:
try:
- list.append(marshal.load(f))
+ elem = marshal.load(p4.stdout)
except EOFError:
break
- self.ret = f.close()
+ if elem['code'] == 'error':
+ raise P4Exception(cmd, elem['data'])
+ list.append(elem)
+ if p4.wait() != 0:
+ raise Exception("'p4 %s' failed" % (cmd,))
return list
def sync(self, id, force=False, trick=False, test=False):
- if force:
- ret = self.p4("sync -f %s@%s"%(self.repopath, id))[0]
- elif trick:
- ret = self.p4("sync -k %s@%s"%(self.repopath, id))[0]
- elif test:
- ret = self.p4("sync -n %s@%s"%(self.repopath, id))[0]
- else:
- ret = self.p4("sync %s@%s"%(self.repopath, id))[0]
- if ret['code'] == "error":
- data = ret['data'].upper()
- if data.find('VIEW') > 0:
- die("Perforce reports %s is not in client view"% self.repopath)
- elif data.find('UP-TO-DATE') < 0:
- die("Could not sync files from perforce", self.repopath)
+ try:
+ if force:
+ self.p4("sync -f %s@%s"%(self.repopath, id))
+ elif trick:
+ self.p4("sync -k %s@%s"%(self.repopath, id))
+ elif test:
+ self.p4("sync -n %s@%s"%(self.repopath, id))
+ else:
+ self.p4("sync %s@%s"%(self.repopath, id))
+ except P4Exception, e:
+ data = e.errmsg.upper()
+ if data.find('VIEW') > 0:
+ die("Perforce reports %s is not in client view: %s"
+ % (self.repopath, e))
+ elif data.find('UP-TO-DATE') < 0:
+ die(e)
def changes(self, since=0):
try:
@@ -105,8 +119,8 @@ class p4_command:
list.append(rec['change'])
list.reverse()
return list
- except:
- return []
+ except P4Exception, e:
+ die(e)
def authors(self, filename):
f=open(filename)
@@ -122,7 +136,8 @@ class p4_command:
try:
user = self.p4("users", id)[0]
self.userlist[id] = (user['FullName'], user['Email'])
- except:
+ except P4Exception, e:
+ report(2, "P4: missing user %s" % (id,))
self.userlist[id] = (id, "")
return self.userlist[id]
@@ -143,7 +158,7 @@ class p4_command:
def where(self):
try:
return self.p4("where %s" % self.repopath)[-1]['path']
- except:
+ except P4Exception, e:
return ""
def describe(self, num):
@@ -153,16 +168,18 @@ class p4_command:
self.date = self._format_date(time.localtime(long(desc['time'])))
return self
+class GitException(Exception): pass
+
class git_command:
def __init__(self):
try:
self.version = self.git("--version")[0][12:].rstrip()
- except:
- die("Could not find the \"git\" command")
+ except GitException, e:
+ die(e)
try:
self.gitdir = self.get_single("rev-parse --git-dir")
report(2, "gdir:", self.gitdir)
- except:
+ except GitException, e:
die("Not a git repository... did you forget to \"git init\" ?")
try:
self.cdup = self.get_single("rev-parse --show-cdup")
@@ -170,38 +187,47 @@ class git_command:
os.chdir(self.cdup)
self.topdir = os.getcwd()
report(2, "topdir:", self.topdir)
- except:
+ except GitException, e:
die("Could not find top git directory")
- def git(self, cmd):
- global logfile
+ def git(self, cmd, stdin=None):
report(2, "GIT:", cmd)
- f=os.popen('git %s 2>>%s' % (cmd,logfile), 'rb')
- r=f.readlines()
- self.ret = f.close()
- return r
+ cmdlist = ['git'] + cmd.split(' ')
+ git = subprocess.Popen(cmdlist,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = git.communicate(stdin)
+ if git.wait() != 0:
+ raise GitException("'git %s' failed: %s" % (cmd, stderr))
+ if stderr != '':
+ report(2, stderr)
+ return re.findall(r'.*\n', stdout)
def get_single(self, cmd):
- return self.git(cmd)[0].rstrip()
+ list = self.git(cmd)
+ if len(list) != 1:
+ raise GitException("%r returned %r" % (cmd, list))
+ return list[0].rstrip()
def current_branch(self):
try:
testit = self.git("rev-parse --verify HEAD")[0]
return self.git("symbolic-ref HEAD")[0][11:].rstrip()
- except:
+ except GitException, e:
return None
def get_config(self, variable):
try:
return self.git("config --get %s" % variable)[0].rstrip()
- except:
+ except GitException, e:
return None
def set_config(self, variable, value):
try:
self.git("config %s %s"%(variable, value) )
- except:
- die("Could not set %s to " % variable, value)
+ except GitException, e:
+ die(e)
def make_tag(self, name, head):
self.git("tag -f %s %s"%(name,head))
@@ -217,7 +243,8 @@ class git_command:
return 0
def update_index(self):
- self.git("ls-files -m -d -o -z | git update-index --add --remove -z --stdin")
+ files = self.git("ls-files -m -d -o -z")
+ self.git("update-index --add --remove -z --stdin", stdin=files)
def checkout(self, branch):
self.git("checkout %s" % branch)
@@ -226,15 +253,21 @@ class git_command:
self.git("symbolic-ref HEAD refs/heads/%s" % branch)
def remove_files(self):
- self.git("ls-files | xargs rm")
+ files = self.git("ls-files")
+ for file in files:
+ os.unlink(file)
def clean_directories(self):
self.git("clean -d")
def fresh_branch(self, branch):
report(1, "Creating new branch", branch)
- self.git("ls-files | xargs rm")
- os.remove(".git/index")
+ self.remove_files()
+ try:
+ os.remove(".git/index")
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
self.repoint_head(branch)
self.git("clean -d")
@@ -243,21 +276,17 @@ class git_command:
def commit(self, author, email, date, msg, id):
self.update_index()
- fd=open(".msg", "w")
- fd.writelines(msg)
- fd.close()
try:
current = self.get_single("rev-parse --verify HEAD")
head = "-p HEAD"
- except:
+ except GitException, e:
current = ""
head = ""
tree = self.get_single("write-tree")
for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]:
os.environ['GIT_AUTHOR_%s'%r] = l
os.environ['GIT_COMMITTER_%s'%r] = l
- commit = self.get_single("commit-tree %s %s < .msg" % (tree,head))
- os.remove(".msg")
+ commit = self.get_single("commit-tree %s %s" % (tree,head), stdin=msg)
self.make_tag("p4/%s"%id, commit)
self.git("update-ref HEAD %s %s" % (commit, current) )
@@ -273,7 +302,7 @@ for o, a in opts:
if o == "-v":
verbosity += 1
if o in ("--log"):
- logfile = a
+ logfile = file(a, "a")
if o in ("--notags"):
tagall = False
if o in ("-h", "--help"):
@@ -293,7 +322,10 @@ for o, a in opts:
if len(args) == 2:
branch = args[1]
- git.checkout(branch)
+ try:
+ git.checkout(branch)
+ except GitException, e:
+ pass
if branch == git.current_branch():
die("Branch %s already exists!" % branch)
report(1, "Setting perforce to ", args[0])
--
1.5.2
next prev parent reply other threads:[~2007-06-03 3:59 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-31 16:47 git-p4import.py robustness changes Scott Lamb
2007-05-31 23:53 ` Junio C Hamano
2007-06-02 20:41 ` Scott Lamb
2007-06-02 21:33 ` Junio C Hamano
2007-06-02 23:21 ` Scott Lamb
2007-06-02 23:52 ` Junio C Hamano
2007-06-03 13:11 ` Simon Hausmann
2007-06-03 20:12 ` Scott Lamb
2007-06-04 5:54 ` Shawn O. Pearce
2007-06-04 6:09 ` Dana How
2007-06-04 6:18 ` Shawn O. Pearce
2007-06-04 7:19 ` Scott Lamb
2007-06-05 7:21 ` Simon Hausmann
2007-06-04 8:41 ` Marius Storm-Olsen
2007-06-04 5:56 ` Shawn O. Pearce
2007-06-12 21:46 ` Simon Hausmann
2007-06-13 21:06 ` Scott Lamb
2007-06-13 22:34 ` Simon Hausmann
2007-06-14 5:35 ` Shawn O. Pearce
2007-06-14 21:44 ` Simon Hausmann
2007-06-15 3:13 ` Shawn O. Pearce
2007-06-15 5:30 ` Marius Storm-Olsen, mstormo_git
2007-06-03 3:58 ` Scott Lamb [this message]
2007-06-03 3:58 ` [PATCH 2/4] git-p4import: use lists of subcommand arguments Scott Lamb
2007-06-03 3:58 ` [PATCH 3/4] git-p4import: resume on correct p4 changeset Scott Lamb
2007-06-03 3:58 ` [PATCH 4/4] git-p4import: partial history Scott Lamb
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=1180843126948-git-send-email-slamb@slamb.org \
--to=slamb@slamb.org \
--cc=git@vger.kernel.org \
--cc=junkio@cox.net \
/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).