pluginfactory 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/rake/packaging.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  #
2
2
  # Packaging Rake Tasks
3
- # $Id: packaging.rb 21 2008-08-07 23:45:52Z deveiant $
3
+
4
4
  #
5
5
 
6
6
  require 'rbconfig'
7
+ require 'pathname'
7
8
  require 'rake/packagetask'
8
9
  require 'rake/gempackagetask'
9
10
 
11
+ require Pathname( __FILE__ ).dirname.expand_path + 'hg.rb'
12
+
10
13
  include Config
11
14
 
12
15
  ### Task: gem
@@ -16,8 +19,7 @@ Rake::PackageTask.new( PKG_NAME, PKG_VERSION ) do |task|
16
19
  task.need_tar_bz2 = true
17
20
  task.need_zip = true
18
21
  task.package_dir = PKGDIR.to_s
19
- task.package_files = RELEASE_FILES.
20
- collect {|f| f.relative_path_from(BASEDIR).to_s }
22
+ task.package_files = RELEASE_FILES.collect {|f| f.to_s }
21
23
  end
22
24
  task :package => [:gem]
23
25
 
@@ -36,14 +38,31 @@ file gempath.to_s => [PKGDIR.to_s] + GEMSPEC.files do
36
38
  end
37
39
  end
38
40
 
41
+
42
+ prerelease_gempath = PKGDIR + SNAPSHOT_GEM_NAME
43
+
44
+ desc "Build a pre-release RubyGem package"
45
+ task :prerelease_gem => prerelease_gempath.to_s
46
+ file prerelease_gempath.to_s => [PKGDIR.to_s] + GEMSPEC.files do
47
+ when_writing( "Creating prerelease GEM" ) do
48
+ gemspec = GEMSPEC.clone
49
+ gemspec.version = Gem::Version.create( "%s.%s" % [GEMSPEC.version, PKG_BUILD] )
50
+ Gem::Builder.new( gemspec ).build
51
+ verbose( true ) do
52
+ mv SNAPSHOT_GEM_NAME, prerelease_gempath
53
+ end
54
+ end
55
+ end
56
+
57
+
39
58
  ### Task: install
40
59
  desc "Install #{PKG_NAME} as a conventional library"
41
- task :install do
60
+ task :install => "spec:quiet" do
42
61
  log "Installing #{PKG_NAME} as a conventional library"
43
62
  sitelib = Pathname.new( CONFIG['sitelibdir'] )
44
63
  sitearch = Pathname.new( CONFIG['sitearchdir'] )
45
64
  Dir.chdir( LIBDIR ) do
46
- LIB_FILES.each do |libfile|
65
+ LIB_FILES.collect {|path| Pathname(path) }.each do |libfile|
47
66
  relpath = libfile.relative_path_from( LIBDIR )
48
67
  target = sitelib + relpath
49
68
  FileUtils.mkpath target.dirname,
@@ -53,8 +72,10 @@ task :install do
53
72
  end
54
73
  end
55
74
  if EXTDIR.exist?
75
+ trace " looking for a binary extension (%s)" % [ EXTDIR + "*.#{Config::CONFIG['DLEXT']}" ]
56
76
  Dir.chdir( EXTDIR ) do
57
- Pathname.glob( EXTDIR + Config::CONFIG['DLEXT'] ) do |dl|
77
+ Pathname.glob( "*.#{Config::CONFIG['DLEXT']}" ) do |dl|
78
+ trace " found: #{dl}"
58
79
  target = sitearch + dl.basename
59
80
  FileUtils.install dl, target,
60
81
  :mode => 0755, :verbose => true, :noop => $dryrun
@@ -82,7 +103,7 @@ task :uninstall do
82
103
  sitearch = Pathname.new( CONFIG['sitearchdir'] )
83
104
 
84
105
  Dir.chdir( LIBDIR ) do
85
- LIB_FILES.each do |libfile|
106
+ LIB_FILES.collect {|path| Pathname(path) }.each do |libfile|
86
107
  relpath = libfile.relative_path_from( LIBDIR )
87
108
  target = sitelib + relpath
88
109
  FileUtils.rm_f target, :verbose => true, :noop => $dryrun
@@ -91,8 +112,10 @@ task :uninstall do
91
112
  end
92
113
  end
93
114
  if EXTDIR.exist?
115
+ trace " looking for a binary extension (%s)" % [ EXTDIR + "*.#{Config::CONFIG['DLEXT']}" ]
94
116
  Dir.chdir( EXTDIR ) do
95
- Pathname.glob( EXTDIR + Config::CONFIG['DLEXT'] ) do |dl|
117
+ Pathname.glob( "*.#{Config::CONFIG['DLEXT']}" ) do |dl|
118
+ trace " found: #{dl}"
96
119
  target = sitearch + dl.basename
97
120
  FileUtils.rm target, :verbose => true, :noop => $dryrun
98
121
  end
@@ -110,3 +133,12 @@ end
110
133
 
111
134
 
112
135
 
136
+ desc "Add development depdendencies to the gemspec -- this is meant to be chained " +
137
+ "together with :gem"
138
+ task :include_dev_dependencies do
139
+ DEVELOPMENT_DEPENDENCIES.each do |name, version|
140
+ version = '>= 0' if version.length.zero?
141
+ GEMSPEC.add_development_dependency( name, version )
142
+ end
143
+ end
144
+
data/rake/publishing.rb CHANGED
@@ -26,8 +26,8 @@ class Net::SMTP
26
26
  return self
27
27
  end
28
28
  end
29
-
30
-
29
+
30
+
31
31
  #######
32
32
  private
33
33
  #######
@@ -100,7 +100,7 @@ begin
100
100
 
101
101
 
102
102
  namespace :release do
103
- task :default => [ 'svn:release', :upload, :publish, :announce ]
103
+ task :default => [ :prep_release, :upload, :publish, :announce ]
104
104
 
105
105
  desc "Re-publish the release with the current version number"
106
106
  task :rerelease => [ :upload, :publish, :announce ]
@@ -111,31 +111,28 @@ begin
111
111
  $publish_privately = true
112
112
  Rake::Task['release:rerelease'].invoke
113
113
  end
114
-
114
+
115
115
 
116
116
  desc "Generate the release notes"
117
117
  task :notes => [RELEASE_NOTES_FILE]
118
118
  file RELEASE_NOTES_FILE do |task|
119
- last_rel_tag = get_latest_release_tag() or
120
- fail ">>> No releases tagged! Try running 'rake svn:release' first"
121
- trace "Last release tag is: %p" % [ last_rel_tag ]
122
- start = get_last_changed_rev( last_rel_tag ) || 1
123
- trace "Starting rev is: %p" % [ start ]
124
- log_output = make_svn_log( '.', start, 'HEAD' )
119
+ last_tag = MercurialHelpers.get_tags.grep( /\d+\.\d+\.\d+/ ).
120
+ collect {|ver| vvec(ver) }.sort.last.unpack( 'N*' ).join('.')
125
121
 
126
122
  File.open( task.name, File::WRONLY|File::TRUNC|File::CREAT ) do |fh|
127
- fh.print( log_output )
123
+ fh.puts "Release Notes for #{PKG_VERSION}",
124
+ "--------------------------------", '', ''
128
125
  end
129
126
 
130
127
  edit task.name
131
128
  end
132
129
  CLOBBER.include( RELEASE_NOTES_FILE )
133
-
134
-
130
+
131
+
135
132
  desc "Upload project documentation and packages to #{PROJECT_HOST}"
136
133
  task :upload => [ :upload_docs, :upload_packages ]
137
134
  task :project => :upload # the old name
138
-
135
+
139
136
  desc "Publish the project docs to #{PROJECT_HOST}"
140
137
  task :upload_docs => [ :rdoc ] do
141
138
  when_writing( "Publishing docs to #{PROJECT_SCPDOCURL}" ) do
@@ -172,7 +169,7 @@ begin
172
169
  == Installation
173
170
 
174
171
  Via gems:
175
-
172
+
176
173
  $ sudo gem install #{GEMSPEC.name}
177
174
 
178
175
  or from source:
@@ -185,7 +182,7 @@ begin
185
182
  == Changes
186
183
  #{relnotes}
187
184
  }.gsub( /^\t+/, '' )
188
-
185
+
189
186
  File.open( task.name, File::WRONLY|File::TRUNC|File::CREAT ) do |fh|
190
187
  fh.print( announce_body )
191
188
  end
@@ -193,8 +190,8 @@ begin
193
190
  edit task.name
