reap 6.0.2 → 9.2.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 (174) hide show
  1. data/CHANGES +6 -0
  2. data/COPYING +666 -395
  3. data/MANIFEST +139 -0
  4. data/NOTES +12 -0
  5. data/README +19 -163
  6. data/bin/reap-announce +7 -0
  7. data/bin/reap-check-load +8 -0
  8. data/bin/reap-check-syntax +7 -0
  9. data/bin/reap-clean +7 -0
  10. data/bin/reap-clobber +7 -0
  11. data/bin/reap-doc +7 -0
  12. data/bin/reap-doc-rdoc +7 -0
  13. data/bin/reap-doc-ri +7 -0
  14. data/bin/reap-init +69 -0
  15. data/bin/reap-inspect +7 -0
  16. data/bin/reap-install +8 -0
  17. data/bin/reap-install-gem +8 -0
  18. data/bin/reap-log +7 -0
  19. data/bin/reap-log-changes +8 -0
  20. data/bin/reap-log-notes +8 -0
  21. data/bin/reap-make +7 -0
  22. data/bin/reap-make-clean +7 -0
  23. data/bin/reap-make-distclean +7 -0
  24. data/bin/reap-make-extconf +7 -0
  25. data/bin/reap-make-static +8 -0
  26. data/bin/reap-package +8 -0
  27. data/bin/reap-package-gem +7 -0
  28. data/bin/reap-package-tgz +7 -0
  29. data/bin/reap-package-zip +7 -0
  30. data/bin/reap-prepare +7 -0
  31. data/bin/reap-publish +7 -0
  32. data/bin/reap-release +7 -0
  33. data/bin/reap-scaffold +8 -0
  34. data/bin/reap-scm-branch +7 -0
  35. data/bin/reap-scm-tag +7 -0
  36. data/bin/reap-spec +7 -0
  37. data/bin/reap-spec-doc +8 -0
  38. data/bin/reap-stamp +7 -0
  39. data/bin/reap-stats +7 -0
  40. data/bin/reap-test +7 -0
  41. data/bin/reap-test-cross +7 -0
  42. data/bin/reap-test-load +9 -0
  43. data/bin/reap-test-solo +7 -0
  44. data/bin/reap-uninstall +7 -0
  45. data/bin/reap-uninstall-gem +7 -0
  46. data/data/reap/base/CHANGES +19 -0
  47. data/data/reap/base/COPYING +674 -0
  48. data/data/reap/base/NOTES +12 -0
  49. data/data/reap/base/README +8 -0
  50. data/data/reap/build/rake/Rakefile +130 -0
  51. data/{forge/reference/installers → data/reap/build/rake}/setup.rb +155 -97
  52. data/data/reap/build/rake-lite/install.rb +79 -0
  53. data/data/reap/build/tasks/task/rdoc +211 -0
  54. data/data/reap/{setup.rb → build/tasks/task/setup} +248 -200
  55. data/data/reap/build/tasks/task/test +38 -0
  56. data/data/reap/init/meta/project.yaml +21 -0
  57. data/demo/README +15 -0
  58. data/demo/lib/foo/foo.rb +7 -0
  59. data/demo/meta/VERSION +1 -0
  60. data/demo/meta/project.yaml +21 -0
  61. data/lib/reap/application.rb +80 -0
  62. data/lib/reap/default.yaml +77 -0
  63. data/lib/reap/extensions/array.rb +50 -0
  64. data/lib/reap/extensions/hash.rb +63 -0
  65. data/lib/reap/extensions/string.rb +31 -0
  66. data/lib/reap/extensions.rb +6 -0
  67. data/lib/reap/iobject.rb +264 -0
  68. data/lib/reap/manager/announce.rb +193 -0
  69. data/lib/reap/manager/check.rb +109 -0
  70. data/lib/reap/manager/clean.rb +58 -0
  71. data/lib/reap/manager/gem.rb +200 -0
  72. data/lib/reap/manager/html.rb +69 -0
  73. data/lib/reap/manager/log.rb +214 -0
  74. data/lib/reap/manager/make.rb +109 -0
  75. data/lib/reap/manager/pack.rb +232 -0
  76. data/lib/reap/manager/publish.rb +72 -0
  77. data/lib/reap/manager/rdoc.rb +194 -0
  78. data/lib/reap/manager/release.rb +78 -0
  79. data/lib/reap/manager/rubyforge.rb +44 -0
  80. data/lib/reap/manager/scaffold.rb +138 -0
  81. data/lib/reap/manager/scm.rb +66 -0
  82. data/lib/reap/manager/site.rb +27 -0
  83. data/lib/reap/manager/spec.rb +94 -0
  84. data/lib/reap/manager/stats.rb +145 -0
  85. data/lib/reap/manager/svn.rb +76 -0
  86. data/lib/reap/manager/test.rb +389 -0
  87. data/lib/reap/manager.rb +74 -0
  88. data/lib/reap/metadata.rb +603 -0
  89. data/lib/reap/project.rb +165 -0
  90. data/lib/reap/settings.rb +67 -0
  91. data/lib/reap/systems/rubyforge.rb +737 -0
  92. data/lib/reap/systems/subversion.rb +333 -0
  93. data/lib/reap/utilities/fileutils.rb +304 -0
  94. data/lib/reap/utilities/netutils.rb +221 -0
  95. data/lib/reap/utilities/setuputils.rb +124 -0
  96. data/lib/reap/utilities/shellutils.rb +175 -0
  97. data/log/Changelog.txt +107 -0
  98. data/log/FIXME.txt +25 -0
  99. data/log/TODO.txt +72 -0
  100. data/meta/VERSION +1 -0
  101. data/meta/description +4 -0
  102. data/meta/project.yaml +20 -0
  103. data/task/man +14 -0
  104. data/task/rdoc +20 -0
  105. data/{data/reap/scaffold/standard/setup.rb → task/setup} +248 -200
  106. metadata +225 -153
  107. data/ProjectInfo +0 -105
  108. data/bin/reap +0 -5
  109. data/bin/rubytest +0 -5
  110. data/data/reap/install.rb +0 -62
  111. data/data/reap/scaffold/standard/COPYING +0 -403
  112. data/data/reap/scaffold/standard/ChangeLog +0 -0
  113. data/data/reap/scaffold/standard/INSTALL +0 -14
  114. data/data/reap/scaffold/standard/ProjectInfo +0 -77
  115. data/data/reap/scaffold/standard/README +0 -3
  116. data/data/reap/scaffold/standard/Rakefile +0 -10
  117. data/data/reap/scaffold/standard/TODO +0 -0
  118. data/data/reap/scaffold/subversion/trunk/COPYING +0 -403
  119. data/data/reap/scaffold/subversion/trunk/ChangeLog +0 -0
  120. data/data/reap/scaffold/subversion/trunk/INSTALL +0 -14
  121. data/data/reap/scaffold/subversion/trunk/ProjectInfo +0 -76
  122. data/data/reap/scaffold/subversion/trunk/README +0 -3
  123. data/data/reap/scaffold/subversion/trunk/Rakefile +0 -10
  124. data/data/reap/scaffold/subversion/trunk/TODO +0 -0
  125. data/data/reap/scaffold/subversion/trunk/setup.rb +0 -1568
  126. data/forge/ProjectInfo +0 -38
  127. data/forge/ProjectInfo.rb +0 -76
  128. data/forge/TODO +0 -10
  129. data/forge/installer.rb +0 -250
  130. data/forge/reference/Rakefile +0 -124
  131. data/forge/reference/Rakefile.htm +0 -69
  132. data/forge/reference/aRakefile +0 -60
  133. data/forge/reference/compositepublisher.rb +0 -24
  134. data/forge/reference/ftptools.rb +0 -139
  135. data/forge/reference/installers/package.rb +0 -629
  136. data/forge/reference/license-each.rb +0 -85
  137. data/forge/reference/publisher.rb +0 -75
  138. data/forge/reference/rubyforge.rb +0 -247
  139. data/forge/reference/rubyforgepublisher.rb +0 -18
  140. data/forge/reference/sshpublisher.rb +0 -47
  141. data/forge/reference/suby-cvs.rb +0 -46
  142. data/forge/scaffold.rb +0 -126
  143. data/forge/unit_runner/README +0 -6
  144. data/forge/unit_runner/commentrunner.rb +0 -62
  145. data/forge/unit_runner/cunit.rb +0 -17
  146. data/forge/unit_runner/forkedrunner.rb +0 -91
  147. data/forge/unit_runner/sample.rb +0 -16
  148. data/lib/reap/bin/reap.rb +0 -230
  149. data/lib/reap/bin/rubytest.rb +0 -53
  150. data/lib/reap/class/announce.rb +0 -220
  151. data/lib/reap/class/doap.rb +0 -80
  152. data/lib/reap/class/extest.rb +0 -146
  153. data/lib/reap/class/filer.rb +0 -62
  154. data/lib/reap/class/manifest.rb +0 -68
  155. data/lib/reap/class/package.rb +0 -576
  156. data/lib/reap/class/publish.rb +0 -152
  157. data/lib/reap/class/rdoc.rb +0 -123
  158. data/lib/reap/class/test.rb +0 -264
  159. data/lib/reap/projectinfo.rb +0 -208
  160. data/lib/reap/rake.rb +0 -42
  161. data/lib/reap/reap.rb +0 -89
  162. data/lib/reap/tasks.rb +0 -756
  163. data/lib/reap/taskutils.rb +0 -122
  164. data/note/LATEST +0 -44
  165. data/note/doap.xml +0 -28
  166. data/note/history/Rakefile-0.1 +0 -308
  167. data/sample/ProjectInfo +0 -96
  168. data/sample/Rakefile +0 -9
  169. data/sample/Reapfile +0 -11
  170. data/sample/task/demo.rb +0 -15
  171. data/setup.rb +0 -1568
  172. data/web/ProjectInfo.html +0 -75
  173. data/web/images/grape.jpg +0 -0
  174. data/web/index.html +0 -312
