reap 9.3.5 → 9.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGES +10 -0
  2. data/MANIFEST +37 -21
  3. data/NOTES +13 -11
  4. data/bin/reap-announce +40 -2
  5. data/bin/reap-check-load +20 -2
  6. data/bin/reap-check-syntax +20 -2
  7. data/bin/reap-clean +24 -2
  8. data/bin/reap-clobber +17 -2
  9. data/bin/reap-doc +12 -2
  10. data/bin/reap-doc-rdoc +17 -2
  11. data/bin/reap-doc-ri +16 -2
  12. data/bin/reap-doc-spec +18 -0
  13. data/bin/reap-init +9 -0
  14. data/bin/reap-inspect +20 -2
  15. data/bin/reap-install +13 -2
  16. data/bin/reap-install-gem +14 -2
  17. data/bin/reap-log +15 -2
  18. data/bin/reap-log-changes +15 -2
  19. data/bin/reap-log-notes +20 -2
  20. data/bin/reap-make +16 -2
  21. data/bin/reap-make-clean +10 -2
  22. data/bin/reap-make-distclean +18 -2
  23. data/bin/reap-make-extconf +14 -2
  24. data/bin/reap-make-static +14 -2
  25. data/bin/reap-package +25 -2
  26. data/bin/reap-package-gem +14 -2
  27. data/bin/reap-package-tgz +14 -2
  28. data/bin/reap-package-zip +14 -2
  29. data/bin/reap-prepare +21 -2
  30. data/bin/reap-publish +25 -2
  31. data/bin/reap-release +22 -2
  32. data/bin/reap-rollout +32 -2
  33. data/bin/reap-scaffold +16 -2
  34. data/bin/reap-scm-branch +13 -2
  35. data/bin/reap-scm-tag +13 -2
  36. data/bin/reap-spec +14 -2
  37. data/bin/reap-stats +21 -2
  38. data/bin/reap-test +14 -2
  39. data/bin/reap-test-cross +23 -2
  40. data/bin/reap-test-load +17 -2
  41. data/bin/reap-test-solo +19 -2
  42. data/bin/reap-uninstall +14 -2
  43. data/bin/reap-uninstall-gem +17 -2
  44. data/bin/reap-version +10 -2
  45. data/lib/reap/announcement.rb +136 -0
  46. data/lib/reap/application.rb +3 -1
  47. data/lib/reap/default.yaml +12 -12
  48. data/lib/reap/defaults.rb +49 -0
  49. data/lib/reap/emailer.rb +189 -0
  50. data/lib/reap/extensions.rb +1 -2
  51. data/lib/reap/hosts.rb +4 -0
  52. data/lib/reap/hosts/host.rb +69 -0
  53. data/lib/reap/hosts/mailinglist.rb +83 -0
  54. data/lib/reap/{systems → hosts}/rubyforge.rb +72 -60
  55. data/lib/reap/hosts/rubytalk.rb +39 -0
  56. data/lib/reap/iobject.rb +5 -3
  57. data/lib/reap/metadata.rb +31 -4
  58. data/lib/reap/project.rb +101 -41
  59. data/lib/reap/project/announce.rb +50 -180
  60. data/lib/reap/project/check.rb +1 -1
  61. data/lib/reap/project/gem.rb +32 -68
  62. data/lib/reap/project/log.rb +12 -7
  63. data/lib/reap/project/make.rb +0 -1
  64. data/lib/reap/project/package.rb +228 -75
  65. data/lib/reap/project/rdoc.rb +9 -8
  66. data/lib/reap/project/release.rb +52 -6
  67. data/lib/reap/project/scm.rb +40 -25
  68. data/lib/reap/project/spec.rb +3 -3
  69. data/lib/reap/project/test.rb +1 -2
  70. data/lib/reap/project/version.rb +18 -4
  71. data/lib/reap/runmodes.rb +24 -0
  72. data/lib/reap/settings.rb +3 -14
  73. data/lib/reap/systems.rb +4 -0
  74. data/lib/reap/systems/git.rb +0 -0
  75. data/lib/reap/systems/hg.rb +0 -0
  76. data/lib/reap/systems/{subversion.rb → svn.rb} +47 -16
  77. data/lib/reap/systems/system.rb +53 -0
  78. data/lib/reap/tool.rb +38 -0
  79. data/lib/reap/utilities.rb +43 -86
  80. data/log/{Changelog.txt → changelog.rdoc} +56 -0
  81. data/log/fixme.rdoc +25 -0
  82. data/log/todo.rdoc +85 -0
  83. data/meta/project.yaml +13 -2
  84. data/meta/version +1 -0
  85. data/setup.rb +74 -64
  86. data/task/allshare.rb +109 -0
  87. data/task/clean +13 -0
  88. data/task/compile +28 -0
  89. data/task/configure +372 -0
  90. data/task/install +1481 -0
  91. data/test/case/test_init.rb +32 -0
  92. data/test/case/test_scaffold.rb +32 -0
  93. data/test/data/scaffold/meta/project.yaml +28 -0
  94. data/test/lib/case_testable.rb +23 -0
  95. metadata +64 -31
  96. data/bin/reap-spec-doc +0 -8
  97. data/demo/README +0 -15
  98. data/demo/lib/foo/foo.rb +0 -7
  99. data/demo/meta/VERSION +0 -1
  100. data/demo/meta/project.yaml +0 -21
  101. data/lib/reap/project/rubyforge.rb +0 -71
  102. data/lib/reap/project/svn.rb +0 -76
  103. data/log/Fixme.txt +0 -22
  104. data/log/Todo.txt +0 -84
  105. data/meta/VERSION +0 -1