194
191
  end
195
192
  CLOBBER.include( RELEASE_ANNOUNCE_FILE )
196
-
197
-
193
+
194
+
198
195
  desc 'Send out a release announcement'
199
196
  task :announce => [RELEASE_ANNOUNCE_FILE] do
200
197
  email = TMail::Mail.new
@@ -217,13 +214,13 @@ begin
217
214
  puts '---',
218
215
  email.to_s,
219
216
  '---'
220
-
217
+
221
218
  ask_for_confirmation( "Will send via #{SMTP_HOST}." ) do
222
219
  pwent = Etc.getpwuid( Process.euid )
223
220
  curuser = pwent ? pwent.name : 'unknown'
224
221
  username = prompt_with_default( "SMTP user", curuser )
225
222
  password = prompt_for_password()
226
-
223
+
227
224
  trace "Creating SMTP connection to #{SMTP_HOST}:#{SMTP_PORT}"
228
225
  smtp = Net::SMTP.new( SMTP_HOST, SMTP_PORT )
229
226
  smtp.set_debug_output( $stdout )
@@ -237,73 +234,77 @@ begin
237
234
  trace "done."
238
235
  end
239
236
  end
240
-
241
-
237
+
238
+
242
239
  desc 'Publish the new release to RubyForge'
243
240
  task :publish => [:clean, :package, :notes] do |task|
244
241
  project = GEMSPEC.rubyforge_project
245
242
 
246
- rf = RubyForge.new
247
- log "Loading RubyForge config"
248
- rf.configure
249
-
250
- group_id = rf.autoconfig['group_ids'][RUBYFORGE_GROUP] or
251
- fail "Your configuration doesn't have a group id for '#{RUBYFORGE_GROUP}'"
252
-
253
- # If this project doesn't yet exist, create it
254
- unless rf.autoconfig['package_ids'].key?( project )
255
- ask_for_confirmation( "Package '#{project}' doesn't exist on RubyForge. Create it?" ) do
256
- log "Creating new package '#{project}'"
257
- rf.create_package( group_id, project )
258
- end
259
- end
260
-
261
- package_id = rf.autoconfig['package_ids'][ project ]
262
-
263
- # Make sure this release doesn't already exist
264
- releases = rf.autoconfig['release_ids']
265
- if releases.key?( GEMSPEC.name ) && releases[ GEMSPEC.name ].key?( PKG_VERSION )
266
- log "Rubyforge seems to already have #{ PKG_FILE_NAME }"
243
+ if $publish_privately
244
+ log "Skipping push of release files to RubyForge"
267
245
  else
268
- config = rf.userconfig or
269
- fail "You apparently haven't set up your RubyForge credentials on this machine."
270
- config['release_notes'] = GEMSPEC.description
271
- config['release_changes'] = File.read( RELEASE_NOTES_FILE )
272
-
273
- files = FileList[ PKGDIR + GEM_FILE_NAME ]
274
- files.include PKGDIR + "#{PKG_FILE_NAME}.tar.gz"
275
- files.include PKGDIR + "#{PKG_FILE_NAME}.tar.bz2"
276
- files.include PKGDIR + "#{PKG_FILE_NAME}.zip"
277
-
278
- log "Releasing #{PKG_FILE_NAME}"
279
- when_writing do
280
- log "Publishing to RubyForge: \n",
281
- "\tproject: #{RUBYFORGE_GROUP}\n",
282
- "\tpackage: #{PKG_NAME.downcase}\n",
283
- "\tpackage version: #{PKG_VERSION}\n",
284
- "\tfiles: " + files.collect {|f| f.to_s }.join(', ') + "\n"
285
-
286
- ask_for_confirmation( "Publish to RubyForge?" ) do
287
- log 'Logging in...'
288
- rf.login
289
- log "Adding the new release to the '#{project}' project"
290
- rf.add_release( group_id, package_id, PKG_VERSION, *files )
246
+ rf = RubyForge.new
247
+ log "Loading RubyForge config"
248
+ rf.configure
249
+
250
+ group_id = rf.autoconfig['group_ids'][RUBYFORGE_GROUP] or
251
+ fail "Your configuration doesn't have a group id for '#{RUBYFORGE_GROUP}'"
252
+
253
+ # If this project doesn't yet exist, create it
254
+ unless rf.autoconfig['package_ids'].key?( project )
255
+ ask_for_confirmation( "Package '#{project}' doesn't exist on RubyForge. Create it?" ) do
256
+ log "Creating new package '#{project}'"
257
+ rf.create_package( group_id, project )
258
+ end
259
+ end
260
+
261
+ package_id = rf.autoconfig['package_ids'][ project ]
262
+
263
+ # Make sure this release doesn't already exist
264
+ releases = rf.autoconfig['release_ids']
265
+ if releases.key?( GEMSPEC.name ) && releases[ GEMSPEC.name ].key?( PKG_VERSION )
266
+ log "Rubyforge seems to already have #{ PKG_FILE_NAME }"
267
+ else
268
+ config = rf.userconfig or
269
+ fail "You apparently haven't set up your RubyForge credentials on this machine."
270
+ config['release_notes'] = GEMSPEC.description
271
+ config['release_changes'] = File.read( RELEASE_NOTES_FILE )
272
+
273
+ files = FileList[ PKGDIR + GEM_FILE_NAME ]
274
+ files.include PKGDIR + "#{PKG_FILE_NAME}.tar.gz"
275
+ files.include PKGDIR + "#{PKG_FILE_NAME}.tar.bz2"
276
+ files.include PKGDIR + "#{PKG_FILE_NAME}.zip"
277
+
278
+ log "Releasing #{PKG_FILE_NAME}"
279
+ when_writing do
280
+ log "Publishing to RubyForge: \n",
281
+ "\tproject: #{RUBYFORGE_GROUP}\n",
282
+ "\tpackage: #{PKG_NAME.downcase}\n",
283
+ "\tpackage version: #{PKG_VERSION}\n",
284
+ "\tfiles: " + files.collect {|f| f.to_s }.join(', ') + "\n"
285
+
286
+ ask_for_confirmation( "Publish to RubyForge?" ) do
287
+ log 'Logging in...'
288
+ rf.login
289
+ log "Adding the new release to the '#{project}' project"
290
+ rf.add_release( group_id, package_id, PKG_VERSION, *files )
291
+ end
291
292
  end
292
293
  end
293
294
  end
294
295
  end
295
296
  end
296
-
297
+
297
298
  rescue LoadError => err
298
299
  if !Object.const_defined?( :Gem )
299
300
  require 'rubygems'
300
301
  retry
301
302
  end
302
-
303
+
303
304
  task :no_release_tasks do
304
305
  fail "Release tasks not defined: #{err.message}"
305
306
  end
306
-
307
+
307
308
  task :release => :no_release_tasks
308
309
  task "release:announce" => :no_release_tasks
309
310
  task "release:publish" => :no_release_tasks
data/rake/rdoc.rb CHANGED
@@ -1,45 +1,30 @@
1
1
  #
2
2
  # RDoc Rake tasks
3
- # $Id: rdoc.rb 86 2009-02-23 06:38:40Z deveiant $
3
+
4
4
  #
5
5
 
6
+ gem 'rdoc', '>= 2.4.3'
7
+
8
+ require 'rubygems'
6
9
  require 'rdoc/rdoc'
7
10
  require 'rake/clean'
8
-
9
-
10
- if RDoc::RDoc::GENERATORS.key?( 'darkfish' )
11
- $have_darkfish = true
12
- else
13
- trace "No darkfish generator."
14
- $have_darkfish = false
15
- end
16
-
11
+ require 'rdoc/task'
17
12
 
18
13
  # Append docs/lib to the load path if it exists for a locally-installed Darkfish
19
14
  DOCSLIB = DOCSDIR + 'lib'
20
15
  $LOAD_PATH.unshift( DOCSLIB.to_s ) if DOCSLIB.exist?
21
16
 
22
17
  # Make relative string paths of all the stuff we need to generate docs for
23
- DOCFILES = LIB_FILES + EXT_FILES + GEMSPEC.extra_rdoc_files
18
+ DOCFILES = Rake::FileList[ LIB_FILES + EXT_FILES + GEMSPEC.extra_rdoc_files ]
24
19
 
25
20
 
26
21
  directory RDOCDIR.to_s
27
22
  CLOBBER.include( RDOCDIR )
28
23
 
29
24
  desc "Build API documentation in #{RDOCDIR}"
