Hi all, Please find attached the patch of the prefix repoman sources against the current trunk. I hope I removed all hunks that have prefix-only changes.
The current diff is mainly SVN support for Repoman. I extracted the SVN diffs only. Most of the original work was done by Kito, and recently I wiped the dust off of it, and finalised it into some working version. So far the good news, the bad news now regarding this patch: I had to somehow hardcode the svn repo being used, as I didn't find a way to let repoman figure out dynamically what the "offset" in the SVN repository is where the portage tree starts. This is kind of similar to how CVS support is done, where this offset is also hardcoded. While I think repoman's CVS support has always been used as-is -- nowadays people prefer to start non-CVS repos, the SVN support as in this patch would, considering the many overlays in SVN around, surely benefit from some sort of solution that allows to set the "repository offset" or something, e.g. through a variable. Thoughts? -- Fabian Groffen Gentoo on a different level
--- ../../trunk/bin/repoman 2006-11-23 18:15:36 +0100 +++ bin/repoman 2006-11-20 21:52:30 +0100 @@ -407,9 +409,80 @@ os.environ["FEATURES"]=repoman_settings["FEATURES"]+" cvs" isCvs = True -if not "--pretend" in myoptions and not isCvs: + try: + isCvs=True + myrepofile=open("CVS/Repository") + myreporoot=myrepofile.readline()[:-1] + myrepofile.close() + myrepofile=open("CVS/Root") + myreporootpath=string.split(myrepofile.readline()[:-1], ":")[-1] + myrepofile.close() + if myreporootpath == myreporoot[:len(myreporootpath)]: + # goofy os x cvs co. + myreporoot = myreporoot[len(myreporootpath):] + while myreporoot and myreporoot[0] == '/': + myreporoot = myreporoot[1:] + except SystemExit, e: + raise # Need to propogate this + except: + err("Error grabbing repository information; exiting.") + myreporootpath=os.path.normpath(myreporootpath) + if myreporootpath=="/space/cvsroot": + print + print + print red("You're using the wrong cvsroot. For Manifests to be correct, you must") + print red("use the same base cvsroot path that the servers use. Please try the") + print red("following script to remedy this:") + print + print "cd my_cvs_tree" + print + print "rm -Rf [a-z]*" + print "cvs up" + print + if portage.userland=="BSD" or portage.userland=="Darwin": + print "find ./ -type f -regex '.*/CVS/Root$' -print0 | xargs -0 sed \\" + else: + print "find ./ -type f -regex '.*/CVS/Root$' -print0 | xargs -0r sed \\" + fi + print " -i 's:/space/cvsroot$:/home/cvsroot:'" + print + print red("You must clear and re-update your tree as all header tags will cause") + print red("problems in manifests for all rsync and /home/cvsroot users.") + print + print "You should do this to any other gentoo trees your have as well," + print "excluding the deletions. 'gentoo-src' should be /home/cvsroot." + print + sys.exit(123) + +isSvn=False +myreporoot=None +if os.path.isdir(".svn"): + if "svn" not in repoman_settings.features: + print + print + print red('!!! You do not have ')+bold('FEATURES="svn" ')+red("enabled...") + print red("!!! ")+bold("Adding \"svn\" to FEATURES") + print + os.environ["FEATURES"]=repoman_settings["FEATURES"]+" svn" + + try: + isSvn=True + myrepoinfo = os.popen("svn info").readlines() + myurl = myrepoinfo[1][5:].rstrip() + myreproot = myrepoinfo[2][17:].rstrip() + # This one is EVIL, but I don't know how to solve the problem of + # getting rid of /trunk/prefix-overlay. This only works on the + # prefix overlay. + myreporoot = "/".join(myurl[len(myreproot):].split("/")[2:]) + myreporootpath = "/" + "/".join(myreproot.split("/")[3:]) + except SystemExit, e: + raise # Need to propogate this + except: + err("Error grabbing repository information; exiting.") + +if not "--pretend" in myoptions and not isCvs and not isSvn: print - print darkgreen("Not in a CVS repository; enabling pretend mode.") + print darkgreen("Not in a CVS or SVN repository; enabling pretend mode.") myoptions.append("--pretend"); @@ -490,14 +563,17 @@ myreporoot = os.path.basename(portdir_overlay) myreporoot += mydir[len(portdir_overlay):-1] -reposplit=string.split(myreporoot,"/") +if isSvn: + reposplit=string.split(myreporoot,"/") +else: + reposplit=string.split(myreporoot,"/") repolevel=len(reposplit) # check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting. # Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating. # this check ensure that repoman knows where it is, and the manifest recommit is at least possible. if mymode == "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 cvs or svn 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("***") @@ -775,7 +851,7 @@ s = s[s.rfind("\n") + 1:] fails["file.UTF8"].append("%s/%s: line %i, just after: '%s'" % (checkdir, y, line, s)) - if isCvs: + if isCvs or isSvn: try: mystat=os.stat(checkdir+"/files")[0] if len(ebuildlist) and not S_ISDIR(mystat): @@ -787,37 +863,83 @@ fails["filedir.missing"].append(checkdir) continue try: - myf=open(checkdir+"/CVS/Entries","r") - myl=myf.readlines() + if isCvs: + myf=open(checkdir+"/CVS/Entries","r") + if isSvn: + 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 isCvs: + if l[0]!="/": + continue + splitl=l[1:].split("/") + if not len(splitl): + continue + if splitl[0][-7:]==".ebuild": + eadded.append(splitl[0][:-7]) + if isSvn: + l = l.rstrip(); + if l[-1:] == "/": + continue + if l[-7:] == ".ebuild": + eadded.append(l[:-7]) + if isSvn: + 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 mymode=="commit": + if mymode=="commit" and isCvs: stats["CVS/Entries.IO_error"] += 1 fails["CVS/Entries.IO_error"].append(checkdir+"/CVS/Entries") + if mymode=="commit" and isSvn: + stats["svn.IO_error"] += 1 + fails["svn.IO_error"].append(checkdir+"svn info") continue try: - myf=open(checkdir+"/files/CVS/Entries","r") + if isCvs: + myf=open(checkdir+"/files/CVS/Entries","r") + if isSvn: + 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 isCvs: + if l[0]!="/": + continue + splitl=l[1:].split("/") + if not len(splitl): + continue + if splitl[0][:7]=="digest-": + dadded.append(splitl[0][7:]) + if isSvn: + l = l.rstrip(); + if l[-1:] == "/": + continue + if l[:7] == "digest-": + dadded.append(l[7:]) + if isSvn: + 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 mymode=="commit": + if mymode=="commit" and isCvs: stats["CVS/Entries.IO_error"] += 1 fails["CVS/Entries.IO_error"].append(checkdir+"/files/CVS/Entries") + if mymode=="commit" and isSvn: + stats["svn.IO_error"] += 1 + fails["svn.IO_error"].append(checkdir+"/files svn info") continue if mymode == "commit": @@ -834,7 +956,7 @@ for y in filesdirlist: if y[:7]=="digest-": if y[7:] not in dadded: - #digest not added to cvs + #digest not added to cvs or svn stats["digest.notadded"]=stats["digest.notadded"]+1 fails["digest.notadded"].append(x+"/files/"+y) if y[7:] in eadded: @@ -849,10 +971,14 @@ if y[7:] not in ebuildlist: #stray digest if mymode=="fix": + if isCvs: + vcsrm="cvs rm -f" + if isSvn: + vcsrm="svn rm --force" if "--pretend" in myoptions: - print "(cd "+repodir+"/"+x+"/files; cvs rm -f "+y+")" + print "(cd "+repodir+"/"+x+"/files; "+vcsrm+" "+y+")" else: - os.system("(cd "+repodir+"/"+x+"/files; cvs rm -f "+y+")") + os.system("(cd "+repodir+"/"+x+"/files; "+vcsrm+" "+y+")") else: stats["digest.stray"]=stats["digest.stray"]+1 fails["digest.stray"].append(x+"/files/"+y) @@ -907,10 +1033,10 @@ else: raise oe if S_ISDIR(mystat.st_mode): - if y == "CVS": + 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. @@ -966,9 +1092,9 @@ if mymode=="fix": if "--pretend" in myoptions: print "You will need to run:" - print " /usr/bin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest" + print " "+portage_const.PORTAGE_BASE+"/bin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest" else: - retval=os.system("/usr/bin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest") + retval=os.system(portage_const.PORTAGE_BASE+"/bin/ebuild "+repodir+"/"+x+"/"+y+".ebuild digest") if retval: print "!!! Exiting on ebuild digest (shell) error code:",retval sys.exit(retval) @@ -1218,7 +1344,7 @@ fails[mykey].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+repr(mydep[1])) # this check needs work, it won't catch (\ndie) - if not os.system("egrep '^[^#]*\([^)]*\<die\>' "+checkdir+"/"+y+".ebuild >/dev/null 2>&1"): + if not os.system(portage_const.EPREFIX+"/usr/bin/grep -E '^[^#]*\([^)]*\<die\>' "+checkdir+"/"+y+".ebuild >/dev/null 2>&1"): stats["ebuild.nesteddie"]=stats["ebuild.nesteddie"]+1 fails["ebuild.nesteddie"].append(x+"/"+y+".ebuild") # uselist checks - global @@ -1390,7 +1518,7 @@ #dofull will be set if we should print a "repoman full" informational message dofull=0 for x in qacats: - if not isCvs and (string.find(x, "notadded") != -1): + if not isCvs and not isSvn and (string.find(x, "notadded") != -1): stats[x] = 0 if stats[x]: dowarn=1 @@ -1469,12 +1597,23 @@ print "!!! Exiting on ebuild digest (shell) error code:",retval sys.exit(retval) - mycvstree=cvstree.getentries("./",recursive=1) - if isCvs and not mycvstree: - print "!!! It seems we don't have a cvs tree?" - sys.exit(3) + if isCvs: + try: + myvcstree=cvstree.getentries("./",recursive=1) + myunadded=cvstree.findunadded(myvcstree,recursive=1,basedir="./") + except SystemExit, e: + raise # TODO propogate this + except: + err("Error retrieving CVS tree; exiting.") - myunadded=cvstree.findunadded(mycvstree,recursive=1,basedir="./") + if isSvn: + 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): @@ -1498,17 +1637,23 @@ if myautoadd: print ">>> Auto-Adding missing digests..." if "--pretend" in myoptions: - print "(/usr/bin/cvs add "+string.join(myautoadd)+")" + if isCvs: + print "(cvs add "+string.join(myautoadd)+")" + if isSvn: + print "(svn add "+string.join(myautoadd)+")" retval=0 else: - retval=os.system("/usr/bin/cvs add "+string.join(myautoadd)) + if isCvs: + retval=os.system("cvs add "+string.join(myautoadd)) + if isSvn: + retval=os.system("svn add "+string.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 @@ -1518,31 +1663,42 @@ retval=["",""] if isCvs: print "Performing a "+green("cvs -n up")+" with a little magic grep to check for updates." - retval=getstatusoutput("/usr/bin/cvs -n up 2>&1 | egrep '^[^\?] .*' | egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'") - + retval=getstatusoutput(portage_const.EPREFIX+"/usr/bin/cvs -n up 2>&1 | "+portage_const.EPREFIX+"/bin/egrep '^[^\?] .*' | "+portage_const.EPREFIX+"/bin/egrep -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'") + if isSvn: + print "Performing a "+green("svn update -u")+" with a little magic grep to check for updates." + retval=getstatusoutput(portage_const.EPREFIX+"/usr/bin/svn status -u 2>&1 | "+portage_const.EPREFIX+"/bin/egrep -v '^. +.*/digest-[^/]+' | "+portage_const.EPREFIX+"/bin/egrep -v '^Status against revision:'") + mylines=string.split(retval[1], "\n") myupdates=[] for x in mylines: if not x: continue - if x[0] not in "UPMAR": # Updates,Patches,Modified,Added,Removed - print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R are ok)") - print red("!!! Note: This is a pretend/no-modify pass...") + if x[0] not in "UPMARD": # Updates,Patches,Modified,Added,Removed/Replaced(svn),Deleted(svn) + print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R,D are ok)") + if isCvs: + print red("!!! Note: This is a pretend/no-modify pass...") + if isSvn: + print red("!!! Note: This your local checkout has been modified!") print retval[1] print sys.exit(1) - elif x[0] in ["U","P"]: + elif isCvs and x[0] in ["U","P"]: myupdates+=[x[2:]] + elif isSvn and x[8] == '*': + myupdates+=[x[9:].lstrip(" 1234567890")] if myupdates: print green("Fetching trivial updates...") if "--pretend" in myoptions: - print "(/usr/bin/cvs up "+string.join(myupdates)+")" + print "(cvs/svn up "+string.join(myupdates)+")" retval=0 else: - retval=os.system("/usr/bin/cvs up "+string.join(myupdates)) + if isCvs: + retval=os.system("cvs up "+string.join(myupdates)) + elif isSvn: + retval=os.system("svn update "+string.join(myupdates)) if retval!=0: - print "!!! cvs exited with an error. Terminating." + print "!!! cvs/svn exited with an error. Terminating." sys.exit(retval) if isCvs: @@ -1552,6 +1708,15 @@ mychanged.remove(manifest) mynew=cvstree.findnew(mycvstree,recursive=1,basedir="./") myremoved=cvstree.findremoved(mycvstree,recursive=1,basedir="./") + if isSvn: + 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") ] + + if isCvs or isSvn: if not (mychanged or mynew or myremoved): print print green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\"\n" @@ -1590,15 +1755,20 @@ raise # We've read the content so the file is no longer needed. commitmessagefile = None - if not commitmessage: - print "Please enter a CVS commit message at the prompt:" + + if not (commitmessage or commitmessagefile): + print "Please enter a commit message at the prompt:" while not commitmessage: try: commitmessage=raw_input(green("> ")) except KeyboardInterrupt: exithandler() try: - commitmessage+="\n(Portage version: "+str(portage.VERSION)+")" + commitmessage+="\n(Portage version: "+str(portage.VERSION)+"-prefix/Repoman-" + if isCvs: + commitmessage+="CVS)" + elif isSvn: + commitmessage+="SVN)" except AttributeError: print "Failed to insert portage version in message!" commitmessage+="\n(Portage version: Unknown)" @@ -1620,12 +1790,19 @@ retval = None if "--pretend" in myoptions: - print "(/usr/bin/cvs -q commit -F "+ commitmessagefile +" "+ string.join(myupdates," ")+")" + if isCvs: + print "(cvs -q commit -F "+commitmessagefile+")" + if isSvn: + print "(svn commit -F "+commitmessagefile+")" + retval=0 else: - retval=os.system("/usr/bin/cvs -q commit -F "+ commitmessagefile + " " +string.join(myupdates, " ")) - if retval: - print "!!! Exiting on cvs (shell) error code:",retval - sys.exit(retval) + if isCvs: + retval=os.system("cvs -q commit -F "+commitmessagefile) + if isSvn: + retval=os.system("svn commit -F "+commitmessagefile) + if retval: + print "!!! Exiting on vcs (shell) error code:",retval + sys.exit(retval) # Setup the GPG commands def gpgsign(filename): @@ -1700,13 +1877,13 @@ # Force an unsigned commit when more than one Manifest needs to be signed. if repolevel < 3 and "sign" in repoman_settings.features: if "--pretend" in myoptions: - print "(/usr/bin/cvs -q commit -F "+commitmessagefile+")" + print "(cvs -q commit -F "+commitmessagefile+")" else: mymsg=open(commitmessagefile,"w") mymsg.write(commitmessage) mymsg.write("\n (Unsigned Manifest commit)") mymsg.close() - retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile) + retval=os.system("cvs -q commit -F "+commitmessagefile) if retval: print "!!! Exiting on cvs (shell) error code:",retval sys.exit(retval) @@ -1750,7 +1927,10 @@ if need_commit or signed: if "--pretend" in myoptions: - print "(/usr/bin/cvs -q commit -F "+commitmessagefile+")" + if isCvs: + print "(cvs -q commit -F "+commitmessagefile+")" + if isSvn: + print "(svn -q commit -F "+commitmessagefile+")" else: mymsg=open(commitmessagefile,"w") mymsg.write(commitmessage) @@ -1759,7 +1939,10 @@ else: mymsg.write("\n (Unsigned Manifest commit)") mymsg.close() - retval=os.system("/usr/bin/cvs -q commit -F "+commitmessagefile) + if isCvs: + retval=os.system("cvs -q commit -F "+commitmessagefile) + if isSvn: + retval=os.system("svn -q commit -F "+commitmessagefile) if retval: print "!!! Exiting on cvs (shell) error code:",retval sys.exit(retval) @@ -1767,10 +1950,10 @@ if unlinkfile: os.unlink(commitmessagefile) print - if isCvs: - print "CVS commit complete." + if isCvs or isSvn: + 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!\"\n" sys.exit(0)