@@ -0,0 +1,39 @@
1
+ require 'reap/hosts/mailinglist'
2
+ require 'reap/emailer'
3
+
4
+ module Reap
5
+ module Hosts
6
+
7
+ # = Rubytalk
8
+ #
9
+ # This is a Maklinglist host. It simply statically sets
10
+ # the ruby-talk@ruby-lang.org email address and passes
11
+ # on to it's superclass.
12
+
13
+ class RubyTalk < Mailinglist
14
+
15
+ register('ruby-talk', 'ruby-talk@ruby-lang.org')
16
+
17
+ EMAIL_ADDRESS = 'ruby-talk@ruby-lang.org'
18
+
19
+ # This sets the mailto address and passes on to the
20
+ # super class.
21
+ #
22
+ # See Mailinglist#announce.
23
+
24
+ def announce(options)
25
+ options = options.rekey(&:to_s)
26
+ options['mailto'] = EMAIL_ADDRESS
27
+ super(options)
28
+ end
29
+
30
+ def announce_confirm?(options={})
31
+ options = options.rekey(&:to_s)
32
+ options['mailto'] = EMAIL_ADDRESS
33
+ super(options)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+
@@ -22,12 +22,14 @@
22
22
  # along with Ratch. If not, see <http://www.gnu.org/licenses/>.
23
23
 
24
24
  require 'yaml'
25
- require 'facets/hash/rekey'
26
-
25
+ require 'facets' #/hash/rekey
27
26
 
28
27
  module Reap
29
28
 
29
+ # = InfoObject
30
30
  #
31
+ # This a base class used by Metadata. It provides a more versitle
32
+ # means of defining a data-oriented class.
31
33
 
32
34
  class InfoObject
33
35
 
@@ -107,7 +109,7 @@ module Reap
107
109
  instance_data.update(data.rekey(:to_s))
108
110
 
109
111
  data.each do |k,v|
110
- send("#{k}=", v) rescue nil
112
+ send("#{k}=", v) if respond_to?("#{k}=")
111
113
  end
112
114
 
113
115
  # TODO Could add yield(self) via:
@@ -22,6 +22,7 @@
22
22
  # along with Ratch. If not, see <http://www.gnu.org/licenses/>.