30
- task :rdoc => [ Rake.application.rakefile, *DOCFILES ] do
31
- args = RDOC_OPTIONS
32
- args += [ '-o', RDOCDIR.to_s ]
33
- args += [ '-f', 'darkfish' ] if $have_darkfish
34
- args += DOCFILES.collect {|pn| pn.to_s }
35
-
36
- trace "Building docs with arguments: %s" % [ args.join(' ') ]
37
- RDoc::RDoc.new.document( args ) rescue nil
38
- end
39
-
40
- desc "Rebuild API documentation in #{RDOCDIR}"
41
- task :rerdoc do
42
- rm_r( RDOCDIR ) if RDOCDIR.exist?
43
- Rake::Task[ :rdoc ].invoke
25
+ RDoc::Task.new do |task|
26
+ task.main = "README"
27
+ task.rdoc_files.include( DOCFILES )
28
+ task.rdoc_dir = RDOCDIR.to_s
29
+ task.options = RDOC_OPTIONS
44
30
  end
45
-
data/rake/style.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Style Fixup Rake Tasks
3
- # $Id: style.rb 10 2008-07-18 15:52:48Z deveiant $
3
+
4
4
  #
5
5
  # Authors:
6
6
  # * Michael Granger <ged@FaerieMUD.org>
data/rake/svn.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Subversion Rake Tasks
3
- # $Id: svn.rb 86 2009-02-23 06:38:40Z deveiant $
3
+
4
4
  #
5
5
  # Authors:
6
6
  # * Michael Granger <ged@FaerieMUD.org>
@@ -10,593 +10,659 @@ require 'pp'
10
10
  require 'yaml'
11
11
  require 'date'
12
12
  require 'time'
13
+ require 'abbrev'
14
+
15
+ unless defined?( SVN_DOTDIR )
16
+
17
+ # Subversion constants -- directory names for releases and tags
18
+ SVN_TRUNK_DIR = 'trunk'
19
+ SVN_RELEASES_DIR = 'releases'
20
+ SVN_BRANCHES_DIR = 'branches'
21
+ SVN_TAGS_DIR = 'tags'
22
+
23
+ SVN_DOTDIR = BASEDIR + '.svn'
24
+ SVN_ENTRIES = SVN_DOTDIR + 'entries'
25
+
26
+ # Ignore .svn directories in the various FileLists used by the main Rakefile
27
+ [
28
+ BIN_FILES,
29
+ LIB_FILES,
30
+ EXT_FILES,
31
+ DATA_FILES,
32
+ SPEC_FILES,
33
+ TEST_FILES,
34
+ EXTRA_PKGFILES,
35
+ ].each {|filelist| filelist.exclude(/\.svn/) }
36
+
37
+ # Strftime format for tags/releases
38
+ TAG_TIMESTAMP_FORMAT = '%Y%m%d-%H%M%S'
39
+ TAG_TIMESTAMP_PATTERN = /\d{4}\d{2}\d{2}-\d{6}/
40
+
41
+ RELEASE_VERSION_PATTERN = /\d+\.\d+\.\d+/
42
+
43
+ DEFAULT_KEYWORDS = %w[Date Rev Author URL Id]
44
+ KEYWORDED_FILEDIRS = %w[applets spec bin etc ext experiments examples lib misc docs]
45
+ KEYWORDED_FILEPATTERN = /
46
+ ^(?:
47
+ (?:meta)?rakefile.* # Rakefiles
48
+ |
49
+ .*\.(?:rb|c|h|js|html|css|template|erb|page) # Source file extensions
50
+ |
51
+ readme|install|todo
52
+ )$/ix
53
+
54
+
55
+
56
+ ###
57
+ ### Subversion-specific Helpers
58
+ ###
59
+ module SubversionHelpers
60
+
61
+ ###############
62
+ module_function
63
+ ###############
64
+
65
+ ### Return a new tag for the given time
66
+ def make_new_tag( time=Time.now )
67
+ return time.strftime( TAG_TIMESTAMP_FORMAT )
68
+ end
13
69
 
14
- # Strftime format for tags/releases
15
- TAG_TIMESTAMP_FORMAT = '%Y%m%d-%H%M%S'
16
- TAG_TIMESTAMP_PATTERN = /\d{4}\d{2}\d{2}-\d{6}/
17
-
18
- RELEASE_VERSION_PATTERN = /\d+\.\d+\.\d+/
19
-
20
- DEFAULT_EDITOR = 'vi'
21
- DEFAULT_KEYWORDS = %w[Date Rev Author URL Id]
22
- KEYWORDED_FILEDIRS = %w[applets spec bin etc ext experiments examples lib misc docs]
23
- KEYWORDED_FILEPATTERN = /
24
- ^(?:
25
- (?:meta)?rakefile.* # Rakefiles
26
- |
27
- .*\.(?:rb|c|h|js|html|css|template|erb|page) # Source file extensions
28
- |
29
- readme|install|todo
30
- )$/ix
31
-
32
- COMMIT_MSG_FILE = 'commit-msg.txt'
33
-
34
- SVN_TRUNK_DIR = 'trunk' unless defined?( SVN_TRUNK_DIR )
35
- SVN_RELEASES_DIR = 'branches' unless defined?( SVN_RELEASES_DIR )
36
- SVN_BRANCHES_DIR = 'branches' unless defined?( SVN_BRANCHES_DIR )
37
- SVN_TAGS_DIR = 'tags' unless defined?( SVN_TAGS_DIR )
38
-
39
- FILE_INDENT = " " * 12
40
- LOG_INDENT = " " * 3
41
-
42
-
43
-
44
- ###
45
- ### Subversion-specific Helpers
46
- ###
47
-
48
- ### Return a new tag for the given time
49
- def make_new_tag( time=Time.now )
50
- return time.strftime( TAG_TIMESTAMP_FORMAT )
51
- end
52
-
53
-
54
- ### Get the subversion information for the current working directory as
55
- ### a hash.
56
- def get_svn_info( dir='.' )
57
- return {} unless File.directory?( File.join(dir, '.svn') )
58
- info = IO.read( '|-' ) or exec 'svn', 'info', dir
59
- return YAML.load( info ) # 'svn info' outputs valid YAML! Yay!
60
- rescue NotImplementedError
61
- trace "No fork(), proceeding without svn info..."
62
- return {}
63
- end
64
-
65
-
66
- ### Get a list of the objects registered with subversion under the specified directory and
67
- ### return them as an Array of Pathame objects.
68
- def get_svn_filelist( dir='.' )
69
- list = IO.read( '|-' ) or exec 'svn', 'st', '-v', '--ignore-externals', dir
70
-
71
- # Split into lines, filter out the unknowns, and grab the filenames as Pathnames
72
- # :FIXME: This will break if we ever put in a file with spaces in its name. This
73
- # will likely be the least of our worries if we do so, however, so it's not worth
74
- # the additional complexity to make it handle that case. If we do need that, there's
75
- # always the --xml output for 'svn st'...
76
- return list.split( $/ ).
77
- reject {|line| line =~ /^(\?|(\s*|--- .*)$)/ }.
78
- collect {|fn| Pathname(fn[/\S+$/]) }
79
- end
80
-
81
- ### Return the URL to the repository root for the specified +dir+.
82
- def get_svn_repo_root( dir='.' )
83
- info = get_svn_info( dir )
84
- return info['Repository Root']
85
- end
86
-
87
-
88
- ### Return the Subversion URL to the given +dir+.
89
- def get_svn_url( dir='.' )
90
- info = get_svn_info( dir )
91
- return info['URL']
92
- end
93
-
94
-
95
- ### Return the path of the specified +dir+ under the svn root of the
96
- ### checkout.
97
- def get_svn_path( dir='.' )
98
- root = get_svn_repo_root( dir )
99
- url = get_svn_url( dir )
100
-
101
- return url.sub( root + '/', '' )
102
- end
103
-
104
-
105
- ### Return the keywords for the specified array of +files+ as a Hash keyed by filename.
106
- def get_svn_keyword_map( *files )
107
- files.flatten!
108
- files.push( '.' ) if files.empty?
109
-
110
- cmd = ['svn', 'pg', 'svn:keywords', *files]
111
-
112
- # trace "Executing: svn pg svn:keywords " + files.join(' ')
113
- output = IO.read( '|-' ) or exec( 'svn', 'pg', 'svn:keywords', *files )
114
-
115
- kwmap = {}
116
- output.split( "\n" ).each do |line|
117
- next if line !~ /\s+-\s+/
118
- path, keywords = line.split( /\s+-\s+/, 2 )
119
- kwmap[ path ] = keywords.split
120
- end
121
-
122
- return kwmap
123
- end
124
-
125
-
126
- ### Return the latest revision number of the specified +dir+ as an Integer.
127
- def get_svn_rev( dir='.' )
128
- info = get_svn_info( dir )
129
- return info['Revision']
130
- end
131
-
132
-
133
- ### Return the latest revision number of the specified +dir+ as an Integer.
134
- def get_last_changed_rev( dir='.' )
135
- info = get_svn_info( dir )
136
- return info['Last Changed Rev']
137
- end
138
-
139
-
140
- ### Return a list of the entries at the specified Subversion url. If
141
- ### no +url+ is specified, it will default to the list in the URL
142
- ### corresponding to the current working directory.
143
- def svn_ls( url=nil )
144
- url ||= get_svn_url()
145
- list = IO.read( '|-' ) or exec 'svn', 'ls', url
146
-
147
- trace 'svn ls of %s: %p' % [url, list] if $trace
148
-
149
- return [] if list.nil? || list.empty?
150
- return list.split( $INPUT_RECORD_SEPARATOR )
151
- end
152
-
153
-
154
- ### Return the URL of the latest timestamp in the tags directory.
155
- def get_latest_svn_timestamp_tag
156
- rooturl = get_svn_repo_root()
157
- tagsurl = rooturl + "/#{SVN_TAGS_DIR}"
158
-
159
- tags = svn_ls( tagsurl ).grep( TAG_TIMESTAMP_PATTERN ).sort
160
- return nil if tags.nil? || tags.empty?
161
- return tagsurl + '/' + tags.last
162
- end
163
-
164
-
165
- ### Get a subversion diff of the specified targets and return it. If no targets are
166
- ### specified, the current directory will be diffed instead.
167
- def get_svn_diff( *targets )
168
- targets << BASEDIR if targets.empty?
169
- trace "Getting svn diff for targets: %p" % [targets]
170
- log = IO.read( '|-' ) or exec 'svn', 'diff', *(targets.flatten)
171
-
172
- return log
173
- end
174
-
175
-
176
- ### Get a subversion status as an Array of tuples of the form:
177
- ### [ <status>, <path> ]
178
- def get_svn_status( *targets )
179
- targets << BASEDIR if targets.empty?
180
- trace "Getting svn status for targets: %p" % [targets]
181
- status = IO.read( '|-' ) or exec 'svn', 'st', '--ignore-externals', *(targets.flatten)
182
- entries = status.split( /\n/ ).
183
- select {|line| line !~ /^(\s*|--- .*)$/ }.
184
- collect do |line|
185
- flag, path = line.strip.split( /\s+/, 2 )
186
- [ flag, Pathname.new(path) ]
187
- end
188
-
189
- return entries
190
- end
191
-
192
-
193
- ### Return the URL of the latest timestamp in the tags directory.
194
- def get_latest_release_tag
195
- rooturl = get_svn_repo_root()
196
- releaseurl = rooturl + "/#{SVN_RELEASES_DIR}"
197
-
198
- tags = svn_ls( releaseurl ).grep( RELEASE_VERSION_PATTERN ).sort_by do |tag|
199
- tag[RELEASE_VERSION_PATTERN].split('.').collect {|i| Integer(i) }
200
- end
201
- return nil if tags.empty?
202
70
 
