--- 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
-