rakish 0.9.01.beta

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.
@@ -0,0 +1,539 @@
1
+ myPath = File.dirname(File.expand_path(__FILE__));
2
+ require "#{myPath}/Rakish.rb"
3
+ require "#{myPath}/BuildConfig.rb"
4
+
5
+ module Rakish
6
+
7
+ # Mostly internal singleton for Rakish.Project[link:./Rakish.html#method-c-Project] and
8
+ # Rakish.Configuration[link:./Rakish.html#method-c-Configuration] loading and management
9
+ class Build
10
+ include Rakish::Util
11
+
12
+ def initialize # :nodoc:
13
+ @startTime = Time.new
14
+
15
+ @projects=[]
16
+ @projectsByModule={}
17
+ @projectsByFile={} # each entry is an array of one or more projects
18
+ @configurationsByName={}
19
+
20
+
21
+ task :resolve do |t|
22
+ if(defined? Rakish::GlobalConfig.instance.nativeConfigName)
23
+ log.info "Starting build. for #{Rakish::GlobalConfig.instance.nativeConfigName}\""
24
+ else
25
+ # if(Rakish::GlobalConfig.instance)
26
+ # Rakish::GlobalConfig.instance.nativeConfigName() = "not set";
27
+ # end
28
+ log.info "Starting build.";
29
+ end
30
+ @projects.each do |p|
31
+ p.preBuild
32
+ p.resolveExports
33
+ end
34
+ end
35
+
36
+ task :_end_ do |t|
37
+ onComplete();
38
+ end
39
+
40
+ Rake.application.top_level_tasks.insert(0,:resolve);
41
+ Rake.application.top_level_tasks << :_end_;
42
+ end
43
+
44
+ def verbose? # :nodoc:
45
+ true
46
+ end
47
+
48
+ # Called when the rake invocation of thie Rakish::Build is complete.
49
+ # Prints a log.info message of the time taken to execute this invocation of 'rake'.
50
+ def onComplete
51
+ dtime = Time.new.to_f - @startTime.to_f;
52
+ ztime = (Time.at(0).utc) + dtime;
53
+ puts(ztime.strftime("Build complete in %H:%M:%S:%3N"))
54
+ end
55
+
56
+ def registerProject(p) # :nodoc: internal used by projects to register themselves wheninitialized
57
+ pname = p.moduleName;
58
+ if(@projectsByModule[pname])
59
+ raise("Error: project \"#{pname}\" already registered")
60
+ end
61
+ @projects << p;
62
+ @projectsByModule[pname]=p;
63
+ (@projectsByFile[p.projectFile]||=[]).push(p);
64
+ end
65
+
66
+ def registerConfiguration(c) # :nodoc: internal used by configurations to register themselves when initialized
67
+ if(@configurationsByName[c.name])
68
+ raise("Error: configuration \"#{c.name}\" already registered");
69
+ end
70
+ @configurationsByName[c.name]=c;
71
+ end
72
+
73
+ # Retrieve an initialized Rakish.Configuration[link:./Rakish.html#method-c-Configuration] by name.
74
+ # If name is nil retrieves the 'root' configuration
75
+ def configurationByName(name)
76
+ @configurationsByName[name||'root']
77
+ end
78
+
79
+ # Retrieve a Rakish.Project[link:./Rakish.html#method-c-Project] by the project name, nil if not found.
80
+ def projectByName(name)
81
+ @projectsByModule[name];
82
+ end
83
+
84
+ # load other project rakefiles from a project into the interpreter unless they have already been loaded
85
+ # selects namespace appropriately
86
+ # returns array of all projects referenced directly by this load
87
+
88
+ def loadProjects(*args) # :nodoc: knternal called by RakishProject to load dependencies.
89
+
90
+ rakefiles = FileSet.new(args);
91
+ projs=[];
92
+ FileUtils.cd File.expand_path(pwd) do;
93
+ namespace ':' do
94
+ lastpath = '';
95
+ begin
96
+ rakefiles.each do |path|
97
+
98
+ lastpath = path;
99
+ projdir = nil;
100
+
101
+ if(File.directory?(path))
102
+ projdir = path;
103
+ path = File.join(projdir,'rakefile.rb');
104
+ else
105
+ projdir = File.dirname(path);
106
+ end
107
+
108
+ FileUtils.cd(projdir) do
109
+ if(require(path))
110
+ # puts "project #{path} loaded" if verbose?
111
+ end
112
+ end
113
+ projs |= @projectsByFile[path];
114
+ end
115
+ rescue LoadError => e
116
+ log.error("#{e}");
117
+ raise e;
118
+ end
119
+ end # namespace
120
+ end # cd
121
+ projs
122
+ end
123
+ end
124
+
125
+ # --------------------------------------------------------------------------
126
+ # Rakish module singleton methods added for Rakish::Project handling.
127
+ #
128
+
129
+
130
+ class << self
131
+ # Retrieve the process' singleton instance of the root Rakish::Build for this rake invocation.
132
+ def build
133
+ @application ||= Rakish::Build.new
134
+ end
135
+
136
+ # Retrieve a Rakish::Project by the project name.
137
+ # calls Rakish::build.projectByName(name)
138
+ def projectByName(name)
139
+ @application.projectByName(name)
140
+ end
141
+ end
142
+
143
+ # Base class for all Rakish.[Projects]
144
+ # Create subclasses of this using Rakish.Project
145
+ class ProjectBase < BuildConfig
146
+ include Rakish::Util
147
+
148
+ # initialize "static" class variables
149
+
150
+ @@globalTargets = Set.new;
151
+
152
+ [
153
+ :default,
154
+ :autogen,
155
+ :cleanautogen,
156
+ :includes,
157
+ :cleanincludes,
158
+ :depends,
159
+ :cleandepends,
160
+ :build,
161
+ :compile,
162
+ :clean,
163
+ :vcproj,
164
+ :vcprojclean
165
+ ].each do |gt|
166
+ @@globalTargets.add(gt);
167
+ task gt;
168
+ end
169
+
170
+ protected
171
+
172
+ # Create a task that will execute all it's actions in the directory and namespace of the
173
+ # creating project
174
+ # it will only set the project scope ONCE upon the first call
175
+ def taskInScope(*args,&block)
176
+ Rake::Task.define_task(*args, &block).setProjectScope(self);
177
+ end
178
+
179
+ # Create a FileTask which will execute all actions in the directory and namespace of this project
180
+ # it will only set the project scope ONCE upon the first call
181
+ def fileInDir(*args, &block)
182
+ Rake::FileTask.define_task(*args, &block).setProjectScope(self);
183
+ end
184
+
185
+ # Called before user supplied initializer block is executed
186
+ # in the project's directory and namespace
187
+ def initProject(args) #
188
+ end
189
+
190
+ public
191
+
192
+ # When called from within a project, exports a namespace internal task to
193
+ # a global task by the same name as the task within the projects namespace.
194
+ # not safe if called on a task outside the project's namespace
195
+ # returns the task that is exported if the input argument is a task.
196
+ # example:
197
+ # exportedTask = export task :aTask => [ :prerequisite ] do |t|
198
+ # log.debug("invoking #{t.name}");
199
+ # end
200
+ def export(name, &b)
201
+
202
+ exported = name;
203
+ if(name.is_a? Rake::Task)
204
+ if(block_given?)
205
+ # this to cover for ruby argument parsing and precidence
206
+ # so you don't have to add parentheses around the task declaraton
207
+ # as in: export (task => [prereq] do |t| { blah blah });
208
+ name.actions << b;
209
+ end
210
+ name = name.to_s().sub("#{myNamespace}:",'').to_sym;
211
+ else
212
+ # TODO: look up actual task and set exported to it for return value.
213
+ name = name.to_sym;
214
+ exported = nil
215
+ end
216
+
217
+ if(exported.is_a? Rake::FileTask)
218
+ log.warn("attempt to export FileTask #{name.name}");
219
+ return exported;
220
+ end
221
+
222
+ @exported_ ||= Set.new;
223
+ if(@exported_.add?(name))
224
+ namespace(':') do
225
+ task name;
226
+ end
227
+ end
228
+ return(exported);
229
+ end
230
+
231
+ task :default => [ :build ];
232
+ task :rebuild => [ :cleandepends, :depends, :clean, :build ];
233
+
234
+ # returns the Rake task namespace for this project
235
+ attr_reader :myNamespace
236
+ alias :moduleName :myNamespace
237
+
238
+ # full path of the file containing this project
239
+ attr_reader :projectFile
240
+ # directory containing the file for this project
241
+ attr_reader :projectDir
242
+ # name of this project
243
+ attr_reader :myName
244
+ # package name for this project
245
+ attr_reader :myPackage
246
+ # UUID of this project
247
+ attr_reader :projectId
248
+ # list of projects specified that this is dependent on ( not recursive - only direct dependencies )
249
+ attr_reader :dependencies
250
+
251
+ # Get intermediate output directory for this module common to all configurations
252
+ def nativeObjDir
253
+ @nativeObjDir||="#{getAnyAbove(:nativeObjDir)}/#{moduleName()}";
254
+ end
255
+
256
+ # Get directory containing the file for this project
257
+ attr_property :projectObjectPath
258
+
259
+ # Get configuration specific intermediate output directory
260
+ def nativeObjectPath
261
+ @nativeObjectPath||="#{nativeObjDir()}/#{nativeConfigName()}";
262
+ end
263
+
264
+ # return self for inheriting PropertyBag configurations
265
+ def project
266
+ self
267
+ end
268
+
269
+ def addProjectDependencies(*args) # :nodoc: not used anywhere at present
270
+ # NOTE: for some unknown reason when this is called from initialize exception handling is
271
+ # somehow screwed up so we don't call it from there.
272
+ begin
273
+ projs = @build.loadProjects(*args);
274
+ if(@dependencies)
275
+ @dependencies = @dependencies + (projs - @dependencies);
276
+ else
277
+ @dependencies = projs;
278
+ end
279
+ rescue LoadError=>e
280
+ log.error("dependency not found in #{myFile}: #{e}");
281
+ raise e
282
+ end
283
+ end
284
+
285
+ # Add file or files to be deleted in the :clean task
286
+ # used by task builder modules included in a project
287
+ def addCleanFiles(*args)
288
+ unless(@cleanFiles_)
289
+ @cleanFiles_ = FileSet.new(*args);
290
+ task :clean do |t|
291
+ deleteFiles(@cleanFiles_)
292
+ end
293
+ else
294
+ @cleanFiles_.include(*args)
295
+ end
296
+ end
297
+
298
+ # Add a directory to be removed upon ":clean"
299
+ # used by task builder modules included in a project
300
+ def addCleanDir(name)
301
+ name = File.expand_path(name);
302
+ task :clean do |t|
303
+ rm_rf(name);
304
+ end
305
+ end
306
+
307
+
308
+ # Create a new project
309
+ #
310
+ # <b>named args:</b>
311
+ #
312
+ # :name => name of this project, defaults to parent directory name
313
+ # :package => package name for this project defaults to nothing
314
+ # :config => explicit parent configuration, defaults to the GlobalConfig
315
+ # :dependsUpon => array of project directories or specific rakefile paths this project
316
+ # depends upon
317
+ # :id => uuid to assign to project in "uuid string format"
318
+ # '2CD0548E-6945-4b77-83B9-D0993009CD75'
319
+ #
320
+ # &block is always yielded to in the directory of the projects file, and the
321
+ # Rake namespace of the new project (project scope), and called in the project instance's context
322
+
323
+ def initialize(args={},&block) # :nodoc:
324
+
325
+ # derive path to file declaring this project - from loaded file that
326
+ # called this initializer
327
+
328
+ @build = Rakish.build
329
+
330
+ myFile = nil
331
+ regex = Regexp.new(Regexp.escape(File.dirname(__FILE__)));
332
+ caller.each do |clr|
333
+ unless(clr =~ regex)
334
+ clr =~ /\:\d/
335
+ myFile = $`;
336
+ break;
337
+ end
338
+ end
339
+
340
+ # if(clr =~ /:in `<top \(required\)>'$/)
341
+ # $` =~ /:\d+$/
342
+ # myFile = File.expand_path($`)
343
+ # break
344
+ # end
345
+
346
+ fileDependencies = args[:dependsUpon] || Array.new;
347
+
348
+ parent = @build.configurationByName(args[:config]);
349
+
350
+ @projectFile = myFile
351
+ @projectDir = File.dirname(myFile)
352
+ @projectId = args[:id]
353
+
354
+ name = args[:name];
355
+ name ||= @projectDir.pathmap('%n') # namespace = projName for this Module
356
+ projName = name;
357
+ package = args[:package];
358
+ if(package)
359
+ projName = "#{package}-#{name}";
360
+ end
361
+ @myNamespace = projName
362
+ @myName = name;
363
+ @myPackage = package;
364
+
365
+ cd @projectDir, :verbose=>verbose? do
366
+
367
+ # load all project files this is dependent on relative to this project's directory
368
+ begin
369
+ @dependencies = @build.loadProjects(*fileDependencies);
370
+ rescue LoadError => e
371
+ log.error("dependency not found in #{myFile}: #{e}");
372
+ raise e
373
+ end
374
+
375
+ # call instance initializer block inside local namespace and project's directory.
376
+ # and in the directory the defining file is contained in.
377
+ ns = Rake.application.in_namespace(@myNamespace) do
378
+
379
+ # initialize properties from the parent configuration and initialize included modules.
380
+ super(parent,args) {}
381
+
382
+ if(RUBY_VERSION =~ /^2./)
383
+ @myNamespace = Rake.application.current_scope.path;
384
+ else
385
+ @myNamespace = "#{Rake.application.current_scope.join(':')}"
386
+ end
387
+
388
+ initProject(args);
389
+ instance_eval(&block) if block;
390
+
391
+ end
392
+
393
+ # register this project after the initialization has loaded all
394
+ # the other dependencies for proper dependency initialization order
395
+ @build.registerProject(self);
396
+ end
397
+ end
398
+
399
+ # link global tasks to this project's tasks if they are defined and set as exported
400
+ def resolveExports # :nodoc:
401
+ targets = @exported_ || Set.new;
402
+ targets.merge(@@globalTargets);
403
+
404
+ targets.each do |gt|
405
+ tname = "rake:#{@myNamespace}:#{gt}"
406
+ tsk = Rake.application.lookup(tname);
407
+ # overide invoke_with_call_chain to print the exportend tasks as they are invoked
408
+ if(tsk)
409
+ tsk.instance_eval do
410
+ alias :_o_iwcc_ :invoke_with_call_chain
411
+ def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
412
+ unless @already_invoked
413
+ log.info("---- #{name()}")
414
+ end
415
+ _o_iwcc_(task_args, invocation_chain);
416
+ end
417
+ end
418
+ task gt => [ tname ];
419
+ end
420
+ end
421
+ end
422
+
423
+ # execute block inside this projects Rake namespace
424
+ # for use in tasks
425
+ def inMyNamespace(&block)
426
+ namespace(":#{@myNamespace}",&block)
427
+ end
428
+
429
+
430
+ # called after initializers on all projects and before rake
431
+ # starts executing tasks
432
+ def preBuild # :nodoc:
433
+ cd @projectDir, :verbose=>verbose? do
434
+ tname = "#{@myNamespace}:preBuild"
435
+ ns = Rake.application.in_namespace(@myNamespace) do
436
+ log.info("pre building #{@myNamespace}");
437
+ # optional project pre build task
438
+ doPreBuild = Rake.application.lookup(tname);
439
+ doPreBuild.invoke if doPreBuild;
440
+ end
441
+ end
442
+ end
443
+
444
+ # show projects scope for debuggin purposes.
445
+ def showScope(here='') # :nodoc:
446
+ log.info("#{here} #{@myNamespace} ns = :#{currentNamespace}");
447
+ end
448
+
449
+ end
450
+
451
+ @@projectClassesByIncluded_ = {}; # :nodoc:
452
+
453
+ protected
454
+
455
+ # Dynamically create a new anonymous class < Rakish::ProjectBase or get one from
456
+ # the cache withthe same base class and included module set if there is one.
457
+ #
458
+ # Maybe its senseless optimization but I wanted a freer dynamic project
459
+ # declaration system without having to explicitly create new classes with
460
+ # explicit names everywhere. I did learn something about Ruby however :)
461
+ # the "opts" can be the same ones that would be used as args{} for
462
+ # Rakish::ProjectBase.new and Rakish.Project[link:./Rakish.html#method-c-Project]
463
+ #
464
+ # named opts:
465
+ # :extends => Base class of the newly created class defaults to ProjectBase
466
+ # :includes => If provided, ProjectModules and other modules to "include" in this class.
467
+
468
+ def self.getProjectClass(opts={})
469
+
470
+ # get the base project type to extend the class from
471
+ # and get list of explicit modules to include
472
+ # eliminate duplicate modules, and sort the list.
473
+
474
+ extends = opts[:extends]||ProjectBase;
475
+
476
+ # if no explicit inclusions just return the class
477
+ return(extends) unless(included=opts[:includes]);
478
+
479
+ included.flatten!
480
+ if included.length > 1
481
+ # TODO: maybe get a list of all included modules and generate a hash
482
+ # TODO: but this likely not needed or won't make things faster
483
+ # TODO: not sure how ruby's string keys for hashes work.
484
+ included = Set.new(included).to_a();
485
+ included.sort! do |a,b|
486
+ a.to_s <=> b.to_s
487
+ end
488
+ end
489
+ key=[extends,included] # key is explicit definition of class
490
+
491
+ # if we already have created a class for the specific included set use it
492
+ unless projClass = @@projectClassesByIncluded_[key]
493
+ # otherwise create a new class and include the requested modules
494
+ # log.debug("new class including [#{included.join(',')}]");
495
+ projClass = Class.new(extends) do
496
+ included.each do |i|
497
+ include i;
498
+ end
499
+ end
500
+ @@projectClassesByIncluded_[key] = projClass;
501
+ end
502
+ projClass;
503
+ end
504
+
505
+ public
506
+
507
+ # Declare and create a new empty Project that subclasses Rakish::ProjectBase
508
+ #
509
+ # named args:
510
+ #
511
+ # :name => name of this project, defaults to parent directory name
512
+ # :package => package name for this project defaults to nothing
513
+ # :config => explicit parent configuration name, defaults to 'root'
514
+ # :dependsUpon => array of project directories or specific rakefile paths this project
515
+ # depends upon
516
+ # :id => uuid to assign to project in "uuid string format"
517
+ # '2CD0548E-6945-4b77-83B9-D0993009CD75'
518
+ # :includes => If provided, ProjectModules and other modules to "include" in this project.
519
+ #
520
+ # &b is always yielded to in the directory of the project's file, and the
521
+ # Rake namespace of the new project (project scope), and called in the project instance's context
522
+
523
+ def self.Project(args={},&b)
524
+ baseIncludes = args[:baseIncludes];
525
+ if(baseIncludes)
526
+ includes=[baseIncludes]
527
+ if(args[:includes])
528
+ includes << opts[:includes]
529
+ end
530
+ args[:includes]=includes
531
+ end
532
+ getProjectClass(args).new(args,&b)
533
+ end
534
+
535
+ # initialize the build application instance
536
+ Rakish.build
537
+
538
+ end # Rakish
539
+
@@ -0,0 +1,58 @@
1
+ myPath = File.dirname(File.expand_path(__FILE__));
2
+ require "#{myPath}/BuildConfig.rb"
3
+
4
+ module Rakish
5
+
6
+ # Nacent project inclusion module for invoking Rdoc
7
+ module RubydocModule
8
+ include BuildConfigModule
9
+
10
+ protected
11
+
12
+ addInitBlock do |pnt,opts|
13
+ if(pnt != nil)
14
+ end
15
+ end
16
+
17
+ class RubydocBuilder < BuildConfig
18
+ include RubydocModule
19
+
20
+
21
+ def doBuildRubydocs(t) # :nodoc:
22
+
23
+
24
+ cd "#{t.config.projectDir}/../lib/rakish" do
25
+ command = [ 'rdoc',
26
+ "--output=#{t.config.projectDir}/rdoc",
27
+ ];
28
+ execLogged(command);
29
+ end
30
+
31
+
32
+ end
33
+
34
+ # create task to invoke Rdoc to the specifications in this builder.
35
+ def rubydocTask
36
+ tsk = Rake::Task.define_unique_task &CreateRubydocAction;
37
+ tsk.config = self;
38
+ tsk
39
+ end
40
+
41
+ # action for rdoc task.
42
+ # :nodoc:
43
+ CreateRubydocAction = ->(t) do
44
+ t.config.doBuildRubydocs(t);
45
+ end
46
+
47
+ end
48
+
49
+ # Creates a RubydocBuilder for the including project's configuration
50
+ def createRubydocBuilder
51
+ RubydocBuilder.new(self);
52
+ end
53
+
54
+ public
55
+
56
+ end
57
+
58
+ end # Rakish
@@ -0,0 +1,45 @@
1
+ myPath = File.dirname(File.expand_path(__FILE__));
2
+ require "#{myPath}/JavaProjects.rb"
3
+
4
+ module Rakish
5
+
6
+
7
+ module TomcatProjectConfig
8
+ include JavaProjectConfig
9
+ end
10
+
11
+ module WarBuilderModule
12
+ include JarBuilderModule
13
+
14
+ class WarBuilder < JarBuilder
15
+ # create task for building jar file to specifications stored in builder.
16
+ def warFileTask(*args)
17
+ tsk = jarTask(*args);
18
+ tsk
19
+ end
20
+ end
21
+
22
+ def createWarBuilder
23
+ WarBuilder.new(self); # for now we make the parent project the parent config
24
+ end
25
+
26
+ end
27
+
28
+ module TomcatProjectModule
29
+ include TomcatProjectConfig
30
+ include WarBuilderModule
31
+
32
+ protected
33
+
34
+ addInitBlock do |pnt,opts|
35
+ if(pnt != nil)
36
+ @java_home = pnt.get(:java_home);
37
+ end
38
+ @java_home ||= File.expand_path(ENV['JAVA_HOME']);
39
+ end
40
+
41
+ public
42
+
43
+ end
44
+
45
+ end # Rakish