203
- return releaseurl + '/' + tags.last
204
- end
71
+ ### Get the subversion information for the current working directory as
72
+ ### a hash.
73
+ def get_svn_info( dir='.' )
74
+ return {} unless File.directory?( File.join(dir, '.svn') )
75
+ info = IO.read( '|-' ) or exec 'svn', 'info', dir.to_s
76
+ return YAML.load( info ) # 'svn info' outputs valid YAML! Yay!
77
+ rescue NotImplementedError
78
+ trace "No fork(), proceeding without svn info..."
79
+ return {}
80
+ end
81
+
82
+
83
+ ### Get a list of the objects registered with subversion under the specified directory and
84
+ ### return them as an Array of Pathame objects.
85
+ def get_svn_filelist( dir='.' )
86
+ list = IO.read( '|-' ) or exec 'svn', 'st', '-v', '--ignore-externals', dir
87
+
88
+ # Split into lines, filter out the unknowns, and grab the filenames as Pathnames
89
+ # :FIXME: This will break if we ever put in a file with spaces in its name. This
90
+ # will likely be the least of our worries if we do so, however, so it's not worth
91
+ # the additional complexity to make it handle that case. If we do need that, there's
92
+ # always the --xml output for 'svn st'...
93
+ return list.split( $/ ).
94
+ reject {|line| line =~ /^(\?|(\s*|--- .*)$)/ }.
95
+ collect {|fn| Pathname(fn[/\S+$/]) }
96
+ end
97
+
98
+ ### Return the URL to the repository root for the specified +dir+.
99
+ def get_svn_repo_root( dir='.' )
100
+ info = get_svn_info( dir )
101
+ return info['Repository Root']
102
+ end
103
+
205
104
 
105
+ ### Return the Subversion URL to the given +dir+.
106
+ def get_svn_url( dir='.' )
107
+ info = get_svn_info( dir )
108
+ return info['URL']
109
+ end
206
110
 
207
- ### Extract a diff from the specified subversion working +dir+ and return it.
208
- def make_svn_commit_log( dir='.' )
209
- diff = IO.read( '|-' ) or exec 'svn', 'diff'
210
- fail "No differences." if diff.empty?
211
111
 
212
- return diff
213
- end
112
+ ### Return the path of the specified +dir+ under the svn root of the
113
+ ### checkout.
114
+ def get_svn_path( dir='.' )
115
+ root = get_svn_repo_root( dir )
116
+ url = get_svn_url( dir )
117
+
118
+ return url.sub( root + '/', '' )
119
+ end
214
120
 
215
121
 
216
- ### Extract the svn log from the specified subversion working +dir+,
217
- ### starting from rev +start+ and ending with rev +finish+, and return it.
218
- def make_svn_log( dir='.', start='PREV', finish='HEAD' )
219
- trace "svn log -r#{start}:#{finish} #{dir}"
220
- log = IO.read( '|-' ) or exec 'svn', 'log', "-r#{start}:#{finish}", dir
221
- fail "No log between #{start} and #{finish}." if log.empty?
122
+ ### Return the keywords for the specified array of +files+ as a Hash keyed by filename.
123
+ def get_svn_keyword_map( *files )
124
+ files.flatten!
125
+ files.push( '.' ) if files.empty?
222
126
 
223
- return log
224
- end
127
+ cmd = ['svn', 'pg', 'svn:keywords', *files]
225
128
 
129
+ # trace "Executing: svn pg svn:keywords " + files.join(' ')
130
+ output = IO.read( '|-' ) or exec( 'svn', 'pg', 'svn:keywords', *files )
226
131
 
227
- ### Extract the verbose XML svn log from the specified subversion working +dir+,
228
- ### starting from rev +start+ and ending with rev +finish+, and return it.
229
- def make_xml_svn_log( dir='.', start='PREV', finish='HEAD' )
230
- trace "svn log --xml --verbose -r#{start}:#{finish} #{dir}"
231
- log = IO.read( '|-' ) or exec 'svn', 'log', '--verbose', '--xml', "-r#{start}:#{finish}", dir
232
- fail "No log between #{start} and #{finish}." if log.empty?
132
+ kwmap = {}
133
+ output.split( "\n" ).each do |line|
134
+ next if line !~ /\s+-\s+/
135
+ path, keywords = line.split( /\s+-\s+/, 2 )
136
+ kwmap[ path ] = keywords.split
137
+ end
233
138
 
234
- return log
235
- end
139
+ return kwmap
140
+ end
236
141
 
237
142
 
238
- ### Create a changelog from the subversion log of the specified +dir+ and return it.
239
- def make_svn_changelog( dir='.' )
240
- require 'xml/libxml'
143
+ ### Return the latest revision number of the specified +dir+ as an Integer.
144
+ def get_svn_rev( dir='.' )
145
+ info = get_svn_info( dir )
146
+ return info['Revision']
147
+ end
148
+ alias get_vcs_rev get_svn_rev
241
149
 
242
- changelog = ''
243
- path_prefix = '/' + get_svn_path( dir ) + '/'
244
150
 
