#!/usr/bin/python# This Source Code Form is subject to the terms of the Mozilla Public# License, v. 2.0. If a copy of the MPL was not distributed with this# file, You can obtain one at http://mozilla.org/MPL/2.0/.LIBFFI_DIRS=(('js/ctypes/libffi','libffi'),)HG_EXCLUSIONS=['.hg','.hgignore','.hgtags']CVSROOT_LIBFFI=':pserver:anoncvs@sources.redhat.com:/cvs/libffi'importosimportsysimportdatetimeimportshutilimportglobfromoptparseimportOptionParserfromsubprocessimportcheck_calltopsrcdir=os.path.dirname(__file__)iftopsrcdir=='':topsrcdir='.'defcheck_call_noisy(cmd,*args,**kwargs):print"Executing command:",cmdcheck_call(cmd,*args,**kwargs)defdo_hg_pull(dir,repository,hg):fulldir=os.path.join(topsrcdir,dir)# clone if the dir doesn't exist, pull if it doesifnotos.path.exists(fulldir):check_call_noisy([hg,'clone',repository,fulldir])else:cmd=[hg,'pull','-u','-R',fulldir]ifrepositoryisnotNone:cmd.append(repository)check_call_noisy(cmd)check_call([hg,'parent','-R',fulldir,'--template=Updated to revision {node}.\n'])defdo_hg_replace(dir,repository,tag,exclusions,hg):""" Replace the contents of dir with the contents of repository, except for files matching exclusions. """fulldir=os.path.join(topsrcdir,dir)ifos.path.exists(fulldir):shutil.rmtree(fulldir)assertnotos.path.exists(fulldir)check_call_noisy([hg,'clone','-u',tag,repository,fulldir])forthinginexclusions:forexcludedinglob.iglob(os.path.join(fulldir,thing)):ifos.path.isdir(excluded):shutil.rmtree(excluded)else:os.remove(excluded)defdo_cvs_export(modules,tag,cvsroot,cvs):"""Check out a CVS directory without CVS metadata, using "export" modules is a list of directories to check out and the corresponding cvs module, e.g. (('js/ctypes/libffi', 'libffi'),) """formodule_tupleinmodules:module=module_tuple[0]cvs_module=module_tuple[1]fullpath=os.path.join(topsrcdir,module)ifos.path.exists(fullpath):print"Removing '%s'"%fullpathshutil.rmtree(fullpath)(parent,leaf)=os.path.split(module)print"CVS export begin: "+datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")check_call_noisy([cvs,'-d',cvsroot,'export','-r',tag,'-d',leaf,cvs_module],cwd=os.path.join(topsrcdir,parent))print"CVS export end: "+datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")deftoggle_trailing_blank_line(depname):"""If the trailing line is empty, then we'll delete it. Otherwise we'll add a blank line."""lines=open(depname,"r").readlines()ifnotlines:print>>sys.stderr,"unexpected short file"returnifnotlines[-1].strip():# trailing line is blank, removing itopen(depname,"wb").writelines(lines[:-1])else:# adding blank lineopen(depname,"ab").write("\n")defget_trailing_blank_line_state(depname):lines=open(depname,"r").readlines()ifnotlines:print>>sys.stderr,"unexpected short file"return"no blank line"ifnotlines[-1].strip():return"has blank line"else:return"no blank line"defupdate_nspr_or_nss(tag,depfile,destination,hgpath):destination=destination.rstrip('/')permanent_patch_dir=destination+'/patches'temporary_patch_dir=destination+'.patches'ifos.path.exists(temporary_patch_dir):print"please clean up leftover directory "+temporary_patch_dirsys.exit(2)warn_if_patch_exists(permanent_patch_dir)# protect patch directory from being removed by do_hg_replaceifos.path.exists(permanent_patch_dir):shutil.move(permanent_patch_dir,temporary_patch_dir)# now update the destinationprint"reverting to HG version of %s to get its blank line state"%depfilecheck_call_noisy([options.hg,'revert',depfile])old_state=get_trailing_blank_line_state(depfile)print"old state of %s is: %s"%(depfile,old_state)do_hg_replace(destination,hgpath,tag,HG_EXCLUSIONS,options.hg)new_state=get_trailing_blank_line_state(depfile)print"new state of %s is: %s"%(depfile,new_state)ifold_state==new_state:print"toggling blank line in: ",depfiletoggle_trailing_blank_line(depfile)tag_file=destination+"/TAG-INFO"print>>file(tag_file,"w"),tag# move patch directory back to a subdirectoryifos.path.exists(temporary_patch_dir):shutil.move(temporary_patch_dir,permanent_patch_dir)defwarn_if_patch_exists(path):# If the given patch directory exists and contains at least one file,# then print warning and wait for the user to acknowledge.ifos.path.isdir(path)andos.listdir(path):print"========================================"print"WARNING: At least one patch file exists"print"in directory: "+pathprint"You must manually re-apply all patches"print"after this script has completed!"print"========================================"raw_input("Press Enter to continue...")returno=OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname")o.add_option("--skip-mozilla",dest="skip_mozilla",action="store_true",default=False,help="Obsolete")o.add_option("--cvs",dest="cvs",default=os.environ.get('CVS','cvs'),help="The location of the cvs binary")o.add_option("--cvsroot",dest="cvsroot",help="The CVSROOT for libffi (default : %s)"%CVSROOT_LIBFFI)o.add_option("--hg",dest="hg",default=os.environ.get('HG','hg'),help="The location of the hg binary")o.add_option("--repo",dest="repo",help="the repo to update from (default: upstream repo)")try:options,args=o.parse_args()action=args[0]exceptIndexError:o.print_help()sys.exit(2)ifactionin('checkout','co'):print>>sys.stderr,"Warning: client.py checkout is obsolete."passelifactionin('update_nspr'):tag,=args[1:]depfile="nsprpub/config/prdepend.h"ifnotoptions.repo:options.repo='https://hg.mozilla.org/projects/nspr'update_nspr_or_nss(tag,depfile,'nsprpub',options.repo)elifactionin('update_nss'):tag,=args[1:]depfile="security/nss/coreconf/coreconf.dep"ifnotoptions.repo:options.repo='https://hg.mozilla.org/projects/nss'update_nspr_or_nss(tag,depfile,'security/nss',options.repo)elifactionin('update_libffi'):tag,=args[1:]ifnotoptions.cvsroot:options.cvsroot=CVSROOT_LIBFFIdo_cvs_export(LIBFFI_DIRS,tag,options.cvsroot,options.cvs)else:o.print_help()sys.exit(2)