rant 0.3.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 (64) hide show
  1. data/COPYING +504 -0
  2. data/README +203 -0
  3. data/Rantfile +104 -0
  4. data/TODO +19 -0
  5. data/bin/rant +12 -0
  6. data/bin/rant-import +12 -0
  7. data/devel-notes +50 -0
  8. data/doc/configure.rdoc +40 -0
  9. data/doc/csharp.rdoc +74 -0
  10. data/doc/rant-import.rdoc +32 -0
  11. data/doc/rant.rdoc +24 -0
  12. data/doc/rantfile.rdoc +227 -0
  13. data/doc/rubyproject.rdoc +210 -0
  14. data/lib/rant.rb +9 -0
  15. data/lib/rant/cs_compiler.rb +334 -0
  16. data/lib/rant/import.rb +291 -0
  17. data/lib/rant/import/rubydoc.rb +125 -0
  18. data/lib/rant/import/rubypackage.rb +417 -0
  19. data/lib/rant/import/rubytest.rb +97 -0
  20. data/lib/rant/plugin/README +50 -0
  21. data/lib/rant/plugin/configure.rb +345 -0
  22. data/lib/rant/plugin/csharp.rb +275 -0
  23. data/lib/rant/plugin_methods.rb +41 -0
  24. data/lib/rant/rantenv.rb +217 -0
  25. data/lib/rant/rantfile.rb +664 -0
  26. data/lib/rant/rantlib.rb +1118 -0
  27. data/lib/rant/rantsys.rb +258 -0
  28. data/lib/rant/rantvar.rb +82 -0
  29. data/rantmethods.rb +79 -0
  30. data/run_import +7 -0
  31. data/run_rant +7 -0
  32. data/setup.rb +1360 -0
  33. data/test/Rantfile +2 -0
  34. data/test/plugin/configure/Rantfile +47 -0
  35. data/test/plugin/configure/test_configure.rb +58 -0
  36. data/test/plugin/csharp/Hello.cs +10 -0
  37. data/test/plugin/csharp/Rantfile +30 -0
  38. data/test/plugin/csharp/src/A.cs +8 -0
  39. data/test/plugin/csharp/src/B.cs +8 -0
  40. data/test/plugin/csharp/test_csharp.rb +99 -0
  41. data/test/project1/Rantfile +127 -0
  42. data/test/project1/test_project.rb +203 -0
  43. data/test/project2/buildfile +14 -0
  44. data/test/project2/rantfile.rb +20 -0
  45. data/test/project2/sub1/Rantfile +12 -0
  46. data/test/project2/test_project.rb +87 -0
  47. data/test/project_rb1/README +14 -0
  48. data/test/project_rb1/bin/wgrep +5 -0
  49. data/test/project_rb1/lib/wgrep.rb +56 -0
  50. data/test/project_rb1/rantfile.rb +30 -0
  51. data/test/project_rb1/test/tc_wgrep.rb +21 -0
  52. data/test/project_rb1/test/text +3 -0
  53. data/test/project_rb1/test_project_rb1.rb +153 -0
  54. data/test/test_env.rb +47 -0
  55. data/test/test_filetask.rb +57 -0
  56. data/test/test_lighttask.rb +49 -0
  57. data/test/test_metatask.rb +29 -0
  58. data/test/test_rant_interface.rb +65 -0
  59. data/test/test_sys.rb +61 -0
  60. data/test/test_task.rb +115 -0
  61. data/test/toplevel.rf +11 -0
  62. data/test/ts_all.rb +4 -0
  63. data/test/tutil.rb +95 -0
  64. metadata +133 -0
