Add subversion support for repoman (patch by Fabien Groffen, http://archives.gentoo...
authorMarius Mauch <genone@gentoo.org>
Tue, 13 May 2008 22:33:58 +0000 (22:33 -0000)
committerMarius Mauch <genone@gentoo.org>
Tue, 13 May 2008 22:33:58 +0000 (22:33 -0000)
svn path=/main/trunk/; revision=10325

bin/repoman
pym/portage/sets/libs.py
pym/repoman/utilities.py

index ad487fd8b211462ee467e620ba205bbc6ee4994d..953e4d88ef244e1740ce70c52527f19d8aca9a1e 100755 (executable)
@@ -421,12 +421,13 @@ if options.mode in ('last', 'lfull'):
 can_force = True
 
 
-isCvs=False
-myreporoot=None
+vcs = None
 if os.path.isdir("CVS"):
-       isCvs = True
+       vcs = "cvs"
+if os.path.isdir(".svn"):
+       vcs = "svn"
 
-if isCvs and \
+if vcs == "cvs" and \
        "commit" == options.mode and \
        "RMD160" not in portage.checksum.hashorigin_map:
        from portage.util import grablines
@@ -444,8 +445,8 @@ if isCvs and \
                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 vcs:
+       logging.info("Not in a version controlled repository; enabling pretend mode.")
        options.pretend = True
 
 try:
@@ -488,7 +489,7 @@ repolevel = len(reposplit)
 # 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 +695,8 @@ else:
        #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 vcs:
+       utilities.detect_vcs_conflicts(options, vcs)
 
 if options.mode == "manifest":
        pass
@@ -705,7 +706,7 @@ else:
        print green("\nRepoMan 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 +813,86 @@ for x in scanlist:
        if not os.path.isdir(os.path.join(checkdir, "files")):
                has_filesdir = False
 
-       if isCvs:
+       if vcs:
                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 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 vcs 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 +947,11 @@ for x in scanlist:
                                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 +1016,8 @@ for x in scanlist:
                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 vcs 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 +1559,23 @@ else:
        if options.pretend:
                print green("RepoMan sez:"), "\"So, you want to play it safe. Good call.\"\n"
 
-       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 vcs == "cvs":
+               try:
+                       myvcstree=portage.cvstree.getentries("./",recursive=1)
+                       myunadded=portage.cvstree.findunadded(myvcstree,recursive=1,basedir="./")
+               except SystemExit, e:
+                       raise  # TODO propogate this
+               except:
+                       err("Error retrieving CVS tree; exiting.")
 
-       myunadded=portage.cvstree.findunadded(mycvstree,recursive=1,basedir="./")
+       if 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 +1599,30 @@ else:
        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,recursive=1,basedir="./")
                mynew=portage.cvstree.findnew(mycvstree,recursive=1,basedir="./")
@@ -1566,6 +1631,18 @@ else:
                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 vcs:
                if not (mychanged or mynew or myremoved):
                        print green("RepoMan sez:"), "\"Doing nothing is not always good for QA.\""
                        print
@@ -1575,18 +1652,18 @@ else:
 
        # 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)]
-       myupdates=mychanged+mynew
-       myheaders=[]
-       mydirty=[]
-       headerstring="'\$(Header|Id)"
-       headerstring+=".*\$'"
+       mymanifests = [f for f in mychanged if "Manifest" == os.path.basename(f)]
+       mychanged = [f for f in mychanged if "Manifest" != os.path.basename(f)]
+       myupdates = mychanged + mynew
+       myheaders = []
+       mydirty = []
+       headerstring = "'\$(Header|Id)"
+       headerstring += ".*\$'"
        for myfile in myupdates:
                if myfile in bin_blobs:
                        continue
                myout = commands.getstatusoutput("egrep -q "+headerstring+" "+myfile)
-               if myout[0]==0:
+               if myout[0] == 0:
                        myheaders.append(myfile)
 
        print "*",green(str(len(myupdates))),"files being committed...",green(str(len(myheaders))),"have headers that will change."
@@ -1627,7 +1704,8 @@ else:
                sys.stderr.write("Failed to insert portage version in message!\n")
                sys.stderr.flush()
                portage_version = "Unknown"
-       commitmessage += "\n(Portage version: "+str(portage_version)
+       unameout = commands.getstatusoutput("uname -srp")[1]
+       commitmessage+="\n(Portage version: "+str(portage_version)+"/"+vcs+"/"+unameout
        if options.force:
                commitmessage += ", RepoMan options: --force"
        commitmessage += ")"
@@ -1648,12 +1726,21 @@ else:
 
                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 +1846,20 @@ else:
                # 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("\n (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 +1915,10 @@ else:
 
        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 +1928,10 @@ else:
                        else:
                                mymsg.write("\n (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 +1941,10 @@ else:
                                sys.exit(retval)
 
        print
-       if isCvs:
-               print "CVS commit complete."
+       if vcs:
+               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)
 
index 4ab8a33fe04a4f4115e09c4871bd76f584ea7bcc..8159cc35f946d9fbc4eaf702fa93b6df0f431ea1 100644 (file)
@@ -37,7 +37,11 @@ class PreservedLibraryConsumerSet(LibraryConsumerSet):
                if reg:
                        for libs in reg.getPreservedLibs().values():
                                for lib in libs:
-                                       #print lib, self.dbapi.linkmap.findConsumers(lib)
+                                       if self.debug:
+                                               print lib
+                                               for x in sorted(self.dbapi.linkmap.findConsumers(lib)):
+                                                       print "    ", x
+                                               print "-"*40
                                        consumers.update(self.dbapi.linkmap.findConsumers(lib))
                else:
                        return
@@ -46,5 +50,5 @@ class PreservedLibraryConsumerSet(LibraryConsumerSet):
                self._setAtoms(self.mapPathsToAtoms(consumers))
 
        def singleBuilder(cls, options, settings, trees):
-               return PreservedLibraryConsumerSet(trees["vartree"].dbapi)
+               return PreservedLibraryConsumerSet(trees["vartree"].dbapi, True)
        singleBuilder = classmethod(singleBuilder)
index 7666ba5d6ff8f12c9ed6f8c191d4db27c69d8e0c..28df593cf04a73848d6333ffc5781105a98f062e 100644 (file)
@@ -42,30 +42,39 @@ def detect_vcs_conflicts(options, vcs):
                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)