rant 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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