@@ -0,0 +1,125 @@
1
+
2
+ require 'rant/rantlib'
3
+
4
+ module Rant
5
+ class Generators::RubyDoc
6
+
7
+ class << self
8
+
9
+ def rant_generate(app, ch, args, &block)
10
+ if !args || args.empty?
11
+ self.new(app, ch, &block)
12
+ elsif args.size == 1
13
+ name, pre, file, ln = app.normalize_task_arg(args.first, ch)
14
+ self.new(app, ch, name, pre, &block)
15
+ else
16
+ app.abort(app.pos_text(file, ln),
17
+ "RubyDoc takes only one additional argument, " +
18
+ "which should be like one given to the `task' command.")
19
+ end
20
+ end
21
+ end
22
+
23
+ # Directory where (html) output goes to.
24
+ # Defaults to "doc".
25
+ attr_accessor :op_dir
26
+ alias dir op_dir
27
+ alias dir= op_dir=
28
+ # Files and directories to document. Initialized to an array
29
+ # with the single entry "lib" if a directory of this name
30
+ # exists, or to an empty array otherwise.
31
+ attr_accessor :files
32
+ # List of other options. Initialized to and empty array.
33
+ attr_accessor :opts
34
+
35
+ # Print rdoc command if true. Defaults to false.
36
+ attr_accessor :verbose
37
+
38
+ # Task name of rdoc-task.
39
+ attr_reader :name
40
+
41
+ def initialize(app, ch, name = :doc, prerequisites = [], &block)
42
+ @name = name
43
+ @pre = prerequisites
44
+ @op_dir = "doc"
45
+ @files = test(?d, "lib") ? ["lib"] : []
46
+ @opts = []
47
+ @verbose = false
48
+
49
+ yield self if block_given?
50
+ app.var["gen-rubydoc-rdoc_opts"] = self.rdoc_opts.dup
51
+
52
+ @pre ||= []
53
+ @pre.concat(self.rdoc_source_deps)
54
+ index = self.op_html_index
55
+ # define task task with given name first, so that it takes
56
+ # any previously set description
57
+ t = app.task(:__caller__ => ch, @name => [])
58
+ # The task which will actually run rdoc.
59
+ t << app.file(:__caller__ => ch, index => @pre) { |t|
60
+ # We delay the require of the RDoc code until it is
61
+ # actually needed, so it will be only loaded if the
62
+ # rdoc task has to be run.
63
+ require 'rdoc/rdoc'
64
+ args = self.rdoc_args
65
+ app.cmd_msg "rdoc #{args.join(' ')}" if @verbose
66
+ begin
67
+ RDoc::RDoc.new.document(args)
68
+ rescue RDoc::RDocError => e
69
+ $stderr.puts e.message
70
+ t.fail
71
+ end
72
+ }
73
+ end
74
+
75
+ # Get a list of all options as they would be given to +rdoc+
76
+ # on the commandline.
77
+ def rdoc_opts
78
+ optlist = []
79
+ optlist << "-o" << @op_dir if @op_dir
80
+ if @opts
81
+ # validate opts
82
+ case @opts
83
+ when Array # ok, nothing to do
84
+ when String
85
+ @opts = @opts.split
86
+ else
87
+ if @opts.respond_to? :to_ary
88
+ @opts = @opts.to_ary
89
+ else
90
+ raise RantfileException,
91
+ "RDoc options should be a string or a list of strings."
92
+ end
93
+ end
94
+ optlist.concat @opts
95
+ end
96
+ optlist
97
+ end
98
+ alias options rdoc_opts
99
+
100
+ # Get a list with all arguments which would be given to rdoc
101
+ # on the commandline.
102
+ def rdoc_args
103
+ al = rdoc_opts
104
+ al.concat @files if @files
105
+ al
106
+ end
107
+
108
+ def op_html_index
109
+ File.join(@op_dir, "index.html")
110
+ end
111
+
112
+ def rdoc_source_deps
113
+ # TODO: optimize and refine
114
+ deps = []
115
+ @files.each { |e|
116
+ if test(?d, e)
117
+ deps.concat Dir["#{e}/**/*.rb"]
118
+ else
119
+ deps << e
120
+ end
121
+ }
122
+ deps
123
+ end
124
+ end # class Generators::RubyDoc
125
+ end # module Rant
@@ -0,0 +1,417 @@
1
+
2
+ require 'rant/rantlib'
3
+
4
+ =begin
5
+ class Rant::MethodRecorder
6
+ ACCEPT_ALL_BLOCK = lambda { true }
7
+ def intialize(&accept)
8
+ @ml = []
9
+ @accept = &accept || ACCEPT_ALL_BLOCK
10
+ end
11
+ def method_missing(sym, *args)
12
+ if @accept.call(sym, args)
13
+ @ml << [sym, args]
14
+ else
15
+ super
16
+ end
17
+ end
18
+ end
19
+ =end
20
+
21
+ class Rant::RubyPackage
22
+
23
+ class << self
24
+ def rant_generate(app, ch, args, &block)
25
+ if !args || args.empty?
26
+ self.new(:app => app, :__caller__ => ch, &block)
27
+ elsif args.size == 1
28
+ pkg_name = case args.first
29
+ when String: args.first
30
+ when Symbol: args.first.to_s
31
+ else
32
+ app.abort("RubyDoc takes only one additional " +
33
+ "argument, which should be a string or symbol.")
34
+ end
35
+ self.new(:app => app, :__caller__ => ch,
36
+ :name => pkg_name, &block)
37
+ else
38
+ app.abort(app.pos_text(file, ln),
39
+ "RubyDoc takes only one additional argument, " +
40
+ "which should be a string or symbol.")
41
+ end
42
+ end
43
+ end
44
+
45
+ # Attributes with a single value.
46
+ PACKAGE_SINGLE_ATTRS = [
47
+ "name",
48
+ "date",
49
+ "description",
50
+ "email",
51
+ "has_rdoc",
52
+ "homepage",
53
+ "platform",
54
+ "required_ruby_version",
55
+ "rubyforge_project",
56
+ "summary",
57
+ "version",
58
+ ]
59
+
60
+ # These attributes may be set to a single value, which will be
61
+ # converted to an array with a single element.
62
+ PACKAGE_TO_LIST_ATTRS = [
63
+ "author",
64
+ "bindir",
65
+ "executable",
66
+ "extension",
67
+ "files",
68
+ "rdoc_options",
69
+ "requires",
70
+ "test_files",
71
+ "test_suite",
72
+ ]
73
+
74
+ PACKAGE_ATTRS = PACKAGE_SINGLE_ATTRS + PACKAGE_TO_LIST_ATTRS
75
+
76
+ EXPLICIT_GEM_MAPPING = {
77
+ "executable" => "executables"
78
+ # add requires => requirements ?
79
+ }
80
+
81
+ PACKAGE_NO_VAL = Object.new
82
+
83
+ PACKAGE_SINGLE_ATTRS.each { |a|
84
+ eval <<-EOM, binding
85
+ def #{a}(val = PACKAGE_NO_VAL)
86
+ if val.equal? PACKAGE_NO_VAL
87
+ @data["#{a}"]
88
+ else
89
+ self.#{a} = val
90
+ end
91
+ end
92
+ def #{a}=(val)
93
+ @data["#{a}"] = val
94
+ end
95
+ EOM
96
+ }
97
+ PACKAGE_TO_LIST_ATTRS.each { |a|
98
+ eval <<-EOM, binding
99
+ def #{a}(val0 = PACKAGE_NO_VAL, *args)
100
+ if val0.equal? PACKAGE_NO_VAL
101
+ @data["#{a}"]
102
+ else
103
+ self.#{a} = [val0, *args].flatten
104
+ end
105
+ end
106
+ def #{a}=(val)
107
+ unless val.nil? || Array === val
108
+ val = [val]
109
+ end
110
+ @data["#{a}"] = val
111
+ end
112
+ EOM
113
+ }
114
+
115
+ # A hash containing all package information.
116
+ attr_reader :data
117
+ # Directory where packages go to. Defaults to "pkg".
118
+ attr_accessor :pkg_dir
119
+
120
+ def initialize(opts = {})
121
+ @app = opts[:app] || Rant.rantapp
122
+ @pkg_dir = "pkg"
123
+ @pkg_dir_task = nil
124
+ @dist_dir_task = nil
125
+ @gem_task = nil
126
+ @tar_task = nil
127
+ @zip_task = nil
128
+ @package_task = nil
129
+ name = opts[:name]
130
+ @ch = opts[:__caller__] || Rant::Lib.parse_caller_elem(caller[0])
131
+ unless name
132
+ # use directory name as project name
133
+ name = File.split(Dir.pwd)[1]
134
+ # reset name if it contains a slash or a backslash
135
+ name = nil if name =~ /\/|\\/
136
+ end
137
+ @data = { "name" => name }
138
+
139
+ yield self if block_given?
140
+ end
141
+
142
+ def method_missing(sym, *args)
143
+ super unless args.size == 1
144
+ a = sym.to_s
145
+ if a =~ /^gem_([^=]+)=$/
146
+ @data["gem-#$1"] = args.first
147
+ else
148
+ super
149
+ end
150
+ end
151
+
152
+ def map_to_gemspec spec
153
+ mapped_attrs = []
154
+ # Map attributes from data to the gem spec as explicitely
155
+ # specified.
156
+ EXPLICIT_GEM_MAPPING.each_pair { |attr, gem_attr|
157
+ setter = "#{gem_attr}="
158
+ if @data.key? attr
159
+ mapped_attrs << attr
160
+ spec.send setter, @data[attr]
161
+ end
162
+ }
163
+ # Try to map other attributes.
164
+ @data.each_pair { |attr, val|
165
+ next if attr =~ /^gem\-./
166
+ next if mapped_attrs.include? attr
167
+ setter = "#{attr}="
168
+ spec.send(setter, val) if spec.respond_to? setter
169
+ }
170
+ # `gem-' attributes override others for gem spec
171
+ @data.each_pair { |attr, val|
172
+ if attr =~ /^gem\-(.+)$/
173
+ spec.send("#$1=", val)
174
+ end
175
+ }
176
+ end
177
+
178
+ def pkg_dir_task
179
+ return if @pkg_dir_task
180
+ if @dist_dir_task
181
+ # not ideal but should work: If only the gem task will
182
+ # be run, dist dir creation wouldn't be necessary
183
+ return @pkg_dir_task = @dist_dir_task
184
+ end
185
+ @pkg_dir_task = @app.gen(Rant::Generators::Directory, @pkg_dir)
186
+ end
187
+
188
+ def dist_dir_task
189
+ return if @dist_dir_task
190
+ pkg_name = pkg_dist_dir
191
+ dist_dir = pkg_dist_dir
192
+ @dist_dir_task = @app.gen(Rant::Generators::Directory,
193
+ dist_dir => files) { |t|
194
+ # ensure to create new and empty destination directory
195
+ if Dir.entries(dist_dir).size > 2 # "." and ".."
196
+ @app.sys.rm_rf(dist_dir)
197
+ @app.sys.mkdir(dist_dir)
198
+ end
199
+ # evaluate directory structure first
200
+ dirs = []
201
+ fl = []
202
+ files.each { |e|
203
+ if test(?d, e)
204
+ dirs << e unless dirs.include? e
205
+ else # assuming e is a file
206
+ fl << e
207
+ dir = File.dirname(e)
208
+ dirs << dir unless dir == "." || dirs.include?(dir)
209
+ end
210
+ }
211
+ # create directory structure
212
+ dirs.each { |dir|
213
+ dest = File.join(dist_dir, dir)
214
+ @app.sys.mkpath(dest) unless test(?d, dest)
215
+ }
216
+ # link or copy files
217
+ fl.each { |f|
218
+ dest = File.join(dist_dir, f)
219
+ @app.sys.safe_ln(f, dest)
220
+ }
221
+ }
222
+ end
223
+
224
+ # Create task for gem building. If tname is a true value, a
225
+ # shortcut-task will be created.
226
+ def gem_task(tname = :gem)
227
+ # We first define the task to create the gem, and afterwards
228
+ # the task to create the pkg directory to ensure that a
229
+ # pending description is used to describe the gem task.
230
+ pkg_name = gem_pkg_path
231
+ if tname
232
+ # shortcut task
233
+ @app.task({:__caller__ => @ch, tname => pkg_name})
234
+ end
235
+ # actual gem-creating task
236
+ @gem_task = @app.file({:__caller__ => @ch,
237
+ pkg_name => [@pkg_dir] + files}) { |t|
238
+ # We require rubygems as late as possible to save some
239
+ # execution cycles if possible ;)
240
+ begin
241
+ require 'rubygems'
242
+ rescue LoadError => e
243
+ t.fail "Couldn't load `rubygems'. " +
244
+ "Probably RubyGems isn't installed on your system."
245
+ end
246
+ Gem.manage_gems
247
+ # map rdoc options from application vars
248
+ @data["rdoc_options"] ||= @app.var["gen-rubydoc-rdoc_opts"]
249
+ if @data["rdoc_options"]
250
+ # remove the --op option, otherwise rubygems will
251
+ # install the rdoc in the wrong directory (at least as
252
+ # of version 0.8.6 of rubygems)
253
+ @data["rdoc_options"] = without_rdoc_op_opt(@data["rdoc_options"])
254
+ # automatically set "has_rdoc" to true unless it was
255
+ # explicitely set to false (but if someone sets
256
+ # options for rdoc, he probably wants to run rdoc...)
257
+ @data["has_rdoc"] = true if @data["has_rdoc"].nil?
258
+ end
259
+ spec = Gem::Specification.new do |s|
260
+ map_to_gemspec(s)
261
+ end
262
+ fn = nil
263
+ begin
264
+ fn = Gem::Builder.new(spec).build
265
+ rescue Gem::InvalidSpecificationException => e
266
+ t.fail "Invalid Gem specification: " + e.message
267
+ rescue Gem::Exception => e
268
+ t.fail "Gem error: " + e.message
269
+ end
270
+ @app.sys.mv(fn, @pkg_dir) if @pkg_dir
271
+ }
272
+ pkg_dir_task
273
+ end
274
+
275
+ def tar_task(tname = :tar)
276
+ # Create tar task first to ensure that a pending description
277
+ # is used for the tar task and not for the dist dir task.
278
+ pkg_name = tar_pkg_path
279
+ pkg_files = files
280
+ if tname
281
+ # shortcut task
282
+ @app.task({:__caller__ => @ch, tname => pkg_name})
283
+ end
284
+ # actual tar-creating task
285
+ @tar_task = @app.file(:__caller__ => @ch,
286
+ pkg_name => [pkg_dist_dir] + pkg_files) { |t|
287
+ @app.sys.cd(@pkg_dir) {
288
+ @app.sys %W(tar zcf #{tar_pkg_name} #{pkg_base_name})
289
+ }
290
+ }
291
+ dist_dir_task
292
+ end
293
+
294
+ def zip_task(tname = :zip)
295
+ # Create zip task first to ensure that a pending description
296
+ # is used for the zip task and not for the dist dir task.
297
+ pkg_name = zip_pkg_path
298
+ pkg_files = files
299
+ if tname
300
+ # shortcut task
301
+ @app.task({:__caller__ => @ch, tname => pkg_name})
302
+ end
303
+ # actual zip-creating task
304
+ @zip_task = @app.file(:__caller__ => @ch,
305
+ pkg_name => [pkg_dist_dir] + pkg_files) { |t|
306
+ @app.sys.cd(@pkg_dir) {
307
+ # zip options:
308
+ # y: store symlinks instead of referenced files
309
+ # r: recurse into directories
310
+ # q: quiet operation
311
+ @app.sys %W(zip -yqr #{zip_pkg_name} #{pkg_base_name})
312
+ }
313
+ }
314
+ dist_dir_task
315
+ end
316
+
317
+ # Create a task which runs gem/zip/tar tasks.
318
+ def package_task(tname = :package)
319
+ def_tasks = [@gem_task, @tar_task, @zip_task].compact
320
+ if def_tasks.empty?
321
+ # take description for overall package task
322
+ pdesc = @app.pop_desc
323
+ unless def_available_tasks
324
+ @app.desc pdesc
325
+ @app.warn_msg("No tools for packaging available (tar, zip, gem):",
326
+ "Can't generate task `#{tname}'.")
327
+ return
328
+ end
329
+ @app.desc pdesc
330
+ end
331
+ pre = []
332
+ pre << tar_pkg_path if @tar_task
333
+ pre << zip_pkg_path if @zip_task
334
+ pre << gem_pkg_path if @gem_task
335
+ @app.task(:__caller__ => @ch, tname => pre)
336
+ end
337
+
338
+ # Returns true if at least one task was defined.
339
+ def def_available_tasks
340
+ defined = false
341
+ if Rant::Env.have_tar?
342
+ # we don't create shortcut tasks, hence nil as argument
343
+ self.tar_task(nil)
344
+ defined = true
345
+ end
346
+ if Rant::Env.have_zip?
347
+ self.zip_task(nil)
348
+ defined = true
349
+ end
350
+ begin
351
+ require 'rubygems'
352
+ self.gem_task(nil)
353
+ defined = true
354
+ rescue LoadError
355
+ end
356
+ defined
357
+ end
358
+
359
+ def pkg_base_name
360
+ unless name
361
+ @app.abort(@app.pos_text(@ch[:file], @ch[:ln]),
362
+ "`name' required for packaging")
363
+ end
364
+ version ? "#{name}-#{version}" : name
365
+ end
366
+
367
+ def gem_pkg_path
368
+ pkg_dist_dir + ".gem"
369
+ end
370
+
371
+ #--
372
+ # Arghhh... tar makes me feel angry
373
+ #++
374
+
375
+ def tar_pkg_name
376
+ pkg_base_name + ".tar.gz"
377
+ end
378
+
379
+ def tar_pkg_path
380
+ pkg_dist_dir + ".tar.gz"
381
+ end
382
+
383
+ def zip_pkg_name
384
+ pkg_base_name + ".zip"
385
+ end
386
+
387
+ def zip_pkg_path
388
+ pkg_dist_dir + ".zip"
389
+ end
390
+
391
+ def pkg_dist_dir
392
+ @pkg_dir ? File.join(@pkg_dir, pkg_base_name) : pkg_base_name
393
+ end
394
+
395
+ # Remove -o and --op options from rdoc arguments.
396
+ # Note that this only works if -o isn't part of an argument with
397
+ # multiple one-letter options!
398
+ def without_rdoc_op_opt(rdoc_args)
399
+ last_was_op = false
400
+ rdoc_args.reject { |arg|
401
+ if last_was_op
402
+ last_was_op = false
403
+ next true
404
+ end
405
+ case arg
406
+ when /^(-o|--op)$/
407
+ last_was_op = true
408
+ true
409
+ when /^-o./
410
+ true
411
+ else
412
+ false
413
+ end
414
+ }
415
+ end
416
+
417
+ end # class Rant::RubyPackage