23
23
 
24
24
  require 'facets/dir/multiglob'
25
+ require 'facets/platform'
25
26
  require 'reap/iobject'
26
27
 
27
28
  module Reap
@@ -90,6 +91,9 @@ class Project
90
91
 
91
92
  def initialize(location, data={})
92
93
  @location = location
94
+
95
+ @autodoc = true
96
+
93
97
  super(data)
94
98
  end
95
99
 
@@ -128,7 +132,7 @@ class Project
128
132
  attr_accessor :description, :synopsis
129
133
 
130
134
  # "Unix" name of this project.
131
- attr_accessor :project, :name
135
+ attr_accessor :project, :name, :unixname
132
136
 
133
137
  # Overrides Project#name.
134
138
  # TODO: Fit release name into name or package_name (?)
@@ -211,6 +215,12 @@ class Project
211
215
  end
212
216
 
213
217
 
218
+ # URI of host providers.
219
+ attr_accessor :hosts do
220
+ @hosts || {'rubyforge'=>{}, 'rubytalk'=>{} }
221
+ end
222
+
223
+
214
224
  # Version
215
225
  #------------------------------------------------------------------------
216
226
 
@@ -437,6 +447,15 @@ class Project
437
447
 
438
448
  attr_accessor :platform
439
449
 
450
+ def platform=(pl)
451
+ case pl.to_s.downcase
452
+ when 'current'
453
+ @platform = Platform.local.to_s
454
+ else
455
+ @platform = pl
456
+ end
457
+ end
458
+
440
459
  # Architecture(s) this package can be run on: any, i386, i686, ppc, etc.
441
460
  # This is strictly informational and is inteded to indicate the possiblities,
442
461
  # not the particular platform this package runs on.
@@ -451,7 +470,13 @@ class Project
451
470
  # Packages that are intended to compile on install may need this. It is a list
452
471
  # of "extension scripts" which generate Makefiles for use in compilation.
453
472
  attr_accessor :extensions do
454
- [@extensions || Dir.glob(File.join(location, 'ext/**/extconf.rb'))].flatten.compact
473
+ @extensions ||= (
474
+ exts = []
475
+ Dir.chdir(location) do
476
+ exts = Dir.glob('ext/**/extconf.rb')
477
+ end
478
+ exts.flatten.compact
479
+ )
455
480
  end
456
481
 
457
482
  #
@@ -460,9 +485,11 @@ class Project
460
485
  #end
461
486
 
462
487
  # Generate documentation on installation?
463
- attr_accessor :document, :has_rdoc
488
+ attr_accessor :autodoc, :has_rdoc
489
+
490
+ # Files to be documented.
491
+ attr_accessor :document
464
492
 
465
- #
466
493
  #attr_accessor :package_directory, :package_store do
467
494
  # @package_directory || 'pkg'
468
495
  #end
@@ -2,6 +2,7 @@ module Reap
2
2
  require 'yaml'
3
3
  require 'rbconfig'
4
4
  require 'reap/utilities'
5
+ require 'reap/hosts'
5
6
 
6
7
  # = Project
7
8
  #
@@ -12,6 +13,8 @@ module Reap
12
13
  class Project
13
14
  require 'reap/metadata'
14
15
  require 'reap/settings'
16
+ require 'reap/defaults'
17
+ require 'reap/runmodes'
15
18
 
16
19
  # Load up the tools
17
20
  require "reap/project/announce.rb"
@@ -30,7 +33,6 @@ module Reap
30
33
  require "reap/project/spec.rb"
31
34
  require "reap/project/stats.rb"
32
35
  require "reap/project/scm.rb"
33
- require "reap/project/svn.rb"
34
36
  require "reap/project/test.rb"
35
37
  require "reap/project/version.rb"
36
38
 
@@ -40,15 +42,15 @@ module Reap
40
42
 
41
43
  def initialize(options=nil)
