sprout 0.7.220-x86-darwin-10
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.
- data/MIT-LICENSE +20 -0
- data/TODO +12 -0
- data/bin/sprout +128 -0
- data/doc/Bundle +14 -0
- data/doc/Generator +35 -0
- data/doc/Library +63 -0
- data/doc/Task +21 -0
- data/doc/Tool +20 -0
- data/lib/platform.rb +109 -0
- data/lib/progress_bar.rb +354 -0
- data/lib/sprout/archive_unpacker.rb +225 -0
- data/lib/sprout/builder.rb +44 -0
- data/lib/sprout/commands/generate.rb +9 -0
- data/lib/sprout/dynamic_accessors.rb +34 -0
- data/lib/sprout/general_tasks.rb +6 -0
- data/lib/sprout/generator/base_mixins.rb +186 -0
- data/lib/sprout/generator/named_base.rb +227 -0
- data/lib/sprout/generator.rb +7 -0
- data/lib/sprout/log.rb +46 -0
- data/lib/sprout/process_runner.rb +111 -0
- data/lib/sprout/project_model.rb +278 -0
- data/lib/sprout/remote_file_loader.rb +71 -0
- data/lib/sprout/remote_file_target.rb +151 -0
- data/lib/sprout/simple_resolver.rb +88 -0
- data/lib/sprout/tasks/erb_resolver.rb +118 -0
- data/lib/sprout/tasks/gem_wrap_task.rb +200 -0
- data/lib/sprout/tasks/git_task.rb +134 -0
- data/lib/sprout/tasks/library_task.rb +118 -0
- data/lib/sprout/tasks/sftp_task.rb +248 -0
- data/lib/sprout/tasks/ssh_task.rb +153 -0
- data/lib/sprout/tasks/tool_task.rb +793 -0
- data/lib/sprout/tasks/zip_task.rb +158 -0
- data/lib/sprout/template_resolver.rb +207 -0
- data/lib/sprout/user.rb +383 -0
- data/lib/sprout/version.rb +12 -0
- data/lib/sprout/version_file.rb +89 -0
- data/lib/sprout/zip_util.rb +61 -0
- data/lib/sprout.rb +496 -0
- data/rakefile.rb +150 -0
- data/samples/gem_wrap/rakefile.rb +17 -0
- metadata +174 -0
data/lib/sprout/user.rb
ADDED
@@ -0,0 +1,383 @@
|
|
1
|
+
require 'platform'
|
2
|
+
require 'sprout/log'
|
3
|
+
require 'sprout/process_runner'
|
4
|
+
|
5
|
+
module Sprout
|
6
|
+
|
7
|
+
class ExecutionError < StandardError # :nodoc:
|
8
|
+
end
|
9
|
+
|
10
|
+
# The User class provides a single and consistent interface to User based paths
|
11
|
+
# and features so that Sprout implementation code doesn't need to be concerned
|
12
|
+
# with which Operating system it is running on.
|
13
|
+
#
|
14
|
+
class User
|
15
|
+
@@user = nil
|
16
|
+
|
17
|
+
# Retrieve a user instance that represents the currently logged in user on this system.
|
18
|
+
def User.new(os=nil, impl=nil)
|
19
|
+
if(os.nil? && impl.nil? && @@user)
|
20
|
+
return @@user
|
21
|
+
end
|
22
|
+
if(os.nil?)
|
23
|
+
os = Platform::OS
|
24
|
+
end
|
25
|
+
if(impl.nil?)
|
26
|
+
impl = Platform::IMPL
|
27
|
+
end
|
28
|
+
if(os == :win32 && impl == :vista)
|
29
|
+
@@user = VistaUser.new
|
30
|
+
elsif(os == :win32 && impl == :cygwin)
|
31
|
+
@@user = CygwinUser.new
|
32
|
+
elsif(os == :win32)
|
33
|
+
@@user = WinUser.new
|
34
|
+
elsif(os == :unix && impl == :macosx)
|
35
|
+
@@user = OSXUser.new
|
36
|
+
# elsif(os == :unix && impl == :linux)
|
37
|
+
# @@user = UnixUser.new
|
38
|
+
else
|
39
|
+
@@user = UnixUser.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def User.user=(user) # :nodoc:
|
44
|
+
@@user = user
|
45
|
+
end
|
46
|
+
|
47
|
+
def User.home=(path) # :nodoc:
|
48
|
+
User.new().home = path
|
49
|
+
end
|
50
|
+
|
51
|
+
def User.is_a?(type)
|
52
|
+
User.new().is_a?(type)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Pass an executable or binary file name and find out if that file exists in the system
|
56
|
+
# path or not
|
57
|
+
def User.in_path?(executable)
|
58
|
+
User.new().in_path?(executable)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Retrieve the full path to an executable that exists in the user path
|
62
|
+
def User.get_exe_path(executable)
|
63
|
+
return User.new().get_exe_path(executable)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return the home path for the currently logged in user. If the user name is lbayes, this should be:
|
67
|
+
#
|
68
|
+
# Windows XP:: C:\Documents And Settings\lbayes
|
69
|
+
# Cygwin:: /cygdrive/c/Documents And Settings/lbayes
|
70
|
+
# OS X:: /Users/lbayes
|
71
|
+
# Linux:: ~/
|
72
|
+
def User.home
|
73
|
+
User.new().home
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns the home path for a named application based on the currently logged in user and operating system.
|
77
|
+
# If the user name is lbayes and the application name is Sprouts, this path will be:
|
78
|
+
#
|
79
|
+
# Windows XP:: C:\Documents And Settings\lbayes\Local Settings\Application Data\Sprouts
|
80
|
+
# Cygwin:: /cygdrive/c/Documents And Settings/Local Settings/Application Data/Sprouts
|
81
|
+
# OS X:: /Users/lbayes/Library/Sprouts
|
82
|
+
# Linux:: ~/.sprouts
|
83
|
+
def User.application_home(name)
|
84
|
+
return User.new().application_home(name)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns the library path on the current system. This is the general path where all applications should
|
88
|
+
# store configuration or session data.
|
89
|
+
#
|
90
|
+
# Windows XP:: C:\Documents And Settings\lbayes\Local Settings\Application Data
|
91
|
+
# Cygwin:: /cygdrive/c/Documents And Settings/lbayes/Local Settings/Application Data
|
92
|
+
# OS X:: /Users/lbayes/Library
|
93
|
+
# Linux:: ~/
|
94
|
+
def User.library
|
95
|
+
return User.new().library
|
96
|
+
end
|
97
|
+
|
98
|
+
# Execute a named tool sprout. The full sprout name should be provided to the tool parameter, and
|
99
|
+
# a string of shell parameters that will be sent to the tool itself.
|
100
|
+
def User.execute(tool, options='')
|
101
|
+
return User.new().execute(tool, options)
|
102
|
+
end
|
103
|
+
|
104
|
+
def User.execute_silent(tool, options='')
|
105
|
+
return User.new().execute_silent(tool, options)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Execute a named tool sprout as a new thread and return that thread
|
109
|
+
def User.execute_thread(tool, options='')
|
110
|
+
if(Log.debug)
|
111
|
+
return ThreadMock.new
|
112
|
+
else
|
113
|
+
return User.new().execute_thread(tool, options)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Clean a path string in such a way that works for each platform. For example, Windows doesn't like
|
118
|
+
# it when we backslash to escape spaces in a path because that is the character they use as a delimiter.
|
119
|
+
# And OS X doesn't really like it when we wrap paths in quotes.
|
120
|
+
def User.clean_path(path)
|
121
|
+
return User.new().clean_path(path)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
#############################
|
127
|
+
# UnixUser class
|
128
|
+
class UnixUser # :nodoc:
|
129
|
+
|
130
|
+
def initialize
|
131
|
+
setup_user
|
132
|
+
@home = nil
|
133
|
+
end
|
134
|
+
|
135
|
+
def setup_user
|
136
|
+
end
|
137
|
+
|
138
|
+
def home=(path)
|
139
|
+
@home = path
|
140
|
+
end
|
141
|
+
|
142
|
+
def home
|
143
|
+
if(@home)
|
144
|
+
return @home
|
145
|
+
end
|
146
|
+
|
147
|
+
# Original implementation:
|
148
|
+
#["HOME", "USERPROFILE"].each do |homekey|
|
149
|
+
# Change submitted by Michael Fleet (disinovate)
|
150
|
+
# Does this work for everyone on Windows?
|
151
|
+
["USERPROFILE", "HOME"].each do |homekey|
|
152
|
+
return @home = ENV[homekey] if ENV[homekey]
|
153
|
+
end
|
154
|
+
|
155
|
+
if ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
|
156
|
+
return @home = "#{ENV["HOMEDRIVE"]}:#{ENV["HOMEPATH"]}"
|
157
|
+
end
|
158
|
+
|
159
|
+
begin
|
160
|
+
return @home = File.expand_path("~")
|
161
|
+
rescue StandardError => e
|
162
|
+
if File::ALT_SEPARATOR
|
163
|
+
return @home = "C:\\"
|
164
|
+
else
|
165
|
+
return @home = "/"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_exe_path(executable)
|
171
|
+
paths = get_paths
|
172
|
+
file = nil
|
173
|
+
paths.each do |path|
|
174
|
+
file = File.join(path, executable)
|
175
|
+
if(File.exists?(file))
|
176
|
+
return file
|
177
|
+
end
|
178
|
+
end
|
179
|
+
return nil
|
180
|
+
end
|
181
|
+
|
182
|
+
def in_path?(executable)
|
183
|
+
return !get_exe_path(executable).nil?
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_paths
|
187
|
+
return ENV['PATH'].split(':')
|
188
|
+
end
|
189
|
+
|
190
|
+
def library
|
191
|
+
return home
|
192
|
+
end
|
193
|
+
|
194
|
+
def platform
|
195
|
+
if(Platform::OS == :win32)
|
196
|
+
return :win32
|
197
|
+
elsif(Platform::IMPL == :macosx)
|
198
|
+
return :macosx
|
199
|
+
else
|
200
|
+
return Platform::IMPL
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def get_process_runner(command)
|
205
|
+
return ProcessRunner.new(command)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Creates a new process, executes the command
|
209
|
+
# and returns the result and throws if the process
|
210
|
+
# writes to stderr
|
211
|
+
def execute(tool, options='')
|
212
|
+
Log.puts(">> Execute: #{File.basename(tool)} #{options}")
|
213
|
+
tool = clean_path(tool)
|
214
|
+
runner = get_process_runner("#{tool} #{options}")
|
215
|
+
|
216
|
+
error = runner.read_err
|
217
|
+
result = runner.read
|
218
|
+
|
219
|
+
if(result.size > 0)
|
220
|
+
Log.puts result
|
221
|
+
end
|
222
|
+
|
223
|
+
if(error.size > 0)
|
224
|
+
raise ExecutionError.new("[ERROR] #{error}")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Creates and returns the process without
|
229
|
+
# attempting to read or write to the stream.
|
230
|
+
# This is useful for interacting with
|
231
|
+
# long-lived CLI processes like FCSH or FDB.
|
232
|
+
def execute_silent(tool, options='')
|
233
|
+
tool = clean_path(tool)
|
234
|
+
return get_process_runner("#{tool} #{options}")
|
235
|
+
end
|
236
|
+
|
237
|
+
def execute_thread(tool, options='')
|
238
|
+
return Thread.new do
|
239
|
+
execute(tool, options)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def clean_path(path)
|
244
|
+
if(path.index(' '))
|
245
|
+
# Changed 2/26/2008 in attempt to support
|
246
|
+
# ToolTask.PathsParam s that have spaces in the values
|
247
|
+
return path.split(' ').join('\ ')
|
248
|
+
# return %{'#{path}'}
|
249
|
+
end
|
250
|
+
return path
|
251
|
+
end
|
252
|
+
|
253
|
+
def application_home(name)
|
254
|
+
return File.join(library, format_application_name(name.to_s));
|
255
|
+
end
|
256
|
+
|
257
|
+
def format_application_name(name)
|
258
|
+
if(name.index('.') != 0)
|
259
|
+
name = '.' + name
|
260
|
+
end
|
261
|
+
return name.split(" ").join("_").downcase
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class OSXUser < UnixUser # :nodoc:
|
266
|
+
@@LIBRARY = 'Library'
|
267
|
+
|
268
|
+
def library
|
269
|
+
lib = File.join(home, @@LIBRARY)
|
270
|
+
if(File.exists?(lib))
|
271
|
+
return lib
|
272
|
+
else
|
273
|
+
return super
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def format_application_name(name)
|
278
|
+
return name.capitalize
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
class WinUser < UnixUser # :nodoc:
|
283
|
+
@@LOCAL_SETTINGS = "Local\ Settings"
|
284
|
+
@@APPLICATION_DATA = "Application\ Data"
|
285
|
+
|
286
|
+
def initialize
|
287
|
+
super
|
288
|
+
@home = nil
|
289
|
+
end
|
290
|
+
|
291
|
+
def setup_user
|
292
|
+
end
|
293
|
+
|
294
|
+
def home
|
295
|
+
usr = super
|
296
|
+
if(usr.index "My Documents")
|
297
|
+
usr = File.dirname(usr)
|
298
|
+
end
|
299
|
+
return usr
|
300
|
+
end
|
301
|
+
|
302
|
+
def get_paths
|
303
|
+
return ENV['PATH'].split(';')
|
304
|
+
end
|
305
|
+
|
306
|
+
def library
|
307
|
+
# For some reason, my homepath returns inside 'My Documents'...
|
308
|
+
application_data = File.join(home, @@LOCAL_SETTINGS, @@APPLICATION_DATA)
|
309
|
+
if(File.exists?(application_data))
|
310
|
+
return application_data
|
311
|
+
else
|
312
|
+
return super
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def clean_path(path)
|
317
|
+
path = path.split('/').join("\\")
|
318
|
+
if(path.index(' '))
|
319
|
+
return %{"#{path}"}
|
320
|
+
end
|
321
|
+
return path
|
322
|
+
end
|
323
|
+
|
324
|
+
def format_application_name(name)
|
325
|
+
return name.capitalize
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
class CygwinUser < WinUser # :nodoc:
|
330
|
+
|
331
|
+
def initialize
|
332
|
+
super
|
333
|
+
@home = nil
|
334
|
+
@win_home = nil
|
335
|
+
@win_home_cyg_path = nil
|
336
|
+
end
|
337
|
+
|
338
|
+
def setup_user
|
339
|
+
end
|
340
|
+
|
341
|
+
def clean_path(path)
|
342
|
+
if(path.index(' '))
|
343
|
+
return %{'#{path}'}
|
344
|
+
end
|
345
|
+
return path
|
346
|
+
end
|
347
|
+
|
348
|
+
def win_home
|
349
|
+
if(@win_home.nil?)
|
350
|
+
@win_home = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
|
351
|
+
end
|
352
|
+
return @win_home
|
353
|
+
end
|
354
|
+
|
355
|
+
def home
|
356
|
+
if(@home.nil?)
|
357
|
+
path = win_home.split('\\').join("/")
|
358
|
+
path = path.split(":").join("")
|
359
|
+
parts = path.split("/")
|
360
|
+
path = parts.shift().downcase + "/" + parts.join("/")
|
361
|
+
@home = "/cygdrive/" + path
|
362
|
+
end
|
363
|
+
return @home
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
367
|
+
|
368
|
+
class VistaUser < WinUser # :nodoc:
|
369
|
+
def home
|
370
|
+
profile = ENV['USERPROFILE']
|
371
|
+
if(profile)
|
372
|
+
return profile
|
373
|
+
end
|
374
|
+
return super
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
class ThreadMock # :nodoc:
|
379
|
+
def alive?
|
380
|
+
return false
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Sprout
|
2
|
+
|
3
|
+
# Used by the GitTask to load, parse and persist Version information
|
4
|
+
# related to a project.
|
5
|
+
# Expects a file with a 3 digit number, separated by periods like:
|
6
|
+
#
|
7
|
+
# 3.4.2
|
8
|
+
#
|
9
|
+
# Create with a path to the file like:
|
10
|
+
#
|
11
|
+
# version = VersionFile.new('path/Version.txt')
|
12
|
+
#
|
13
|
+
class VersionFile
|
14
|
+
|
15
|
+
def initialize(file_path)
|
16
|
+
@file_path = file_path
|
17
|
+
read_value
|
18
|
+
end
|
19
|
+
|
20
|
+
def value=(value)
|
21
|
+
@value = value
|
22
|
+
write_value
|
23
|
+
end
|
24
|
+
|
25
|
+
def value
|
26
|
+
@value
|
27
|
+
end
|
28
|
+
|
29
|
+
def major_version
|
30
|
+
@value.split('.').shift.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def minor_version
|
34
|
+
@value.split('.')[1].to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def revision
|
38
|
+
@value.split('.').pop.to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def increment_revision
|
42
|
+
self.revision = self.revision + 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
@value
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_str
|
50
|
+
@value
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_tag
|
54
|
+
parts = value.split('.')
|
55
|
+
parts[0] = add_leading_zeros(parts[0], 2)
|
56
|
+
parts[1] = add_leading_zeros(parts[1], 2)
|
57
|
+
parts[2] = add_leading_zeros(parts[2], 3)
|
58
|
+
return parts.join('.')
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def add_leading_zeros(str, digits)
|
64
|
+
(digits - str.size).times do
|
65
|
+
str = "0#{str}"
|
66
|
+
end
|
67
|
+
str
|
68
|
+
end
|
69
|
+
|
70
|
+
def read_value
|
71
|
+
File.open(@file_path, 'r') do |file|
|
72
|
+
@value = file.read.strip
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def write_value
|
77
|
+
File.open(@file_path, 'r+') do |file|
|
78
|
+
file.write @value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def revision=(revision)
|
83
|
+
parts = @value.split('.')
|
84
|
+
parts[2] = revision
|
85
|
+
@value = parts.join('.')
|
86
|
+
write_value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
module Sprout
|
3
|
+
class ZipUtil #:nodoc:
|
4
|
+
|
5
|
+
# Pack up an archive from a directory on disk
|
6
|
+
def self.pack(input, archive, excludes)
|
7
|
+
Zip::ZipFile.open(archive, Zip::ZipFile::CREATE) do |zip|
|
8
|
+
add_file_to_zip(zip, input, excludes)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Unpack an archive to a directory on disk
|
13
|
+
def self.unpack(archive, destination)
|
14
|
+
Zip::ZipFile.open(archive) do |zip|
|
15
|
+
unpack_file(zip, destination)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.unpack_file(zip, destination, path='')
|
20
|
+
if(zip.file.file?(path))
|
21
|
+
File.open(File.join(destination, path), 'w') do |dest|
|
22
|
+
zip.file.open(path) do |src|
|
23
|
+
dest.write src.read
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
Dir.mkdir(File.join(destination, path))
|
28
|
+
zip.dir.foreach(path) do |dir|
|
29
|
+
unpack_file(zip, destination, File.join(path, dir))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_file_to_zip(zip, path, excludes)
|
35
|
+
if(File.directory?(path))
|
36
|
+
zip.dir.mkdir(path)
|
37
|
+
Dir.open(path).each do |child|
|
38
|
+
if(!excluded?(child, excludes))
|
39
|
+
add_file_to_zip(zip, File.join(path, child), excludes)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
else
|
43
|
+
File.open(path) do |src|
|
44
|
+
zip.file.open(path, 'w') do |dest|
|
45
|
+
dest.write src.read
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.excluded?(str, excludes)
|
52
|
+
excludes.each do |exc|
|
53
|
+
if(str == exc)
|
54
|
+
return true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|