rake/svn.rb
changeset 9 143e61e24c08
parent 8 308f7dc97753
child 10 389e66b0d38e
--- a/rake/svn.rb	Wed Aug 06 17:38:56 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,328 +0,0 @@
-#####################################################################
-###	S U B V E R S I O N   T A S K S   A N D   H E L P E R S
-#####################################################################
-
-require 'pp'
-require 'yaml'
-require 'English'
-
-# Strftime format for tags/releases
-TAG_TIMESTAMP_FORMAT = '%Y%m%d-%H%M%S'
-TAG_TIMESTAMP_PATTERN = /\d{4}\d{2}\d{2}-\d{6}/
-
-RELEASE_VERSION_PATTERN = /\d+\.\d+\.\d+/
-
-DEFAULT_EDITOR = 'vi'
-DEFAULT_KEYWORDS = %w[Date Rev Author URL Id]
-KEYWORDED_FILEDIRS = %w[applets bin etc lib misc]
-KEYWORDED_FILEPATTERN = /^(?:Rakefile|.*\.(?:rb|js|html|template))$/i
-
-COMMIT_MSG_FILE = 'commit-msg.txt'
-
-###
-### Subversion-specific Helpers
-###
-
-### Return a new tag for the given time
-def make_new_tag( time=Time.now )
-	return time.strftime( TAG_TIMESTAMP_FORMAT )
-end
-
-
-### Get the subversion information for the current working directory as
-### a hash.
-def get_svn_info( dir='.' )
-	info = IO.read( '|-' ) or exec 'svn', 'info', dir
-	return YAML.load( info ) # 'svn info' outputs valid YAML! Yay!
-end
-
-
-### Get a list of the objects registered with subversion under the specified directory and
-### return them as an Array of Pathame objects.
-def get_svn_filelist( dir='.' )
-	list = IO.read( '|-' ) or exec 'svn', 'st', '-v', '--ignore-externals', dir
-
-	# Split into lines, filter out the unknowns, and grab the filenames as Pathnames
-	# :FIXME: This will break if we ever put in a file with spaces in its name. This
-	# will likely be the least of our worries if we do so, however, so it's not worth
-	# the additional complexity to make it handle that case. If we do need that, there's
-	# always the --xml output for 'svn st'...
-	return list.split( $/ ).
-		reject {|line| line =~ /^\?/ }.
-		collect {|fn| Pathname(fn[/\S+$/]) }
-end
-
-### Return the URL to the repository root for the specified +dir+.
-def get_svn_repo_root( dir='.' )
-	info = get_svn_info( dir )
-	return info['URL'].sub( %r{/trunk$}, '' )
-end
-
-
-### Return the Subversion URL to the given +dir+.
-def get_svn_url( dir='.' )
-	info = get_svn_info( dir )
-	return info['URL']
-end
-
-
-### Return the path of the specified +dir+ under the svn root of the 
-### checkout.
-def get_svn_path( dir='.' )
-	root = get_svn_repo_root( dir )
-	url = get_svn_url( dir )
-	
-	return url.sub( root + '/', '' )
-end
-
-
-### Return the keywords for the specified array of +files+ as a Hash keyed by filename.
-def get_svn_keyword_map( files )
-	cmd = ['svn', 'pg', 'svn:keywords', *files]
-
-	# trace "Executing: svn pg svn:keywords " + files.join(' ')
-	output = IO.read( '|-' ) or exec( 'svn', 'pg', 'svn:keywords', *files )
-	
-	kwmap = {}
-	output.split( "\n" ).each do |line|
-		next if line !~ /\s+-\s+/
-		path, keywords = line.split( /\s+-\s+/, 2 )
-		kwmap[ path ] = keywords.split
-	end
-	
-	return kwmap
-end
-
-
-### Return the latest revision number of the specified +dir+ as an Integer.
-def get_svn_rev( dir='.' )
-	info = get_svn_info( dir )
-	return info['Revision']
-end
-
-
-### Return a list of the entries at the specified Subversion url. If
-### no +url+ is specified, it will default to the list in the URL
-### corresponding to the current working directory.
-def svn_ls( url=nil )
-	url ||= get_svn_url()
-	list = IO.read( '|-' ) or exec 'svn', 'ls', url
-
-	trace 'svn ls of %s: %p' % [url, list] if $trace
-	
-	return [] if list.nil? || list.empty?
-	return list.split( $INPUT_RECORD_SEPARATOR )
-end
-
-
-### Return the URL of the latest timestamp in the tags directory.
-def get_latest_svn_timestamp_tag
-	rooturl = get_svn_repo_root()
-	tagsurl = rooturl + '/tags'
-	
-	tags = svn_ls( tagsurl ).grep( TAG_TIMESTAMP_PATTERN ).sort
-	return nil if tags.nil? || tags.empty?
-	return tagsurl + '/' + tags.last
-end
-
-
-### Get a subversion diff of the specified targets and return it. If no targets are
-### specified, the current directory will be diffed instead.
-def get_svn_diff( *targets )
-	targets << BASEDIR if targets.empty?
-	trace "Getting svn diff for targets: %p" % [targets]
-	log = IO.read( '|-' ) or exec 'svn', 'diff', *(targets.flatten)
-
-	return log
-end
-
-
-### Return the URL of the latest timestamp in the tags directory.
-def get_latest_release_tag
-	rooturl    = get_svn_repo_root()
-	releaseurl = rooturl + '/releases'
-	
-	tags = svn_ls( releaseurl ).grep( RELEASE_VERSION_PATTERN ).sort_by do |tag|
-		tag.split('.').collect {|i| Integer(i) }
-	end
-	return nil if tags.empty?
-
-	return releaseurl + '/' + tags.last
-end
-
-
-### Extract a diff from the specified subversion working +dir+, rewrite its
-### file lines as Trac links, and return it.
-def make_svn_commit_log( dir='.' )
-	editor_prog = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
-	
-	diff = IO.read( '|-' ) or exec 'svn', 'diff'
-	fail "No differences." if diff.empty?
-
-	return diff
-end
-
-
-
-###
-### Tasks
-###
-
-desc "Subversion tasks"
-namespace :svn do
-
-	desc "Copy the HEAD revision of the current trunk/ to tags/ with a " +
-		 "current timestamp."
-	task :tag do
-		svninfo   = get_svn_info()
-		tag       = make_new_tag()
-		svntrunk  = svninfo['URL']
-		svntagdir = svninfo['URL'].sub( %r{trunk$}, 'tags' )
-		svntag    = svntagdir + '/' + tag
-
-		desc = "Tagging trunk as #{svntag}"
-		ask_for_confirmation( desc ) do
-			msg = prompt_with_default( "Commit log: ", "Tagging for code push" )
-			run 'svn', 'cp', '-m', msg, svntrunk, svntag
-		end
-	end
-
-
-	desc "Copy the most recent tag to releases/#{PKG_VERSION}"
-	task :release do
-		last_tag    = get_latest_svn_timestamp_tag()
-		svninfo     = get_svn_info()
-		release     = PKG_VERSION
-		svnrel      = svninfo['URL'] + '/releases'
-		svnrelease  = svnrel + '/' + release
-
-		if last_tag.nil?
-			error "There are no tags in the repository"
-			fail
-		end
-
-		releases = svn_ls( svnrel )
-		trace "Releases: %p" % [releases]
-		if releases.include?( release )
-			error "Version #{release} already has a branch (#{svnrelease}). Did you mean" +
-				"to increment the version in #{PKG_VERSION_FROM}?"
-			fail
-		else
-			trace "No #{svnrel} version currently exists"
-		end
-		
-		desc = "Release tag\n  #{last_tag}\nto\n  #{svnrelease}"
-		ask_for_confirmation( desc ) do
-			msg = prompt_with_default( "Commit log: ", "Branching for release" )
-			run 'svn', 'cp', '-m', msg, last_tag, svnrelease
-		end
-	end
-
-	### Task for debugging the #get_target_args helper
-	task :show_targets do
-		$stdout.puts "Targets from ARGV (%p): %p" % [ARGV, get_target_args()]
-	end
-
-
-	desc "Generate a commit log"
-	task :commitlog => [COMMIT_MSG_FILE]
-	
-	desc "Show the (pre-edited) commit log for the current directory"
-	task :show_commitlog => [COMMIT_MSG_FILE] do
-		ask_for_confirmation( "Confirm? " ) do
-			args = get_target_args()
-			puts get_svn_diff( *args )
-		end
-	end
-	
-
-	file COMMIT_MSG_FILE do
-		args = get_target_args()
-		diff = get_svn_diff( *args )
-		
-		File.open( COMMIT_MSG_FILE, File::WRONLY|File::EXCL|File::CREAT ) do |fh|
-			fh.print( diff )
-		end
-
-		editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
-		system editor, COMMIT_MSG_FILE
-		unless $?.success?
-			fail "Editor exited uncleanly."
-		end
-	end
-
-
-	desc "Update from Subversion"
-	task :update do
-		run 'svn', 'up', '--ignore-externals'
-	end
-
-
-	desc "Check in all the changes in your current working copy"
-	task :checkin => ['svn:update', 'coverage:verify', 'svn:fix_keywords', COMMIT_MSG_FILE] do
-		targets = get_target_args()
-		$deferr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
-		ask_for_confirmation( "Continue with checkin?" ) do
-			run 'svn', 'ci', '-F', COMMIT_MSG_FILE, targets
-			rm_f COMMIT_MSG_FILE
-		end
-	end
-	task :commit => :checkin
-	task :ci => :checkin
-		
-	
-	task :clean do
-		rm_f COMMIT_MSG_FILE
-	end
-
-
-	desc "Check and fix any missing keywords for any files in the project which need them"
-	task :fix_keywords do
-		log "Checking subversion keywords..."
-		paths = get_svn_filelist( BASEDIR ).
-			select {|path| path.file? && path.to_s =~ KEYWORDED_FILEPATTERN }
-
-		trace "Looking at %d paths for keywords:\n  %p" % [paths.length, paths]
-		kwmap = get_svn_keyword_map( paths )
-
-		buf = ''
-		PP.pp( kwmap, buf, 132 )
-		trace "keyword map is: %s" % [buf]
-		
-		files_needing_fixups = paths.find_all do |path|
-			(kwmap[path.to_s] & DEFAULT_KEYWORDS) != DEFAULT_KEYWORDS
-		end
-		
-		unless files_needing_fixups.empty?
-			$deferr.puts "Files needing keyword fixes: ",
-				files_needing_fixups.collect {|f|
-					"  %s: %s" % [f, kwmap[f] ? kwmap[f].join(' ') : "(no keywords)"]
-				}
-			ask_for_confirmation( "Will add default keywords to these files." ) do
-				run 'svn', 'ps', 'svn:keywords', DEFAULT_KEYWORDS.join(' '), *files_needing_fixups
-			end
-		else
-			log "Keywords are all up to date."
-		end
-	end
-
-	
-	task :debug_helpers do
-		methods = [
-			:make_new_tag,
-			:get_svn_info,
-			:get_svn_repo_root,
-			:get_svn_url,
-			:get_svn_path,
-			:svn_ls,
-			:get_latest_svn_timestamp_tag,
-		]
-		maxlen = methods.collect {|sym| sym.to_s.length }.max
-		
-		methods.each do |meth|
-			res = send( meth )
-			puts "%*s => %p" % [ maxlen, colorize(meth.to_s, :cyan), res ]
-		end
-	end
-end
-