newgem 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 1.0.3 2008-10-31
2
+
3
+ * GitHub RubyGem support. `rake gemspec` generates a clean `my_project.gemspec` file that will work with GitHub
4
+ * update plain theme to a peppermint green colour; updated newgem's own website to same theme
5
+
1
6
  == 1.0.2 2008-10-30
2
7
 
3
8
  * Lighthouse Project created for tickets/suggestions: http://drnic.lighthouseapp.com/projects/18881-newgem
data/Manifest.txt CHANGED
@@ -40,6 +40,8 @@ features/newgem_cli.feature
40
40
  features/rubygem_tasks.feature
41
41
  features/steps/cli.rb
42
42
  features/steps/env.rb
43
+ features/steps/rubygems.rb
44
+ lib/hoe-patched.rb
43
45
  lib/newgem.rb
44
46
  lib/newgem/quick_template.rb
45
47
  lib/newgem/rubyforge.rb
@@ -64,6 +66,7 @@ newgem_theme_generators/plain_theme/plain_theme_generator.rb
64
66
  newgem_theme_generators/plain_theme/templates/website/javascripts/rounded_corners_lite.inc.js
65
67
  newgem_theme_generators/plain_theme/templates/website/stylesheets/screen.css
66
68
  newgem_theme_generators/plain_theme/templates/website/template.html.erb
69
+ patches/hoe/0001-readme-can-be-txt-or-rdoc.patch
67
70
  rubygems_generators/executable/USAGE
68
71
  rubygems_generators/executable/executable_generator.rb
69
72
  rubygems_generators/executable/templates/bin/app.rb.erb
@@ -6,8 +6,9 @@ Feature: RubyGems can have a website to promote and teach
6
6
 
7
7
  Scenario: Deploy project website via local rsync
8
8
  Given an existing newgem scaffold [called 'my_project']
9
- Given project website configuration for safe folder on local machine
10
- When task 'rake website' is invoked
9
+ And project website configuration for safe folder on local machine
10
+ When 'install_website' generator is invoked with arguments ''
11
+ And task 'rake website' is invoked
11
12
  Then file 'website/index.html' is created
12
13
  Then remote file 'index.html' is created after local rsync
13
14
  Then remote folder 'rdoc' is created after local rsync
@@ -16,4 +16,12 @@ Feature: Generated RubyGems have various rake tasks to aide their development
16
16
  Given an existing newgem scaffold [called 'my_project'] that has 'README.rdoc' not 'README.txt'
17
17
  When task 'rake -T' is invoked
18
18
  Then output does not match /README.txt is missing/
19
+
20
+ Scenario: Generate a gemspec that can build the RubyGem
21
+ Given an existing newgem scaffold [called 'my_project']
22
+ And 'pkg' folder is deleted
23
+ When task 'rake gemspec' is invoked
24
+ Then file 'my_project.gemspec' is created
25
+ And gemspec builds the RubyGem successfully
26
+ And output does match /Successfully built RubyGem/
19
27
 
