You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@manifoldcf.apache.org by kw...@apache.org on 2014/08/12 20:22:05 UTC
svn commit: r1617551 - /manifoldcf/release-scripts/next_major_version.py
Author: kwright
Date: Tue Aug 12 18:22:05 2014
New Revision: 1617551
URL: http://svn.apache.org/r1617551
Log:
Add script for updating major version
Added:
manifoldcf/release-scripts/next_major_version.py (with props)
Added: manifoldcf/release-scripts/next_major_version.py
URL: http://svn.apache.org/viewvc/manifoldcf/release-scripts/next_major_version.py?rev=1617551&view=auto
==============================================================================
--- manifoldcf/release-scripts/next_major_version.py (added)
+++ manifoldcf/release-scripts/next_major_version.py Tue Aug 12 18:22:05 2014
@@ -0,0 +1,471 @@
+import sys
+import os
+import shutil
+import subprocess
+import codecs
+
+""" Doesn't handle non-stored svn passwords properly!!"""
+
+def svn_command(command_array):
+ """ Invoke svn command """
+ popen = subprocess.Popen(["svn"] + command_array,
+ stdout=None, stderr=None, stdin=None)
+ popen.communicate()
+ rcode = popen.returncode
+ if rcode != 0:
+ raise Exception("svn invocation errored with code %d" % rcode)
+
+def remove_dir(directory_path):
+ """ Remove a directory and all of its contents """
+ shutil.rmtree(directory_path)
+ #print "Pretend cleanup '%s'..." % directory_path
+
+def get_line_end(line):
+ """ Get the line end characters for the line """
+ if len(line) >= 2 and line[len(line)-2] == '\r':
+ return "\r\n"
+ return "\n"
+
+def match_change_txt_dev_line(line):
+ """ Find a line looking like this:
+ ===== nnn-dev =====
+ """
+ index = line.find("=== ")
+ if index == -1:
+ return False
+ end_index = line.find("-dev ===", index + 4)
+ return end_index != -1
+
+def make_change_txt_dev_line(dev_version, line_end):
+ return "======================= %s-dev =====================%s" % (dev_version, line_end);
+
+def set_change_file_dev_row(change_file_path, new_dev_version):
+ """ Convert the -dev row in a change file to a release row """
+ converted = False
+ temp_file = "%s.tmp" % change_file_path
+ fd = codecs.open(change_file_path, "r", "utf-8")
+ try:
+ out_fd = codecs.open(temp_file, "w", "utf-8")
+ try:
+ for line in fd:
+ if converted:
+ out_fd.write(line)
+ else:
+ if match_change_txt_dev_line(line):
+ out_fd.write(make_change_txt_dev_line(new_dev_version, get_line_end(line)))
+ converted = True
+ else:
+ out_fd.write(line)
+ finally:
+ out_fd.close()
+ finally:
+ fd.close()
+
+ # Remove old file and rename temp file
+ os.unlink(change_file_path)
+ os.rename(temp_file, change_file_path)
+
+
+IN_BODY = 0
+IN_PREAMBLE = 1
+IN_COMMENT = 2
+IN_TAG_NAME = 3
+IN_TAG_BODY = 4
+IN_END_TAG_NAME = 5
+IN_BODY_SEEN_LEFTANGLE = 6
+IN_BODY_SEEN_LEFTANGLE_BANG = 7
+IN_BODY_SEEN_LEFTANGLE_BANG_DASH = 9
+IN_COMMENT_SEEN_DASH = 11
+IN_COMMENT_SEEN_DASH_DASH = 12
+IN_PREAMBLE_SEEN_QUESTION = 13
+IN_TAG_BODY_SEEN_SLASH = 14
+IN_TAG_SEEN_SLASH = 15
+
+class TagScanner:
+
+ def __init__( self, action_object ):
+ self.state = IN_BODY
+ self.tag_name = None
+ self.action_object = action_object
+ self.body_accumulator = u''
+
+ def end( self ):
+ if self.state != IN_BODY:
+ raise Exception("At end, in unknown state %d" % self.state)
+ self.action_object.write(self.action_object.map_body(self.body_accumulator))
+
+ def accept_character( self, char ):
+ uchar = unicode(char)
+ if self.state == IN_BODY:
+ if uchar == u'<':
+ self.state = IN_BODY_SEEN_LEFTANGLE
+ else:
+ self.body_accumulator += uchar
+
+ elif self.state == IN_PREAMBLE:
+ if uchar == u'?':
+ self.state = IN_PREAMBLE_SEEN_QUESTION
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+
+ elif self.state == IN_COMMENT:
+ if uchar == u'-':
+ self.state = IN_COMMENT_SEEN_DASH
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+
+ elif self.state == IN_TAG_NAME:
+ if uchar <= u' ':
+ self.action_object.found_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.state = IN_TAG_BODY
+ elif uchar == u'>':
+ self.action_object.found_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.state = IN_BODY
+ elif uchar == u'/':
+ self.action_object.found_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.state = IN_TAG_SEEN_SLASH
+ else:
+ self.tag_name += uchar
+ self.action_object.write(uchar)
+
+ elif self.state == IN_TAG_SEEN_SLASH:
+ if uchar == u'>':
+ self.action_object.found_end_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.state = IN_BODY
+ self.tag_name = None
+ elif uchar == u'/':
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+ self.state = IN_TAG_BODY
+
+ elif self.state == IN_TAG_BODY:
+ if uchar == u'/':
+ self.state = IN_TAG_BODY_SEEN_SLASH
+ self.action_object.write(uchar)
+ elif uchar == u'>':
+ self.state = IN_BODY
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+
+ elif self.state == IN_TAG_BODY_SEEN_SLASH:
+ if uchar == u'>':
+ self.action_object.found_end_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.state = IN_BODY
+ self.tag_name = None
+ elif uchar == u'/':
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+ self.state = IN_TAG_BODY
+
+ elif self.state == IN_END_TAG_NAME:
+ if uchar == u'>':
+ self.state = IN_BODY
+ self.action_object.found_end_tag(self.tag_name)
+ self.action_object.write(uchar)
+ self.tag_name = None
+ else:
+ self.action_object.write(uchar)
+ self.tag_name += uchar
+
+ elif self.state == IN_BODY_SEEN_LEFTANGLE:
+ if uchar == u'!':
+ self.state = IN_BODY_SEEN_LEFTANGLE_BANG
+ elif uchar == u'?':
+ self.action_object.write(self.action_object.map_body(self.body_accumulator))
+ self.body_accumulator = u""
+ self.action_object.write(u'<')
+ self.action_object.write(u'?')
+ self.body_accumulator = u""
+ self.state = IN_PREAMBLE
+ elif uchar == u'/':
+ self.state = IN_END_TAG_NAME
+ self.action_object.write(self.action_object.map_body(self.body_accumulator))
+ self.body_accumulator = u""
+ self.action_object.write(u'<')
+ self.action_object.write(u'/')
+ self.tag_name = u""
+ elif uchar == u'<':
+ self.body_accumulator += u'<'
+ else:
+ self.action_object.write(self.action_object.map_body(self.body_accumulator))
+ self.body_accumulator = u""
+ self.action_object.write(u'<')
+ self.action_object.write(uchar)
+ self.tag_name = u"" + uchar
+ self.state = IN_TAG_NAME
+
+ elif self.state == IN_BODY_SEEN_LEFTANGLE_BANG:
+ if uchar == u'-':
+ self.state = IN_BODY_SEEN_LEFTANGLE_BANG_DASH
+ else:
+ self.body_accumulator += u'<'
+ self.body_accumulator += u'!'
+ self.body_accumulator += uchar
+
+ elif self.state == IN_BODY_SEEN_LEFTANGLE_BANG_DASH:
+ if uchar == u'-':
+ self.state = IN_COMMENT
+ self.action_object.write(self.action_object.map_body(self.body_accumulator))
+ self.body_accumulator = u""
+ self.action_object.write(u"<!--")
+ else:
+ self.state = IN_BODY
+ self.body_accumulator += u"<!-"
+ self.body_accumulator += uchar
+
+ elif self.state == IN_COMMENT_SEEN_DASH:
+ if uchar == u'-':
+ self.state = IN_COMMENT_SEEN_DASH_DASH
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+ self.state = IN_COMMENT
+
+ elif self.state == IN_COMMENT_SEEN_DASH_DASH:
+ if uchar == u'>':
+ self.state = IN_BODY
+ self.action_object.write(uchar)
+ elif uchar == u'-':
+ self.action_object.write(uchar)
+ else:
+ self.state = IN_COMMENT
+ self.action_object.write(uchar)
+
+ elif self.state == IN_PREAMBLE_SEEN_QUESTION:
+ if uchar == u'>':
+ self.state = IN_BODY
+ self.action_object.write(uchar)
+ elif uchar == u'?':
+ self.action_object.write(uchar)
+ else:
+ self.action_object.write(uchar)
+ self.state = IN_PREAMBLE
+
+ else:
+ raise Exception("Unknown state %d" % self.state)
+
+
+class ActionBase:
+ def __init__( self, output_stream ):
+ self.output_stream = output_stream
+
+ def write( self, chars ):
+ self.output_stream.write( chars )
+
+ def map_body( self, body_text ):
+ return body_text
+
+ def found_end_tag( self, tag_name ):
+ pass
+
+ def found_tag( self, tag_name ):
+ pass
+
+
+class HierarchicalAction(ActionBase):
+ def __init__( self, output_stream ):
+ ActionBase.__init__( self, output_stream )
+ self.tag_hierarchy = [ ]
+
+ def found_tag( self, tag_name ):
+ self.tag_hierarchy += [ tag_name ]
+ self.enter_tag( self.make_tag_string( ) )
+
+ def found_end_tag( self, tag_name ):
+ if len(self.tag_hierarchy) == 0 or self.tag_hierarchy[len(self.tag_hierarchy)-1] != tag_name:
+ raise Exception("Unmatched end tag '%s'" % tag_name)
+ self.exit_tag( self.make_tag_string( ) )
+ del self.tag_hierarchy[len(self.tag_hierarchy)-1]
+
+ def make_tag_string( self ):
+ tag_string = u""
+ for tag in self.tag_hierarchy:
+ tag_string += u"/" + tag
+ return tag_string
+
+ def enter_tag( self, hierarchy_string ):
+ pass
+
+ def exit_tag( self, hierarchy_string ):
+ pass
+
+class PomAction(HierarchicalAction):
+ def __init__( self, output_stream, new_version, root_parent ):
+ HierarchicalAction.__init__( self, output_stream )
+ self.accumulator = None
+ self.modules = [ ]
+ self.new_version = new_version
+ self.replace = False
+ self.root_parent = root_parent
+
+ def enter_tag( self, hierarchy_string ):
+ if hierarchy_string == u"/project/modules/module":
+ self.accumulator = u""
+ elif hierarchy_string == u"/project/version":
+ self.replace = True
+ elif hierarchy_string == u"/project/parent/version" and not self.root_parent:
+ self.replace = True
+
+ def exit_tag( self, hierarchy_string ):
+ if hierarchy_string == u"/project/modules/module":
+ self.modules += [ self.accumulator ]
+ self.accumulator = None
+ elif hierarchy_string == u"/project/version":
+ self.replace = False
+ elif hierarchy_string == u"/project/parent/version" and not self.root_parent:
+ self.replace = False
+
+ def map_body( self, body_text ):
+ if self.accumulator != None:
+ self.accumulator += body_text
+ if self.replace:
+ return self.new_version
+ return body_text
+
+def fix_pom_xml(pom_file_path, pom_version, root_parent):
+ """
+ Fix primary versions in a pom file to become the specified pom_version.
+ Returns an array of child project names (NOT paths).
+ """
+ rval = None
+ temp_file = "%s.tmp" % pom_file_path
+ fd = codecs.open(pom_file_path, "r", "utf-8")
+ try:
+ out_fd = codecs.open(temp_file, "w", "utf-8")
+ try:
+ action_object = PomAction(out_fd, pom_version, root_parent)
+ ts = TagScanner(action_object)
+ for line in fd:
+ for char in line:
+ ts.accept_character(char)
+ ts.end()
+ rval = action_object.modules
+ finally:
+ out_fd.close()
+ finally:
+ fd.close()
+
+ os.unlink(pom_file_path)
+ os.rename(temp_file, pom_file_path)
+ return rval
+
+def update_poms(root_directory, pom_version, root_parent=True):
+ """ Update all poms in a project """
+ dirs = fix_pom_xml( "%s/pom.xml" % root_directory, pom_version, root_parent )
+ for dir in dirs:
+ update_poms( "%s/%s" % (root_directory, dir), pom_version, root_parent=False )
+
+def convert_build_xml_line(line, build_version):
+ """
+ Fills value in where property name is "release-version", e.g. <property name="release-version" value="1.6-dev"/>
+ """
+ string_to_match = "<property name=\"release-version\" value=\""
+ index = line.find(string_to_match)
+ if index == -1:
+ return line
+ end_index = line.find("\"", index + len(string_to_match))
+ if end_index == -1:
+ raise Exception("Can't substitute line '%s'" % line)
+ return line[0:index] + string_to_match + build_version + line[end_index:len(line)]
+
+def fix_build_xml(build_file_path, build_version):
+ """ Update version number in build.xml to be the specified one. """
+ temp_file = "%s.tmp" % build_file_path
+ fd = codecs.open(build_file_path, "r", "utf-8")
+ try:
+ out_fd = codecs.open(temp_file, "w", "utf-8")
+ try:
+ for line in fd:
+ out_fd.write(convert_build_xml_line(line, build_version))
+ finally:
+ out_fd.close()
+ finally:
+ fd.close()
+
+ # Remove old file and rename temp file
+ os.unlink(build_file_path)
+ os.rename(temp_file, build_file_path)
+
+def checkout_tree(tree_directory_path, svn_url):
+ """ Check out the specified svn tree to the specified place """
+ svn_command(["co", svn_url, tree_directory_path])
+
+def commit_tree(tree_directory_path, commit_message):
+ """ Commit the svn tree using the specified commit message """
+ svn_command([ "-m", commit_message, "commit", tree_directory_path])
+ #print "Pretend commit..."
+
+def create_branch(trunk_url, branch_url, branch_message):
+ """ Create a branch with the given branch message """
+ svn_command([ "-m", branch_message, "copy", trunk_url, branch_url])
+ #print "Pretend create branch..."
+
+def new_major_version(legacy_major_version, new_trunk_major_version, working_directory):
+ """ Create a legacy branch, and modify trunk also to reset versions """
+ # Basic checks
+ if not os.path.exists(working_directory):
+ raise Exception("Working directory '%s' does not appear to exist" % working_directory)
+ if legacy_major_version.find("-SNAPSHOT") >= 0 or legacy_major_version.find("-dev") >= 0:
+ raise Exception("Legacy major version '%s' cannot contain SNAPSHOT or dev" % legacy_major_version)
+ if legacy_major_version.find(".") >= 0 or legacy_major_version.find(" ") >= 0:
+ raise Exception("Legacy major version '%s' cannot contain '.' or ' '" % legacy_major_version)
+ if new_trunk_major_version.find("-SNAPSNOT") >= 0 or new_trunk_major_version.find("-dev") >= 0:
+ raise Exception("New trunk version '%s' cannot contain SNAPSHOT or dev" % new_trunk_major_version)
+ if new_trunk_major_version.find(".") >= 0 or new_trunk_major_version.find(" ") >= 0:
+ raise Exception("New trunk version '%s' cannot contain '.' or ' '" % new_trunk_major_version)
+
+ # Point to all the right places
+ trunk_url = "https://svn.apache.org/repos/asf/manifoldcf/trunk"
+ branch_url = "https://svn.apache.org/repos/asf/manifoldcf/branches/branch_%sx" % legacy_major_version
+ trunk_dir = "%s/trunk" % working_directory
+
+ trunk_changes_file = "%s/CHANGES.txt" % trunk_dir
+ trunk_build_xml_file = "%s/build.xml" % trunk_dir
+ new_trunk_version = "%s.0" % new_trunk_major_version
+
+ # Directly copy trunk to branch, with NO other changes
+ print >>sys.stderr, "Creating %sx dev branch..." % legacy_major_version
+ copy_trunk_to_branch(trunk_url, branch_url, legacy_major_version);
+ create_branch(trunk_url, branch_url, "Create a %sx dev branch." % legacy_major_version)
+
+ # Check out trunk.
+ print >>sys.stderr, "Checking out trunk..."
+ checkout_tree(trunk_dir, trunk_url)
+
+ # Modify CHANGES.txt
+ set_change_file_dev_row(trunk_changes_file, new_trunk_version)
+ fix_build_xml(trunk_build_xml_file, "%s-dev" % new_trunk_version)
+ update_poms(trunk_dir, "%s-SNAPSHOT" % new_trunk_version)
+ print >>sys.stderr, "Committing trunk version increment..."
+ commit_tree(trunk_dir, "Prepare trunk for %s development" % new_trunk_version)
+
+ # Finally, delete trunk checkout (we're done with it)
+ print >>sys.stderr, "Cleaning up trunk temporary files..."
+ remove_dir(trunk_dir)
+ print >>sys.stderr, "Trunk version updated!"
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3 and len(sys.argv) != 4:
+ print >> sys.stderr, "Usage: %s <legacy_dev_major_version> <new_trunk_major_version> [<working_directory>]" % sys.argv[0]
+ sys.exit(1)
+
+ legacy_major_version = sys.argv[1]
+ trunk_major_version = sys.argv[2]
+ if len(sys.argv) > 3:
+ working_dir = sys.argv[3]
+ else:
+ working_dir = "."
+
+ new_major_version(legacy_major_version, trunk_major_version, working_dir)
+
+
\ No newline at end of file
Propchange: manifoldcf/release-scripts/next_major_version.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: manifoldcf/release-scripts/next_major_version.py
------------------------------------------------------------------------------
svn:keywords = Id