245
- xmllog = make_xml_svn_log( dir, 0 )
151
+ ### Return the latest revision number of the specified +dir+ as an Integer.
152
+ def get_last_changed_rev( dir='.' )
153
+ info = get_svn_info( dir )
154
+ return info['Last Changed Rev']
155
+ end
246
156
 
247
- parser = XML::Parser.string( xmllog )
248
- root = parser.parse.root
249
- root.find( '//log/logentry' ).to_a.reverse.each do |entry|
250
- trace "Making a changelog entry for r%s" % [ entry['revision'] ]
251
157
 
252
- added = []
253
- deleted = []
254
- changed = []
158
+ ### Return a list of the entries at the specified Subversion url. If
159
+ ### no +url+ is specified, it will default to the list in the URL
160
+ ### corresponding to the current working directory.
161
+ def svn_ls( url=nil )
162
+ url ||= get_svn_url()
163
+ list = IO.read( '|-' ) or exec 'svn', 'ls', url
255
164
 
256
- entry.find( 'paths/path').each do |path|
257
- pathname = path.content
258
- pathname.sub!( path_prefix , '' ) if pathname.count('/') > 1
165
+ trace 'svn ls of %s: %p' % [url, list] if $trace
259
166
 
260
- case path['action']
261
- when 'A', 'R'
262
- if path['copyfrom-path']
263
- verb = path['action'] == 'A' ? 'renamed' : 'copied'
264
- added << "%s\n#{FILE_INDENT}-> #{verb} from %s@r%s" % [
265
- pathname,
266
- path['copyfrom-path'],
267
- path['copyfrom-rev'],
268
- ]
269
- else
270
- added << "%s (new)" % [ pathname ]
167
+ return [] if list.nil? || list.empty?
168
+ return list.split( $INPUT_RECORD_SEPARATOR )
169
+ end
170
+
171
+
172
+ ### Return the URL of the latest timestamp in the tags directory.
173
+ def get_latest_svn_timestamp_tag
174
+ rooturl = get_svn_repo_root()
175
+ tagsurl = rooturl + "/#{SVN_TAGS_DIR}"
176
+
177
+ tags = svn_ls( tagsurl ).grep( TAG_TIMESTAMP_PATTERN ).sort
178
+ return nil if tags.nil? || tags.empty?
179
+ return tagsurl + '/' + tags.last
180
+ end
181
+
182
+
183
+ ### Get a subversion diff of the specified targets and return it. If no targets are
184
+ ### specified, the current directory will be diffed instead.
185
+ def get_svn_diff( *targets )
186
+ targets << BASEDIR if targets.empty?
187
+ trace "Getting svn diff for targets: %p" % [targets]
188
+ log = IO.read( '|-' ) or exec 'svn', 'diff', *(targets.flatten)
189
+
190
+ return log
191
+ end
192
+
193
+
194
+ ### Generate a commit log and invoke the user's editor on it.
195
+ def edit_commit_log
196
+ diff = make_commit_log()
197
+
198
+ File.open( COMMIT_MSG_FILE, File::WRONLY|File::TRUNC|File::CREAT ) do |fh|
199
+ fh.print( diff )
200
+ end
201
+
202
+ edit( COMMIT_MSG_FILE )
203
+ end
204
+
205
+
206
+ ### Get a subversion status as an Array of tuples of the form:
207
+ ### [ <status>, <path> ]
208
+ def get_svn_status( *targets )
209
+ targets << BASEDIR if targets.empty?
210
+ trace "Getting svn status for targets: %p" % [targets]
211
+ status = IO.read( '|-' ) or exec 'svn', 'st', '--ignore-externals', *(targets.flatten)
212
+ entries = status.split( /\n/ ).
213
+ select {|line| line !~ /^(\s*|--- .*)$/ }.
214
+ collect do |line|
215
+ flag, path = line.strip.split( /\s+/, 2 )
216
+ [ flag, Pathname.new(path) ]
271
217
  end
272
-
273
- when 'M'
274
- changed << pathname
275
-
276
- when 'D'
277
- deleted << pathname
278
-
279
- else
280
- log "Unknown action %p in rev %d" % [ path['action'], entry['revision'] ]
218
+
219
+ return entries
220
+ end
221
+
222
+
223
+ ### Return the URL of the latest timestamp in the tags directory.
224
+ def get_latest_release_tag
225
+ rooturl = get_svn_repo_root()
226
+ releaseurl = rooturl + "/#{SVN_RELEASES_DIR}"
227
+
228
+ tags = svn_ls( releaseurl ).grep( RELEASE_VERSION_PATTERN ).sort_by do |tag|
229
+ tag[RELEASE_VERSION_PATTERN].split('.').collect {|i| Integer(i) }
281
230
  end
282
-
283
- end
284
-
285
- date = Time.parse( entry.find_first('date').content )
286
-
287
- # cvs2svn doesn't set 'author'
288
- author = 'unknown'
289
- if entry.find_first( 'author' )
290
- author = entry.find_first( 'author' ).content
291
- end
292
-
293
- msg = entry.find_first( 'msg' ).content
294
- rev = entry['revision']
295
-
296
- changelog << "-- #{date.rfc2822} by #{author} (r#{rev}) -----\n"
297
- changelog << " Added: " << humanize_file_list(added) << "\n" unless added.empty?
298
- changelog << " Changed: " << humanize_file_list(changed) << "\n" unless changed.empty?
299
- changelog << " Deleted: " << humanize_file_list(deleted) << "\n" unless deleted.empty?
300
- changelog << "\n"
301
-
302
- indent = msg[/^(\s*)/] + LOG_INDENT
303
-
304
- changelog << indent << msg.strip.gsub(/\n\s*/m, "\n#{indent}")
305
- changelog << "\n\n\n"
306
- end
307
-
308
- return changelog
309
- end
231
+ return nil if tags.empty?
310
232
 
233
+ return releaseurl + '/' + tags.last
234
+ end
311
235
 
312
- ### Returns a human-scannable file list by joining and truncating the list if it's too long.
313
- def humanize_file_list( list, indent=FILE_INDENT )
314
- listtext = list[0..5].join( "\n#{indent}" )
315
- if list.length > 5
316
- listtext << " (and %d other/s)" % [ list.length - 5 ]
317
- end
318
-
319
- return listtext
320
- end
321
236
 
237
+ ### Return the names of all existing branches.
238
+ def get_branch_names
239
+ rooturl = get_svn_repo_root()
240
+ branchesurl = rooturl + "/#{SVN_BRANCHES_DIR}"
322
241
 
323
- ### Add the list of +pathnames+ to the svn:ignore list.
324
- def svn_ignore_files( *pathnames )
325
- pathnames.flatten!
242
+ return svn_ls( branchesurl )
243
+ end
326
244
 
327
- map = pathnames.inject({}) do |map,path|
328
- map[ path.dirname ] ||= []
329
- map[ path.dirname ] << path.basename
330
- map
331
- end
332
245
 
333
- trace "Ignoring %d files in %d directories." % [ pathnames.length, map.length ]
246
+ ### Extract a diff from the specified subversion working +dir+ and return it.
247
+ def make_svn_commit_log( dir='.' )
248
+ diff = IO.read( '|-' ) or exec 'svn', 'diff'
249
+ fail "No differences." if diff.empty?
334
250
 
335
- map.each do |dir, files|
336
- trace " %s: %p" % [ dir, files ]
337
- io = open( '|-' ) or exec 'svn', 'pg', 'svn:ignore', dir
338
- ignorelist = io.read.strip
339
- ignorelist << "\n" << files.join("\n")
340
- system 'svn', 'ps', 'svn:ignore', ignorelist, dir
341
- end
342
- end
251
+ return diff
252
+ end
343
253
 
344
254
 
345
- ### Delete the files in the given +filelist+ after confirming with the user.
346
- def delete_extra_files( filelist )
347
- description = humanize_file_list( filelist, ' ' )
348
- log "Files to delete:\n ", description
349
- ask_for_confirmation( "Really delete them?", false ) do
350
- filelist.each do |f|
351
- rm_rf( f, :verbose => true )
255
+ ### Extract the svn log from the specified subversion working +dir+,
256
+ ### starting from rev +start+ and ending with rev +finish+, and return it.
257
+ def make_svn_log( dir='.', start='PREV', finish='HEAD' )
258
+ trace "svn log -r#{start}:#{finish} #{dir}"
259
+ log = IO.read( '|-' ) or exec 'svn', 'log', "-r#{start}:#{finish}", dir
260
+ fail "No log between #{start} and #{finish}." if log.empty?
261
+
262
+ return log
352
263
  end