@@ -0,0 +1,8 @@
1
+ Then /^gemspec builds the RubyGem successfully$/ do
2
+ @stdout = File.expand_path(File.join(@tmp_root, "rake.out"))
3
+ FileUtils.chdir(@active_project_folder) do
4
+ system "gem build #{@project_name}.gemspec > #{@stdout}"
5
+ gemspec = Dir['**/*.gem'].first
6
+ gemspec.should_not be_nil
7
+ end
8
+ end
@@ -0,0 +1,1029 @@
1
+ # Patched version of Hoe to allow any README.* file
2
+ # Pending acceptance of ticket with this feature
3
+ # File created by 'rake hoe:patch' in newgem
4
+ # from patch files in patches/hoe/*.patch
5
+
6
+ # -*- ruby -*-
7
+
8
+ require 'rubygems'
9
+ require 'rake'
10
+ require 'rake/gempackagetask'
11
+ require 'rake/rdoctask'
12
+ require 'rake/testtask'
13
+ require 'rbconfig'
14
+ require 'rubyforge'
15
+ require 'yaml'
16
+
17
+ begin
18
+ gem 'rdoc'
19
+ rescue Gem::LoadError
20
+ end
21
+
22
+ ##
23
+ # hoe - a tool to help rake
24
+ #
25
+ # Hoe is a simple rake/rubygems helper for project Rakefiles. It
26
+ # generates all the usual tasks for projects including rdoc generation,
27
+ # testing, packaging, and deployment.
28
+ #
29
+ # == Using Hoe
30
+ #
31
+ # === Basics
32
+ #
33
+ # Use this as a minimal starting point:
34
+ #
35
+ # require 'hoe'
36
+ #
37
+ # Hoe.new("project_name", '1.0.0') do |p|
38
+ # p.rubyforge_name = "rf_project"
39
+ # # add other details here
40
+ # end
41
+ #
42
+ # # add other tasks here
43
+ #
44
+ # === Tasks Provided:
45
+ #
46
+ # announce:: Create news email file and post to rubyforge.
47
+ # audit:: Run ZenTest against the package.
48
+ # check_manifest:: Verify the manifest.
49
+ # clean:: Clean up all the extras.
50
+ # config_hoe:: Create a fresh ~/.hoerc file.
51
+ # debug_gem:: Show information about the gem.
52
+ # default:: Run the default tasks.
53
+ # deps:email:: Print a contact list for gems dependent on this gem
54
+ # deps:fetch:: Fetch all the dependent gems of this gem into tarballs
55
+ # deps:list:: List all the dependent gems of this gem
56
+ # docs:: Build the docs HTML Files
57
+ # email:: Generate email announcement file.
58
+ # gem:: Build the gem file hoe-1.8.0.gem
59
+ # generate_key:: Generate a key for signing your gems.
60
+ # install_gem:: Install the package as a gem.
61
+ # multi:: Run the test suite using multiruby.
62
+ # package:: Build all the packages
63
+ # post_blog:: Post announcement to blog.
64
+ # post_news:: Post announcement to rubyforge.
65
+ # publish_docs:: Publish RDoc to RubyForge.
66
+ # release:: Package and upload the release to rubyforge.
67
+ # ridocs:: Generate ri locally for testing.
68
+ # tasks:: Generate a list of tasks for doco.
69
+ # test:: Run the test suite.
70
+ # test_deps:: Show which test files fail when run alone.
71
+ #
72
+ # === Extra Configuration Options:
73
+ #
74
+ # Run +config_hoe+ to generate a new ~/.hoerc file. The file is a
75
+ # YAML formatted config file with the following settings:
76
+ #
77
+ # exclude:: A regular expression of files to exclude from
78
+ # +check_manifest+.
79
+ # publish_on_announce:: Run +publish_docs+ when you run +release+.
80
+ # signing_key_file:: Signs your gems with this private key.
81
+ # signing_cert_file:: Signs your gem with this certificate.
82
+ # blogs:: An array of hashes of blog settings.
83
+ #
84
+ # Run +config_hoe+ and see ~/.hoerc for examples.
85
+ #
86
+ # === Signing Gems:
87
+ #
88
+ # Run the 'generate_key' task. This will:
89
+ #
90
+ # 1. Configure your ~/.hoerc.
91
+ # 2. Generate a signing key and certificate.
92
+ # 3. Install the private key and public certificate files into ~/.gem.
93
+ # 4. Upload the certificate to RubyForge.
94
+ #
95
+ # Hoe will now generate signed gems when the package task is run. If you have
96
+ # multiple machines you build gems on, be sure to install your key and
97
+ # certificate on each machine.
98
+ #
99
+ # Keep your private key secret! Keep your private key safe!
100
+ #
101
+ # To make sure your gems are signed run:
102
+ #
103
+ # rake package; tar tf pkg/yourproject-1.2.3.gem
104
+ #
105
+ # If your gem is signed you will see:
106
+ #
107
+ # data.tar.gz
108
+ # data.tar.gz.sig
109
+ # metadata.gz
110
+ # metadata.gz.sig
111
+ #
112
+ # === Platform awareness
113
+ #
114
+ # Hoe allows bundling of pre-compiled extensions in the +package+ task.
115
+ #
116
+ # To create a package for your current platform:
117
+ #
118
+ # rake package INLINE=1
119
+ #
120
+ # This will force Hoe analize your +Inline+ already compiled
121
+ # extensions and include them in your gem.
122
+ #
123
+ # If somehow you need to force a specific platform:
124
+ #
125
+ # rake package INLINE=1 FORCE_PLATFORM=mswin32
126
+ #
127
+ # This will set the +Gem::Specification+ platform to the one indicated in
128
+ # +FORCE_PLATFORM+ (instead of default Gem::Platform::CURRENT)
129
+ #
130
+
131
+ class Hoe
132
+ VERSION = '1.8.0'
133
+ GEMURL = URI.parse 'http://gems.rubyforge.org' # for namespace :deps below
134
+
135
+ ruby_prefix = Config::CONFIG['prefix']
136
+ sitelibdir = Config::CONFIG['sitelibdir']
137
+
138
+ ##
139
+ # Used to specify a custom install location (for rake install).
140
+
141
+ PREFIX = ENV['PREFIX'] || ruby_prefix
142
+
143
+ ##
144
+ # Used to add extra flags to RUBY_FLAGS.
145
+
146
+ RUBY_DEBUG = ENV['RUBY_DEBUG']
147
+
148
+ default_ruby_flags = "-w -I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}" +
149
+ (RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
150
+
151
+ ##
152
+ # Used to specify flags to ruby [has smart default].
153
+
154
+ RUBY_FLAGS = ENV['RUBY_FLAGS'] || default_ruby_flags
155
+
156
+ ##
157
+ # Used to add flags to test_unit (e.g., -n test_borked).
158
+
159
+ FILTER = ENV['FILTER'] # for tests (eg FILTER="-n test_blah")
160
+
161
+ # :stopdoc:
162
+
163
+ RUBYLIB = if PREFIX == ruby_prefix then
164
+ sitelibdir
165
+ else
166
+ File.join(PREFIX, sitelibdir[ruby_prefix.size..-1])
167
+ end
168
+
169
+ DLEXT = Config::CONFIG['DLEXT']
170
+
171
+ WINDOZE = /djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
172
+
173
+ DIFF = if WINDOZE
174
+ 'diff.exe'
175
+ else
176
+ if system("gdiff", __FILE__, __FILE__)
177
+ 'gdiff' # solaris and kin suck
178
+ else
179
+ 'diff'
180
+ end
181
+ end unless defined? DIFF
182
+
183
+ # :startdoc:
184
+
185
+ ##
186
+ # *Recommended*: The author(s) of the package. (can be array)
187
+ # Really. Set this or we'll tease you.
188
+
189
+ attr_accessor :author
190
+
191
+ ##
192
+ # Populated automatically from the manifest. List of executables.
193
+
194
+ attr_accessor :bin_files # :nodoc:
195
+
196
+ ##
197
+ # *Optional*: An array of the project's blog categories. Defaults to project name.
198
+
199
+ attr_accessor :blog_categories
200
+
201
+ ##
202
+ # Optional: A description of the release's latest changes. Auto-populates.
203
+
204
+ attr_accessor :changes
205
+
206
+ ##
207
+ # Optional: An array of file patterns to delete on clean.
208
+
209
+ attr_accessor :clean_globs
210
+
211
+ ##
212
+ # Optional: A description of the project. Auto-populates.
213
+
214
+ attr_accessor :description
215
+
216
+ ##
217
+ # Optional: What sections from the readme to use for auto-description. Defaults to %w(description).
218
+
219
+ attr_accessor :description_sections
220
+
221
+ ##
222
+ # *Recommended*: The author's email address(es). (can be array)
223
+
224
+ attr_accessor :email
225
+
226
+ ##
227
+ # Optional: An array of rubygem dependencies.
228
+
229
+ attr_accessor :extra_deps
230
+
231
+ ##
232
+ # Optional: An array of rubygem developer dependencies.
233
+
234
+ attr_accessor :extra_dev_deps
235
+
236
+ ##
237
+ # Populated automatically from the manifest. List of library files.
238
+
239
+ attr_accessor :lib_files # :nodoc:
240
+
241
+ ##
242
+ # Optional: Array of incompatible versions for multiruby filtering. Used as a regex.
243
+
244
+ attr_accessor :multiruby_skip
245
+
246
+ ##
247
+ # *MANDATORY*: The name of the release.
248
+
249
+ attr_accessor :name
250
+
251
+ ##
252
+ # Optional: Should package create a tarball? [default: true]
253
+
254
+ attr_accessor :need_tar
255
+
256
+ ##
257
+ # Optional: Should package create a zipfile? [default: false]
258
+
259
+ attr_accessor :need_zip
260
+
261
+ ##
262
+ # Optional: A post-install message to be displayed when gem is installed.
263
+
264
+ attr_accessor :post_install_message
265
+
266
+ ##
267
+ # Optional: A regexp to match documentation files against the manifest.
268
+
269
+ attr_accessor :rdoc_pattern
270
+
271
+ ##
272
+ # Optional: Name of RDoc destination directory on Rubyforge. [default: +name+]
273
+
274
+ attr_accessor :remote_rdoc_dir
275
+
276
+ ##
277
+ # Optional: Flags for RDoc rsync. [default: "-av --delete"]
278
+
279
+ attr_accessor :rsync_args
280
+
281
+ ##
282
+ # Optional: The name of the rubyforge project. [default: name.downcase]
283
+
284
+ attr_accessor :rubyforge_name
285
+
286
+ ##
287
+ # The Gem::Specification.
288
+
289
+ attr_accessor :spec # :nodoc:
290
+
291
+ ##
292
+ # Optional: A hash of extra values to set in the gemspec. Value may be a proc.
293
+
294
+ attr_accessor :spec_extras
295
+
296
+ ##
297
+ # Optional: A short summary of the project. Auto-populates.
298
+
299
+ attr_accessor :summary
300
+
301
+ ##
302
+ # Optional: Number of sentences from description for summary. Defaults to 1.
303
+
304
+ attr_accessor :summary_sentences
305
+
306
+ ##
307
+ # Populated automatically from the manifest. List of tests.
308
+
309
+ attr_accessor :test_files # :nodoc:
310
+
311
+ ##
312
+ # Optional: An array of test file patterns [default: test/**/test_*.rb]
313
+
314
+ attr_accessor :test_globs
315
+
316
+ ##
317
+ # Optional: What test library to require [default: test/unit]
318
+
319
+ attr_accessor :testlib
320
+
321
+ ##
322
+ # Optional: The url(s) of the project. (can be array). Auto-populates.
323
+
324
+ attr_accessor :url
325
+
326
+ ##
327
+ # *MANDATORY*: The version. Don't hardcode! use a constant in the project.
328
+
329
+ attr_accessor :version
330
+
331
+ ##
332
+ # Add extra dirs to both $: and RUBY_FLAGS (for test runs)
333
+
334
+ def self.add_include_dirs(*dirs)
335
+ dirs = dirs.flatten
336
+ $:.unshift(*dirs)
337
+ Hoe::RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(":")}:")
338
+ end
339
+
340
+ def normalize_deps deps
341
+ Array(deps).map { |o| String === o ? [o] : o }
342
+ end
343
+
344
+ def missing name
345
+ warn "** #{name} is missing or in the wrong format for auto-intuiting."
346
+ warn " run `sow blah` and look at its text files"
347
+ end
348
+
349
+ def readme_name
350
+ Dir['README*'].first || 'README.txt'
351
+ end
352
+
353
+ def initialize(name, version) # :nodoc:
354
+ self.name = name
355
+ self.version = version
356
+
357
+ # Defaults
358
+ self.author = []
359
+ self.clean_globs = %w(diff diff.txt email.txt ri deps .source_index
360
+ *.gem *~ **/*~ *.rbc **/*.rbc)
361
+ self.description_sections = %w(description)
362
+ self.blog_categories = [name]
363
+ self.email = []
364
+ self.extra_deps = []
365
+ self.extra_dev_deps = []
366
+ self.multiruby_skip = []
367
+ self.need_tar = true
368
+ self.need_zip = false
369
+ self.rdoc_pattern = /^(lib|bin|ext)|txt|rdoc$/
370
+ self.remote_rdoc_dir = name
371
+ self.rsync_args = '-av --delete'
372
+ self.rubyforge_name = name.downcase
373
+ self.spec_extras = {}
374
+ self.summary_sentences = 1
375
+ self.test_globs = ['test/**/test_*.rb']
376
+ self.testlib = 'test/unit'
377
+ self.post_install_message = nil
378
+
379
+ yield self if block_given?
380
+
381
+ # Intuit values:
382
+
383
+ readme = File.read(readme_name).split(/^(=+ .*)$/)[1..-1] rescue ''
384
+ unless readme.empty? then
385
+ sections = readme.map { |s|
386
+ s =~ /^=/ ? s.strip.downcase.chomp(':').split.last : s.strip
387
+ }
388
+ sections = Hash[*sections]
389
+ desc = sections.values_at(*description_sections).join("\n\n")
390
+ summ = desc.split(/\.\s+/).first(summary_sentences).join(". ")
391
+
392
+ self.description ||= desc
393
+ self.summary ||= summ
394
+ self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/)
395
+ else
396
+ missing readme_name
397
+ end
398
+
399
+ self.changes ||= begin
400
+ h = File.read("History.txt")
401
+ h.split(/^(===.*)/)[1..2].join.strip
402
+ rescue
403
+ missing 'History.txt'
404
+ ''
405
+ end
406
+
407
+ %w(email author).each do |field|
408
+ value = self.send(field)
409
+ if value.nil? or value.empty? then
410
+ if Time.now < Time.local(2008, 4, 1) then
411
+ warn "Hoe #{field} value not set - Fix by 2008-04-01!"
412
+ self.send "#{field}=", "doofus"
413
+ else
414
+ abort "Hoe #{field} value not set. aborting"
415
+ end
416
+ end
417
+ end
418
+
419
+ hoe_deps = {
420
+ 'rake' => ">= #{RAKEVERSION}",
421
+ 'rubyforge' => ">= #{::RubyForge::VERSION}",
422
+ }
423
+
424
+ self.extra_deps = normalize_deps extra_deps
425
+ self.extra_dev_deps = normalize_deps extra_dev_deps
426
+
427
+ if name == 'hoe' then
428
+ hoe_deps.each do |pkg, vers|
429
+ extra_deps << [pkg, vers]
430
+ end
431
+ else
432
+ extra_dev_deps << ['hoe', ">= #{VERSION}"] unless hoe_deps.has_key? name
433
+ end
434
+
435
+ define_tasks
436
+ end
437
+
438
+ def developer name, email
439
+ self.author << name
440
+ self.email << email
441
+ end
442
+
443
+ def with_config # :nodoc:
444
+ rc = File.expand_path("~/.hoerc")
445
+ exists = File.exist? rc
446
+ config = exists ? YAML.load_file(rc) : {}
447
+ yield(config, rc)
448
+ end
449
+
450
+ def define_tasks # :nodoc:
451
+ desc 'Run the default tasks.'
452
+ task :default => :test
453
+
454
+ desc 'Run the test suite. Use FILTER to add to the command line.'
455
+ task :test do
456
+ run_tests
457
+ end
458
+
459
+ desc 'Show which test files fail when run alone.'
460
+ task :test_deps do
461
+ tests = Dir["test/**/test_*.rb"] + Dir["test/**/*_test.rb"]
462
+
463
+ tests.each do |test|
464
+ if not system "ruby -Ibin:lib:test #{test} &> /dev/null" then
465
+ puts "Dependency Issues: #{test}"
466
+ end
467
+ end
468
+ end
469
+
470
+ desc 'Run the test suite using multiruby.'
471
+ task :multi do
472
+ run_tests :multi
473
+ end
474
+
475
+ ############################################################
476
+ # Packaging and Installing
477
+
478
+ signing_key = nil
479
+ cert_chain = []
480
+
481
+ with_config do |config, path|
482
+ break unless config['signing_key_file'] and config['signing_cert_file']
483
+ key_file = File.expand_path config['signing_key_file'].to_s
484
+ signing_key = key_file if File.exist? key_file
485
+
486
+ cert_file = File.expand_path config['signing_cert_file'].to_s
487
+ cert_chain << cert_file if File.exist? cert_file
488
+ end
489
+
490
+ self.spec = Gem::Specification.new do |s|
491
+ s.name = name
492
+ s.version = version
493
+ s.summary = summary
494
+ case author
495
+ when Array
496
+ s.authors = author
497
+ else
498
+ s.author = author
499
+ end
500
+ s.email = email
501
+ s.homepage = Array(url).first
502
+ s.rubyforge_project = rubyforge_name
503
+
504
+ s.description = description
505
+
506
+ extra_deps.each do |dep|
507
+ s.add_dependency(*dep)
508
+ end
509
+
510
+ extra_dev_deps.each do |dep|
511
+ s.add_development_dependency(*dep)
512
+ end
513
+
514
+ s.files = File.read("Manifest.txt").delete("\r").split(/\n/)
515
+ s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
516
+
517
+ s.bindir = "bin"
518
+ dirs = Dir['{lib,ext}']
519
+ s.require_paths = dirs unless dirs.empty?
520
+
521
+ s.rdoc_options = ['--main', readme_name]
522
+ s.extra_rdoc_files = s.files.grep(/(txt|rdoc)$/)
523
+ s.has_rdoc = true
524
+
525
+ s.post_install_message = post_install_message
526
+
527
+ if test ?f, "test/test_all.rb" then
528
+ s.test_file = "test/test_all.rb"
529
+ else
530
+ s.test_files = Dir[*test_globs]
531
+ end
532
+
533
+ if signing_key and cert_chain then
534
+ s.signing_key = signing_key
535
+ s.cert_chain = cert_chain
536
+ end
537
+
538
+ ############################################################
539
+ # Allow automatic inclusion of compiled extensions
540
+ if ENV['INLINE'] then
541
+ s.platform = ENV['FORCE_PLATFORM'] || Gem::Platform::CURRENT
542
+ # name of the extension is CamelCase
543
+ alternate_name = if name =~ /[A-Z]/ then
544
+ name.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
545
+ elsif name =~ /_/ then
546
+ name.capitalize.gsub(/_([a-z])/) { $1.upcase }
547
+ end
548
+
549
+ # Try collecting Inline extensions for +name+
550
+ if defined?(Inline) then
551
+ directory 'lib/inline'
552
+
553
+ extensions = Dir.chdir(Inline::directory) {
554
+ Dir["Inline_{#{name},#{alternate_name}}_*.#{DLEXT}"]
555
+ }
556
+ extensions.each do |ext|
557
+ # add the inlined extension to the spec files
558
+ s.files += ["lib/inline/#{ext}"]
559
+
560
+ # include the file in the tasks
561
+ file "lib/inline/#{ext}" => ["lib/inline"] do
562
+ cp File.join(Inline::directory, ext), "lib/inline"
563
+ end
564
+ end
565
+ end
566
+ end
567
+
568
+ # Do any extra stuff the user wants
569
+ spec_extras.each do |msg, val|
570
+ case val
571
+ when Proc
572
+ val.call(s.send(msg))
573
+ else
574
+ s.send "#{msg}=", val
575
+ end
576
+ end
577
+ end
578
+
579
+ desc 'Show information about the gem.'
580
+ task :debug_gem do
581
+ puts spec.to_ruby
582
+ end
583
+
584
+ self.lib_files = spec.files.grep(/^(lib|ext)/)
585
+ self.bin_files = spec.files.grep(/^bin/)
586
+ self.test_files = spec.files.grep(/^test/)
587
+
588
+ Rake::GemPackageTask.new spec do |pkg|
589
+ pkg.need_tar = @need_tar
590
+ pkg.need_zip = @need_zip
591
+ end
592
+
593
+ desc 'Install the package as a gem.'
594
+ task :install_gem => [:clean, :package] do
595
+ gem = Dir['pkg/*.gem'].first
596
+ sh "#{'sudo ' unless WINDOZE}gem install --local #{gem}"
597
+ end
598
+
599
+ desc 'Package and upload the release to rubyforge.'
600
+ task :release => [:clean, :package] do |t|
601
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
602
+ abort "Versions don't match #{v} vs #{version}" if v != version
603
+ pkg = "pkg/#{name}-#{version}"
604
+
605
+ if $DEBUG then
606
+ puts "release_id = rf.add_release #{rubyforge_name.inspect}, #{name.inspect}, #{version.inspect}, \"#{pkg}.tgz\""
607
+ puts "rf.add_file #{rubyforge_name.inspect}, #{name.inspect}, release_id, \"#{pkg}.gem\""
608
+ end
609
+
610
+ rf = RubyForge.new.configure
611
+ puts "Logging in"
612
+ rf.login
613
+
614
+ c = rf.userconfig
615
+ c["release_notes"] = description if description
616
+ c["release_changes"] = changes if changes
617
+ c["preformatted"] = true
618
+
619
+ files = [(@need_tar ? "#{pkg}.tgz" : nil),
620
+ (@need_zip ? "#{pkg}.zip" : nil),
621
+ "#{pkg}.gem"].compact
622
+
623
+ puts "Releasing #{name} v. #{version}"
624
+ rf.add_release rubyforge_name, name, version, *files
625
+ end
626
+
627
+ ############################################################
628
+ # Doco
629
+
630
+ Rake::RDocTask.new(:docs) do |rd|
631
+ rd.main = readme_name
632
+ rd.options << '-d' if RUBY_PLATFORM !~ /win32/ and `which dot` =~ /\/dot/ and not ENV['NODOT']
633
+ rd.rdoc_dir = 'doc'
634
+ files = spec.files.grep(rdoc_pattern)
635
+ files -= ['Manifest.txt']
636
+ rd.rdoc_files.push(*files)
637
+
638
+ title = "#{name}-#{version} Documentation"
639
+ title = "#{rubyforge_name}'s " + title if rubyforge_name != name
640
+
641
+ rd.options << "-t #{title}"
642
+ end
643
+
644
+ desc 'Generate ri locally for testing.'
645
+ task :ridocs => :clean do
646
+ sh %q{ rdoc --ri -o ri . }
647
+ end
648
+
649
+ desc 'Publish RDoc to RubyForge.'
650
+ task :publish_docs => [:clean, :docs] do
651
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
652
+ host = "#{config["username"]}@rubyforge.org"
653
+
654
+ remote_dir = "/var/www/gforge-projects/#{rubyforge_name}/#{remote_rdoc_dir}"
655
+ local_dir = 'doc'
656
+
657
+ sh %{rsync #{rsync_args} #{local_dir}/ #{host}:#{remote_dir}}
658
+ end
659
+
660
+ # no doco for this one
661
+ task :publish_on_announce do
662
+ with_config do |config, _|
663
+ Rake::Task['publish_docs'].invoke if config["publish_on_announce"]
664
+ end
665
+ end
666
+
667
+ ############################################################
668
+ # Dependencies:
669
+
670
+ namespace :deps do
671
+ require 'zlib' # HACK for rubygems 1.3.0
672
+ require 'rubygems/remote_fetcher'
673
+
674
+ @@index = nil
675
+
676
+ def self.get_source_index
677
+ return @@index if @@index
678
+
679
+ dump = unless File.exist? '.source_index' then
680
+ url = GEMURL + "Marshal.#{Gem.marshal_version}.Z"
681
+ dump = Gem::RemoteFetcher.fetcher.fetch_path url
682
+ dump = Gem.inflate dump
683
+ open '.source_index', 'wb' do |io| io.write dump end
684
+ dump
685
+ else
686
+ open '.source_index', 'rb' do |io| io.read end
687
+ end
688
+
689
+ @@index = Marshal.load dump
690
+ end
691
+
692
+ def self.get_latest_gems
693
+ @@cache ||= get_source_index.latest_specs
694
+ end
695
+
696
+ def self.get_gems_by_name
697
+ @@by_name ||= Hash[*get_latest_gems.map { |gem|
698
+ [gem.name, gem, gem.full_name, gem]
699
+ }.flatten]
700
+ end
701
+
702
+ def self.dependent_upon name
703
+ get_latest_gems.find_all { |gem|
704
+ gem.dependencies.any? { |dep| dep.name == name }
705
+ }
706
+ end
707
+
708
+
709
+ desc "List all the dependent gems of this gem"
710
+ task :list do
711
+ gems = self.get_gems_by_name
712
+ gem = gems[self.name]
713
+
714
+ abort "Couldn't find gem: #{self.name}" unless gem
715
+
716
+ deps = self.dependent_upon self.name
717
+ max = deps.map { |s| s.full_name.size }.max
718
+
719
+ puts " dependents:"
720
+ unless deps.empty? then
721
+ deps.sort_by { |spec| spec.full_name }.each do |spec|
722
+ vers = spec.dependencies.find {|s| s.name == name }.requirement_list
723
+ puts " %-*s - %s" % [max, spec.full_name, vers.join(", ")]
724
+ end
725
+ else
726
+ puts " none"
727
+ end
728
+ end
729
+
730
+ desc "Print a contact list for gems dependent on this gem"
731
+ task :email do
732
+ gems = self.get_gems_by_name
733
+ gem = gems[self.name]
734
+
735
+ abort "Couldn't find gem: #{self.name}" unless gem
736
+
737
+ deps = self.dependent_upon self.name
738
+
739
+ email = deps.map { |s| s.email }.flatten.sort.uniq
740
+ email = email.map { |s| s.split(/,\s*/) }.flatten.sort.uniq
741
+
742
+ email.map! { |s| # don't you people realize how easy this is?
743
+ s.gsub(/ at | _at_ |\s*(atmark|@nospam@|-at?-|@at?@|<at?>|\[at?\]|\(at?\))\s*/i, '@').gsub(/\s*(dot|\[d(ot)?\]|\.dot\.)\s*/i, '.').gsub(/\s+com$/, '.com')
744
+ }
745
+
746
+ bad, good = email.partition { |e| e !~ /^[\w.+-]+\@[\w.+-]+$/ }
747
+
748
+ warn "Rejecting #{bad.size} email. I couldn't unmunge them." unless
749
+ bad.empty?
750
+
751
+ puts good.join(", ")
752
+ end
753
+
754
+ desc "Fetch all the dependent gems of this gem into tarballs"
755
+ task :fetch do
756
+ gems = self.get_gems_by_name
757
+ gem = gems[self.name]
758
+ deps = self.dependent_upon self.name
759
+
760
+ mkdir "deps" unless File.directory? "deps"
761
+ Dir.chdir "deps" do
762
+ begin
763
+ deps.sort_by { |spec| spec.full_name }.each do |spec|
764
+ full_name = spec.full_name
765
+ tgz_name = "#{full_name}.tgz"
766
+ gem_name = "#{full_name}.gem"
767
+
768
+ next if File.exist? tgz_name
769
+ FileUtils.rm_rf [full_name, gem_name]
770
+
771
+ begin
772
+ warn "downloading #{full_name}"
773
+ Gem::RemoteFetcher.fetcher.download(spec, GEMURL, Dir.pwd)
774
+ FileUtils.mv "cache/#{gem_name}", '.'
775
+ rescue Gem::RemoteFetcher::FetchError
776
+ warn " failed"
777
+ next
778
+ end
779
+
780
+ warn "converting #{gem_name} to tarball"
781
+
782
+ system "gem unpack #{gem_name} 2> /dev/null"
783
+ system "gem spec -l #{gem_name} > #{full_name}/gemspec.rb"
784
+ system "tar zmcf #{tgz_name} #{full_name}"
785
+ FileUtils.rm_rf [full_name, gem_name, "cache"]
786
+ end
787
+ ensure
788
+ FileUtils.rm_rf "cache"
789
+ end
790
+ end
791
+ end
792
+ end
793
+
794
+ ############################################################
795
+ # Misc/Maintenance:
796
+
797
+ desc 'Run ZenTest against the package.'
798
+ task :audit do
799
+ libs = %w(lib test ext).join(File::PATH_SEPARATOR)
800
+ sh "zentest -I=#{libs} #{spec.files.grep(/^(lib|test)/).join(' ')}"
801
+ end
802
+
803
+ desc 'Clean up all the extras.'
804
+ task :clean => [ :clobber_docs, :clobber_package ] do
805
+ clean_globs.each do |pattern|
806
+ files = Dir[pattern]
807
+ rm_rf files, :verbose => true unless files.empty?
808
+ end
809
+ end
810
+
811
+ desc 'Create a fresh ~/.hoerc file.'
812
+ task :config_hoe do
813
+ with_config do |config, path|
814
+ default_config = {
815
+ "exclude" => /tmp$|CVS|\.svn/,
816
+ "publish_on_announce" => false,
817
+ "signing_key_file" => "~/.gem/gem-private_key.pem",
818
+ "signing_cert_file" => "~/.gem/gem-public_cert.pem",
819
+ "blogs" => [ {
820
+ "user" => "user",
821
+ "url" => "url",
822
+ "extra_headers" => {
823
+ "mt_convert_breaks" => "markdown"
824
+ },
825
+ "blog_id" => "blog_id",
826
+ "password"=>"password",
827
+ } ],
828
+ }
829
+ File.open(path, "w") do |f|
830
+ YAML.dump(default_config.merge(config), f)
831
+ end
832
+
833
+ editor = ENV['EDITOR'] || 'vi'
834
+ system "#{editor} #{path}" if ENV['SHOW_EDITOR'] != 'no'
835
+ end
836
+ end
837
+
838
+ desc 'Generate email announcement file.'
839
+ task :email do
840
+ require 'rubyforge'
841
+ subject, title, body, urls = announcement
842
+
843
+ File.open("email.txt", "w") do |mail|
844
+ mail.puts "Subject: [ANN] #{subject}"
845
+ mail.puts
846
+ mail.puts title
847
+ mail.puts
848
+ mail.puts urls
849
+ mail.puts
850
+ mail.puts body
851
+ mail.puts
852
+ mail.puts urls
853
+ end
854
+ puts "Created email.txt"
855
+ end
856
+
857
+ desc 'Post announcement to blog.'
858
+ task :post_blog do
859
+ require 'xmlrpc/client'
860
+
861
+ with_config do |config, path|
862
+ break unless config['blogs']
863
+
864
+ subject, title, body, urls = announcement
865
+ body += "\n\n#{urls}"
866
+
867
+ config['blogs'].each do |site|
868
+ server = XMLRPC::Client.new2(site['url'])
869
+ content = site['extra_headers'].merge(:title => title,
870
+ :description => body,
871
+ :categories => blog_categories)
872
+
873
+ result = server.call('metaWeblog.newPost',
874
+ site['blog_id'],
875
+ site['user'],
876
+ site['password'],
877
+ content,
878
+ true)
879
+ end
880
+ end
881
+ end
882
+
883
+ desc 'Post announcement to rubyforge.'
884
+ task :post_news do
885
+ require 'rubyforge'
886
+ subject, title, body, urls = announcement
887
+
888
+ rf = RubyForge.new.configure
889
+ rf.login
890
+ rf.post_news(rubyforge_name, subject, "#{title}\n\n#{body}")
891
+ puts "Posted to rubyforge"
892
+ end
893
+
894
+ desc 'Create news email file and post to rubyforge.'
895
+ task :announce => [:email, :post_news, :post_blog, :publish_on_announce ]
896
+
897
+ desc 'Verify the manifest.'
898
+ task :check_manifest => :clean do
899
+ f = "Manifest.tmp"
900
+ require 'find'
901
+ files = []
902
+ with_config do |config, _|
903
+ exclusions = config["exclude"]
904
+ abort "exclude entry missing from .hoerc. Aborting." if exclusions.nil?
905
+ Find.find '.' do |path|
906
+ next unless File.file? path
907
+ next if path =~ exclusions
908
+ files << path[2..-1]
909
+ end
910
+ files = files.sort.join "\n"
911
+ File.open f, 'w' do |fp| fp.puts files end
912
+ system "#{DIFF} -du Manifest.txt #{f}"
913
+ rm f
914
+ end
915
+ end
916
+
917
+ desc 'Generate a key for signing your gems.'
918
+ task :generate_key do
919
+ email = spec.email
920
+ abort "No email in your gemspec" if email.nil? or email.empty?
921
+
922
+ key_file = with_config { |config, _| config['signing_key_file'] }
923
+ cert_file = with_config { |config, _| config['signing_cert_file'] }
924
+
925
+ if key_file.nil? or cert_file.nil? then
926
+ ENV['SHOW_EDITOR'] ||= 'no'
927
+ Rake::Task['config_hoe'].invoke
928
+
929
+ key_file = with_config { |config, _| config['signing_key_file'] }
930
+ cert_file = with_config { |config, _| config['signing_cert_file'] }
931
+ end
932
+
933
+ key_file = File.expand_path key_file
934
+ cert_file = File.expand_path cert_file
935
+
936
+ unless File.exist? key_file or File.exist? cert_file then
937
+ sh "gem cert --build #{email}"
938
+ mv "gem-private_key.pem", key_file, :verbose => true
939
+ mv "gem-public_cert.pem", cert_file, :verbose => true
940
+
941
+ puts "Installed key and certificate."
942
+
943
+ rf = RubyForge.new.configure
944
+ rf.login
945
+
946
+ cert_package = "#{rubyforge_name}-certificates"
947
+
948
+ begin
949
+ rf.lookup 'package', cert_package
950
+ rescue
951
+ rf.create_package rubyforge_name, cert_package
952
+ end
953
+
954
+ begin
955
+ rf.lookup('release', cert_package)['certificates']
956
+ rf.add_file rubyforge_name, cert_package, 'certificates', cert_file
957
+ rescue
958
+ rf.add_release rubyforge_name, cert_package, 'certificates', cert_file
959
+ end
960
+
961
+ puts "Uploaded certificate to release \"certificates\" in package #{cert_package}"
962
+ else
963
+ puts "Keys already exist."
964
+ end
965
+ end
966
+
967
+ end # end define
968
+
969
+ def announcement # :nodoc:
970
+ changes = self.changes.rdoc_to_markdown
971
+ subject = "#{name} #{version} Released"
972
+ title = "#{name} version #{version} has been released!"
973
+ body = "#{description}\n\nChanges:\n\n#{changes}".rdoc_to_markdown
974
+ urls = Array(url).map { |s| "* <#{s.strip.rdoc_to_markdown}>" }.join("\n")
975
+
976
+ return subject, title, body, urls
977
+ end
978
+
979
+ def run_tests(multi=false) # :nodoc:
980
+ msg = multi ? :sh : :ruby
981
+ cmd = if test ?f, 'test/test_all.rb' then
982
+ "#{RUBY_FLAGS} test/test_all.rb #{FILTER}"
983
+ else
984
+ tests = ["rubygems", self.testlib] +
985
+ test_globs.map { |g| Dir.glob(g) }.flatten
986
+ tests.map! {|f| %Q(require "#{f}")}
987
+ "#{RUBY_FLAGS} -e '#{tests.join("; ")}' #{FILTER}"
988
+ end
989
+
990
+ excludes = multiruby_skip.join(":")
991
+ ENV['EXCLUDED_VERSIONS'] = excludes
992
+ cmd = "multiruby #{cmd}" if multi
993
+
994
+ send msg, cmd
995
+ end
996
+
997
+ ##
998
+ # Reads a file at +path+ and spits out an array of the +paragraphs+ specified.
999
+ #
1000
+ # changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
1001
+ # summary, *description = p.paragraphs_of('README.txt', 3, 3..8)
1002
+
1003
+ def paragraphs_of(path, *paragraphs)
1004
+ File.read(path).delete("\r").split(/\n\n+/).values_at(*paragraphs)
1005
+ end
1006
+ end
1007
+
1008
+ # :enddoc:
1009
+
1010
+ class ::Rake::SshDirPublisher # :nodoc:
1011
+ attr_reader :host, :remote_dir, :local_dir
1012
+ end
1013
+
1014
+ class String
1015
+ def rdoc_to_markdown
1016
+ self.gsub(/^mailto:/, '').gsub(/^(=+)/) { "#" * $1.size }
1017
+ end
1018
+ end
1019
+
1020
+ if $0 == __FILE__ then
1021
+ out = `rake -T | egrep -v "redocs|repackage|clobber|trunk"`
1022
+ if ARGV.empty? then
1023
+ # # default:: Run the default tasks.
1024
+ puts out.gsub(/(\s*)\#/, '::\1').gsub(/^rake /, '# ')
1025
+ else
1026
+ # * default - Run the default tasks.
1027
+ puts out.gsub(/\#/, '-').gsub(/^rake /, '* ')
1028
+ end
1029
+ end