42
44
  @options = options || {}
43
- begin
44
- @location = locate
45
- raise LoadError, "no .reap configuration file" unless @location
46
45
 
47
- @metadata = Metadata.read(location)
48
- @settings = Settings.read(location, @metadata)
49
- rescue LoadError => e
50
- abort e.message.capitalize + '.'
51
- end
46
+ @location = locate
47
+
48
+ raise LoadError, "no .reap configuration file" unless @location
49
+
50
+ @metadata = Metadata.read(location)
51
+ @settings = Settings.read(location, @metadata)
52
+ @defaults = Defaults.new(@metadata)
53
+ @runmodes = RunModes.new(options)
52
54
  end
53
55
 
54
56
  # Location of project.
@@ -59,30 +61,35 @@ module Reap
59
61
 
60
62
  def metadata ; @metadata ; end
61
63
 
62
- # Configuration data.
64
+ # Task defaults.
65
+
66
+ def defaults ; @defaults ; end
67
+
68
+ # Task user settings.
63
69
 
64
70
  def settings ; @settings ; end
65
71
 
66
- alias_method :configuration, :settings
72
+ # Run modes.
67
73
 
68
- #alias_method :config, :configuration
74
+ def runmodes ; @runmodes ; end
69
75
 
70
76
  # Common options.
71
77
 
72
78
  def options ; @options ; end
79
+
73
80
  #alias_method :init_options, :options # TODO: Improve me! (see stamp.rb)
74
81
 
75
- def dryrun? ; options['dryrun'] ; end
76
- def trace? ; options['trace'] ; end
77
- def force? ; options['force'] ; end
78
- def verbose? ; options['verbose'] ; end
79
- def debug? ; options['debug'] ; end
82
+ def dryrun? ; runmodes.dryrun? ; end
83
+ def trace? ; runmodes.trace? ; end
84
+ def force? ; runmodes.force? ; end
85
+ def verbose? ; runmodes.verbose? ; end
86
+ def debug? ; runmodes.debug? ; end
80
87
 
81
- def dryrun=(x) ; options['dryrun'] = x ; end
82
- def trace=(x) ; options['trace'] = x ; end
83
- def force=(x) ; options['force'] = x ; end
84
- def verbose=(x) ; options['verbose'] = x ; end
85
- def debug=(x) ; options['debug'] = x ; end
88
+ def dryrun=(x) ; runmodes.dryrun = x ; end
89
+ def trace=(x) ; runmodes.trace = x ; end
90
+ def force=(x) ; runmodes.force = x ; end
91
+ def verbose=(x) ; runmodes.verbose = x ; end
92
+ def debug=(x) ; runmodes.debug = x ; end
86
93
 
87
94
  alias_method :noharm?, :dryrun?
88
95
  alias_method :noharm=, :dryrun=
@@ -90,14 +97,22 @@ module Reap
90
97
  # Invoke a tool.
91
98
 
92
99
  def invoke(command, *args)
93
- #display_location
94
- meth = method(command)
95
- chdir_to_project do
96
- case meth.arity
97
- when 0
98
- meth.call
100
+ begin
101
+ #display_location
102
+ meth = method(command)
103
+ chdir_to_project do
104
+ case meth.arity
105
+ when 0
106
+ meth.call
107
+ else
108
+ meth.call(*args)
109
+ end
110
+ end
111
+ rescue LoadError => e
112
+ if trace?
113
+ raise e
99
114
  else
100
- meth.call(*args)
115
+ abort e.message.capitalize + '.'
101
116
  end
102
117
  end
103
118
  end
@@ -137,10 +152,27 @@ module Reap
137
152
  args = options['arguments']
138
153
  if args
139
154
  args.each do |field|
140
- puts metadata.send(field)
155
+ case field
156
+ when 'defaults'
157
+ y defaults
158
+ when 'settings'
159
+ y settings
160
+ when 'metadata'
161
+ y metadata
162
+ else
163
+ puts metadata.send(field)
164
+ end
141
165
  end