353
- end
354
- end
355
264
 
356
265
 
266
+ ### Extract the verbose XML svn log from the specified subversion working +dir+,
267
+ ### starting from rev +start+ and ending with rev +finish+, and return it.
268
+ def make_xml_svn_log( dir='.', start='PREV', finish='HEAD' )
269
+ trace "svn log --xml --verbose -r#{start}:#{finish} #{dir}"
270
+ log = IO.read( '|-' ) or exec 'svn', 'log', '--verbose', '--xml', "-r#{start}:#{finish}", dir
271
+ fail "No log between #{start} and #{finish}." if log.empty?
272
+
273
+ return log
274
+ end
275
+
276
+
277
+ ### Create a changelog from the subversion log of the specified +dir+ and return it.
278
+ def make_svn_changelog( dir='.' )
279
+ require 'xml/libxml'
280
+
281
+ changelog = ''
282
+ path_prefix = '/' + get_svn_path( dir ) + '/'
283
+
284
+ xmllog = make_xml_svn_log( dir, 0 )
285
+
286
+ parser = XML::Parser.string( xmllog )
287
+ root = parser.parse.root
288
+ root.find( '//log/logentry' ).to_a.reverse.each do |entry|
289
+ trace "Making a changelog entry for r%s" % [ entry['revision'] ]
357
290
 
358
- ###
359
- ### Tasks
360
- ###
291
+ added = []
292
+ deleted = []
293
+ changed = []
361
294
 
362
- desc "Subversion tasks"
363
- namespace :svn do
295
+ entry.find( 'paths/path').each do |path|
296
+ pathname = path.content
297
+ pathname.sub!( path_prefix , '' ) if pathname.count('/') > 1
364
298
 
365
- desc "Copy the HEAD revision of the current #{SVN_TRUNK_DIR}/ to #{SVN_TAGS_DIR}/ with a " +
366
- "current timestamp."
367
- task :tag do
368
- svninfo = get_svn_info()
369
- tag = make_new_tag()
370
- svntrunk = svninfo['Repository Root'] + "/#{SVN_TRUNK_DIR}"
371
- svntagdir = svninfo['Repository Root'] + "/#{SVN_TAGS_DIR}"
372
- svntag = svntagdir + '/' + tag
299
+ case path['action']
300
+ when 'A', 'R'
301
+ if path['copyfrom-path']
302
+ verb = path['action'] == 'A' ? 'renamed' : 'copied'
303
+ added << "%s\n#{FILE_INDENT}-> #{verb} from %s@r%s" % [
304
+ pathname,
305
+ path['copyfrom-path'],
306
+ path['copyfrom-rev'],
307
+ ]
308
+ else
309
+ added << "%s (new)" % [ pathname ]
310
+ end
373
311
 
374
- desc = "Tagging trunk as #{svntag}"
375
- ask_for_confirmation( desc ) do
376
- msg = prompt_with_default( "Commit log: ", "Tagging for code push" )
377
- run 'svn', 'cp', '-m', msg, svntrunk, svntag
312
+ when 'M'
313
+ changed << pathname
314
+
315
+ when 'D'
316
+ deleted << pathname
317
+
318
+ else
319
+ log "Unknown action %p in rev %d" % [ path['action'], entry['revision'] ]
320
+ end
321
+
322
+ end
323
+
324
+ date = Time.parse( entry.find_first('date').content )
325
+
326
+ # cvs2svn doesn't set 'author'
327
+ author = 'unknown'
328
+ if entry.find_first( 'author' )
329
+ author = entry.find_first( 'author' ).content
330
+ end
331
+
332
+ msg = entry.find_first( 'msg' ).content
333
+ rev = entry['revision']
334
+
335
+ changelog << "-- #{date.rfc2822} by #{author} (r#{rev}) -----\n"
336
+ changelog << " Added: " << humanize_file_list(added) << "\n" unless added.empty?
337
+ changelog << " Changed: " << humanize_file_list(changed) << "\n" unless changed.empty?
338
+ changelog << " Deleted: " << humanize_file_list(deleted) << "\n" unless deleted.empty?
339
+ changelog << "\n"
340
+
341
+ indent = msg[/^(\s*)/] + LOG_INDENT
342
+
343
+ changelog << indent << msg.strip.gsub(/\n\s*/m, "\n#{indent}")
344
+ changelog << "\n\n\n"
345
+ end
346
+
347
+ return changelog
378
348
  end
379
- end
380
349
 
381
350
 
382
- desc "Copy the HEAD revision of the current #{SVN_TRUNK_DIR}/ to #{SVN_BRANCHES_DIR} with a " +
383
- "user-specified name."
384
- task :branch, [:name] do |task, args|
385
- unless args.name
386
- args.name = prompt( "Branch name" ) or abort
387
- end
388
-
389
- svninfo = get_svn_info()
390
- svntrunk = Pathname.new( svninfo['Repository Root'] ) + SVN_TRUNK_DIR
391
- svnbranchdir = Pathname.new( svninfo['Repository Root'] ) + SVN_BRANCHES_DIR
392
- svnbranch = svnbranchdir + args.name
393
-
394
- desc = "Making a new branch: #{svnbranch}"
395
- ask_for_confirmation( desc ) do
396
- msg = prompt_with_default( "Commit log: ", "Making a '#{args.name}' branch" )
397
- run 'svn', 'cp', '-m', msg, svntrunk, svnbranch
398
- ask_for_confirmation( "Switch to the new branch?", false ) do
399
- run 'svn', 'sw', svnbranch
351
+ ### Returns a human-scannable file list by joining and truncating the list if it's too long.
352
+ def humanize_file_list( list, indent=FILE_INDENT )
353
+ listtext = list[0..5].join( "\n#{indent}" )
354
+ if list.length > 5
355
+ listtext << " (and %d other/s)" % [ list.length - 5 ]
400
356
  end
357
+
358
+ return listtext
401
359
  end
402
- end
403
-
404
-
405
- desc "Switch to the trunk if the working copy isn't there already."
406
- task :trunk do
407
- svninfo = get_svn_info()
408
- svntrunk = Pathname.new( svninfo['Repository Root'] ) + SVN_TRUNK_DIR
409
-
410
- if svninfo['URL'] != svntrunk.to_s
411
- log "Switching to #{svntrunk}"
412
- run 'svn', 'sw', svntrunk
413
- else
414
- log "You are already on trunk (#{svntrunk})"
360
+
361
+
362
+ ### Add the list of +pathnames+ to the svn:ignore list.
363
+ def svn_ignore_files( *pathnames )
364
+ pathnames.flatten!
365
+
366
+ map = pathnames.inject({}) do |map,path|
367
+ map[ path.dirname ] ||= []
368
+ map[ path.dirname ] << path.basename
369
+ map
370
+ end
371
+
372
+ trace "Ignoring %d files in %d directories." % [ pathnames.length, map.length ]
373
+
374
+ map.each do |dir, files|
375
+ trace " %s: %p" % [ dir, files ]
376
+ io = open( '|-' ) or exec 'svn', 'pg', 'svn:ignore', dir
377
+ ignorelist = io.read.strip
378
+ ignorelist << "\n" << files.join("\n")
379
+ system 'svn', 'ps', 'svn:ignore', ignorelist, dir
380
+ end
415
381
  end
416
- end
417
-
418
-
419
- desc "Copy the most recent tag to #{SVN_RELEASES_DIR}/#{PKG_VERSION}"
420
- task :release do
421
- last_tag = get_latest_svn_timestamp_tag()
422
- svninfo = get_svn_info()
423
- svnroot = Pathname.new( svninfo['Repository Root'] )
424
- svntrunk = svnroot + SVN_TRUNK_DIR
425
- svnrel = svnroot + SVN_RELEASES_DIR
426
- release = PKG_VERSION
427
- svnrelease = svnrel + release
428
-
429
- unless svn_ls( svnrel.dirname ).include?( svnrel.basename.to_s + '/' )
430
- log "Releases path #{svnrel} does not exist."
431
- ask_for_confirmation( "To continue I'll need to create it." ) do
432
- run 'svn', 'mkdir', svnrel, '-m', 'Creating releases/ directory'
382
+
383
+
384
+ ### Delete the files in the given +filelist+ after confirming with the user.
385
+ def delete_extra_files( filelist )
386
+ description = humanize_file_list( filelist, ' ' )
387
+ log "Files to delete:\n ", description
388
+ ask_for_confirmation( "Really delete them?", false ) do
389
+ filelist.each do |f|
390
+ rm_rf( f, :verbose => true )
391
+ end
433
392
  end
