reap 9.3.5 → 9.4.0

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