sprout 0.7.191-mswin32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sprout might be problematic. Click here for more details.

@@ -0,0 +1,466 @@
1
+ require 'rubygems'
2
+ require 'archive/tar/minitar'
3
+ require 'rake'
4
+ require 'rake/clean'
5
+
6
+ # This is a fix for Issue #106
7
+ # http://code.google.com/p/projectsprouts/issues/detail?id=106
8
+ # Which is created because the new version (1.0.1) of RubyGems
9
+ # includes open-uri, while older versions do not.
10
+ # When open-uri is included twice, we get a bunch of nasty
11
+ # warnings because constants are being overwritten.
12
+ if(Gem::Version.new(Gem::RubyGemsVersion) != Gem::Version.new('1.0.1'))
13
+ require 'open-uri'
14
+ end
15
+
16
+ $:.push(File.dirname(__FILE__))
17
+ require 'progress_bar'
18
+ require 'sprout/log'
19
+ require 'sprout/user'
20
+ require 'sprout/zip_util'
21
+ require 'sprout/remote_file_target'
22
+ require 'sprout/remote_file_loader'
23
+ require 'sprout/simple_resolver'
24
+ require 'sprout/template_resolver'
25
+
26
+ require 'rubygems/installer'
27
+ require 'rubygems/source_info_cache'
28
+ require 'rubygems/version'
29
+ require 'rubygems/digest/md5'
30
+
31
+ require 'sprout/project_model'
32
+ require 'sprout/builder'
33
+ require 'sprout/version'
34
+ require 'sprout/tasks/tool_task'
35
+ require 'sprout/general_tasks'
36
+
37
+ module Sprout
38
+ SUDO_INSTALL_GEMS = 'false' == ENV['SUDO_INSTALL_GEMS'] ? false : true
39
+
40
+ class SproutError < StandardError #:nodoc:
41
+ end
42
+
43
+ # Sprouts is an open-source, cross-platform project generation and configuration tool
44
+ # for ActionScript 2, ActionScript 3, Adobe AIR and Flex projects. It is built on top
45
+ # of Ruby Gems, Rubigen Generators and is intended to work on any platform that Ruby runs
46
+ # on including specifically, Windows XP, Windows Vista, Cygwin, OS X and Linux.
47
+ #
48
+ # Sprouts can be separated into some core concepts as follows:
49
+ #
50
+ # ----
51
+ # == Tools
52
+ # :include: ../doc/Tool
53
+ #
54
+ # ----
55
+ # == Libraries
56
+ # :include: ../doc/Library
57
+ #
58
+ # ----
59
+ # == Bundles
60
+ # :include: ../doc/Bundle
61
+ #
62
+ # ----
63
+ # == Generators
64
+ # :include: ../doc/Generator
65
+ #
66
+ # ----
67
+ # == Tasks
68
+ # :include: ../doc/Task
69
+ #
70
+ # ----
71
+ # == Sprout
72
+ #
73
+ # Tools, Libraries and Bundles are distributed as RubyGems and given a specific gem name suffix. For some examples:
74
+ # sprout-flex3sdk-tool
75
+ # sprout-asunit-library
76
+ # sprout-as3-bundle
77
+ #
78
+ # The Sprout application provides shared functionality for each of the different types of Sprouts.
79
+ #
80
+ # The Sprout command line tool primarily provides access to project generators from any sprout bundle that is available
81
+ # to your system, either locally or from the network.
82
+ #
83
+ # When executed from the system path, this class will download and install a named bundle, and execute a +project+
84
+ # generator within that bundle. Following is an example:
85
+ #
86
+ # sprout -n as3 SomeProject
87
+ #
88
+ # The previous command will download and install the latest version of the sprout-as3-bundle gem and initiate the
89
+ # project_generator with a single argument of 'SomeProject'. If the string passed to the -n parameter begins with
90
+ # 'sprout-' it will be unmodified for the lookup. For example:
91
+ #
92
+ # spout -n sprout-as3-bundle SomeProject
93
+ #
94
+ # will not have duplicate strings prepended or suffixed.
95
+ #
96
+ # ----
97
+ # Some additional resources or references:
98
+ #
99
+ # Rake:
100
+ # http://rake.rubyforge.org
101
+ # http://martinfowler.com/articles/rake.html
102
+ #
103
+ # RubyGems:
104
+ # * http://www.rubygems.org
105
+ # * http://www.linuxjournal.com/article/8967
106
+ #
107
+ # Ruby Raven (Mostly Inspiration)
108
+ # * http://raven.rubyforge.org
109
+ #
110
+ class Sprout
111
+ @@default_rakefiles = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
112
+
113
+ @@name = 'Sprouts'
114
+ @@cache = 'cache'
115
+ @@lib = 'lib'
116
+ @@spec = 'sprout.spec'
117
+ @@home = File.expand_path(File.dirname(File.dirname(__FILE__)))
118
+
119
+ # Execute a generator that is available locally or from the network.
120
+ # * +sprout_name+ A full gem name (ex., sprout-as3-bundle) that contains a generator that matches +generator_name+
121
+ # * +generator_name+ A string like 'project' or 'class' that maps to a generator
122
+ # * +params+ Arbitrary parameters to pass to the generator
123
+ # * +project_path+ Optional parameter. Will default to the nearest folder that contains a valid Rakefile.
124
+ # This Rakefile will usually be loaded by the referenced Generator, and it should have a configured ProjectModel
125
+ # defined in it.
126
+ def self.generate(sprout_name, generator_name, params, project_path=nil)
127
+ RubiGen::Base.use_sprout_sources!(sprout_name, project_path)
128
+ generator = RubiGen::Base.instance(generator_name, params)
129
+ generator.command(:create).invoke!
130
+ end
131
+
132
+ # Remove all installed RubyGems that begin with the string 'sprout' and clear the local sprout cache
133
+ def self.remove_all
134
+ # Set up sudo prefix if not on win machine
135
+ # Only show confirmation if there is at least one installed sprout gem
136
+ confirmation = false
137
+ count = 0
138
+ # For each sprout found, remove it!
139
+ RubiGen::GemGeneratorSource.new().each_sprout do |sprout|
140
+ count += 1
141
+ command = "#{get_gem_preamble} uninstall -x -a -i -q #{sprout.name}"
142
+
143
+ if(!confirmation)
144
+ break unless confirmation = remove_gems_confirmation
145
+ end
146
+ raise ">> Exited with errors: #{$?}" unless system(command)
147
+ end
148
+
149
+ if(confirmation)
150
+ puts "All Sprout gems have been successfully uninstalled"
151
+ elsif(count > 0)
152
+ puts "Some Sprout gems have been left on the system"
153
+ else
154
+ puts "No Sprout gems were found on this system"
155
+ end
156
+
157
+ # Now clear out the cache
158
+ cache = File.dirname(File.dirname(Sprout.sprout_cache))
159
+
160
+ if(File.exists?(cache))
161
+ puts "\n[WARNING]\n\nAbout to irrevocably destroy the sprout cache at:\n\n#{cache}\n\n"
162
+ puts "Are you absolutely sure? [Yn]"
163
+ response = $stdin.gets.chomp!
164
+ if(response.downcase.index('y'))
165
+ FileUtils.rm_rf(cache)
166
+ else
167
+ puts "Leaving the Sprout file cache in tact...."
168
+ end
169
+ else
170
+ puts "No cached files found on this system"
171
+ end
172
+
173
+ puts "To completely remove sprouts now, run:"
174
+ puts " #{get_gem_preamble} uninstall sprout"
175
+ end
176
+
177
+ # Build up the platform-specific preamble required
178
+ # to call the gem binary from Kernel.execute
179
+ def self.get_gem_preamble
180
+ usr = User.new()
181
+ if(!usr.is_a?(WinUser))
182
+ # Everyone but Win and Cygwin users get 'sudo '
183
+ return "#{SUDO_INSTALL_GEMS ? 'sudo ' : ''}gem"
184
+ elsif(!usr.is_a?(CygwinUser))
185
+ # We're in the DOS Shell
186
+ return "ruby #{get_executable_from_path('gem')}"
187
+ end
188
+ # We're either a CygwinUser or some other non-sudo supporter
189
+ return 'gem'
190
+ end
191
+
192
+ # Retrieve the full path to an executable that is
193
+ # available in the system path
194
+ def self.get_executable_from_path(exe)
195
+ path = ENV['PATH']
196
+ file_path = nil
197
+ path.split(get_path_delimiter).each do |p|
198
+ file_path = File.join(p, exe)
199
+ # file_path = file_path.split("/").join("\\")
200
+ # file_path = file_path.split("\\").join("/")
201
+ if(File.exists?(file_path))
202
+ return User.clean_path(file_path)
203
+ end
204
+ end
205
+ return nil
206
+ end
207
+
208
+ def self.get_path_delimiter
209
+ usr = User.new
210
+ if(usr.is_a?(WinUser) && !usr.is_a?(CygwinUser))
211
+ return ';'
212
+ else
213
+ return ':'
214
+ end
215
+ end
216
+
217
+ def self.remove_gems_confirmation
218
+ msg =<<EOF
219
+ About to uninstall all RubyGems that match 'sprout-'....
220
+ Are you sure you want to do this? [Yn]
221
+ EOF
222
+ puts msg
223
+ response = $stdin.gets.chomp!
224
+ if(response.downcase.index('y'))
225
+ return true
226
+ end
227
+ return false
228
+ end
229
+
230
+ # Retrieve the file target to an executable by sprout name. Usually, these are tool sprouts.
231
+ # * +name+ Full sprout gem name that contains an executable file
232
+ # * +archive_path+ Optional parameter for tools that contain more than one executable, or for
233
+ # when you don't want to use the default executable presented by the tool. For example, the Flex 2 SDK
234
+ # has many executables, when this method is called for them, one might use something like:
235
+ # Sprout::Sprout.get_executable('sprout-flex3sdk-tool', 'bin/mxmlc')
236
+ # * +version+ Optional parameter to specify a particular gem version for this executable
237
+ def self.get_executable(name, archive_path=nil, version=nil)
238
+ target = self.sprout(name, version)
239
+ if(archive_path)
240
+ # If caller sent in a relative path to an executable (e.g., bin/mxmlc), use it
241
+ exe = File.join(target.installed_path, archive_path)
242
+ if(User.new.is_a?(WinUser) && !archive_path.match(/.exe$/))
243
+ # If we're on Win (even Cygwin), add .exe to support custom binaries (see sprout-flex3sdk-tool)
244
+ exe << '.exe'
245
+ end
246
+ elsif(target.url)
247
+ # Otherwise, use the default path to an executable if the RemoteFileTarget has a url prop
248
+ exe = File.join(target.installed_path, target.archive_path)
249
+ else
250
+ # Otherwise attempt to run the feature from the system path
251
+ exe = target.archive_path
252
+ end
253
+
254
+ if(File.exists?(exe) && !File.directory?(exe) && File.stat(exe).mode != 33261)
255
+ File.chmod 0755, exe
256
+ end
257
+
258
+ return exe
259
+ end
260
+
261
+ # Allows us to easily download and install RubyGem sprouts by name and
262
+ # version.
263
+ # Returns a RubyGem Gem Spec[http://rubygems.org/read/chapter/20]
264
+ # when installation is complete. If the installed gem has a Ruby file
265
+ # configured to 'autorequire', that file will also be required by this
266
+ # method so that any provided Ruby functionality will be immediately
267
+ # available to client scripts. If the installed gem contains a
268
+ # 'sprout.spec' file, any RemoteFileTargets will be resolved synchronously
269
+ # and those files will be available in the Sprout::Sprout.cache.
270
+ #
271
+ def self.sprout(name, version=nil)
272
+ name = sprout_to_gem_name(name)
273
+ gem_spec = self.find_gem_spec(name, version)
274
+ sprout_spec_path = File.join(gem_spec.full_gem_path, @@spec)
275
+
276
+ if(gem_spec.autorequire)
277
+ $:.push(File.join(gem_spec.full_gem_path, 'lib'))
278
+ require gem_spec.autorequire
279
+ end
280
+ if(File.exists?(sprout_spec_path))
281
+ # Ensure the requisite files get downloaded and unpacked
282
+ Builder.build(sprout_spec_path, gem_file_cache(gem_spec.name, gem_spec.version))
283
+ else
284
+ return gem_spec
285
+ end
286
+ end
287
+
288
+ # Return sprout-#{name}-bundle for any name that does not begin with 'sprout-'. This was used early on in development
289
+ # but should possibly be removed as we move forward and try to support arbitrary RubyGems.
290
+ def self.sprout_to_gem_name(name)
291
+ if(!name.match(/^sprout-/))
292
+ name = "sprout-#{name}-bundle"
293
+ end
294
+ return name
295
+ end
296
+
297
+ # Return the home directory for this Sprout installation
298
+ def self.home
299
+ return @@home
300
+ end
301
+
302
+ # Return the location on disk where this installation of Sprouts stores it's cached files.
303
+ # If the currently installed version of Sprouts were 0.7 and your system username were 'foo'
304
+ # this would return the following locations:
305
+ # * +OSX+ /Users/foo/Library/Sprouts/cache/0.7
306
+ # * +Windows+ C:/Documents And Settings/foo/Local Settings/Application Data/Sprouts/cache/0.7
307
+ # * +Linux+ ~/.sprouts/cache/0.7
308
+ def self.sprout_cache
309
+ home = User.application_home(@@name)
310
+ return File.join(home, @@cache, "#{VERSION::MAJOR}.#{VERSION::MINOR}")
311
+ end
312
+
313
+ # Return the +sprout_cache+ combined with the passed in +name+ and +version+ so that you will get
314
+ # a cache location for a specific gem.
315
+ def self.gem_file_cache(name, version)
316
+ return File.join(sprout_cache, "#{name}-#{version}")
317
+ end
318
+
319
+ # Retrieve the RubyGems gem spec for a particular gem +name+ that meets the provided +requirements+.
320
+ # +requirements+ are provided as a string value like:
321
+ # '>= 0.0.1'
322
+ # or
323
+ # '0.0.1'
324
+ # This method will actually download and install the provided gem by +name+ and +requirements+ if
325
+ # it is not found locally on the system.
326
+ def self.find_gem_spec(name, requirements=nil, recursed=false)
327
+ specs = Gem::cache.search(/.*#{name}$/).reverse # Found specs are returned in order from oldest to newest!?
328
+ requirement = nil
329
+ if(requirements)
330
+ requirement = Gem::Requirement.new(requirements)
331
+ end
332
+ specs.each do |spec|
333
+ if(requirements)
334
+ if(requirement.satisfied_by?(spec.version))
335
+ return spec
336
+ end
337
+ else
338
+ return spec
339
+ end
340
+ end
341
+
342
+ if(recursed)
343
+ raise SproutError.new("Gem Spec not found for #{name} #{requirements}")
344
+ else
345
+ msg = ">> Loading gem [#{name}]"
346
+ msg << " #{requirements}" if requirements
347
+ msg << " from #{gem_sources.join(', ')} with it's dependencies"
348
+ Log.puts msg
349
+ parts = [ 'ins', '-r', name ]
350
+ # This url should be removed once released, released gems should be hosted from the rubyforge
351
+ # project, and development gems will be hosted on our domain.
352
+ parts << "--source #{gem_sources.join(' --source ')}" if(Log.debug || name.index('sprout-'))
353
+ parts << "-v #{requirements}" unless requirements.nil?
354
+
355
+ self.load_gem(parts.join(" "))
356
+ Gem::cache.refresh!
357
+ return find_gem_spec(name, requirements, true)
358
+ end
359
+ end
360
+
361
+ def self.load_gem(args)
362
+ # This must use a 'system' call because RubyGems
363
+ # sends an 'exit'?
364
+ system("#{get_gem_preamble} #{args}")
365
+ end
366
+
367
+ ##
368
+ # List of files to ignore when copying project templates
369
+ # These files will not be copied
370
+ @@COPY_IGNORE_FILES = ['.', '..', '.svn', '.DS_Store', 'CVS', '.cvs' 'Thumbs.db', '__MACOSX', '.Trashes', 'Desktop DB', 'Desktop DF']
371
+ # Do not copy files found in the ignore_files list
372
+ def self.ignore_file? file
373
+ @@COPY_IGNORE_FILES.each do |name|
374
+ if(name == file)
375
+ return true
376
+ end
377
+ end
378
+ return false
379
+ end
380
+
381
+ def self.gem_sources=(sources) # :nodoc:
382
+ if(sources.is_a?(String))
383
+ # TODO: Clean up the string that is sent in,
384
+ # maybe even split space or comma-delimited?
385
+ sources = [sources]
386
+ end
387
+ @@gem_sources = sources
388
+ end
389
+
390
+ # TODO: Should be updated after release so that all gems are
391
+ # loaded form rubyforge instead of projectsprouts, only development
392
+ # gems will continue to be hosted at this default domain.
393
+ def self.gem_sources # :nodoc:
394
+ @@gem_sources ||= ['http://gems.rubyforge.org']
395
+ end
396
+
397
+ def self.project_name=(name) # :nodoc:
398
+ @@project_name = name
399
+ end
400
+
401
+ # Return the current project_name assuming someone has already set it, otherwise return an empty string
402
+ def self.project_name
403
+ @@project_name ||= ''
404
+ end
405
+
406
+ def self.project_path=(path) # :nodoc:
407
+ @@project_rakefile = child_rakefile(path)
408
+ @@project_path = path
409
+ end
410
+
411
+ # project_path should step backward in the file system
412
+ # until it encounters a rakefile. The parent directory
413
+ # of that rakefile should be returned.
414
+ # If no rakefile is found, it should return Dir.pwd
415
+ def self.project_path
416
+ @@project_path ||= self.project_path = get_implicit_project_path(Dir.pwd)
417
+ end
418
+
419
+ # Return the rakefile in the current +project_path+
420
+ def self.project_rakefile
421
+ if(!defined?(@@project_rakefile))
422
+ path = project_path
423
+ end
424
+ return @@project_rakefile ||= nil
425
+ end
426
+
427
+ # Look in the provided +dir+ for files that meet the criteria to be a valid Rakefile.
428
+ def self.child_rakefile(dir)
429
+ @@default_rakefiles.each do |file|
430
+ rake_path = File.join(dir, file)
431
+ if(File.exists?(rake_path))
432
+ return rake_path
433
+ end
434
+ end
435
+ return nil
436
+ end
437
+
438
+ def self.get_implicit_project_path(path)
439
+ # We have recursed to the root of the filesystem, return nil
440
+ if(path.nil? || path == '/' || path.match(/[A-Z]\:\//))
441
+ return Dir.pwd
442
+ end
443
+ # Look for a rakefile as a child of the current path
444
+ if(child_rakefile(path))
445
+ return path
446
+ end
447
+ # No rakefile and no root found, check in parent dir
448
+ return Sprout.get_implicit_project_path(File.dirname(path))
449
+ end
450
+
451
+ end
452
+ end
453
+
454
+ # Set an array of URLs to use as gem repositories when loading Sprout gems.
455
+ # Any rakefile that requires the sprout gem can use this method as follows:
456
+ #
457
+ # set_sources ['http://gems.yourdomain.com']
458
+ #
459
+ def set_sources(sources)
460
+ Sprout::Sprout.gem_sources = sources
461
+ end
462
+
463
+ # Helper method that will download and install remote sprouts by name and version
464
+ def sprout(name, version=nil)
465
+ Sprout::Sprout.sprout(name, version)
466
+ end