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,97 @@
1
+
2
+ require 'rant/rantlib'
3
+
4
+ module Rant
5
+ class Generators::RubyTest
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 =
14
+ app.normalize_task_arg(args.first, ch)
15
+ self.new(app, ch, name, pre, &block)
16
+ else
17
+ app.abort(app.pos_text(file, ln),
18
+ "RubyTest takes only one additional argument, " +
19
+ "which should be like one given to the `task' command.")
20
+ end
21
+ end
22
+ end
23
+
24
+ attr_accessor :verbose
25
+ attr_accessor :libs
26
+ attr_accessor :options
27
+ attr_accessor :test_dirs
28
+ attr_accessor :pattern
29
+ attr_accessor :test_files
30
+ # Directory where to run unit tests.
31
+ attr_accessor :test_dir
32
+
33
+ def initialize(app, cinf, name = :test, prerequisites = [], &block)
34
+ @name = name
35
+ @pre = prerequisites
36
+ @block = block
37
+ @verbose = nil
38
+ cf = cinf[:file]
39
+ @libs = []
40
+ libdir = File.join(File.dirname(
41
+ File.expand_path(cf)), 'lib')
42
+ @libs << libdir if test(?d, libdir)
43
+ @options = []
44
+ @test_dirs = []
45
+ @pattern = nil
46
+ @test_files = nil
47
+ @test_dir = nil
48
+ yield self if block_given?
49
+ @pattern = "test*.rb" if @pattern.nil? && @test_files.nil?
50
+
51
+ @pre ||= []
52
+ # define the task
53
+ app.task({:__caller__ => cinf, @name => @pre}) { |t|
54
+ arg = ""
55
+ libpath = (@libs.nil? || @libs.empty?) ?
56
+ nil : @libs.join(File::PATH_SEPARATOR)
57
+ if libpath
58
+ arg << "-I " << Env.shell_path(libpath) << " "
59
+ end
60
+ arg << "-S testrb " << optlist
61
+ if @test_dir
62
+ app.context.sys.cd(@test_dir) {
63
+ arg << filelist.arglist
64
+ app.context.sys.ruby arg
65
+ }
66
+ else
67
+ if test(?d, "test")
68
+ @test_dirs << "test"
69
+ elsif test(?d, "tests")
70
+ @test_dirs << "tests"
71
+ end
72
+ arg << filelist.arglist
73
+ app.context.sys.ruby arg
74
+ end
75
+ }
76
+ end
77
+ def optlist
78
+ options = (@options.is_a? Array) ?
79
+ @options.arglist : @options
80
+ ENV["TESTOPTS"] || options || ""
81
+ end
82
+ def filelist
83
+ return Dir[ENV['TEST']] if ENV['TEST']
84
+ filelist = @test_files || []
85
+ if filelist.empty?
86
+ if @test_dirs && !@test_dirs.empty?
87
+ @test_dirs.each { |dir|
88
+ filelist.concat(Dir[File.join(dir, @pattern)])
89
+ }
90
+ else
91
+ filelist.concat(Dir[@pattern]) if @pattern
92
+ end
93
+ end
94
+ filelist
95
+ end
96
+ end # class Generators::RubyTest
97
+ end # module Rant
@@ -0,0 +1,50 @@
1
+
2
+ = Rant plugins
3
+
4
+ An Rant plugin provides additional functionality for the Rant program.
5
+ Every Ruby script (file ending in <tt>.rb</tt>) in the
6
+ <tt>rant/plugin</tt> directory is considered a plugin. Normally, it
7
+ contains one class in the Rant::Plugin module.
8
+
9
+ == Requirements for a plugin
10
+
11
+ One file ending in <tt>.rb</tt> in the <tt>rant/plugin</tt> directory.
12
+ One class, defined in this file, in the Rant::Plugin namespace
13
+ responding to the +new_plugin+ method. Note that the *class* has to
14
+ respond!
15
+
16
+ This is a list of all methods the plugin class/instance has to respond
17
+ to:
18
+
19
+ === Class methods:
20
+
21
+ [plugin_create]
22
+ Instantiates the plugin. Will be called every time a new
23
+ Rant::RantApp is created.
24
+
25
+ === Instance methods:
26
+
27
+ [rant_plugin_init]
28
+ Called on Rant startup. Usually directly after plugin
29
+ instantiation.
30
+ [rant_start]
31
+ Called before Rant runs the first task.
32
+ [rant_done]
33
+ Called when Rant has *successfully* processed all required
34
+ tasks.
35
+ [rant_plugin_stop]
36
+ Signals that the plugin should be stopped.
37
+ The plugin object should respond by disposing all reserved
38
+ resources, closing open files etc.
39
+ [rant_quit]
40
+ This is always called before the Rant application quits, even
41
+ if there was a failure. Usually immediately called after
42
+ +rant_plugin_stop+.
43
+
44
+ == Startup
45
+
46
+ Every time a Rant application is initialized, it calls the
47
+ +plugin_create+ method of every class (which has this method) in the
48
+ Plugin module. This method should return a new plugin instance.
49
+
50
+ == Shutdown
@@ -0,0 +1,345 @@
1
+
2
+ require 'rant/plugin_methods'
3
+ require 'yaml'
4
+
5
+ # Configure plugin for Rant
6
+
7
+ module Rant::Plugin
8
+
9
+ # === Startup of configure plugin
10
+ # ==== Config file exists
11
+ # The configuration file will be read and the data hash
12
+ # set up accordingly.
13
+ # ==== Config file doesn't exist
14
+ # The configuration process is run with +startup_modes+ which
15
+ # has to be one of CHECK_MODES. +startup_modes+ defaults to
16
+ # :default, which means if the configfile doesn't exist,
17
+ # all values will be set to their defaults on startup.
18
+ # === Access to configuration in Rantfile
19
+ # You can access all configuration values through the <tt>[]</tt>
20
+ # and <tt>[]=</tt> operators of the configure plugin.
21
+ #
22
+ # Example of configure in Rantfile:
23
+ #
24
+ # conf = plugin :Configure do |conf|
25
+ # conf.task # define a task named :configure
26
+ # conf.check "profile" do |c|
27
+ # c.default "full"
28
+ # c.guess { ENV["PROFILE"] }
29
+ # c.interact {
30
+ # conf.prompt "What build-profile should be used?"
31
+ # }
32
+ # end
33
+ # conf.check "optimize" do |c|
34
+ # c.default true
35
+ # c.guess { ENV["OPTIMIZE"] }
36
+ # c.interact {
37
+ # conf.ask_yes_no "Optimize build?"
38
+ # }
39
+ # end
40
+ # end
41
+ #
42
+ # # Set default target depending on profile:
43
+ # task :default => conf["profile"]
44
+ class Configure
45
+ include ::Rant::PluginMethods
46
+ include ::Rant::Console
47
+
48
+ class << self
49
+ def rant_plugin_new(app, cinf, *args, &block)
50
+ if args.size > 1
51
+ app.abort(app.pos_text(cinf[:file], cinf[:ln]),
52
+ "Configure plugin takes only one argument.")
53
+ end
54
+ self.new(app, args.first, &block)
55
+ end
56
+ end
57
+
58
+ CHECK_MODES = [
59
+ :default,
60
+ :env,
61
+ :guess,
62
+ :interact,
63
+ ]
64
+
65
+ # Name for this plugin instance. Defaults to "configure".
66
+ attr_reader :name
67
+
68
+ # Name of configuration file.
69
+ attr_accessor :file
70
+
71
+ # This flag is used to determine if data has changed and
72
+ # should be saved to file.
73
+ attr_accessor :modified
74
+
75
+ # An array with all checks to perform.
76
+ attr_reader :checklist
77
+
78
+ # Decide what the configure plugin does on startup if the
79
+ # configuration file doesn't exist. Initialized to
80
+ # <tt>[:guess]</tt>.
81
+ attr_accessor :init_modes
82
+
83
+ # Decide what the configure plugin does *after* reading the
84
+ # configuration file (or directly after running +init_modes+
85
+ # if the configuration file doesn't exist).
86
+ # Initialized to <tt>[:env]</tt>, probably the only usefull
87
+ # value.
88
+ attr_accessor :override_modes
89
+
90
+ # Don't write to file, config values will be lost when
91
+ # rant exits!
92
+ attr_accessor :no_write
93
+
94
+ # Don't read or write to configuration file nor run +guess+ or
95
+ # +interact+ blocks if *first* target given on commandline
96
+ # is in this list. This is usefull for targets that remove
97
+ # the configuration file.
98
+ # Defaults are "distclean", "clobber" and "clean".
99
+ attr_reader :no_action_list
100
+
101
+ def initialize(app, name = nil)
102
+ @name = name || rant_plugin_type
103
+ @app = app or raise ArgumentError, "no application given"
104
+ @file = "config"
105
+ @checklist = []
106
+ @init_modes = [:guess]
107
+ @override_modes = [:env]
108
+ @no_write = false
109
+ @modified = false
110
+ @no_action_list = ["distclean", "clobber", "clean"]
111
+ @no_action = false
112
+ @configured = false
113
+
114
+ yield self if block_given?
115
+
116
+ run_checklist([:default])
117
+ # we don't need to save our defaults
118
+ @modified = false
119
+ end
120
+
121
+ # Get the value for +key+ from +checklist+ or +nil+ if there
122
+ # isn't a check with the given +key+.
123
+ def [](key)
124
+ c = checklist.find { |c| c.key == key }
125
+ c ? c.value : nil
126
+ end
127
+
128
+ # Creates new check with default value if key doesn't exist.
129
+ def []=(key, val)
130
+ c = checklist.find { |c| c.key == key }
131
+ if c
132
+ if c.value != val
133
+ c.value = val
134
+ @modified = true
135
+ end
136
+ else
137
+ self.check(key) { |c|
138
+ c.default val
139
+ }
140
+ end
141
+ end
142
+
143
+ # Sets the specified check if a check with the given key
144
+ # exists.
145
+ # Returns the value if it was set, nil otherwise.
146
+ def set_if_exists(key, value)
147
+ c = checklist.find { |c| c.key == key }
148
+ if c
149
+ c.value = value
150
+ @modified = true
151
+ else
152
+ nil
153
+ end
154
+ end
155
+
156
+ # Builds a hash with all key-value pairs from checklist.
157
+ def data
158
+ hsh = {}
159
+ @checklist.each { |c|
160
+ hsh[c.key] = c.value
161
+ }
162
+ hsh
163
+ end
164
+
165
+ # This is true, if either a configure task was run, or the
166
+ # configuration file was read.
167
+ def configured?
168
+ @configured
169
+ end
170
+
171
+ # Define a task with +name+ that will run the configuration
172
+ # process in the given +check_modes+. If no task name is given
173
+ # or it is +nil+, the plugin name will be used as task name.
174
+ def task(name = nil, check_modes = [:guess, :interact])
175
+ name ||= @name
176
+ cinf = ::Rant::Lib.parse_caller_elem(caller[0])
177
+ file = cinf[:file]
178
+ ln = cinf[:ln] || 0
179
+ if !Array === check_modes || check_modes.empty?
180
+ @app.abort(@app.pos_text(file, ln),
181
+ "check_modes given to configure task has to be an array",
182
+ "containing at least one CHECK_MODE symbol")
183
+ end
184
+ check_modes.each { |cm|
185
+ unless CHECK_MODES.include? cm
186
+ @app.abort(@app.pos_text(file,ln),
187
+ "Unknown checkmode `#{cm.to_s}'.")
188
+ end
189
+ }
190
+ nt = @app.task(name) { |t|
191
+ run_checklist(check_modes)
192
+ save
193
+ @configured = true
194
+ }
195
+ nt
196
+ end
197
+
198
+ def check(key, val = nil, &block)
199
+ checklist << ConfigureCheck.new(key, val, &block)
200
+ end
201
+
202
+ # Run the configure process in the given modes.
203
+ def run_checklist(modes = [:guess, :interact])
204
+ @checklist.each { |c|
205
+ c.run_check(modes)
206
+ }
207
+ @modified = true
208
+ end
209
+
210
+ # Write configuration if modified.
211
+ def save
212
+ return if @no_write
213
+ write_yaml if @modified
214
+ true
215
+ end
216
+
217
+ # Immediately write configuration to +file+.
218
+ def write
219
+ write_yaml
220
+ @modified = false
221
+ end
222
+
223
+ ###### overriden plugin methods ##############################
224
+ def rant_plugin_type
225
+ "configure"
226
+ end
227
+
228
+ def rant_plugin_name
229
+ @name
230
+ end
231
+
232
+ def rant_plugin_init
233
+ @no_action = @no_action_list.include? @app.cmd_targets.first
234
+ @no_action || init_config
235
+ end
236
+
237
+ def rant_plugin_stop
238
+ @no_action || save
239
+ end
240
+ ##############################################################
241
+
242
+ private
243
+
244
+ # Returns true on success, nil on failure.
245
+ def init_config
246
+ if File.exist? @file
247
+ read_yaml
248
+ @configured = true
249
+ elsif !@init_modes == [:default]
250
+ run_checklist @init_modes
251
+ end
252
+ if @override_modes && !@override_modes.empty?
253
+ run_checklist @override_modes
254
+ end
255
+ end
256
+
257
+ def write_yaml
258
+ @app.msg 1, "Writing config to `#{@file}'."
259
+ File.open(@file, "w") { |f|
260
+ f << data.to_yaml
261
+ f << "\n"
262
+ }
263
+ true
264
+ rescue
265
+ @app.abort("When writing configuration: " + $!.message,
266
+ "Ensure writing to file (doesn't need to exist) `#{@file}'",
267
+ "is possible and try to reconfigure!")
268
+ end
269
+
270
+ def read_yaml
271
+ File.open(@file) { |f|
272
+ YAML.load_documents(f) { |doc|
273
+ if doc.is_a? Hash
274
+ doc.each_pair { |k, v|
275
+ self[k] = v
276
+ }
277
+ else
278
+ @app.abort("Invalid config file `#{@file}'.",
279
+ "Please remove this file or reconfigure.")
280
+ end
281
+ }
282
+ }
283
+ rescue
284
+ @app.abort("When attempting to read config: " + $!.message)
285
+ end
286
+
287
+ end # class Configure
288
+ class ConfigureCheck
289
+ include ::Rant::Console
290
+
291
+ public :msg, :prompt, :ask_yes_no
292
+
293
+ attr_reader :key
294
+ attr_accessor :value
295
+ attr_writer :default
296
+ attr_accessor :guess_block
297
+ attr_accessor :interact_block
298
+ attr_accessor :react_block
299
+ def initialize(key, val = nil)
300
+ @key = key or raise ArgumentError, "no key given"
301
+ @value = @default = val
302
+ @guess_block = nil
303
+ @interact_block = nil
304
+ @react_block = nil
305
+ yield self if block_given?
306
+ end
307
+ def default(val)
308
+ @default = val
309
+ @value = @default if @value.nil?
310
+ end
311
+ def guess(&block)
312
+ @guess_block = block
313
+ end
314
+ def interact(&block)
315
+ @interact_block = block
316
+ end
317
+ def react(&block)
318
+ @react_block = block
319
+ end
320
+
321
+ # Run checks as specified by +modes+. +modes+ has to be a list
322
+ # of symbols from the Configure::CHECK_MODES.
323
+ def run_check(modes = [:guess], env = ENV)
324
+ val = nil
325
+ modes.each { |mode|
326
+ case mode
327
+ when :default
328
+ val = @default
329
+ when :env
330
+ val = env[@key]
331
+ when :interact
332
+ val = @interact_block[self] if @interact_block
333
+ when :guess
334
+ val = @guess_block[self] if @guess_block
335
+ else
336
+ raise "unknown configure mode"
337
+ end
338
+ break unless val.nil?
339
+ }
340
+ val.nil? or @value = val
341
+ @react_block && @react_block[@value]
342
+ @value
343
+ end
344
+ end # class ConfigureCheck
345
+ end # module Rant::Plugin