142
166
  else
143
- y self
167
+ puts
168
+ puts "#{metadata.title} #{metadata.version}"
169
+ puts metadata.brief
170
+ puts metadata.homepage
171
+ puts
172
+ puts metadata.description
173
+ puts
174
+ puts metadata.copyright
175
+ puts
144
176
  end
145
177
  end
146
178
 
@@ -172,23 +204,51 @@ module Reap
172
204
  return loc
173
205
  end
174
206
 
175
- #
207
+ # Tasks use this to automatically combine commandline options,
208
+ # user settings, defualts.
176
209
 
177
210
  def configure_options(options, *entries)
211
+ config = {}
212
+
213
+ entries.each do |entry|
214
+ config.update(defaults[entry] || {})
215
+ end
216
+
217
+ entries.each do |entry|
218
+ config.update(settings[entry] || {})
219
+ end
220
+
178
221
  options = (options || {}).rekey(&:to_s)
179
- entries.inject(options) do |memo, entry|
180
- (settings[entry] || {}).merge(memo)
222
+ config.update(options)
223
+
224
+ return config
225
+ end
226
+
227
+ # Access to selected hosts.
228
+
229
+ def hosts(select=nil)
230
+ @hosts ||= {}
231
+ select ||= metadata.hosts.keys
232
+ result = []
233
+ metadata.hosts.each do |key, options|
234
+ next unless select.include?(key)
235
+ host_class = options['type'] ? Hosts.registry[options['type']] : Hosts.registry[key]
236
+ next unless host_class
237
+ # cache hosts
238
+ @hosts[key] ||= host_class.from_project(self, options)
239
+ result |= [@hosts[key]]
181
240
  end
241
+ return result
182
242
  end
183
243
 
184
- # Helper method for cleaning list options.
185
- # This will split the option on ':' or ';'
186
- # if it is a string, rather than an array.
187
- # And it will make sure there are no nil elements.
244
+ # Access to project's scource control management system.
188
245
 
189
- def list_option(option)
190
- option = option.to_s.split(/[:;,]/) unless Array===option
191
- [option].compact.flatten
246
+ def scm
247
+ @scm ||= (
248
+ if system = Systems.current
249
+ system.from_project(self, {}) #TODO: metadata.scm is a hash?
250
+ end
251
+ )
192
252
  end
193
253
 
194
254
  end
@@ -1,205 +1,75 @@
1
+ require 'reap/announcement'
2
+
1
3
  module Reap
2
4
 
3
5
  class Project
4
-
5
- # Make a release announcement. Generates and can email release
6
- # announcements. The announcement if built from the README file
7
- # unless another file is specified.
8
- #
9
- # This will subsititue the first line mathing /please see notes/i
6
+
7
+ # Generate and email a release announcement. The announcement
8
+ # text is read from ANNOUNCE{.txt} or another template file
9
+ # is specified, or if no template is given, the announcemnet
10
+ # is automatically built from project metadata, ant the
11
+ # CHANGES and NOTES files.
12
+ #
13
+ # Templates support metadata substitutions using $name$ syntax.
14
+ # Also, it will subsititue the first line matching /please see notes/i
10
15
  # for the notelog. And /please see change/i for the changelog.
11
- #
16
+ #
12
17
  # The following settings apply:
