After a short discussion on #-portage, here a feature patch from the
prefix branch, diffed to the trunk, irrelevant hunks removed.
Antarus once was working on factoring out the vcs bits of repoman into
pym/repoman/utilities.py, but he never finished it. I'm willing to give
that some more time, provided it'll end up in the trunk. Sofar, here's
the svn patch that we tested extensively in Prefix

I still believe
that it has a significant value for non-Prefix users (overlays...), even
though the code doesn't deserve any price for its beauty. I'd say it
fits nicely with large chunks of Portage
--
Fabian Groffen
Gentoo on a different level
--- ../../trunk/bin/repoman 2008-04-27 17:36:15 +0200
+++ bin/repoman 2008-05-12 19:28:49 +0200
@@ -421,12 +419,16 @@
can_force = True
-isCvs=False
-myreporoot=None
+isVcs = False
+vcs = '
if os.path.isdir("CVS"):
- isCvs = True
+ isVcs = True
+ vcs = "cvs"
+if os.path.isdir(".svn"):
+ isVcs = True
+ vcs = "svn"
-if isCvs and
+if isVcs and vcs == "cvs" and
"commit" == options.mode and
"RMD160" not in portage.checksum.hashorigin_map:
from portage.util import grablines
@@ -444,8 +446,8 @@
sys.exit(1)
del repo_lines
-if options.mode == 'commit' and not options.pretend and not isCvs:
- logging.info("Not in a CVS repository; enabling pretend mode.")
+if options.mode == 'commit' and not options.pretend and not isVcs:
+ logging.info("Not in a version controlled repository; enabling pretend mode.")
options.pretend = True
try:
@@ -488,7 +490,7 @@
# Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating.
# this check ensures that repoman knows where it is, and the manifest recommit is at least possible.
if options.mode == 'commit' and repolevel not in [1,2,3]:
- print red("***")+" Commit attempts *must* be from within a cvs co, category, or package directory."
+ print red("***")+" Commit attempts *must* be from within a vcs co, category, or package directory."
print red("***")+" Attempting to commit from a packages files directory will be blocked for instance."
print red("***")+" This is intended behaviour, to ensure the manifest is recommited for a package."
print red("***")
@@ -694,8 +696,8 @@
#this can be problematic if xmllint changes their output
xmllint_capable=True
-if options.mode == 'commit' and isCvs:
- utilities.detect_vcs_conflicts(options, vcs="cvs")
+if options.mode == 'commit' and isVcs:
+ utilities.detect_vcs_conflicts(options, vcs)
if options.mode == "manifest":
pass
@@ -705,7 +707,7 @@
print green("
RepoMan scours the neighborhood...")
new_ebuilds = set()
-if isCvs:
+if vcs == "cvs":
mycvstree = cvstree.getentries("./", recursive=1)
mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
new_ebuilds.update(x for x in mynew if x.endswith(".ebuild"))
@@ -812,40 +814,86 @@
if not os.path.isdir(os.path.join(checkdir, "files")):
has_filesdir = False
- if isCvs:
+ if isVcs:
try:
- myf=open(checkdir+"/CVS/Entries","r")
- myl=myf.readlines()
+ if vcs == "cvs":
+ myf=open(checkdir+"/CVS/Entries","r")
+ if vcs == "svn":
+ myf=os.popen("svn update > /dev/null; svn list")
+ myl=myf.readlines()
+ myf.close()
for l in myl:
- if l[0]!="/":
- continue
- splitl=l[1:].split("/")
- if not len(splitl):
- continue
- if splitl[0][-7:]==".ebuild":
- eadded.append(splitl[0][:-7])
+ if vcs == "cvs":
+ if l[0]!="/":
+ continue
+ splitl=l[1:].split("/")
+ if not len(splitl):
+ continue
+ if splitl[0][-7:]==".ebuild":
+ eadded.append(splitl[0][:-7])
+ if vcs == "svn":
+ l = l.rstrip();
+ if l[-1:] == "/":
+ continue
+ if l[-7:] == ".ebuild":
+ eadded.append(l[:-7])
+ if vcs == "svn":
+ myf=os.popen("svn status")
+ myl=myf.readlines()
+ myf.close()
+ for l in myl:
+ if l[0] == "A":
+ l = l.rstrip().split(' ')[-1]
+ if l[-7:] == ".ebuild":
+ eadded.append(l[:-7])
except IOError:
- if options.mode == 'commit':
+ if options.mode == 'commit' and vcs == "cvs":
stats["CVS/Entries.IO_error"] += 1
fails["CVS/Entries.IO_error"].append(checkdir+"/CVS/Entries")
+ if options.mode == 'commit' and vcs == "svn":
+ stats["svn.IO_error"] += 1
+ fails["svn.IO_error"].append(checkdir+"svn info")
continue
- if isCvs and has_filesdir:
+ if isVcs and has_filesdir:
try:
- myf=open(checkdir+"/files/CVS/Entries","r")
+ if vcs == "cvs":
+ myf=open(checkdir+"/files/CVS/Entries","r")
+ if vcs == "svn":
+ myf=os.popen("svn list "+os.path.normpath(checkdir+"/files"))
myl=myf.readlines()
+ myf.close()
for l in myl:
- if l[0]!="/":
- continue
- splitl=l[1:].split("/")
- if not len(splitl):
- continue
- if splitl[0][:7]=="digest-":
- dadded.append(splitl[0][7:])
+ if vcs == "cvs":
+ if l[0]!="/":
+ continue
+ splitl=l[1:].split("/")
+ if not len(splitl):
+ continue
+ if splitl[0][:7]=="digest-":
+ dadded.append(splitl[0][7:])
+ if vcs == "svn":
+ l = l.rstrip();
+ if l[-1:] == "/":
+ continue
+ if l[:7] == "digest-":
+ dadded.append(l[7:])
+ if vcs == "svn":
+ myf=os.popen("svn status "+os.path.normpath(checkdir+"/files"))
+ myl=myf.readlines()
+ myf.close()
+ for l in myl:
+ if l[0] == "A":
+ l = l.rstrip().split(' ')[-1]
+ if l[:7] == "digest-":
+ dadded.append(l[7:])
except IOError:
- if options.mode == 'commit':
+ if options.mode == 'commit' and vcs == "cvs":
stats["CVS/Entries.IO_error"] += 1
fails["CVS/Entries.IO_error"].append(checkdir+"/files/CVS/Entries")
+ if options.mode == 'commit' and vcs == "svn":
+ stats["svn.IO_error"] += 1
+ fails["svn.IO_error"].append(checkdir+"/files svn info")
continue
mf = Manifest(checkdir, repoman_settings["DISTDIR"])
@@ -900,10 +948,11 @@
else:
raise oe
if S_ISDIR(mystat.st_mode):
- if y == "CVS":
+ # !!! VCS "portability" alert! Need some function isVcsDir() or alike !!!
+ if y == "CVS" or y == ".svn":
continue
for z in os.listdir(checkdir+"/files/"+y):
- if z == "CVS":
+ if z == "CVS" or z == ".svn":
continue
filesdirlist.append(y+"/"+z)
# current policy is no files over 20k, this is the check.
@@ -968,8 +1017,8 @@
if stat.S_IMODE(os.stat(full_path).st_mode) & 0111:
stats["file.executable"] += 1
fails["file.executable"].append(x+"/"+y+".ebuild")
- if isCvs and y not in eadded:
- #ebuild not added to cvs
+ if isVcs and y not in eadded:
+ #ebuild not added to vcs
stats["ebuild.notadded"]=stats["ebuild.notadded"]+1
fails["ebuild.notadded"].append(x+"/"+y+".ebuild")
if y in dadded:
@@ -1511,12 +1560,23 @@
if options.pretend:
print green("RepoMan sez:"), ""So, you want to play it safe. Good call."
"
- mycvstree=portage.cvstree.getentries("./",recursive=1)
- if isCvs and not mycvstree:
- print "!!! It seems we don't have a cvs tree?"
- sys.exit(3)
+ if isVcs and vcs == "cvs":
+ try:
+ myvcstree=portage.cvstree.getentries("./",recursive=1)
+ myunadded=portage.cvstree.findunadded(myvcstree,re cursive=1,basedir="./")
+ except SystemExit, e:
+ raise # TODO propogate this
+ except:
+ err("Error retrieving CVS tree; exiting.")
- myunadded=portage.cvstree.findunadded(mycvstree,re cursive=1,basedir="./")
+ if isVcs and vcs == "svn":
+ try:
+ svnstatus=os.popen("svn status").readlines()
+ myunadded = [ "./"+elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") ]
+ except SystemExit, e:
+ raise # TODO propogate this
+ except:
+ err("Error retrieving SVN info; exiting.")
myautoadd=[]
if myunadded:
for x in range(len(myunadded)-1,-1,-1):
@@ -1540,24 +1600,30 @@
if myautoadd:
print ">>> Auto-Adding missing digests..."
if options.pretend:
- print "(/usr/bin/cvs add "+" ".join(myautoadd)+")"
+ if vcs == "cvs":
+ print "(cvs add "+" ".join(myautoadd)+")"
+ if vcs == "svn":
+ print "(svn add "+" ".join(myautoadd)+")"
retval=0
else:
- retval=os.system("/usr/bin/cvs add "+" ".join(myautoadd))
+ if vcs == "cvs":
+ retval=os.system("cvs add "+" ".join(myautoadd))
+ if vcs == "svn":
+ retval=os.system("svn add "+" ".join(myautoadd))
if retval:
- print "!!! Exiting on cvs (shell) error code:",retval
+ print "!!! Exiting on vcs (shell) error code:",retval
sys.exit(retval)
if myunadded:
- print red("!!! The following files are in your cvs tree but are not added to the master")
- print red("!!! tree. Please remove them from the cvs tree or add them to the master tree.")
+ print red("!!! The following files are in your local tree but are not added to the master")
+ print red("!!! tree. Please remove them from the local tree or add them to the master tree.")
for x in myunadded:
print " ",x
print
print
sys.exit(1)
- if isCvs:
+ if vcs == "cvs":
mycvstree=portage.cvstree.getentries("./",recursive=1)
mychanged=portage.cvstree.findchanged(mycvstree,re cursive=1,basedir="./")
mynew=portage.cvstree.findnew(mycvstree,recursive= 1,basedir="./")
@@ -1566,6 +1632,18 @@
bin_blobs = set(portage.cvstree.findoption(mycvstree, bin_blob_pattern,
recursive=1, basedir="./"))
+
+ if vcs == "svn":
+ svnstatus = os.popen("svn status").readlines()
+ mychanged = [ elem.rstrip()[7:] for elem in svnstatus if elem.startswith("M") ]
+ for manifest in [ file for file in mychanged if '/Manifest' in file ]:
+ mychanged.remove(manifest)
+ mynew = [ elem.rstrip()[7:] for elem in svnstatus if elem.startswith("A") ]
+ myremoved = [ elem.rstrip()[7:] for elem in svnstatus if elem.startswith("D") ]
+ # no idea how to detect binaries in SVN
+ bin_blobs = []
+
+ if isVcs:
if not (mychanged or mynew or myremoved):
print green("RepoMan sez:"), ""Doing nothing is not always good for QA.""
print
@@ -1575,8 +1653,14 @@
# Manifests need to be regenerated after all other commits, so don't commit
# them now even if they have changed.
- mymanifests = [f for f in mychanged if 'Manifest' == os.path.basename(f)]
- mychanged = [f for f in mychanged if 'Manifest' != os.path.basename(f)]
+ # However, in SVN mode, the manifest won't change, hence, if we
+ # don't sign, we can commit it right away, avoiding an extra commit,
+ # of course this assumes SVN doesn't do Header: expansion.
+ if vcs != "svn" or "sign" in repoman_settings.features:
+ mymanifests = [f for f in mychanged if "Manifest" == os.path.basename(f)]
+ mychanged = [f for f in mychanged if "Manifest" != os.path.basename(f)]
+ else:
+ mymanifests = [] # avoid undefined error
myupdates=mychanged+mynew
myheaders=[]
mydirty=[]
@@ -1627,7 +1711,8 @@
sys.stderr.write("Failed to insert portage version in message!
")
sys.stderr.flush()
portage_version = "Unknown"
- commitmessage += "
(Portage version: "+str(portage_version)
+ unameout = commands.getstatusoutput("uname -srp")[1]
+ commitmessage+="
(Portage version: "+str(portage_version)+"/"+vcs+"/"+unameout
if options.force:
commitmessage += ", RepoMan options: --force"
commitmessage += ")"
@@ -1648,12 +1733,21 @@
retval = None
if options.pretend:
- print "(/usr/bin/cvs -q commit -F %s %s)" %
- (commitmessagefile, " ".join(myfiles))
+ if vcs == "cvs":
+ print "(cvs -q commit -F %s %s)" %
+ (commitmessagefile, " ".join(myfiles))
+ if vcs == "svn":
+ print "(svn commit -F %s %s)" %
+ (commitmessagefile, " ".join(myfiles))
else:
- retval = spawn(["/usr/bin/cvs", "-q", "commit",
- "-F", commitmessagefile] + myfiles,
- env=os.environ)
+ if vcs == "cvs":
+ retval = spawn(["cvs", "-q", "commit",
+ "-F", commitmessagefile] + myfiles,
+ env=os.environ)
+ if vcs == "svn":
+ retval = spawn(["svn", "commit",
+ "-F", commitmessagefile] + myfiles,
+ env=os.environ)
try:
os.unlink(commitmessagefile)
except OSError:
@@ -1759,14 +1853,20 @@
# Force an unsigned commit when more than one Manifest needs to be signed.
if repolevel < 3 and "sign" in repoman_settings.features:
if options.pretend:
- print "(/usr/bin/cvs -q commit -F commitmessagefile)"
+ if vcs == "cvs":
+ print "(cvs -q commit -F commitmessagefile)"
+ if vcs == "svn":
+ print "(svn -q commit -F commitmessagefile)"
else:
fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
mymsg = os.fdopen(fd, "w")
mymsg.write(commitmessage)
mymsg.write("
(Unsigned Manifest commit)")
mymsg.close()
- retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile)
+ if vcs == "cvs":
+ retval=os.system("cvs -q commit -F "+commitmessagefile)
+ if vcs == "svn":
+ retval=os.system("svn -q commit -F "+commitmessagefile)
try:
os.unlink(commitmessagefile)
except OSError:
@@ -1822,7 +1922,10 @@
if manifest_commit_required or signed:
if options.pretend:
- print "(/usr/bin/cvs -q commit -F commitmessagefile)"
+ if vcs == "cvs":
+ print "(cvs -q commit -F commitmessagefile)"
+ if vcs == "svn":
+ print "(svn -q commit -F commitmessagefile)"
else:
fd, commitmessagefile = tempfile.mkstemp(".repoman.msg")
mymsg = os.fdopen(fd, "w")
@@ -1832,7 +1935,10 @@
else:
mymsg.write("
(Unsigned Manifest commit)")
mymsg.close()
- retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile)
+ if vcs == "cvs":
+ retval=os.system("cvs -q commit -F "+commitmessagefile)
+ if vcs == "svn":
+ retval=os.system("svn -q commit -F "+commitmessagefile)
try:
os.unlink(commitmessagefile)
except OSError:
@@ -1842,10 +1948,10 @@
sys.exit(retval)
print
- if isCvs:
- print "CVS commit complete."
+ if isVcs:
+ print "Commit complete."
else:
- print "repoman was too scared by not seeing any familiar cvs file that he forgot to commit anything"
+ print "repoman was too scared by not seeing any familiar version control file that he forgot to commit anything"
print green("RepoMan sez:"), ""If everyone were like you, I'd be out of business!"
"
sys.exit(0)
--- ../../trunk/pym/repoman/utilities.py 2008-04-27 17:35:59 +0200
+++ pym/repoman/utilities.py 2008-02-24 10:33:00 +0100
@@ -42,30 +42,39 @@
retval = commands.getstatusoutput("cvs -n up 2>&1 | " +
"egrep '^[^?] .*' | " +
"egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
+ if vcs == 'svn':
+ logging.info("Performing a " + output.green("svn status -u") +
+ " with a little magic grep to check for updates.")
+ retval = commands.getstatusoutput("svn status -u 2>&1 | " +
+ "egrep -v '^. +.*/digest-[^/]+' | " +
+ "head -n-1")
+ if vcs in ['cvs', 'svn']:
mylines = retval[1].splitlines()
myupdates = []
for line in mylines:
if not line:
continue
- if line[0] not in "UPMAR": # Updates,Patches,Modified,Added,Removed
+ if line[0] not in "UPMARD": # Updates,Patches,Modified,Added,Removed/Replaced(svn),Deleted(svn)
logging.error(red("!!! Please fix the following issues reported " +
- "from cvs: ")+green("(U,P,M,A,R are ok)"))
+ "from cvs: ")+green("(U,P,M,A,R,D are ok)"))
logging.error(red("!!! Note: This is a pretend/no-modify pass..."))
logging.error(retval[1])
sys.exit(1)
- elif line[0] in "UP":
+ elif vcs == 'cvs' and line[0] in "UP":
myupdates.append(line[2:])
+ elif vcs == 'svn' and line[8] == '*':
+ myupdates.append(line[9:].lstrip(" 1234567890"))
if myupdates:
logging.info(green("Fetching trivial updates..."))
if options.pretend:
- logging.info("(cvs up "+" ".join(myupdates)+")")
+ logging.info("(" + vcs + " update " + " ".join(myupdates) + ")")
retval = os.EX_OK
else:
- retval = os.system("cvs up " + " ".join(myupdates))
+ retval = os.system(vcs + " update " + " ".join(myupdates))
if retval != os.EX_OK:
- logging.fatal("!!! cvs exited with an error. Terminating.")
+ logging.fatal("!!! " + cvs + " exited with an error. Terminating.")
sys.exit(retval)