434
- else
435
- trace "Found release dir #{svnrel}"
436
393
  end
437
394
 
438
- releases = svn_ls( svnrel ).collect {|name| name.sub(%r{/$}, '') }
439
- trace "Releases: %p" % [releases]
440
- if releases.include?( release )
441
- error "Version #{release} already has a branch (#{svnrelease}). Did you mean " +
442
- "to increment the version in #{VERSION_FILE}?"
443
- fail
444
- else
445
- trace "No #{release} version currently exists"
395
+ end # module SubversionHelpers
396
+
397
+
398
+ ###
399
+ ### Tasks
400
+ ###
401
+
402
+ desc "Subversion tasks"
403
+ namespace :svn do
404
+ include SubversionHelpers
405
+
406
+ desc "Copy the HEAD revision of the current #{SVN_TRUNK_DIR}/ to #{SVN_TAGS_DIR}/ with a " +
407
+ "current timestamp."
408
+ task :tag do
409
+ svninfo = get_svn_info()
410
+ tag = make_new_tag()
411
+ svntrunk = svninfo['Repository Root'] + "/#{SVN_TRUNK_DIR}"
412
+ svntagdir = svninfo['Repository Root'] + "/#{SVN_TAGS_DIR}"
413
+ svntag = svntagdir + '/' + tag
414
+
415
+ desc = "Tagging trunk as #{svntag}"
416
+ ask_for_confirmation( desc ) do
417
+ msg = prompt_with_default( "Commit log: ", "Tagging for code push" )
418
+ run 'svn', 'cp', '-m', msg, svntrunk, svntag
419
+ end
446
420
  end
447
-
448
- desc = "Tagging trunk as #{svnrelease}..."
449
- ask_for_confirmation( desc ) do
450
- msg = prompt_with_default( "Commit log: ", "Branching for release" )
451
- run 'svn', 'cp', '-m', msg, svntrunk, svnrelease
421
+
422
+
423
+ desc "Copy the HEAD revision of the current #{SVN_TRUNK_DIR}/ to #{SVN_BRANCHES_DIR} with a " +
424
+ "user-specified name."
425
+ task :branch, [:name] do |task, args|
426
+ branchname = args.name
427
+ unless branchname
428
+ branchname = prompt( "Branch name" ) or abort
429
+ end
430
+
431
+ svninfo = get_svn_info()
432
+ svntrunk = Pathname.new( svninfo['Repository Root'] ) + SVN_TRUNK_DIR
433
+ svnbranchdir = Pathname.new( svninfo['Repository Root'] ) + SVN_BRANCHES_DIR
434
+ svnbranch = svnbranchdir + branchname
435
+
436
+ desc = "Making a new branch: #{svnbranch}"
437
+ ask_for_confirmation( desc ) do
438
+ msg = prompt_with_default( "Commit log: ", "Making a '#{args.name}' branch" )
439
+ run 'svn', 'cp', '-m', msg, svntrunk, svnbranch
440
+ ask_for_confirmation( "Switch to the new branch?", false ) do
441
+ run 'svn', 'sw', svnbranch
442
+ end
443
+ end
452
444
  end
453
- end
454
445
 
455
- ### Task for debugging the #get_target_args helper
456
- task :show_targets do
457
- $stdout.puts "Targets from ARGV (%p): %p" % [ARGV, get_target_args()]
458
- end
459
446
 
447
+ desc "Switch the working copy to the named branch"
448
+ task :switch, [:name] do |task, args|
449
+ branches = get_branch_names().collect {|name| name.chomp('/') }
460
450
 
461
- desc "Generate a commit log"
462
- task :commitlog => [COMMIT_MSG_FILE]
463
-
464
- desc "Show the (pre-edited) commit log for the current directory"
465
- task :show_commitlog do
466
- puts make_svn_commit_log()
467
- end
468
-
451
+ unless args.name
452
+ log "Branches are:\n" + branches.collect {|br| " #{br}" }.join( "\n" )
469
453
 
470
- file COMMIT_MSG_FILE do
471
- diff = make_svn_commit_log()
472
-
473
- File.open( COMMIT_MSG_FILE, File::WRONLY|File::EXCL|File::CREAT ) do |fh|
474
- fh.print( diff )
475
- end
454
+ begin
455
+ oldproc = Readline.completion_proc
456
+ abbrev = branches.abbrev
457
+ Readline.completion_proc = lambda{|string| abbrev[string] }
458
+
459
+ name = prompt( "Branch to switch to" ) or abort
460
+ args.with_defaults( :name => name )
461
+ ensure
462
+ Readline.completion_proc = oldproc unless oldproc.nil?
463
+ end
464
+ end
476
465
 
477
- editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
478
- system editor, COMMIT_MSG_FILE
479
- unless $?.success?
480
- fail "Editor exited uncleanly."
466
+ svninfo = get_svn_info()
467
+ abort "Branch '#{args.name}' does not exist" unless branches.include?( args.name )
468
+ branchuri = Pathname.new( svninfo['Repository Root'] ) + SVN_BRANCHES_DIR + args.name
469
+ run 'svn', 'sw', branchuri
481
470
  end
482
- end
471
+ task :sw => :switch
483
472
 
484
473
 
485
- desc "Update from Subversion"
486
- task :update do
487
- run 'svn', 'up', '--ignore-externals'
488
- end
474
+ desc "Switch to the trunk if the working copy isn't there already."
475
+ task :trunk do
476
+ svninfo = get_svn_info()
477
+ svntrunk = Pathname.new( svninfo['Repository Root'] ) + SVN_TRUNK_DIR
478
+
479
+ if svninfo['URL'] != svntrunk.to_s
480
+ log "Switching to #{svntrunk}"
481
+ run 'svn', 'sw', svntrunk
482
+ else
483
+ log "You are already on trunk (#{svntrunk})"
484
+ end
485
+ end
489
486
 
490
487
 
491
- desc "Add/ignore any files that are unknown in the working copy"
492
- task :newfiles do
493
- log "Checking for new files..."
494
- entries = get_svn_status()
495
-
496
- unless entries.empty?
497
- files_to_add = []
498
- files_to_ignore = []
499
- files_to_delete = []
500
-
501
- entries.find_all {|entry| entry[0] == '?'}.each do |entry|
502
- action = prompt_with_default( " #{entry[1]}: (a)dd, (i)gnore, (s)kip (d)elete", 's' )
503
- case action
504
- when 'a'
505
- files_to_add << entry[1]
506
- when 'i'
507
- files_to_ignore << entry[1]
508
- when 'd'
509
- files_to_delete << entry[1]
488
+ desc "Copy the most recent tag to #{SVN_RELEASES_DIR}/#{PKG_VERSION}"
489
+ task :prep_release do
490
+ last_tag = get_latest_svn_timestamp_tag()
491
+ svninfo = get_svn_info()
492
+ svnroot = Pathname.new( svninfo['Repository Root'] )
493
+ svntrunk = svnroot + SVN_TRUNK_DIR
494
+ svnrel = svnroot + SVN_RELEASES_DIR
495
+ release = PKG_VERSION
496
+ svnrelease = svnrel + release
497
+
498
+ unless svn_ls( svnrel.dirname ).include?( svnrel.basename.to_s + '/' )
499
+ log "Releases path #{svnrel} does not exist."
500
+ ask_for_confirmation( "To continue I'll need to create it." ) do
501
+ run 'svn', 'mkdir', svnrel, '-m', 'Creating releases/ directory'
510
502
  end
503
+ else
504
+ trace "Found release dir #{svnrel}"
511
505
  end
512
-
513
- unless files_to_add.empty?
514
- run 'svn', 'add', *files_to_add
506
+
507
+ releases = svn_ls( svnrel ).collect {|name| name.sub(%r{/$}, '') }
508
+ trace "Releases: %p" % [releases]
509
+ if releases.include?( release )
510
+ error "Version #{release} already has a branch (#{svnrelease}). Did you mean " +
511
+ "to increment the version in #{VERSION_FILE}?"
512
+ fail
513
+ else
514
+ trace "No #{release} version currently exists"
515
515
  end
516
-
517
- unless files_to_ignore.empty?
518
- svn_ignore_files( *files_to_ignore )
516
+
517
+ desc = "Tagging trunk as #{svnrelease}..."
518
+ ask_for_confirmation( desc ) do
519
+ msg = prompt_with_default( "Commit log: ", "Branching for release" )
520
+ run 'svn', 'cp', '-m', msg, svntrunk, svnrelease
519
521
  end