13
- #
14
- # title Project title.
15
- # subtitle Brief one-line description.
16
- # version Project version.
17
- # description Long description of project.
18
- # homepage Project homepage web address.
19
- # slogan Motto for you project.
20
- # memo File that contains announcement message.
21
- # template Announcement template file, rather then README.
22
- # mail_to Email address(es) to send announcemnt.
23
- #
24
- # If <em>mail_to</em> is set then these also apply:
25
- #
26
- # from Message FROM address [email].
27
- # subject Subject of email message ([ANN] title verison).
28
- # server Email server to route message.
29
- # port Email server's port.
30
- # domain Email server's domain name.
31
- # account Email account name [email].
32
- # login Login type: plain, cram_md5 or login.
33
- # secure Uses TLS security, true or false?
34
- #
35
- # A template file can be specified that uses "$setting" as
36
- # substitutes for poject information.
18
+ #
19
+ # template Announcement template file (ANNOUNCE.txt).
20
+ # to Email address(es) to send announcemnt.
21
+ #
22
+ # If <em>mailto</em> is set then these also apply:
23
+ #
24
+ # from Message FROM address [email].
25
+ # subject Subject of email message ([ANN] title verison).
26
+ # server Email server to route message.
27
+ # port Email server's port.
28
+ # domain Email server's domain name.
29
+ # account Email account name [email].
30
+ # login Login type: plain, cram_md5 or login.
31
+ # secure Uses TLS security, true or false?
32
+ #
33
+ # The announcement will be printed to standard out before sending
34
+ # so it can be verified.
37
35
 
38
36
  def announce(options=nil)
39
- options = configure_options(options, 'announce', 'mail')
40
-
41
- message = announce_message(options)
42
-
43
- options = options.to_ostruct
44
-
45
- mail_to = options.mail_to
46
- mail_from = options.mail_from
47
- subject = options.subject # Subject line (default is "ANN: project version").
48
- server = options.server # Email server
49
- port = options.port # Emails server port (default is usually correct).
50
- account = options.account # Email account name (defaults to mail_from).
51
- domain = options.domain # User domain (not sure why SMTP requires this?)
52
- login = options.login # Login type (plain, login)
53
- secure = options.secure # Use TLS/SSL true or false?
54
- password = options.password || ENV['EMAIL_PASSWORD']
55
-
56
- title = options.title || metadata.title
57
- version = options.versoin || metadata.version
58
-
59
- # defaults
60
- subject ||= "%s, v%s release"
61
- account ||= mail_from
62
-
63
- subject = subject % [title, version]
37
+ options = configure_options(options, 'announce')
64
38
 
65
- if dryrun?
66
- puts "email '#{subject}'"
67
- puts "\n#{message}\n\n" if verbose?
68
- else
69
- puts "\n#{message}\n\n"
70
- if mail_to
71
- ans = ask("Would you like to email this announcement?", "yN")
72
- case ans.downcase
73
- when 'y', 'yes'
74
- email(message,
75
- :to => mail_to,
76
- :from => mail_from,
77
- :subject => subject,
78
- :server => server,
79
- :port => port,
80
- :domain => domain,
81
- :account => account,
82
- :login => login,
83
- :secure => secure,
84
- :password => password
85
- )
86
- end
87
- end
39
+ announcement = Announcement.new do |ann|
40
+ ann.cutoff = options['cutoff']
41
+ ann.template = options['template']
42
+ ann.metadata = metadata
88
43
  end
89
- end
90
-
91
- # Make a release announcement. Generates and can email a release
92
- # announcements. These are nicely formated message and can
93
- # email the message to the specified address(es).
94
- #
95
- # The following settings apply:
96
- #
97
- # template Announcement file/template.
98
- # cutoff Max number of lines of changelog to show.
99
- #
100
- # A template file can be specified that uses "$setting" as
101
- # substitutes for poject information.
102
-
103
- def announce_message(options={})
104
- config = settings['announce'] || {}
105
- options = config.merge(options).to_ostruct
106
44
 
107
- cutoff = options.cutoff || 30
108
- template = options.template || "{ANNOUNCE}{,.txt}"
109
-
110
- #config['mail_to'] = nil if keys['mail_to'].empty?
111
-
112
- # Build message
113
-
114
- # template
115
- template = Dir.glob(options.template.to_s, File::FNM_CASEFOLD).first
116
-
117
- if template
118
- readme = File.read(template)
119
- readme = unfold_paragraphs(readme)
45
+ if dryrun?
46
+ puts "\n#{announcement.message}\n\n" if verbose?
120
47
  else
