-##############################
- def do_branch (self):
-
- # save self.branch if any, as a hint for the new branch
- # do this before anything else and restore .branch to None,
- # as this is part of the class's logic
- new_trunk_name=None
- if hasattr(self,'branch'):
- new_trunk_name=self.branch
- del self.branch
- elif self.options.new_version:
- new_trunk_name = self.options.new_version
-
- # compute diff - a way to initialize the whole stuff
- # do_diff already does edge_dir initialization
- # and it checks that edge_url and tag_url exist as well
- (spec_dict,edge_url,tag_url,diff_listing) = self.do_diff(compute_only=True)
-
- # the version name in the trunk becomes the new branch name
- branch_name = spec_dict[self.module_version_varname]
-
- # figure new branch name (the one for the trunk) if not provided on the command line
- if not new_trunk_name:
- # heuristic is to assume 'version' is a dot-separated name
- # we isolate the rightmost part and try incrementing it by 1
- version=spec_dict[self.module_version_varname]
- try:
- m=re.compile("\A(?P<leftpart>.+)\.(?P<rightmost>[^\.]+)\Z")
- (leftpart,rightmost)=m.match(version).groups()
- incremented = int(rightmost)+1
- new_trunk_name="%s.%d"%(leftpart,incremented)
- except:
- raise Exception, 'Cannot figure next branch name from %s - exiting'%version
-
- # record starting point tagname
- latest_tag_name = self.tag_name(spec_dict)
-
- print "**********"
- print "Using starting point %s (%s)"%(tag_url,latest_tag_name)
- print "Creating branch %s & moving trunk to %s"%(branch_name,new_trunk_name)
- print "**********"
-
- # print warning if pending diffs
- if diff_listing:
- print """*** WARNING : Module %s has pending diffs on its trunk
-It is safe to proceed, but please note that branch %s
-will be based on latest tag %s and *not* on the current trunk"""%(self.name,branch_name,latest_tag_name)
- while True:
- answer = prompt ('Are you sure you want to proceed with branching',True,('d','iff'))
- if answer is True:
- break
- elif answer is False:
- raise Exception,"User quit"
- elif answer == 'd':
- print '<<<< %s'%tag_url
- print '>>>> %s'%edge_url
- print diff_listing
-
- branch_url = "%s/%s/branches/%s"%(Module.config['svnpath'],self.name,branch_name)
- self.check_svnpath_not_exists (branch_url,"new branch")
-
- # patching trunk
- spec_dict[self.module_version_varname]=new_trunk_name
- spec_dict[self.module_taglevel_varname]='0'
- # remember this in the trunk for easy location of the current branch
- spec_dict['module_current_branch']=branch_name
- self.patch_spec_var(spec_dict,True)
-
- # create commit log file
- tmp="/tmp/branching-%d"%os.getpid()
- f=open(tmp,"w")
- f.write("Branch %s for module %s created (as new trunk) from tag %s\n"%(new_trunk_name,self.name,latest_tag_name))
- f.close()
-
- # we're done, let's commit the stuff
- command="svn diff %s"%self.edge_dir()
- self.run_prompt("Review changes in trunk",command)
- command="svn copy --file %s %s %s"%(tmp,self.edge_url(),branch_url)
- self.run_prompt("Create branch",command)
- command="svn commit --file %s %s"%(tmp,self.edge_dir())
- self.run_prompt("Commit trunk",command)
- new_tag_url=self.tag_url(spec_dict)
- command="svn copy --file %s %s %s"%(tmp,self.edge_url(),new_tag_url)
- self.run_prompt("Create initial tag in trunk",command)
- os.unlink(tmp)
-
-##############################
-class Package:
-
- def __init__(self, package, module, svnpath, spec):
- self.package=package
- self.module=module
- self.svnpath=svnpath
- self.spec=spec
- self.specpath="%s/%s"%(svnpath,spec)
- self.basename=os.path.basename(svnpath)
-
- # returns a http URL to the trac path where full diff can be viewed (between self and pkg)
- # typically http://svn.planet-lab.org/changeset?old_path=Monitor%2Ftags%2FMonitor-1.0-7&new_path=Monitor%2Ftags%2FMonitor-1.0-13
- # xxx quick & dirty: rough url parsing
- def trac_full_diff (self, pkg):
- matcher=re.compile("\A(?P<method>.*)://(?P<hostname>[^/]+)/(svn/)?(?P<path>.*)\Z")
- self_match=matcher.match(self.svnpath)
- pkg_match=matcher.match(pkg.svnpath)
- if self_match and pkg_match:
- (method,hostname,svn,path)=self_match.groups()
- self_path=path.replace("/","%2F")
- pkg_path=pkg_match.group('path').replace("/","%2F")
- return "%s://%s/changeset?old_path=%s&new_path=%s"%(method,hostname,self_path,pkg_path)
- else:
- return None
-
- def details (self):
- return "[%s %s] [%s (spec)]"%(self.svnpath,self.basename,self.specpath)
-
-class Build (Module):
-
- # we cannot get build's svnpath as for other packages as we'd get something in svn+ssh
- # xxx quick & dirty
- def __init__ (self, buildtag,options):
- self.buildtag=buildtag
- # if the buildtag start with a : (to use a branch rather than a tag)
- if buildtag.find(':') == 0 :
- module_name="build%(buildtag)s"%locals()
- self.display=buildtag[1:]
- self.svnpath="http://svn.planet-lab.org/svn/build/branches/%s"%self.display
- else :
- module_name="build@%(buildtag)s"%locals()
- self.display=buildtag
- self.svnpath="http://svn.planet-lab.org/svn/build/tags/%s"%self.buildtag
- Module.__init__(self,module_name,options)
-
- @staticmethod
- def get_distro_from_distrotag (distrotag):
- # mhh: remove -tag* from distrotags to get distro
- n=distrotag.find('-tag')
- if n>0:
- return distrotag[:n]
- else:
- return None
-
- def get_packages (self,distrotag):
- result={}
- distro=Build.get_distro_from_distrotag(distrotag)
- if not distro:
- return result
- make_options="--no-print-directory -C %s stage1=true PLDISTRO=%s PLDISTROTAGS=%s 2> /dev/null"%(self.edge_dir(),distro,distrotag)
- command="make %s packages"%make_options
- make_packages=Command(command,self.options).output_of()
- pkg_line=re.compile("\Apackage=(?P<package>[^\s]+)\s+ref_module=(?P<module>[^\s]+)\s.*\Z")
- for line in make_packages.split("\n"):
- if not line:
- continue
- attempt=pkg_line.match(line)
- if line and not attempt:
- print "====="
- print "WARNING: line not understood from make packages"
- print "in dir %s"%self.edge_dir
- print "with options",make_options
- print 'line=',line
- print "====="
- else:
- (package,module) = (attempt.group('package'),attempt.group('module'))
- command="make %s +%s-SVNPATH"%(make_options,module)
- svnpath=Command(command,self.options).output_of().strip()
- command="make %s +%s-SPEC"%(make_options,package)
- spec=Command(command,self.options).output_of().strip()
- result[package]=Package(package,module,svnpath,spec)
- return result
-
- def get_distrotags (self):
- return [os.path.basename(p) for p in glob("%s/*tags*mk"%self.edge_dir())]
-
-class DiffCache:
-
- def __init__ (self):
- self._cache={}
-
- def key(self, frompath,topath):
- return frompath+'-to-'+topath
-
- def fetch (self, frompath, topath):
- key=self.key(frompath,topath)
- if not self._cache.has_key(key):
- return None
- return self._cache[key]
-
- def store (self, frompath, topath, diff):
- key=self.key(frompath,topath)
- self._cache[key]=diff
-
-class Release:
-
- # header in diff output
- discard_matcher=re.compile("\A(\+\+\+|---).*")
-
- @staticmethod
- def do_changelog (buildtag_new,buildtag_old,options):
- print "----"
- print "----"
- print "----"
- (build_new,build_old) = (Build (buildtag_new,options), Build (buildtag_old,options))
- print "= build tag %s to %s = #build-%s"%(build_old.display,build_new.display,build_new.display)
- for b in (build_new,build_old):
- b.init_module_dir()
- b.init_edge_dir()
- b.update_edge_dir()
- # find out the tags files that are common, unless option was specified
- if options.distrotags:
- distrotags=options.distrotags
- else:
- distrotags_new=build_new.get_distrotags()
- distrotags_old=build_old.get_distrotags()
- distrotags = list(set(distrotags_new).intersection(set(distrotags_old)))
- distrotags.sort()
- if options.verbose: print "Found distrotags",distrotags
- first_distrotag=True
- diffcache = DiffCache()
- for distrotag in distrotags:
- distro=Build.get_distro_from_distrotag(distrotag)
- if not distro:
- continue
- if first_distrotag:
- first_distrotag=False
- else:
- print '----'
- print '== distro %s (%s to %s) == #distro-%s-%s'%(distrotag,build_old.display,build_new.display,distro,build_new.display)
- print ' * from %s/%s'%(build_old.svnpath,distrotag)
- print ' * to %s/%s'%(build_new.svnpath,distrotag)
-
- # parse make packages
- packages_new=build_new.get_packages(distrotag)
- pnames_new=set(packages_new.keys())
- if options.verbose: print 'got packages for ',build_new.display
- packages_old=build_old.get_packages(distrotag)
- pnames_old=set(packages_old.keys())
- if options.verbose: print 'got packages for ',build_old.display
-
- # get created, deprecated, and preserved package names
- pnames_created = list(pnames_new-pnames_old)
- pnames_created.sort()
- pnames_deprecated = list(pnames_old-pnames_new)
- pnames_deprecated.sort()
- pnames = list(pnames_new.intersection(pnames_old))
- pnames.sort()
-
- if options.verbose: print "Found new/deprecated/preserved pnames",pnames_new,pnames_deprecated,pnames
-
- # display created and deprecated
- for name in pnames_created:
- print '=== %s : new package %s -- appeared in %s === #package-%s-%s-%s'%(
- distrotag,name,build_new.display,name,distro,build_new.display)
- pobj=packages_new[name]
- print ' * %s'%pobj.details()
- for name in pnames_deprecated:
- print '=== %s : package %s -- deprecated, last occurrence in %s === #package-%s-%s-%s'%(
- distrotag,name,build_old.display,name,distro,build_new.display)
- pobj=packages_old[name]
- if not pobj.svnpath:
- print ' * codebase stored in CVS, specfile is %s'%pobj.spec
- else:
- print ' * %s'%pobj.details()
-
- # display other packages
- for name in pnames:
- (pobj_new,pobj_old)=(packages_new[name],packages_old[name])
- if options.verbose: print "Dealing with package",name
- if pobj_old.specpath == pobj_new.specpath:
- continue
- specdiff = diffcache.fetch(pobj_old.specpath,pobj_new.specpath)
- if specdiff is None:
- command="svn diff %s %s"%(pobj_old.specpath,pobj_new.specpath)
- specdiff=Command(command,options).output_of()
- diffcache.store(pobj_old.specpath,pobj_new.specpath,specdiff)
- else:
- if options.verbose: print 'got diff from cache'
- if not specdiff:
- continue
- print '=== %s - %s to %s : package %s === #package-%s-%s-%s'%(
- distrotag,build_old.display,build_new.display,name,name,distro,build_new.display)
- print ' * from %s to %s'%(pobj_old.details(),pobj_new.details())
- trac_diff_url=pobj_old.trac_full_diff(pobj_new)
- if trac_diff_url:
- print ' * [%s View full diff]'%trac_diff_url
- print '{{{'
- for line in specdiff.split('\n'):
- if not line:
- continue
- if Release.discard_matcher.match(line):
- continue
- if line[0] in ['@']:
- print '----------'
- elif line[0] in ['+','-']:
- print_fold(line)
- print '}}}'