#!/usr/bin/env python2 import re import os import os.path import pwd import optparse import sys import time import socket #Define the command line options and parse the command line. parser = optparse.OptionParser() parser.add_option("-d","--dry-run",action="store_true", dest="dryRun",default=True, help="Determine the release versions, but do nothing.") parser.add_option("--devel",dest="develRelease", help="Set the new development release to VERSION.", metavar="VERSION") parser.add_option("--stable",dest="stableRelease", help="Set the new stable release to VERSION.", metavar="VERSION") parser.add_option("--apply",action="store_false", dest="dryRun", help="Create a frozen release branch and a new devel head.") parser.add_option("--new-version",action="store_true", dest="newVersion", help="Increment the major version number by 1. Use this is the package has major interface changes.") parser.add_option("--no-mail",action="store_true", dest="noMail", default=False, help="Don't send the freeze mail message (for when you don't have a mailer available).") parser.add_option("--trace",action="store_true", dest="trace", default=True, help="Print commands before executing them.") parser.add_option("--no-trace",action="store_false", dest="trace", help="Don't print commands before executing them.") parser.add_option("--new-copy",action="store_false", dest="continuation", default=True, help="Don't rename current development directory.") parser.add_option("--patch-release",action="store_true", dest="patchRelease", default=False, help="Set a sticky tag for a stable patch release.") parser.add_option("--final-tag",action="store_true", dest="finalTag", default=True, help="Set a sticky tag for the old version.") parser.add_option("--no-final-tag",action="store_false", dest="finalTag", help="Don't set a sticky tag for the old version.") parser.add_option("--make-template",action="store_true", dest="onlyMakeTemplate", default=False, help="Only create a history template file and exit.") parser.add_option("--name_tag",dest="nameTag", help="Set and additional named tag for a stable release of the comet package.") parser.add_option("--version-history",action="store", dest="versionHistory",type="string", default=None, help="Specify version history file. Defaults to None.") parser.add_option("--disable_check_message",action="store_false", dest="check_message",default=True, help="Disable verification checks on the freeze message. Sometimes for minor freezes these cannot be met and this switch can be used to avoid using filler. This does NOT absolve you from using a complete release history in a freeze!") parser.add_option("--skip-uptodate-check",action="store_true", dest="skipuptodatecheck", default=False, help="Skip the module uptodate check. This allows freezing to proceed if the check of the cvs repository appears that the head/patchhead is not the same as this version. Proceed with caution.") (options,args) = parser.parse_args() ############################################################ def System(command): """Run a system command after apply the effect of command line options This responds to the --dry-run and --apply options. """ global options if options.trace: print " Trace: " + command if not options.dryRun: os.system(command) ############################################################ def UnpackVersion(versionString): """Unpack the version string This has the regular expressions needed to turn the text version string into a sequence of integers. Note patch is not required and -1 means no patch number. """ version = 0 release = 0 patch = -1 # Determine the numeric version, release, and patch. match = re.compile(r'v(\d+)r(\d+)p(\d+)').match(versionString) if match: version = int(match.group(1)) release = int(match.group(2)) patch = int(match.group(3)) match = re.compile(r'v(\d+)r(\d+)').match(versionString) if match: version = int(match.group(1)) release = int(match.group(2)) match = re.compile(r'v(\d+)').match(versionString) if match: version = int(match.group(1)) return (version, release, patch) ############################################################ def GetPackageNameAndVersion(): """Get the name and version of the current package. This will return a tuple of the path of the package root, the full package name, the (sub)package name and the package version. For most packages, which are not part of a sub package, the full package name and the (sub)package name are the same. For a sub package, e.g. monitor/monBase, the full package name is 'monitor/monBase' and the (sub)package name is just 'monBase'. Always use the (sub)package name when creating file names because you don't want a / in the filename! To check if we have a package or a subpackge we use the CVS/Repository file as this is a reliable way to get this. Should this be wrong we won't be able to write to the repository anyway. """ # Check if the command is being run in a cmt controlled directory. if not os.path.exists("./requirements"): sys.exit("Not in a CMT package: You must be in the" + " /cmt directory") (path, packageVersion) = os.path.split(os.path.dirname(os.getcwd())) (path, packagePathName) = os.path.split(path) # Get the package name from the CVS/Repository file repFile=open("CVS/Repository",mode="r") fullPackageName = os.path.dirname(repFile.readline().strip()) repFile.close() # Now a bit of work to figure out if we have a package or subpackage. (parentDir, packageName) = os.path.split(fullPackageName) if (parentDir): # We found a subpackge, need to split another directory off the path # to get the install point. (path, dummy) = os.path.split(path) # Sanity check, do the CVS and path agree, they'd better. if (packagePathName != packageName): sys.exit("Package path does not agree with CVS information. Did you rename the package?") return (path,fullPackageName,packageName,packageVersion) ############################################################ def StableRelease(r): """Take an integer release number increment to a stable release number. Stable releases are odd. If an even release number of provided, it is incremented to be an odd value. """ new = r; if new%2 == 0: new = new + 1 return new ############################################################ def IncrementStableRelease(curVer, curRel, curPat): """Increment the version numbers to the next released version. Increment the version to a release version that has the final version digit set to odd, and has no patch number. """ global options newVer = curVer newRel = curRel + 1 newPat = -1 if options.stableRelease != None: (newVer, newRel, newPat) = UnpackVersion(options.stableRelease) # Make sure the new release has a stable release number. if (newPat >= 0): newPat = StableRelease(newPat) else: newRel = StableRelease(newRel) return (newVer, newRel, newPat) ############################################################ def IncrementStablePatchRelease(curVer, curRel, curPat): """Increment the version numbers to the next released version. Increment the version to a release version that has the final version digit set to even. """ global options newVer = curVer newRel = curRel newPat = curPat + 1 if options.stableRelease != None: (newVer, newRel, newPat) = UnpackVersion(options.stableRelease) # Patch Tag should be stable newPat = StableRelease(newPat) return (newVer, newRel, newPat) ############################################################ def DevelRelease(v): """Take an integer release number increment to a development release. Development releases are even. If an odd release number of provided, it is incremented to be an even value. """ new = v; if new%2 == 1: new = new + 1; return new ############################################################ def IncrementDevelRelease(curVer, curRel, curPat): """Increment the version numbers to the next unstable version. Increment the version to an unstable version that has the final version digit set to odd. """ global options newVer = curVer newRel = DevelRelease(curRel + 1) newPat = -1 if options.develRelease != None: (newVer, newRel, newPat) = UnpackVersion(options.develRelease) # Make sure the new release has a development release number. # Being aware of patches. if newPat >= 0: newPat = DevelRelease(newPat) else: newRel = DevelRelease(newRel) return (newVer, newRel, newPat) ############################################################ def IncrementPatchDevelRelease(curVer, curRel, curPat): """Increment the version numbers to the next patch unstable version. This is used to create the new patch head when freezing. Increment the version to an unstable version that has the final version digit set to odd. """ global options newVer = curVer newRel = curRel newPat = DevelRelease(curPat + 1) # Make sure the new release has a development release number. # Being aware of patches. if newPat >= 0: newPat = DevelRelease(newPat) return (newVer, newRel, newPat) ############################################################ def FormatVersion(ver): if ver[2] >= 0: return "v%dr%dp%d" % ver else: return "v%dr%d" % (ver[0], ver[1]) ############################################################ def CheckUnusedVersion(ver,package): """Check the versionID ver isn't hasn't already been applied to this package. """ # Use cmt cvstags to check used versions. try: Versions = os.popen("cmt cvstags "+package) except: sys.exit("Could not run cmt") # Search the output for the requested version. match = re.compile(ver) for line in Versions: if match.match(line): return False return True ############################################################ def GetNextPatchVersion(ver,package): """As all patch heads are now p0, we need to check in with the repository to get the next patch head version""" print "Searching cvs for next stable patch version to "+package+" version "+ver print "Please be patient" # Unpack the version number. trial = UnpackVersion(packageVersion) # Scan until we find an unused candidate. while True: trial = IncrementStablePatchRelease(trial[0], trial[1], trial[2]) trialVersion = FormatVersion(trial) if CheckUnusedVersion(trialVersion,package): return trialVersion return True ############################################################ def EditHistoryMessage(version): """Call the editor to create a new history message This uses the EDITOR environment variable to find the right editor to create a new history message. It then creates a template file and expects the user to fill it. After the template file is created, it verifies that the history message is sufficient. """ global options fileName = options.versionHistory try: editor = os.environ["EDITOR"] except: editor = "emacs -nw" try: histFile = open(fileName,"w") histFile.write(GetFreezeInformation(version)) histFile.write(""" HIST: ***************************************************************** HIST: Add a history message to this file. Lines start with HIST will be HIST: stripped from the final output. There must be a blank line after the HIST: freeze information since the first seven lines of the file will be HIST: modified by comet-freeze. HIST: HIST: This file must not be added to CVS. """) histFile.close() except: sys.exit("Cannot write history template") if not options.onlyMakeTemplate: os.system(editor + " " + fileName) print "\nEdited new history message, saved in \"" + fileName + "\"\n" try: histFile = open(fileName,"r") historyMessage = histFile.read() histFile.close() except: sys.exit("Could not read history template") return historyMessage ############################################################ def GetHistoryMessage(ver): """Get the version history and return it as text. This checks for an existing version history file, but will call the user's editor if the file doesn't exist. After reading the history file it is checked to make sure that it matches the right format, and the freeze information is updated. It also strips the final comments that are not required. """ global options if os.path.exists(options.versionHistory): # If the version history exists, use that file. print "Using the version history from " + options.versionHistory +":" try: histFile = open(options.versionHistory,'r') history = histFile.read() histFile.close() except IOError, hist: sys.exit("Cannot open " + options.versionHistory + " for reading, exiting..") else: history = EditHistoryMessage(ver) #################################################################### # Update the history and freeze information. # Strip the HIST comments from the end of the file. histList = history.splitlines() histList = [line for line in histList[7:] if not line.startswith("HIST")] # Verify that the history file has been updated with a real message. historyOk = 0 for line in histList: if len(line.split()) > 4: historyOk += 1 history = "\n".join(GetFreezeInformation(ver).splitlines()+histList) print history if options.check_message: if historyOk < 3: sys.exit("History message is not long enough. Edit " \ + options.versionHistory) else: print "Message Checking has been disabled. Please do not use this option to avoid writing a full release history." return history ############################################################ def GetHistoryFile(): """Get the name of the history file This returns the name of the history file in the package doc directory. If the file doesn't exist, it will exit the script with a message telling the user how to create the approprate file. """ (path,fullPackage,package,ver)=GetPackageNameAndVersion() if not os.path.exists("../doc/"): print "The package is missing the \"doc\" directory. This must be" print "created before the package can be frozen. To create it, add" print "a new doc directory in " + os.path.realpath("..") print "using \"cvs add doc\"." print "" sys.exit("Missing the ../doc directory") histFile = "../doc/"+package+"History.dox" # check if the history file exists, and create it if it does not. if not os.path.exists(histFile): print "The package history file is missing in the \"doc\" directory." print "It will be created, but you must added the file to CVS using" print "\"cvs add " + histFile + "\" before you can" print "freeze." print "" try: h = open(histFile,"w") h.write("/*! \\page " + fullPackage + "History" + " History for the " + fullPackage + " Package \n" + "*/\n") h.close() except IOError: sys.exit("Unable to create the history file") # Check that the history file is known to CVS. histEntries = "../doc/CVS/Entries" try: histEntriesFile = open(histEntries) entries = histEntriesFile.read() if not re.search(package+"History",entries): sys.exit("Must add the history file to CVS") except IOError: sys.exit("Must add the doc directory to CVS") return histFile ############################################################ def GetFreezeInformation(version): (path,fullPackage,package,ver)=GetPackageNameAndVersion() info = "\\section " + package + "_" + version + "_history Version " \ + version + "\n\n" info += "Freeze information:\n" info += " - Freeze Date: " + time.ctime() + "\n" info += " - Freeze User: " + pwd.getpwuid(os.getuid())[0] + "\n" info += " - Freeze Host: " + socket.getfqdn(socket.gethostname())+"\n" info += "\n" ## If there is a name note it too. if (package == "comet" and options.nameTag): nameTag = options.nameTag info += "COMET Software Version Codename :: "+nameTag+"\n" return info ############################################################ def UpdateVersionHistory(ver): """Update the version history file. This adds the content new version history file to the existing version history. The existing history file is found by GetHistoryFile. This will start an editor and prompt the user to write a history message if the version history was not provided. """ # Look for the version history file. If it cannot be found exit and # request a version be checked out or created. histFileName = GetHistoryFile() try: histFile = open(histFileName,'r') history = histFile.read() histFile.close() except IOError, ver: error = """ This file is required to run comet-freeze. Please check this file out of the repository, or create the file and add it to the repository before running comet-freeze again.""" sys.exit("Cannot read " + histFileName + error) ######################################################## # Make sure that the history is a correct Doxygen page. ######################################################## # Find the right place to insert the new history message. insertHere = re.match(r'^(/\*!.*)(\*/)$',history,re.DOTALL) if not insertHere: sys.exit("History file is not formatted as a block comment.") buildHistory = insertHere.group(1) buildHistory += "\n" buildHistory += GetHistoryMessage(ver) buildHistory += "\n" buildHistory += insertHere.group(2) return buildHistory ################################################################# def CheckRequirementsFile(fullPackage,version): """ Check that the requirements file contains the correct package name and version number for the new freeze. """ packageOK = 0 versionOK = 0 try: reqFile = open("requirements",'r') verCheck = re.compile(r'\Aversion\s+(\w+)') packCheck = re.compile(r'\Apackage\s+(\w+)') for line in reqFile: for ver in verCheck.findall(line): if ver == version : versionOK = 1 for pack in packCheck.findall(line): if pack == fullPackage : packageOK = 1 reqFile.close() except IOError: sys.exit("Cannot read requirements file") return versionOK*packageOK ################################################################ def UpdateRequirementsFile(fullPackage,version): """ Rewrite the contents of requirements to ensure that the package and version number are correct. """ requirements = "package "+fullPackage+"\n" requirements += "version "+version+"\n" try: reqFile = open("requirements",'r') verCheck = re.compile(r'\Aversion') packCheck = re.compile(r'\Apackage') for line in reqFile: if not verCheck.match(line) and not packCheck.match(line): requirements += line reqFile.close() except IOError: sys.exit("Cannot read requirements file") return requirements ################################################################# def WriteRequirementsFile(contents): """ Write contents to the requirements file. """ print " Update requirements file version" if not options.dryRun: try: # Make sure that the file is writable. if (os.path.isfile("requirements")): os.chmod("requirements",0644) reqFile = open("requirements",'w') reqFile.write(contents) reqFile.close() except IOError: sys.exit("Cannot write requirements") return ################################################################# def WriteMailMessage(fullPackageName,freezeTag,develTag,develPatchTag): """ Write the email message for release notifcation. """ historyMessage = GetHistoryMessage(freezeTag) mailMessage = "[FREEZE]\n\n" mailMessage += "Freeze of Package " + fullPackageName + "\n" mailMessage += "New Frozen Version is " + freezeTag + "\n" mailMessage += "New Development Version is " + develTag + "\n" mailMessage += "New Patch Development Version is " + develPatchTag + "\n\n" mailMessage += "The following has been added to the version history:\n" mailMessage += historyMessage return mailMessage ################################################################# def WriteMailPatchMessage(fullPackageName,patchTag): """ Write the email message for release notifcation. This version writes the message for a patched release. """ historyMessage = GetHistoryMessage(patchTag) mailMessage = "[FREEZE]\n\n" mailMessage += "New Patch Applied to Package " + fullPackageName + "\n" mailMessage += "New Patched Version is " + patchTag + "\n\n" mailMessage += "The following has been added to the version history:\n" mailMessage += historyMessage return mailMessage ################################################################# def SendMail(packageName,fullPackageName,freezeTag,mailMessage): """ Send out an email confirming the freeze. """ global options # Check to see if mail has been disabled. if options.noMail: print "WARNING: Not sending the anouncement email." return # Write a tmp file for the email. tfile = "/tmp/freeze_" + packageName + "_" + freezeTag try: mailFile = open(tfile,'w') mailFile.write(mailMessage) mailFile.close() except IOError: sys.exit("Cannot write to /tmp for email.") # Send the mail subject = "[FREEZE] New freeze of package " + fullPackageName + " version " + freezeTag # Send mail to release manager and email list. recipients = "n.mccauley@liv.ac.uk comet-software@mailman.t2k.org" command = "(mail -s \"" + subject + "\" " + recipients + " < " + tfile + ")" System(command) # Remove the temp file. os.remove(tfile) return ################################################################# def CheckUpToDate(): """Check that requirements is up to date with cvs""" # Use cmt cvstags to check used versions. try: Status = os.popen("cvs status requirements") except: sys.exit("Could not run cvs status") # Search the output for the requested version. goodRequirements = False uptodate = re.compile(r'Up-to-date') local = re.compile(r'Locally Modified') for line in Status: if uptodate.search(line): goodRequirements = True if local.search(line): goodRequirements = True if not goodRequirements: sys.exit("The requirements file is not up to date with cvs. Please resolve this conflict before proceeding with the freeze") # Now check the history file. history = GetHistoryFile() os.chdir("..") try: Status = os.popen("cvs status doc/"+history) except: sys.exit("Could not run cvs status") goodHistory = False for line in Status: if uptodate.search(line): goodHistory = True if local.search(line): goodHistory = True os.chdir("cmt") if not goodHistory: sys.exit("The history file "+history+" is not up to date with cvs. Please resolve this conflict before proceeding with the freeze") return True ################################################################# def CheckModuleUpToDate(): # Check to see if the module is uptodate with the repository. os.chdir("../") try: Status = os.popen("cvs -n update -d") except: sys.exit("Could not run cvs update") os.chdir("cmt/") uptodate = True merged = re.compile(r'^M ') updated = re.compile(r'^U ') for line in Status: if merged.search(line): uptodate = False if updated.search(line): uptodate = False if (not uptodate): if (not options.skipuptodatecheck): sys.exit ("The repository seems to have changed since you checked out this version. Please make sure you have comitted to the repository and that this version is what should make up the freeze. If you need to continue please use the command line option --skip-uptodate-check. Cannot Continue") else: print "\n\n============================\nThe repository seems to be different that this version being frozen. As the check is being skipped please proceed with caution\n============================\n\n" ################################################################# def CheckCMT(): # We need to check that cmt is defined as we'll be using it # some important thigns won't happen if it's not set. try: cmtVersion = os.popen("cmt version") foundVersion = False for line in cmtVersion: if (re.compile(r'v(\d+)r(\d+)p(\d+)').match(line)): foundVersion = True print "\nUsing CMT Version "+line if not foundVersion: sys.exit("Cannot run CMT, please enable CMT before using comet-freeze") except: sys.exit("Cannot run CMT, please enable CMT before using comet-freeze") ################################################################# # START THE REAL SCRIPT if options.noMail: print "" print "WARNING: Freeze mail message will not be sent to software list." # Check that CMT is setup so we can run it. CheckCMT() # Get the current package information. (packagePath, fullPackageName, packageName, packageVersion) = GetPackageNameAndVersion() # Set the various release versions. current = UnpackVersion(packageVersion) # Check the current CVS root so that there are no surprises if CVSROOT # isn't properly set. rootFile=open("CVS/Root",mode="r") cvsRoot=rootFile.readline().strip() rootFile.close() if os.environ["CVSROOT"] != cvsRoot: sys.exit("CVSROOT is not properly set") if options.patchRelease: patchTag = GetNextPatchVersion(packageVersion,fullPackageName) patch = UnpackVersion(patchTag) if patch[1] != StableRelease(patch[1]): print "Package %s--%s is not a stable." % (fullPackageName, packageVersion) sys.exit("Patch releases can only be made against a stable release.") currentTag = FormatVersion(current) print "Patching Package: " + fullPackageName print "Current Development Patch Version: " + packageVersion print "Proposed Patch Version: " + patchTag # Check to see if the patchTag has already been used. if not CheckUnusedVersion(patchTag,fullPackageName): sys.exit("Requested patch version "+patchTag+" already in use.\nCheck your versions and if in doubt contact the release manager") # Check history file and requirements are up to date. CheckUpToDate() # Check the module is up to date CheckModuleUpToDate() # Update the version history file before cvs tagging commands. if options.versionHistory == None: options.versionHistory = "./" + patchTag + "_history.txt" buildHistory = UpdateVersionHistory(patchTag) histFileName = GetHistoryFile() (histPath,histName) = os.path.split(histFileName) if not options.dryRun: try: # Make sure that the file is writable. if (os.path.isfile(histFileName)): os.chmod(histFileName,0644) histFile = open(histFileName,'w') histFile.write(buildHistory) histFile.close() except IOError, hist: sys.exit("Cannot write history") mailMessage = WriteMailPatchMessage(fullPackageName,patchTag) # Write the commit message tmpMessage = "/tmp/freeze_commit_" + packageName + "_" + patchTag try: commitFile = open(tmpMessage,'w') commitFile.write("Branch: " + packageVersion + "\n\n" + mailMessage) commitFile.close() except IOError: sys.exit("Cannot write to /tmp for commit message.") # CVS to the TRIUMF repository does not like ../ in filename. System("(cd " + histPath + "; cvs commit -F " + tmpMessage + " " + histName + ")") os.remove(tmpMessage) # Check the requirements file and update if needed. # This occurs after the tags, to ensure it's in the right version. # We need to change tags too because of this. if not CheckRequirementsFile(fullPackageName,patchTag): newRequirements = UpdateRequirementsFile(fullPackageName,patchTag) WriteRequirementsFile(newRequirements) cvsCommand = "cvs commit -m \"Branch: " + packageVersion + " Update version in requirements file for patch release.\" requirements" System(cvsCommand) System("(cd ..; cvs tag -F " + patchTag + ")") # mailMessage = WriteMailPatchMessage(fullPackageName,patchTag) SendMail(packageName,fullPackageName,patchTag,mailMessage) if options.dryRun: print """ Use the --apply option to increment the patch release number of the package. 1) The new patch tag, %s, will be added to the current source for the package %s--%s. Run this command with the --help option for usage help.""" % (patchTag, fullPackageName, packageVersion) else: stable = IncrementStableRelease(current[0], current[1], current[2]) # We might want a new version instead if options.newVersion: stable = IncrementStableRelease(current[0]+1,0,0) devel = IncrementDevelRelease(stable[0], stable[1], stable[2]) develPatch = IncrementPatchDevelRelease(stable[0], stable[1], stable[2]) # We might have a name tag. nameTag = None if (packageName == "comet" and options.nameTag): nameTag = options.nameTag # Generate CMT version strings for the new frozen and development branchs freezeTag = FormatVersion(stable) develTag = FormatVersion(devel) develPatchTag = FormatVersion(develPatch) print "Freezing Package: " + fullPackageName print "Current Release Version: " + packageVersion print "Proposed Release Version: " + freezeTag if (nameTag): print "Proposed Version Name: " + nameTag print "Proposed Release Patch Development Version: " + develPatchTag print "Proposed Development Version: " + develTag # Check the new tags. if not CheckUnusedVersion(freezeTag,fullPackageName): sys.exit("Requested stable version "+freezeTag+" already in use.\nCheck your versions and if in doubt contact the release manager") if not CheckUnusedVersion(develTag,fullPackageName): sys.exit("Requested development version "+develTag+" already in use.\nCheck your versions and if in doubt contact the release manager") if not CheckUnusedVersion(develPatchTag,fullPackageName): sys.exit("Requested patch development version "+develPatchTag+" already in use.\nCheck your versions and if in doubt contact the release manager") if (nameTag): if not CheckUnusedVersion(nameTag,fullPackageName): sys.exit("Requested stable version name "+nameTag+" already in use.\nCheck your versions and if in doubt contact the release manager") # Check history file and requirements are up to date. CheckUpToDate() # Check the module is up to date CheckModuleUpToDate() # Update the version history file before cvs tagging commands. if options.versionHistory == None: options.versionHistory = "./" + freezeTag + "_history.txt" buildHistory = UpdateVersionHistory(freezeTag) histFileName = GetHistoryFile() (histPath,histName) = os.path.split(histFileName) if not options.dryRun: try: # Make sure that the file is writable. if (os.path.isfile(histFileName)): os.chmod(histFileName,0644) histFile = open(histFileName,'w') histFile.write(buildHistory) histFile.close() except IOError, hist: sys.exit("Cannot write history") mailMessage = WriteMailMessage(fullPackageName,freezeTag,develTag,develPatchTag) # Write the commit message tmpMessage = "/tmp/freeze_commit_" + packageName + "_" + freezeTag try: commitFile = open(tmpMessage,'w') commitFile.write(mailMessage) commitFile.close() except IOError: sys.exit("Cannot write to /tmp for commit message.") # CVS to the TRIUMF repository does not like ../ in filename. System("(cd " + histPath + "; cvs commit -F " + tmpMessage + " " + histName + ")") os.remove(tmpMessage) # Check the requirements file and update if needed. if not CheckRequirementsFile(fullPackageName,freezeTag): newRequirements = UpdateRequirementsFile(fullPackageName,freezeTag) WriteRequirementsFile(newRequirements) cvsCommand = "cvs commit -m \"Update version in requirements file for release.\" requirements" System(cvsCommand) # Do the real work. if options.finalTag: System("(cd ..; cvs tag -F " + packageVersion + ")") System("(cd ..; cvs tag -F " + freezeTag + ")") if (nameTag): System("(cd ..; cvs tag -F " + nameTag + ")") # Update version in requirements again. # Then tag the new head. newRequirements = UpdateRequirementsFile(fullPackageName,develTag) WriteRequirementsFile(newRequirements) # Do the commit. cvsCommand = "cvs commit -m \"Update version in requirements file for release.\" requirements" System(cvsCommand) System("(cd ../cmt; cvs tag -F " + develTag + " requirements)") # Check out the new frozen version so we can make the patch head. System("(cd %s; cmt checkout -r %s %s)" % (packagePath,freezeTag,fullPackageName)) # We cannot dry run the patch head test unfortunately. if not options.dryRun: os.chdir(packagePath+"/"+fullPackageName+"/"+freezeTag+"/cmt") System("(cd ..; cvs tag -F -b " + develPatchTag + ")") System("(cd %s; cmt checkout -r %s %s)" % (packagePath,develPatchTag,fullPackageName)); os.chdir(packagePath+"/"+fullPackageName+"/"+develPatchTag+"/cmt") newRequirements = UpdateRequirementsFile(fullPackageName,develPatchTag) WriteRequirementsFile(newRequirements) cvsCommand = "cvs commit -m \"Branch: " + develPatchTag + " Update version in requirements file for release.\" requirements" System(cvsCommand) os.chdir(packagePath+"/"+fullPackageName+"/"+packageVersion+"/cmt") SendMail(packageName,fullPackageName,freezeTag,mailMessage) if options.continuation: System("(cd %s/%s; mv %s %s)" % (packagePath,fullPackageName,packageVersion,develTag)); System("(cd ../cmt; cmt config)") else: System("(cd %s; cmt checkout %s)" % (packagePath,fullPackageName)); if options.dryRun: print """ Use the --apply option to freeze the package. This command is the correct way to freeze a COMET package before it is release, and create a new development version. When a package release is ready to be frozen: 1) Run comet-freeze to create a branch tagged release candidate, %s, and a new head version, %s. 2) Test the new release candidate and commit any fixes to the candidate branch. 3) Check your candidate has an up to date cmt and doc directory so freeze commits will work. 4) This command will update the version number of the HEAD so that work can continue. The HEAD version has a higher version number than the frozen branch. Run this command with the --help option for usage help.""" % (freezeTag, develTag)