121
- readme = ''
122
- readme << "= #{metadata.title} v#{metadata.version}\n\n"
123
- readme << " #{metadata.homepage}\n\n"
124
- readme << "#{metadata.description}\n\n"
125
- readme << "Please see the NOTES file.\n\n"
126
- readme << "== CHANGES\n\n"
127
- readme << "Please see the CHANGES file.\n"
48
+ puts "\n#{announcement.message}\n\n"
128
49
  end
129
50
 
130
- # changelog
131
- file = Dir.glob('change{s,log}{,.txt}', File::FNM_CASEFOLD)[0]
132
- changelog = file ? File.read(file).strip : ''
133
- #changelog = unfold_paragraphs(changelog)
134
- changelog = changelog.split("\n")[0..cutoff].join("\n")
135
-
136
- # noteslog
137
- file = Dir.glob('note{s,log}{,.txt}', File::FNM_CASEFOLD)[0]
138
- notelog = file ? File.read(file).strip : ''
139
- notelog = unfold_paragraphs(notelog)
140
-
141
- # Strip tiny version zero.
142
- #if keys['version'] =~ /[.].*?[.]/
143
- # keys['version'] = keys['version'].chomp('.0')
144
- #end
145
-
146
- # Make announcement message
147
- message = readme.dup
51
+ options['message'] = announcement.message
52
+ options['version'] = metadata.version
148
53
 
149
- #message.gsub!('$readme$', readme || '')
150
- message.sub!(/^\s*please\ see(\ the)?\ notes(.*?)$/i, "\n" + notelog) if notelog
151
- message.sub!(/^\s*please\ see(\ the)?\ change(.*?)$/i, "\n" + changelog) if changelog
54
+ options['title'] ||= metadata.title
55
+ options['subject'] ||= "%s, v%s release"
56
+ options['subject'] = options['subject'] % [ options['title'], metadata.version ]
152
57
 
153
- template = message.dup
58
+ actions = []
59
+ select = options['hosts']
154
60
 
155
- template.scan(/\$(\w+?)\$/m) do |key|
156
- #key = key.strip
157
- name = $1.strip #key[1..-1]
158
- if metadata.respond_to?(name.downcase)
159
- value = metadata.send(name.downcase)
160
- message.gsub!("$#{name}$", value.to_s.strip)
161
- else
162
- puts "Warning: Unknown project field -- #{name}."
163
- end
164
- end
165
-
166
- message.gsub!(/(^|[ ])[$].*?(?=[ ]|$)/,'') # remove unused vars
167
- message.gsub!(/\n\s*\n\s*\n/m,"\n\n") # remove any triple blank lines
168
- message.rstrip!
169
-
170
- return message
171
- end
172
-
173
- def unfold_paragraphs(string)
174
- blank = false
175
- text = ''
176
- string.split(/\n/).each do |line|
177
- if /\S/ !~ line
178
- text << "\n\n"
179
- blank = true
180
- else
181
- if /^(\s+|[*])/ =~ line
182
- text << (line.rstrip + "\n")
183
- else
184
- text << (line.rstrip + " ")
61
+ hosts(select).each do |host|
62
+ if host.respond_to?(:announce)
63
+ if host.announce_confirm?(options)
64
+ actions << lambda{ host.announce(options) }
185
65
  end
186
- blank = false
187
66
  end
188
67
  end
189
- return text
68
+
69
+ actions.each{ |a| a.call }
190
70
  end
191
71
 
192
72
  end
193
73
 
194
74
  end
195
75
 
196
- # keys = {}
197
- # keys['from'] = info.email
198
- # keys.update info.gather('mail')
199
- # keys.update info.gather('announce')
200
- # keys.update info.select(
201
- # :project, :version, :title, :subtitle, :description,
202
- # :homepage, :download, :slogan
203
- # )
204
- # keys.update override if override
205
-