@@ -0,0 +1,333 @@
1
+ require 'reap/utilities/shellutils'
2
+ require 'reap/utilities/fileutils'
3
+
4
+ module Reap
5
+
6
+ class Subversion
7
+ include Utilities::ShellUtils
8
+ include Utilities::FileUtils
9
+
10
+ # Project name (for repository).
11
+
12
+ attr_accessor :project
13
+
14
+ # Current version of project.
15
+
16
+ attr_accessor :version
17
+
18
+ # Developers URL to repository. Defaults to Rubyforge address.
19
+
20
+ attr_accessor :repository
21
+
22
+ # Username. Defaults to ENV['RUBYFORGE_USERNAME'].
23
+
24
+ attr_accessor :username
25
+
26
+ # The URL protocol to use. Defaults to "svn+ssh".
27
+
28
+ attr_accessor :protocol
29
+
30
+ # Prefix to use on tag folder. Default is no prefix.
31
+
32
+ attr_accessor :prefix
33
+
34
+ # Optional commit message. This is intended for commandline
35
+ # usage. (Use -m for shorthand).
36
+
37
+ attr_accessor :message
38
+
39
+ # Directory to store tags. Defaults to tags/.
40
+
41
+ attr_accessor :tagpath
42
+
43
+ # Directory to store branches. Defaults to branches/.
44
+
45
+ attr_accessor :branchpath
46
+
47
+ # Operate in dryrun mode.
48
+
49
+ attr_accessor :dryrun
50
+
51
+ # New Subversion object.
52
+ #
53
+ # TODO: Perhaps format prefix, like:
54
+ # prefix = prefix + '_' if prefix && prefix !~ /[_-]$/
55
+
56
+ def initialize(options={})
57
+ options.each do |k,v|
58
+ send("#{k}=", v) if respond_to?("#{k}=")
59
+ end
60
+
61
+ # defaults are for rubyforge
62
+ @repository ||= "rubyforge.org/var/svn/#{project}"
63
+ @username ||= ENV['RUBYFORGE_USERNAME']
64
+ @protocol ||= "svn+ssh"
65
+ @tagpath ||= "tags"
66
+ @branchpath ||= "branches"
67
+
68
+ if i = @repository.index('//')
69
+ @repository = @repository[i+2..-1]
70
+ end
71
+ end
72
+
73
+ # Developer domain is "username@repository".
74
+
75
+ def developer_domain
76
+ "#{username}@#{repository}"
77
+ end
78
+
79
+ # Branch current version.
80
+ #
81
+ # message Optional commit message. This is intended for commandline
82
+ # usage. (Use -m for shorthand).
83
+ #
84
+ def branch(options={})
85
+ msg = options['message'] || options['m']
86
+ name = "#{prefix}#{version}"
87
+ path = branchpath.to_s
88
+
89
+ if path == '.' or path.empty?
90
+ url = "#{protocol}://" + File.join(developer_domain, name)
91
+ else
92
+ url = "#{protocol}://" + File.join(developer_domain, path, name)
93
+ end
94
+
95
+ case ask("Branch: #{url} ? [yN]").strip.downcase
96
+ when 'y', 'yes'
97
+ #sh "svn copy #{protocol}://#{username}@#{repository}/trunk #{url}"
98
+ sh "svn copy . #{url}"
99
+ end
100
+ end
101
+
102
+ # Tag current version.
103
+ #
104
+ # message Optional commit message. This is intended for commandline
105
+ # usage. (Use -m for shorthand).
106
+ #
107
+ def tag(options={})
108
+ msg = options['message'] || options['m']
109
+ name = "#{prefix}#{version}"
110
+ path = tagpath.to_s
111
+
112
+ if path == '.' or path.empty?
113
+ url = "#{protocol}://" + File.join(developer_domain, name)
114
+ else
115
+ url = "#{protocol}://" + File.join(developer_domain, path, name)
116
+ end
117
+
118
+ case ask("Tag: #{url} ? [yN]").strip.downcase
119
+ when 'y', 'yes'
120
+ #sh "svn copy #{protocol}://#{username}@#{repository}/trunk #{url}"
121
+ sh "svn copy . #{url}"
122
+ end
123
+ end
124
+
125
+ # Create a change log.
126
+ #
127
+ # change File name to store rdoc formated changelog. Default is 'changelog.txt'.
128
+ #
129
+ # output Path to store rdoc formated changelog. Default is 'log'.
130
+ #
131
+ # xmlchange File name to store XML formated changelog. Default is 'changelog.xml'.
132
+ # This also creates a file, if needed, by the same name but with .xsl extension.
133
+ #
134
+ # xmloutput Path to store XML-formated changelog. Default is 'doc/log'.
135
+ #
136
+ # If change or xmlchange contain a path separator ('/', not '\'), then it is assumed they
137
+ # provide their own path and the output fields will not be used. This allows you to set
138
+ # +change+ to "./CHANGES" for instance, without effecting the location of other logs.
139
+ # You can also set change or xmlchange to 'false' to supress creation altogether.
140
+ #
141
+ # TODO: Allow for a way to dump the text-based Changelog to standard out. "$stdout" as the filename?
142
+ # TODO: How to apply naming policy from here?
143
+
144
+ def log(file=nil)
145
+ #txtlog = file #options['change'] || 'changelog.txt'
146
+ #txtdir = options['output'] || 'log'
147
+ #xmllog = options['xmlchange'] || 'changelog.xml'
148
+ #xmldir = options['xmloutput'] || 'doc/log'
149
+ #txtlog = File.join(txtdir, txtlog) unless xmllog.include?('/')
150
+ #xmllog = File.join(xmldir, xmllog) unless xmllog.include?('/')
151
+ text = changelog_text
152
+ if dryrun?
153
+ puts "svn log > #{file}"
154
+ elsif file
155
+ mkdir_p(File.dirname(file))
156
+ File.open(file, 'w'){|f| f << text }
157
+ puts "Updated #{file}"
158
+ else
159
+ puts text
160
+ end
161
+ end
162
+
163
+ #
164
+
165
+ def log_xml(file)
166
+ #xmldir = options['xmloutput'] || 'doc/log'
167
+
168
+ xslfile = file.chomp(File.extname(file)) + '.xsl'
169
+ log_xsl(xslfile)
170
+
171
+ text = changelog_xml
172
+ i = text.index("?>\n")
173
+ text.insert(i+2, "\n" + %[<?xml-stylesheet href="#{xslfile}" type="text/xsl" ?>])
174
+
175
+ if dryrun?
176
+ puts "svn log --xml > #{file}"
177
+ elsif file
178
+ mkdir_p(File.dirname(file))
179
+ File.open(file, 'w'){ |f| f << text }
180
+ puts "Updated #{file}"
181
+ else
182
+ puts text
183
+ end
184
+ end
185
+
186
+ private
187
+
188
+ def changelog_xml
189
+ @changelog_xml ||= `svn log --xml`
190
+ end
191
+
192
+ def changelog_text
193
+ @changelog_text ||= log_format(log_organize(log_parse(changelog_xml)))
194
+ end
195
+
196
+ # Parse xml log into rdoc markup.
197
+
198
+ def log_parse(xml)
199
+ require "rexml/document"
200
+ changes = []
201
+ doc = REXML::Document.new(xml)
202
+ doc.root.elements.each do |element|
203
+ revision = element.attributes["revision"]
204
+ author = element.elements["author"].text
205
+ date = element.elements["date"].text
206
+ message = element.elements["msg"].text
207
+
208
+ revision = revision.strip
209
+ author = author.strip
210
+ date = Date.parse(date)
211
+ message = message.strip
212
+
213
+ changes << [ date, author, revision, message ]
214
+ end
215
+ changes
216
+ end
217
+
218
+ #
219
+
220
+ def log_organize(changes)
221
+ mapped = {}
222
+ changes.each do |date, who, rev, text|
223
+ mapped[[date, who]] ||= []
224
+ mapped[[date, who]] << [text, rev]
225
+ end
226
+ sorted = []
227
+ mapped.each do |(date, who), entries|
228
+ sorted << [ date, who, entries ]
229
+ end
230
+ sorted.sort{ |a,b| b[0] <=> a[0] }
231
+ end
232
+
233
+ #
234
+
235
+ def log_format(sorted)
236
+ string = "= Subversion Changelog\n\n"
237
+ sorted.each do |date, who, entries|
238
+ string << "== #{date} #{who}\n\n" # no email :(
239
+ entries.each do |entry|
240
+ string << "* #{entry.first} (#{entry.last})\n"
241
+ end
242
+ string << "\n"
243
+ end
244
+ string
245
+ end
246
+
247
+ #
248
+
249
+ def log_xsl(xslfile)
250
+ if force? or not File.exist?(xslfile)
251
+ mkdir_p(File.dirname(xslfile))
252
+ if dryrun?
253
+ puts "touch #{xslfile}"
254
+ else
255
+ File.open(xslfile, 'w') do |f|
256
+ f << DEFAULT_LOG_XSL
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ DEFAULT_LOG_XSL = <<-END
263
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
264
+
265
+ <xsl:output cdata-section-elements="script"/>
266
+
267
+ <xsl:template match="/">
268
+ <html>
269
+ <head>
270
+ <title>Changelog</title>
271
+ <link REL='SHORTCUT ICON' HREF="../img/ruby-sm.png" />
272
+ <style>
273
+ td { font-family: sans-serif; padding: 0px 10px; }
274
+ </style>
275
+ </head>
276
+ <body>
277
+ <div class="container">
278
+ <h1>Changelog</h1>
279
+ <table style="width: 100%;">
280
+ <xsl:apply-templates />
281
+ </table>
282
+ </div>
283
+ </body>
284
+ </html>
285
+ </xsl:template>
286
+
287
+ <xsl:template match="logentry">
288
+ <tr>
289
+ <td><b><pre><xsl:value-of select="msg"/></pre></b></td>
290
+ <td><xsl:value-of select="author"/></td>
291
+ <td><xsl:value-of select="date"/></td>
292
+ </tr>
293
+ </xsl:template>
294
+
295
+ </xsl:stylesheet>
296
+ END
297
+
298
+ end
299
+
300
+ end
301
+
302
+
303
+
304
+ =begin
305
+ #
306
+
307
+ def svn_repository_configuration(options, *entries)
308
+ entries << 'svn'
309
+ options = configure_options(options, *entries)
310
+
311
+ options['repository'] ||= metadata.repository
312
+ options['protocol'] ||= 'svn+ssh'
313
+ options['message'] ||= options.delete('m')
314
+ options['tagpath'] ||= 'tags'
315
+
316
+ unless repository
317
+ rubyforge = configuration['rubyforge'] || {}
318
+ projectname = rubyforge['project'] || metadata.name
319
+ options['repository'] = "rubyforge.org/var/svn/#{projectname}"
320
+ end
321
+
322
+ if i = options['repository'].index('//')
323
+ options['repository'] = options['repository'][i+2..-1]
324
+ end
325
+
326
+ if /rubyforge.org/i =~ options['repository']
327
+ options['username'] ||= ENV['RUBYFORGE_USERNAME']
328
+ end
329
+
330
+ return options
331
+ end
332
+ =end
333
+
@@ -0,0 +1,304 @@
1
+ # = TITLE:
2
+ #
3
+ # File Utitlies
4
+ #
5
+ # = COPYING:
6
+ #
7
+ # Copyright (c) 2007,2008 Tiger Ops
8
+ #
9
+ # This file is part of the Reap program.
10
+ #
11
+ # Reap is free software: you can redistribute it and/or modify
12
+ # it under the terms of the GNU General Public License as published by
13
+ # the Free Software Foundation, either version 3 of the License, or
14
+ # (at your option) any later version.
15
+ #
16
+ # Reap is distributed in the hope that it will be useful,
17
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ # GNU General Public License for more details.
20
+ #
21
+ # You should have received a copy of the GNU General Public License
22
+ # along with Reap. If not, see <http://www.gnu.org/licenses/>.
23
+ #
24
+ # TODO:
25
+ #
26
+ # - Move out_of_data? and safe? to Facets FileTest extensions.
27
+
28
+ require 'fileutils'
29
+ require 'facets/ziputils'
30
+
31
+ require 'reap/extensions'
32
+
33
+ #
34
+ module Reap
35
+ module Utilities
36
+
37
+ module FileUtils
38
+
39
+ # Delegate access to FileUtils.
40
+
41
+ def fileutils
42
+ dryrun? ? ::FileUtils::DryRun : ::FileUtils
43
+ end
44
+
45
+ # Add FileUtils Features
46
+
47
+ ::FileUtils.private_instance_methods(false).each do |meth|
48
+ next if meth =~ /^fu_/
49
+ module_eval %{
50
+ def #{meth}(*a,&b)
51
+ fileutils.#{meth}(*a,&b)
52
+ end
53
+ }
54
+ end
55
+
56
+ # Add FileTest Features
57
+
58
+ ::FileTest.private_instance_methods(false).each do |meth|
59
+ next if meth =~ /^fu_/
60
+ module_eval %{
61
+ def #{meth}(*a,&b)
62
+ FileTest.#{meth}(*a,&b)
63
+ end
64
+ }
65
+ end
66
+
67
+ # Specific.
68
+
69
+ def rm_r(*a)
70
+ if dryrun?
71
+ puts "rm_r #{a.join(' ')}"
72
+ else
73
+ fileutils.rm_r(*a)
74
+ end
75
+ end
76
+
77
+ # Bonus FileUtils features.
78
+
79
+ def cd(*a,&b)
80
+ puts "cd #{a}" if dryrun? or trace?
81
+ fileutils.chdir(*a,&b)
82
+ end
83
+
84
+ # Read file.
85
+
86
+ def file_read(path)
87
+ File.read(path)
88
+ end
89
+
90
+ # Write file.
91
+
92
+ def file_write(path, text)
93
+ if dryrun?
94
+ puts "write #{path}"
95
+ else
96
+ File.open(path, 'w'){ |f| f << text }
97
+ end
98
+ end
99
+
100
+ # Assert that a path exists.
101
+
102
+ def exists?(path)
103
+ paths = Dir.glob(path)
104
+ paths.not_empty?
105
+ end
106
+ alias_method :exist?, :exists? ; module_function :exist?
107
+ alias_method :path?, :exists? ; module_function :path?
108
+
109
+ # Assert that a path exists.
110
+
111
+ def exists!(*paths)
112
+ abort "path not found #{path}" unless paths.any?{|path| exists?(path)}
113
+ end
114
+ alias_method :exist!, :exists! ; module_function :exist!
115
+ alias_method :path!, :exists! ; module_function :path!
116
+
117
+ # Is a given path a regular file? If +path+ is a glob
118
+ # then checks to see if all matches are refular files.
119
+
120
+ def file?(path)
121
+ paths = Dir.glob(path)
122
+ paths.not_empty? && paths.all?{ |f| FileTest.file?(f) }
123
+ end
124
+
125
+ # Assert that a given path is a file.
126
+
127
+ def file!(*paths)
128
+ abort "file not found #{path}" unless paths.any?{|path| file?(path)}
129
+ end
130
+
131
+ # Is a given path a directory? If +path+ is a glob
132
+ # checks to see if all matches are directories.
133
+
134
+ def dir?(path)
135
+ paths = Dir.glob(path)
136
+ paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) }
137
+ end
138
+ alias_method :directory?, :dir? ; module_function :directory?
139
+
140
+ # Assert that a given path is a directory.
141
+
142
+ def dir!(*paths)
143
+ paths.each do |path|
144
+ abort "Directory not found: '#{path}'." unless dir?(path)
145
+ end
146
+ end
147
+ alias_method :directory!, :dir! ; module_function :directory!
148
+
149
+ # # Okay, I'm being a dork, but 'fold' seems like a better word
150
+ # # then 'dir', 'folder', or 'directory'.
151
+ #
152
+ # def fold?(path)
153
+ # paths = Dir.glob(path)
154
+ # paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) }
155
+ # end
156
+ #
157
+ # # Assert that a given path is a fold (ie. a folder).
158
+ #
159
+ # def fold!(*paths)
160
+ # abort "fold not found #{path}" unless paths.any?{|path| fold?(path)}
161
+ # end
162
+
163
+ # Return a cached list of the PATH environment variable.
164
+ # This is a support method used by #bin?
165
+
166
+ def command_paths
167
+ @command_paths ||= ENV['PATH'].split(/[:;]/)
168
+ end
169
+
170
+ # Is a file a command executable?
171
+ #
172
+ # TODO: Make more robust. Probably needs to be fixed for Windows.
173
+
174
+ def bin?(fname)
175
+ #@command_paths ||= ENV['PATH'].split(/[:;]/)
176
+ is_bin = command_paths.any? do |f|
177
+ FileTest.exist?(File.join(f, fname))
178
+ end
179
+ #is_bin ? File.basename(fname) : false
180
+ is_bin ? fname : false
181
+ end
182
+
183
+ # Is a path considered reasonably "safe"?
184
+ #
185
+ # TODO: Make more robust.
186
+
187
+ def safe?(path)
188
+ case path
189
+ when *[ '/', '/*', '/**/*' ]
190
+ return false
191
+ end
192
+ true
193
+ end
194
+
195
+ # Does a path need updating, based on given +sources+?
196
+ # This compares mtimes of give paths. Returns false
197
+ # if the path needs to be updated.
198
+
199
+ def out_of_date?(path, *sources)
200
+ return true unless File.exist?(path)
201
+
202
+ sources = sources.collect{ |source| Dir.glob(source) }.flatten
203
+ mtimes = sources.collect{ |file| File.mtime(file) }
204
+
205
+ return true if mtimes.empty? # TODO: This the way to go here?
206
+
207
+ File.mtime(path) < mtimes.max
208
+ end
209
+
210
+ # Glob files.
211
+
212
+ def glob(*args, &blk)
213
+ Dir.glob(*args, &blk)
214
+ end
215
+
216
+ def multiglob(*args, &blk)
217
+ Dir.multiglob(*args, &blk)
218
+ end
219
+
220
+ def multiglob_r(*args, &blk)
221
+ Dir.multiglob_r(*args, &blk)
222
+ end
223
+
224
+ # Stage package by hard linking included files to a stage directory.
225
+ # Stage files in a directory.
226
+ #
227
+ # stage_directory Stage directory.
228
+ # files Files to link to stage.
229
+
230
+ def stage(stage_directory, files)
231
+ return stage_directory if dryrun? # Don't link to stage if dryrun.
232
+
233
+ if File.directory?(stage_directory) # Ensure existance of staging area.
234
+ #raise(???Error, stage_directory) unless force?
235
+ rm_r(stage_directory)
236
+ end
237
+
238
+ mkdir_p(stage_directory) #dir = File.expand_path(stage)
239
+
240
+ #files = package.filelist #+ [package.manifest_file]
241
+
242
+ # TODO Dryrun test here or before folder creation?
243
+ files.each do |f| # Link files into staging area.
244
+ file = File.join(stage_directory, f)
245
+ if File.directory?(f)
246
+ mkdir_p(file)
247
+ else
248
+ unless File.exist?(file) and File.mtime(file) >= File.mtime(f)
249
+ ln(f, file) #safe_ln ?
250
+ end
251
+ end
252
+ end
253
+
254
+ # stage meanifest ?
255
+
256
+ return stage_directory
257
+ end
258
+
259
+ # Create manifest for a directory.
260
+ #
261
+ # TODO: Do this programatically rather then via shell.
262
+
263
+ def stage_manifest(directory)
264
+ cd(directory) do
265
+ sh 'manifest up'
266
+ end
267
+ end
268
+
269
+ # Delegate access to ZipUtils.
270
+
271
+ def ziputils
272
+ dryrun? ? ::ZipUtils::DryRun : ::ZipUtils
273
+ end
274
+
275
+ # Zip folder into file.
276
+
277
+ def zip(folder, file=nil, options={})
278
+ ziputils.zip(folder, file, options)
279
+ end
280
+
281
+ # BZip and tarball folder into file.
282
+
283
+ def tar_bzip(folder, file=nil, options={})
284
+ ziputils.tar_bzip(folder, file, options)
285
+ end
286
+
287
+ # GZip and tarball folder into file. Shortcut for ziputils.tgz.
288
+
289
+ def tgz(folder, file=nil, options={})
290
+ ziputils.tgz(folder, file, options)
291
+ end
292
+
293
+ # # Is a file a task?
294
+ #
295
+ # def task?(path)
296
+ # task = File.dirname($0) + "/#{path}"
297
+ # task.chomp!('!')
298
+ # task if FileTest.file?(task) && FileTest.executable?(task)
299
+ # end
300
+
301
+ end
302
+
303
+ end
304
+ end