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,275 @@
1
+
2
+ # C# plugin for Rant.
3
+
4
+ require 'rant/plugin_methods'
5
+ require 'rant/cs_compiler'
6
+
7
+ module Rant
8
+
9
+ class Generators::Assembly < CsCompiler
10
+ class << self
11
+
12
+ def rant_generate(app, clr, args, &block)
13
+ assembly = self.new(&block)
14
+ if args.size == 1
15
+ targ = args.first
16
+ # embed caller information for correct resolving
17
+ # of source Rantfile
18
+ if targ.is_a? Hash
19
+ targ[:__caller__] = clr
20
+ else
21
+ targ = { :__caller__ => clr, targ => [] }
22
+ end
23
+ app.prepare_task(targ, nil) { |name,pre,blk|
24
+ assembly.out = name
25
+ t = AssemblyTask.new(app, assembly, &block)
26
+ # TODO: optimize
27
+ pre.each { |e| t << e }
28
+ t
29
+ }
30
+ else
31
+ cinf = ::Rant::Lib.parse_caller_elem(clr)
32
+ app.abort(app.pos_text(cinf[:file], cinf[:ln]),
33
+ "Assembly takes one argument, " +
34
+ "which should be like one given to the `task' command.")
35
+ end
36
+ end
37
+
38
+ def csc
39
+ @csc
40
+ end
41
+ def csc= new_csc
42
+ case new_csc
43
+ when CsCompiler
44
+ @csc = new_csc
45
+ when String
46
+ @csc = CsCompiler.new(
47
+ CsCompiler.cs_compiler_name(new_csc))
48
+ @csc.csc_bin = new_csc
49
+ when nil
50
+ @csc = nil
51
+ else
52
+ self.csc = new_csc.to_s
53
+ end
54
+ @csc
55
+ end
56
+ end
57
+ @csc = nil
58
+
59
+ # Maybe:
60
+ # ["object"]
61
+ # Compile to object code. Not *that* usual for .NET.
62
+ # ["dll"]
63
+ # Create a shared library (also called DLL).
64
+ # ["exe"]
65
+ # Create an executable.
66
+ attr_accessor :target
67
+
68
+ def initialize(comp = nil, &init_block)
69
+ super()
70
+ @target = nil
71
+ @init_block = init_block
72
+ take_common_attrs comp if comp
73
+ end
74
+
75
+ # Synonym for +out+.
76
+ def name
77
+ out
78
+ end
79
+
80
+ # Synonym for +out=+.
81
+ def name=(new_name)
82
+ out = new_name
83
+ end
84
+
85
+ # Take common attributes like +optimize+, +csc+ and similar
86
+ # from the compiler object +comp+.
87
+ def take_common_attrs comp
88
+ @csc_name = comp.csc_name
89
+ @long_name = comp.long_name
90
+ @csc = comp.csc
91
+ @debug = comp.debug
92
+ comp.defines.each { |e|
93
+ @defines << e unless @defines.include? e
94
+ }
95
+ comp.lib_link_pathes.each { |e|
96
+ @lib_link_pathes << e unless @lib_link_pathes.include? e
97
+ }
98
+ @optimize = comp.optimize
99
+ @warnings = comp.warnings
100
+ # TODO: we currently take unconditionally all misc- and
101
+ # compiler specific args
102
+ comp.misc_args.each { |e|
103
+ @misc_args << e unless @misc_args.include? e
104
+ }
105
+ comp.specific_args.each_pair { |k,v|
106
+ # k is a compiler name, v is a list of arguments
107
+ # specific to this compiler type.
108
+ cst = @specific_args[k]
109
+ unless cst
110
+ @specific_args[k] = v
111
+ next
112
+ end
113
+ v.each { |e|
114
+ cst << e unless cst.include? e
115
+ }
116
+ }
117
+ end
118
+
119
+ # Call the initialization block and intialize compiler
120
+ # interface.
121
+ def init
122
+ # setup compiler interface
123
+ comp = Plugin::Csharp.csc_for_assembly(self) || self.class.csc
124
+ take_common_attrs comp if comp
125
+
126
+ # call initialization block
127
+ @init_block[self] if @init_block
128
+
129
+ # set target type
130
+ unless @target
131
+ @target = case @out
132
+ when /\.exe$/i: "exe"
133
+ when /\.dll$/i: "dll"
134
+ when /\.obj$/i: "object"
135
+ else "exe"
136
+ end
137
+ end
138
+ # TODO: verify some attributes like @target
139
+ end
140
+
141
+ def compile
142
+ ::Rant::Sys.sh(self.send("cmd_" + @target))
143
+ end
144
+
145
+ end # class Generators::Assembly
146
+
147
+ class AssemblyTask < FileTask
148
+ def initialize(app, assembly)
149
+ @assembly = assembly
150
+ super(app, @assembly.out) { |t|
151
+ app.context.instance_eval {
152
+ sys.sh assembly.send("cmd_" + assembly.target)
153
+ }
154
+ }
155
+ end
156
+ def resolve_prerequisites
157
+ @assembly.init
158
+ @pre.concat(@assembly.sources)
159
+ @pre.concat(@assembly.resources) if @assembly.resources
160
+ super
161
+ end
162
+ ### experimental ###
163
+ def invoke(force = false)
164
+ @assembly.init
165
+ @pre.concat(@assembly.sources)
166
+ @pre.concat(@assembly.resources) if @assembly.resources
167
+ super
168
+ end
169
+ ####################
170
+ end
171
+ end # module Rant
172
+
173
+ module Rant::Plugin
174
+
175
+ # This plugin class is currently designed to be instantiated only
176
+ # once with +rant_plugin_new+.
177
+ class Csharp
178
+ include ::Rant::PluginMethods
179
+
180
+ @plugin_object = nil
181
+ class << self
182
+
183
+ def rant_plugin_new(app, cinf, *args, &block)
184
+ if args.size > 1
185
+ app.abort(app.pos_text(cinf[:file], cinf[:ln]),
186
+ "Csharp plugin takes only one argument.")
187
+ end
188
+ self.new(app, args.first, &block)
189
+ end
190
+
191
+ attr_accessor :plugin_object
192
+
193
+ def csc_for_assembly(task)
194
+ if @plugin_object
195
+ @plugin_object.csc_for_assembly(task)
196
+ else
197
+ nil
198
+ end
199
+ end
200
+ end
201
+
202
+ # Shortcut for rant_plugin_name.
203
+ attr_reader :name
204
+ # A "configure" plugin.
205
+ attr_accessor :config
206
+ # A compiler interface with settings resulting from config.
207
+ attr_reader :config_csc
208
+
209
+ def initialize(app, name = nil)
210
+ @name = name || rant_plugin_type
211
+ @app = app or raise ArgumentError, "no application given"
212
+ @config_csc = nil
213
+ @config = nil
214
+
215
+ self.class.plugin_object = self
216
+
217
+ yield self if block_given?
218
+
219
+ define_config_checks
220
+ end
221
+
222
+ def csc_for_assembly(assembly)
223
+ @config_csc ||= csc_from_config
224
+ @config_csc.nil? ? nil : @config_csc.dup
225
+ end
226
+
227
+ def define_config_checks
228
+ return unless @config
229
+ @config.check "csc" do |c|
230
+ c.default "cscc"
231
+ c.guess {
232
+ Rant::CsCompiler.look_for_cs_compiler
233
+ }
234
+ c.interact {
235
+ c.prompt "Command to invoke your C# Compiler: "
236
+ }
237
+ c.react {
238
+ c.msg "Using `#{c.value}' as C# compiler."
239
+ }
240
+ end
241
+ @config.check "csc-optimize" do |c|
242
+ c.default true
243
+ c.interact {
244
+ c.ask_yes_no "Optimize C# compilation?"
245
+ }
246
+ end
247
+ @config.check "csc-debug" do |c|
248
+ c.default false
249
+ c.interact {
250
+ c.ask_yes_no "Compile C# sources for debugging?"
251
+ }
252
+ end
253
+ end
254
+
255
+ def csc_from_config
256
+ return nil unless @config
257
+ return nil unless @config.configured?
258
+ csc_bin = @config["csc"]
259
+ csc = Rant::CsCompiler.new
260
+ csc.csc = csc_bin
261
+ csc.optimize = @config["csc-optimize"]
262
+ csc.debug = @config["csc-debug"]
263
+ csc
264
+ end
265
+
266
+ ###### methods override from PluginMethods ###################
267
+ def rant_plugin_type
268
+ "csharp"
269
+ end
270
+ def rant_plugin_name
271
+ @name
272
+ end
273
+ ##############################################################
274
+ end # class Csharp
275
+ end # module Rant::Plugin
@@ -0,0 +1,41 @@
1
+
2
+ require 'rant/rantlib'
3
+
4
+ # This module defines all instance methods required for an Rant
5
+ # plugin. Additionally, each plugin class has to define the class
6
+ # method +plugin_create+.
7
+ #
8
+ # Include this module in your plugin class to ensure your plugin won't
9
+ # break when Rant requires new methods.
10
+ module Rant::PluginMethods
11
+ # The type of your plugin as string.
12
+ def rant_plugin_type
13
+ "rant plugin"
14
+ end
15
+ # Please override this method. This is used as a name for your
16
+ # plugin instance.
17
+ def rant_plugin_name
18
+ "rant plugin object"
19
+ end
20
+ # This is used for verification. Usually you don't want to change
21
+ # this for your plugin :-)
22
+ def rant_plugin?
23
+ true
24
+ end
25
+ # Called immediately after registration.
26
+ def rant_plugin_init
27
+ end
28
+ # Called before rant runs the first task.
29
+ def rant_start
30
+ end
31
+ # Called when rant *successfully* processed all required tasks.
32
+ def rant_done
33
+ end
34
+ # You should "shut down" your plugin as response to this method.
35
+ def rant_plugin_stop
36
+ end
37
+ # Called immediately before the rant application return control to
38
+ # the caller.
39
+ def rant_quit
40
+ end
41
+ end # module Rant::PluginMethods
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rbconfig'
4
+
5
+ module Rant end
6
+
7
+ class Rant::Path
8
+ attr_reader :path
9
+ def initialize path, abs_path = nil
10
+ @path = path or raise ArgumentError, "path not given"
11
+ @abs_path = abs_path
12
+ end
13
+ def to_s
14
+ @path.dup
15
+ end
16
+ def to_str
17
+ @path.dup
18
+ end
19
+ def exist?
20
+ File.exist? @path
21
+ end
22
+ def file?
23
+ test ?f, @path
24
+ end
25
+ def dir?
26
+ test ?d, @path
27
+ end
28
+ def mtime
29
+ File.mtime @path
30
+ end
31
+ def absolute_path
32
+ @abs_path ||= File.expand_path(@path)
33
+ end
34
+ end
35
+
36
+ # This module provides some platform indenpendant
37
+ # (let's hope) environment information.
38
+ module Rant::Env
39
+ OS = ::Config::CONFIG['target']
40
+ RUBY = ::Config::CONFIG['ruby_install_name']
41
+
42
+ @@zip_bin = false
43
+ @@tar_bin = false
44
+
45
+ def on_windows?
46
+ OS =~ /mswin/i
47
+ end
48
+
49
+ def have_zip?
50
+ if @@zip_bin == false
51
+ @@zip_bin = find_bin "zip"
52
+ end
53
+ !@@zip_bin.nil?
54
+ end
55
+
56
+ def have_tar?
57
+ if @@tar_bin == false
58
+ @@tar_bin = find_bin "tar"
59
+ end
60
+ !@@tar_bin.nil?
61
+ end
62
+
63
+ # Get an array with all pathes in the PATH
64
+ # environment variable.
65
+ def pathes
66
+ # Windows doesn't care about case in environment variables,
67
+ # but the ENV hash does!
68
+ path = on_windows? ? ENV["Path"] : ENV["PATH"]
69
+ return [] unless path
70
+ if on_windows?
71
+ path.split(";")
72
+ else
73
+ path.split(":")
74
+ end
75
+ end
76
+
77
+ # Searches for bin_name on path and returns
78
+ # an absolute path if successfull or nil
79
+ # if an executable called bin_name couldn't be found.
80
+ def find_bin bin_name
81
+ if on_windows?
82
+ bin_name_exe = nil
83
+ if bin_name !~ /\.[^\.]{1,3}$/i
84
+ bin_name_exe = bin_name + ".exe"
85
+ end
86
+ pathes.each { |dir|
87
+ file = File.join(dir, bin_name)
88
+ return file if test(?f, file)
89
+ if bin_name_exe
90
+ file = File.join(dir, bin_name_exe)
91
+ return file if test(?f, file)
92
+ end
93
+ }
94
+ else
95
+ pathes.each { |dir|
96
+ file = File.join(dir, bin_name)
97
+ return file if test(?x, file)
98
+ }
99
+ end
100
+ nil
101
+ end
102
+
103
+ # Add quotes to a path and replace File::Separators if necessary.
104
+ def shell_path path
105
+ # TODO: check for more characters when deciding wheter to use
106
+ # quotes.
107
+ if on_windows?
108
+ path = path.tr("/", "\\")
109
+ if path.include? ' '
110
+ '"' + path + '"'
111
+ else
112
+ path
113
+ end
114
+ else
115
+ if path.include? ' '
116
+ "'" + path + "'"
117
+ else
118
+ path
119
+ end
120
+ end
121
+ end
122
+
123
+ extend self
124
+ end # module Rant::Env
125
+
126
+ module Rant::Console
127
+ RANT_PREFIX = "rant: "
128
+ ERROR_PREFIX = "[ERROR] "
129
+ WARN_PREFIX = "[WARNING] "
130
+ def msg_prefix
131
+ if defined? @msg_prefix and @msg_prefix
132
+ @msg_prefix
133
+ else
134
+ RANT_PREFIX
135
+ end
136
+ end
137
+ def msg *text
138
+ pre = msg_prefix
139
+ text = text.join("\n" + ' ' * pre.length)
140
+ $stderr.puts(pre + text)
141
+ end
142
+ def err_msg *text
143
+ pre = msg_prefix + ERROR_PREFIX
144
+ text = text.join("\n" + ' ' * pre.length)
145
+ $stderr.puts(pre + text)
146
+ end
147
+ def warn_msg *text
148
+ pre = msg_prefix + WARN_PREFIX
149
+ text = text.join("\n" + ' ' * pre.length)
150
+ $stderr.puts(pre + text)
151
+ end
152
+ def ask_yes_no text
153
+ $stderr.print msg_prefix + text + " [y|n] "
154
+ case $stdin.readline
155
+ when /y|yes/i: true
156
+ when /n|no/i: false
157
+ else
158
+ $stderr.puts(' ' * msg_prefix.length +
159
+ "Please answer with `yes' or `no'")
160
+ ask_yes_no text
161
+ end
162
+ end
163
+ def prompt text
164
+ $stderr.print msg_prefix + text
165
+ input = $stdin.readline
166
+ input ? input.chomp : input
167
+ end
168
+ def option_listing opts
169
+ rs = ""
170
+ opts.each { |lopt, *opt_a|
171
+ if opt_a.size == 2
172
+ # no short option
173
+ mode, desc = opt_a
174
+ else
175
+ sopt, mode, desc = opt_a
176
+ end
177
+ next unless desc # "private" option
178
+ optstr = ""
179
+ arg = nil
180
+ if mode == GetoptLong::REQUIRED_ARGUMENT
181
+ if desc =~ /(\b[A-Z_]{2,}\b)/
182
+ arg = $1
183
+ end
184
+ end
185
+ if lopt
186
+ optstr << lopt
187
+ if arg
188
+ optstr << " " << arg
189
+ end
190
+ optstr = optstr.ljust(30)
191
+ end
192
+ if sopt
193
+ optstr << " " unless optstr.empty?
194
+ optstr << sopt
195
+ if arg
196
+ optstr << " " << arg
197
+ end
198
+ end
199
+ rs << " #{optstr}\n"
200
+ rs << " #{desc.split("\n").join("\n ")}\n"
201
+ }
202
+ rs
203
+ end
204
+
205
+ extend self
206
+ end
207
+
208
+ class Rant::CustomConsole
209
+ include Rant::Console
210
+
211
+ def initialize msg_prefix = RANT_PREFIX
212
+ @msg_prefix = msg_prefix || ""
213
+ end
214
+ def msg_prefix=(str)
215
+ @msg_prefix = str || ""
216
+ end
217
+ end