522
+ end
520
523
 
521
- unless files_to_delete.empty?
522
- delete_extra_files( files_to_delete )
524
+ ### Task for debugging the #get_target_args helper
525
+ task :show_targets do
526
+ $stdout.puts "Targets from ARGV (%p): %p" % [ARGV, get_target_args()]
527
+ end
528
+
529
+
530
+ desc "Update from Subversion"
531
+ task :update do
532
+ run 'svn', 'up', '--ignore-externals'
533
+ end
534
+
535
+
536
+ desc "Add/ignore any files that are unknown in the working copy"
537
+ task :newfiles do
538
+ log "Checking for new files..."
539
+ entries = get_svn_status()
540
+
541
+ unless entries.empty?
542
+ files_to_add = []
543
+ files_to_ignore = []
544
+ files_to_delete = []
545
+
546
+ entries.find_all {|entry| entry[0] == '?'}.each do |entry|
547
+ action = prompt_with_default( " #{entry[1]}: (a)dd, (i)gnore, (s)kip (d)elete", 's' )
548
+ case action
549
+ when 'a'
550
+ files_to_add << entry[1]
551
+ when 'i'
552
+ files_to_ignore << entry[1]
553
+ when 'd'
554
+ files_to_delete << entry[1]
555
+ end
556
+ end
557
+
558
+ unless files_to_add.empty?
559
+ run 'svn', 'add', *files_to_add
560
+ end
561
+
562
+ unless files_to_ignore.empty?
563
+ svn_ignore_files( *files_to_ignore )
564
+ end
565
+
566
+ unless files_to_delete.empty?
567
+ delete_extra_files( files_to_delete )
568
+ end
523
569
  end
524
570
  end
525
- end
526
- task :add => :newfiles
527
-
528
-
529
- desc "Check in all the changes in your current working copy"
530
- task :checkin => ['svn:update', 'svn:newfiles', 'test', 'svn:fix_keywords', COMMIT_MSG_FILE] do
531
- targets = get_target_args()
532
- $stderr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
533
- ask_for_confirmation( "Continue with checkin?" ) do
534
- run 'svn', 'ci', '-F', COMMIT_MSG_FILE, targets
571
+ task :add => :newfiles
572
+
573
+
574
+ desc "Check in all the changes in your current working copy"
575
+ task :checkin => ['svn:update', 'svn:newfiles', 'test', 'svn:fix_keywords', COMMIT_MSG_FILE] do
576
+ targets = get_target_args()
577
+ $stderr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
578
+ ask_for_confirmation( "Continue with checkin?" ) do
579
+ run 'svn', 'ci', '-F', COMMIT_MSG_FILE, targets
580
+ rm_f COMMIT_MSG_FILE
581
+ end
582
+ end
583
+ task :commit => :checkin
584
+ task :ci => :checkin
585
+
586
+
587
+ task :clean do
535
588
  rm_f COMMIT_MSG_FILE
536
589
  end
537
- end
538
- task :commit => :checkin
539
- task :ci => :checkin
540
-
541
-
542
- task :clean do
543
- rm_f COMMIT_MSG_FILE
544
- end
545
590
 
546
-
547
- desc "Check and fix any missing keywords for any files in the project which need them"
548
- task :fix_keywords do
549
- log "Checking subversion keywords..."
550
- paths = get_svn_filelist( BASEDIR ).
551
- select {|path| path.file? && path.to_s =~ KEYWORDED_FILEPATTERN }
552
-
553
- trace "Looking at %d paths for keywords:\n %p" % [paths.length, paths]
554
- kwmap = get_svn_keyword_map( paths )
555
-
556
- buf = ''
557
- PP.pp( kwmap, buf, 132 )
558
- trace "keyword map is: %s" % [buf]
559
-
560
- files_needing_fixups = paths.find_all do |path|
561
- (kwmap[path.to_s] & DEFAULT_KEYWORDS) != DEFAULT_KEYWORDS
562
- end
563
-
564
- unless files_needing_fixups.empty?
565
- $stderr.puts "Files needing keyword fixes: ",
566
- files_needing_fixups.collect {|f|
567
- " %s: %s" % [f, kwmap[f] ? kwmap[f].join(' ') : "(no keywords)"]
568
- }
569
- ask_for_confirmation( "Will add default keywords to these files." ) do
570
- run 'svn', 'ps', 'svn:keywords', DEFAULT_KEYWORDS.join(' '), *files_needing_fixups
591
+
592
+ desc "Check and fix any missing keywords for any files in the project which need them"
593
+ task :fix_keywords do
594
+ log "Checking subversion keywords..."
595
+ paths = get_svn_filelist( BASEDIR ).
596
+ select {|path| path.file? && path.to_s =~ KEYWORDED_FILEPATTERN }
597
+
598
+ trace "Looking at %d paths for keywords:\n %p" % [paths.length, paths]
599
+ kwmap = get_svn_keyword_map( paths )
600
+
601
+ buf = ''
602
+ PP.pp( kwmap, buf, 132 )
603
+ trace "keyword map is: %s" % [buf]
604
+
605
+ files_needing_fixups = paths.find_all do |path|
606
+ (kwmap[path.to_s] & DEFAULT_KEYWORDS) != DEFAULT_KEYWORDS
607
+ end
608
+
609
+ unless files_needing_fixups.empty?
610
+ $stderr.puts "Files needing keyword fixes: ",
611
+ files_needing_fixups.collect {|f|
612
+ " %s: %s" % [f, kwmap[f] ? kwmap[f].join(' ') : "(no keywords)"]
613
+ }
614
+ ask_for_confirmation( "Will add default keywords to these files." ) do
615
+ run 'svn', 'ps', 'svn:keywords', DEFAULT_KEYWORDS.join(' '), *files_needing_fixups
616
+ end
617
+ else
618
+ log "Keywords are all up to date."
571
619
  end
572
- else
573
- log "Keywords are all up to date."
574
620
  end
621
+
622
+
623
+ task :debug_helpers do
624
+ methods = [
625
+ :get_last_changed_rev,
626
+ :get_latest_release_tag,
627
+ :get_latest_svn_timestamp_tag,
628
+ :get_svn_diff,
629
+ :get_svn_filelist,
630
+ :get_svn_info,
631
+ :get_svn_keyword_map,
632
+ :get_svn_path,
633
+ :get_svn_repo_root,
634
+ :get_svn_rev,
635
+ :get_svn_status,
636
+ :get_svn_url,
637
+ :svn_ls,
638
+ ]
639
+ maxlen = methods.collect {|sym| sym.to_s.length }.max
640
+
641
+ methods.each do |meth|
642
+ res = send( meth )
643
+ puts "%*s => %p" % [ maxlen, colorize(meth.to_s, :cyan), res ]
644
+ end
645
+ end
646
+
575
647
  end
576
648
 
577
-
578
- task :debug_helpers do
579
- methods = [
580
- :get_last_changed_rev,
581
- :get_latest_release_tag,
582
- :get_latest_svn_timestamp_tag,
583
- :get_svn_diff,
584
- :get_svn_filelist,
585
- :get_svn_info,
586
- :get_svn_keyword_map,
587
- :get_svn_path,
588
- :get_svn_repo_root,
589
- :get_svn_rev,
590
- :get_svn_status,
591
- :get_svn_url,
592
- :svn_ls,
593
- ]
594
- maxlen = methods.collect {|sym| sym.to_s.length }.max
595
-
596
- methods.each do |meth|
597
- res = send( meth )
598
- puts "%*s => %p" % [ maxlen, colorize(meth.to_s, :cyan), res ]
649
+ if SVN_DOTDIR.exist?
650
+ trace "Defining subversion VCS tasks"
651
+
652
+ desc "Check in all the changes in your current working copy"
653
+ task :ci => 'svn:ci'
654
+ desc "Check in all the changes in your current working copy"
655
+ task :checkin => 'svn:ci'
656
+
657
+ desc "Tag a release"
658
+ task :prep_release => 'svn:prep_release'
659
+
660
+ file COMMIT_MSG_FILE do
661
+ edit_commit_log()
599
662
  end
663
+ else
664
+ trace "Not defining subversion tasks: no #{SVN_DOTDIR}"
600
665
  end
601
- end
666
+
667
+ end # unless defined?( SVN_DOTDIR )
602
668