sprout 0.3.35
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.txt +20 -0
- data/Manifest.txt +9 -0
- data/bin/sprout +167 -0
- data/lib/command.rb +29 -0
- data/lib/file_target.rb +8 -0
- data/lib/generate.rb +37 -0
- data/lib/library.rb +18 -0
- data/lib/log.rb +46 -0
- data/lib/platform.rb +110 -0
- data/lib/progress_bar.rb +314 -0
- data/lib/project.rb +10 -0
- data/lib/project_model.rb +59 -0
- data/lib/remote_file_loader.rb +186 -0
- data/lib/remote_file_target.rb +44 -0
- data/lib/sprout.rb +340 -0
- data/lib/sprout/version.rb +9 -0
- data/lib/task.rb +20 -0
- data/lib/template.rb +37 -0
- data/lib/template_resolver.rb +204 -0
- data/lib/tool.rb +18 -0
- data/lib/user.rb +234 -0
- data/rakefile.rb +146 -0
- data/setup.rb +1585 -0
- metadata +105 -0
data/lib/progress_bar.rb
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
#
|
2
|
+
# Ruby/ProgressBar - a text progress bar library
|
3
|
+
#
|
4
|
+
# Copyright (C) 2001-2005 Satoru Takabayashi <satoru@namazu.org>
|
5
|
+
# All rights reserved.
|
6
|
+
# This is free software with ABSOLUTELY NO WARRANTY.
|
7
|
+
#
|
8
|
+
# You can redistribute it and/or modify it under the terms
|
9
|
+
# of Ruby's license.
|
10
|
+
#
|
11
|
+
|
12
|
+
class ProgressBar
|
13
|
+
VERSION = "0.9"
|
14
|
+
def self.new(title, total)
|
15
|
+
return ProgressBarManager.instance.add(title, total)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ProgressBarImpl
|
20
|
+
|
21
|
+
def initialize (title, total, out = STDERR)
|
22
|
+
@title = title
|
23
|
+
@total = total
|
24
|
+
@out = out
|
25
|
+
@terminal_width = 80
|
26
|
+
@bar_mark = "."
|
27
|
+
@current = 0
|
28
|
+
@previous = 0
|
29
|
+
@finished_p = false
|
30
|
+
@start_time = Time.now
|
31
|
+
@previous_time = @start_time
|
32
|
+
@title_width = 18
|
33
|
+
@format = "%-#{@title_width}s %3d%% %s %s"
|
34
|
+
@format_arguments = [:title, :percentage, :bar, :stat]
|
35
|
+
clear
|
36
|
+
show
|
37
|
+
end
|
38
|
+
attr_reader :title
|
39
|
+
attr_reader :current
|
40
|
+
attr_reader :total
|
41
|
+
attr_accessor :start_time,
|
42
|
+
:title_width,
|
43
|
+
:bar_mark
|
44
|
+
|
45
|
+
private
|
46
|
+
def fmt_bar
|
47
|
+
bar_width = do_percentage * @terminal_width / 100
|
48
|
+
sprintf("|%s%s|",
|
49
|
+
@bar_mark * bar_width,
|
50
|
+
" " * (@terminal_width - bar_width))
|
51
|
+
end
|
52
|
+
|
53
|
+
def fmt_percentage
|
54
|
+
do_percentage
|
55
|
+
end
|
56
|
+
|
57
|
+
def fmt_stat
|
58
|
+
if @finished_p then elapsed else eta end
|
59
|
+
end
|
60
|
+
|
61
|
+
def fmt_stat_for_file_transfer
|
62
|
+
if @finished_p then
|
63
|
+
sprintf("%s %s %s", bytes, transfer_rate, elapsed)
|
64
|
+
else
|
65
|
+
sprintf("%s %s %s", bytes, transfer_rate, eta)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def fmt_title
|
70
|
+
@title[0,(@title_width - 1)] + ":"
|
71
|
+
end
|
72
|
+
|
73
|
+
def convert_bytes (bytes)
|
74
|
+
if bytes < 1024
|
75
|
+
sprintf("%6dB", bytes)
|
76
|
+
elsif bytes < 1024 * 1000 # 1000kb
|
77
|
+
sprintf("%5.1fKB", bytes.to_f / 1024)
|
78
|
+
elsif bytes < 1024 * 1024 * 1000 # 1000mb
|
79
|
+
sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
|
80
|
+
else
|
81
|
+
sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def transfer_rate
|
86
|
+
bytes_per_second = @current.to_f / (Time.now - @start_time)
|
87
|
+
sprintf("%s/s", convert_bytes(bytes_per_second))
|
88
|
+
end
|
89
|
+
|
90
|
+
def bytes
|
91
|
+
convert_bytes(@current)
|
92
|
+
end
|
93
|
+
|
94
|
+
def format_time (t)
|
95
|
+
t = t.to_i
|
96
|
+
sec = t % 60
|
97
|
+
min = (t / 60) % 60
|
98
|
+
hour = t / 3600
|
99
|
+
sprintf("%02d:%02d:%02d", hour, min, sec);
|
100
|
+
end
|
101
|
+
|
102
|
+
# ETA stands for Estimated Time of Arrival.
|
103
|
+
def eta
|
104
|
+
if @current == 0
|
105
|
+
"ETA: --:--:--"
|
106
|
+
else
|
107
|
+
elapsed = Time.now - @start_time
|
108
|
+
eta = elapsed * @total / @current - elapsed;
|
109
|
+
sprintf("ETA: %s", format_time(eta))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def elapsed
|
114
|
+
elapsed = Time.now - @start_time
|
115
|
+
sprintf("Time: %s", format_time(elapsed))
|
116
|
+
end
|
117
|
+
|
118
|
+
def eol
|
119
|
+
if @finished_p then "\n" else "\r" end
|
120
|
+
end
|
121
|
+
|
122
|
+
def do_percentage
|
123
|
+
if @total.zero?
|
124
|
+
100
|
125
|
+
else
|
126
|
+
@current * 100 / @total
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def get_width
|
131
|
+
return 80
|
132
|
+
# FIXME: I don't know how portable it is.
|
133
|
+
default_width = 80
|
134
|
+
begin
|
135
|
+
tiocgwinsz = 0x5413
|
136
|
+
data = [0, 0, 0, 0].pack("SSSS")
|
137
|
+
if @out.ioctl(tiocgwinsz, data) >= 0 then
|
138
|
+
rows, cols, xpixels, ypixels = data.unpack("SSSS")
|
139
|
+
if cols >= 0 then cols else default_width end
|
140
|
+
else
|
141
|
+
default_width
|
142
|
+
end
|
143
|
+
rescue Exception
|
144
|
+
default_width
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def show
|
149
|
+
arguments = @format_arguments.map {|method|
|
150
|
+
method = sprintf("fmt_%s", method)
|
151
|
+
send(method)
|
152
|
+
}
|
153
|
+
line = sprintf(@format, *arguments)
|
154
|
+
|
155
|
+
width = get_width
|
156
|
+
if line.length == width - 1
|
157
|
+
@out.print(line + eol)
|
158
|
+
@out.flush
|
159
|
+
elsif line.length >= width
|
160
|
+
@terminal_width = [@terminal_width - (line.length - width + 1), 0].max
|
161
|
+
if @terminal_width == 0 then @out.print(line + eol) else show end
|
162
|
+
else # line.length < width - 1
|
163
|
+
@terminal_width += width - line.length + 1
|
164
|
+
show
|
165
|
+
end
|
166
|
+
@previous_time = Time.now
|
167
|
+
end
|
168
|
+
|
169
|
+
def show_if_needed
|
170
|
+
if @total.zero?
|
171
|
+
cur_percentage = 100
|
172
|
+
prev_percentage = 0
|
173
|
+
else
|
174
|
+
cur_percentage = (@current * 100 / @total).to_i
|
175
|
+
prev_percentage = (@previous * 100 / @total).to_i
|
176
|
+
end
|
177
|
+
|
178
|
+
# Use "!=" instead of ">" to support negative changes
|
179
|
+
if cur_percentage != prev_percentage ||
|
180
|
+
Time.now - @previous_time >= 1 || @finished_p
|
181
|
+
show
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
public
|
186
|
+
def clear
|
187
|
+
@out.print "\r"
|
188
|
+
@out.print(" " * (get_width - 1))
|
189
|
+
@out.print "\r"
|
190
|
+
end
|
191
|
+
|
192
|
+
def finish
|
193
|
+
@current = @total
|
194
|
+
@finished_p = true
|
195
|
+
show
|
196
|
+
end
|
197
|
+
|
198
|
+
def finished?
|
199
|
+
@finished_p
|
200
|
+
end
|
201
|
+
|
202
|
+
def file_transfer_mode
|
203
|
+
@format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
|
204
|
+
end
|
205
|
+
|
206
|
+
def format= (format)
|
207
|
+
@format = format
|
208
|
+
end
|
209
|
+
|
210
|
+
def format_arguments= (arguments)
|
211
|
+
@format_arguments = arguments
|
212
|
+
end
|
213
|
+
|
214
|
+
def halt
|
215
|
+
@finished_p = true
|
216
|
+
show
|
217
|
+
end
|
218
|
+
|
219
|
+
def inc (step = 1)
|
220
|
+
@current += step
|
221
|
+
@current = @total if @current > @total
|
222
|
+
show_if_needed
|
223
|
+
@previous = @current
|
224
|
+
end
|
225
|
+
|
226
|
+
def set (count)
|
227
|
+
if count < 0 || count > @total
|
228
|
+
@total = count
|
229
|
+
end
|
230
|
+
@current = count
|
231
|
+
show_if_needed
|
232
|
+
@previous = @current
|
233
|
+
end
|
234
|
+
|
235
|
+
def inspect
|
236
|
+
"#<ProgressBar:#{@current}/#{@total}>"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class ReversedProgressBar < ProgressBar
|
241
|
+
def do_percentage
|
242
|
+
100 - super
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class ProgressBarOutputStream
|
247
|
+
attr_reader :title
|
248
|
+
|
249
|
+
def initialize(mgr)
|
250
|
+
@mgr = mgr
|
251
|
+
@msg = ''
|
252
|
+
end
|
253
|
+
|
254
|
+
def print(msg)
|
255
|
+
@msg = msg
|
256
|
+
end
|
257
|
+
|
258
|
+
def flush
|
259
|
+
@mgr.flush
|
260
|
+
end
|
261
|
+
|
262
|
+
def to_s
|
263
|
+
return @msg.clone.split("\n").join("").split("\r").join("")
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
class ProgressBarManager
|
269
|
+
include Singleton
|
270
|
+
|
271
|
+
def initialize
|
272
|
+
@outio = $stderr
|
273
|
+
@finished = {}
|
274
|
+
@bars = {}
|
275
|
+
@outs = {}
|
276
|
+
end
|
277
|
+
|
278
|
+
def add(title, total1)
|
279
|
+
if(@bars[title])
|
280
|
+
raise Error.new
|
281
|
+
end
|
282
|
+
@outs[title] = ProgressBarOutputStream.new(self)
|
283
|
+
@bars[title] = ProgressBarImpl.new(title, total1, @outs[title])
|
284
|
+
end
|
285
|
+
|
286
|
+
def print(title)
|
287
|
+
str = ''
|
288
|
+
str += @outs[title].to_s
|
289
|
+
str += "\r"
|
290
|
+
@outio.print "\r"
|
291
|
+
@outio.print str
|
292
|
+
end
|
293
|
+
|
294
|
+
def flush
|
295
|
+
str = ""
|
296
|
+
|
297
|
+
@bars.keys.each do |title|
|
298
|
+
print(title)
|
299
|
+
end
|
300
|
+
|
301
|
+
finished = true
|
302
|
+
@bars.values.each do |bar|
|
303
|
+
if(bar.finished?)
|
304
|
+
print(bar.title)
|
305
|
+
@outio.print "\n"
|
306
|
+
@outs.delete(bar.title)
|
307
|
+
@bars.delete(bar.title)
|
308
|
+
else
|
309
|
+
finished = false
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
data/lib/project.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module PatternPark
|
3
|
+
class ProjectModel
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
attr_accessor :project_name,
|
7
|
+
:src_dir,
|
8
|
+
:lib_dir,
|
9
|
+
:bin_dir,
|
10
|
+
:test_dir,
|
11
|
+
:asset_dir,
|
12
|
+
:skin_dir,
|
13
|
+
:model_dir,
|
14
|
+
:view_dir,
|
15
|
+
:controller_dir,
|
16
|
+
:language
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@project_name = 'Project'
|
20
|
+
@src_dir = 'src'
|
21
|
+
@lib_dir = 'lib'
|
22
|
+
@bin_dir = 'bin'
|
23
|
+
@test_dir = 'test'
|
24
|
+
@asset_dir = 'assets'
|
25
|
+
@skin_dir = File.join(@asset_dir, 'img', 'skins')
|
26
|
+
|
27
|
+
@language = 'as2'
|
28
|
+
|
29
|
+
@model_dir = nil
|
30
|
+
@view_dir = nil
|
31
|
+
@controller_dir = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def project_path
|
35
|
+
return Sprout.project_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def model_dir
|
39
|
+
if(@model_dir.nil?)
|
40
|
+
@model_dir = File.join(src_dir, project_name.downcase, 'models')
|
41
|
+
end
|
42
|
+
return @model_dir
|
43
|
+
end
|
44
|
+
|
45
|
+
def view_dir
|
46
|
+
if(@view_dir.nil?)
|
47
|
+
@view_dir = File.join(src_dir, project_name.downcase, 'views')
|
48
|
+
end
|
49
|
+
return @view_dir
|
50
|
+
end
|
51
|
+
|
52
|
+
def controller_dir
|
53
|
+
if(@controller_dir.nil?)
|
54
|
+
@controller_dir = File.join(src_dir, project_name.downcase, 'controllers')
|
55
|
+
end
|
56
|
+
return @controller_dir
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module PatternPark
|
4
|
+
class RemoteFileLoader
|
5
|
+
include Archive::Tar
|
6
|
+
|
7
|
+
def get_remote_file(uri, target)
|
8
|
+
if(Sprout.update || !File.exists?(target))
|
9
|
+
begin
|
10
|
+
response = fetch(uri.to_s)
|
11
|
+
rescue SocketError => e
|
12
|
+
puts "[ERROR] Unable to connect to #{uri}"
|
13
|
+
return
|
14
|
+
end
|
15
|
+
FileUtils.makedirs(File.dirname(target))
|
16
|
+
|
17
|
+
if(Sprout.update && File.exists?(target))
|
18
|
+
File.delete(target)
|
19
|
+
end
|
20
|
+
|
21
|
+
File.open(target, 'wb') do |f|
|
22
|
+
f.write(response)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch(location)
|
28
|
+
uri = URI.parse(location)
|
29
|
+
|
30
|
+
# Download the file now to the downloads dir
|
31
|
+
# If the file is an archive (zip, gz, tar, tar.gz, dmg), extract to
|
32
|
+
# AsProject/remote_files/@name/@location
|
33
|
+
# Check the location again...
|
34
|
+
progress = nil
|
35
|
+
response = nil
|
36
|
+
head = nil
|
37
|
+
name = uri.path.split("/").pop
|
38
|
+
|
39
|
+
raise UsageError.new("The RemoteFileTask failed for #{name}. WE can only handle HTTP requests at this time, it seems you were trying: #{location}") if uri.scheme != 'http'
|
40
|
+
|
41
|
+
|
42
|
+
open(uri.to_s, :content_length_proc => lambda {|t|
|
43
|
+
if t && t > 0
|
44
|
+
progress = ProgressBar.new(name, t)
|
45
|
+
progress.file_transfer_mode
|
46
|
+
progress.set(0)
|
47
|
+
else
|
48
|
+
progress = ProgressBar.new(name, 0)
|
49
|
+
progress.file_transfer_mode
|
50
|
+
progress.set(0)
|
51
|
+
end
|
52
|
+
},
|
53
|
+
:progress_proc => lambda {|s|
|
54
|
+
progress.set s if progress
|
55
|
+
}) {|f|
|
56
|
+
response = f.read
|
57
|
+
progress.finish
|
58
|
+
}
|
59
|
+
|
60
|
+
return response
|
61
|
+
end
|
62
|
+
|
63
|
+
def unpack_downloaded_file(file_name, dir)
|
64
|
+
if(!File.exists?(dir))
|
65
|
+
if(is_zip?(file_name))
|
66
|
+
unpack_zip(file_name, dir)
|
67
|
+
elsif(is_targz?(file_name))
|
68
|
+
unpack_targz(file_name, dir)
|
69
|
+
elsif(is_dmg?(file_name))
|
70
|
+
unpack_dmg(file_name, dir)
|
71
|
+
elsif(is_swc?(file_name))
|
72
|
+
# just copy the swc...
|
73
|
+
elsif(is_rb?(file_name))
|
74
|
+
return
|
75
|
+
elsif(!is_exe?(file_name))
|
76
|
+
raise UsageError.new("RemoteFileTask does not know how to unpack files of type: #{file_name}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def unpack_zip(zip_file, dir)
|
82
|
+
# Avoid the rubyzip Segmentation Fault bug
|
83
|
+
# at least on os x...
|
84
|
+
if(RUBY_PLATFORM =~ /darwin/)
|
85
|
+
# Unzipping on OS X
|
86
|
+
FileUtils.makedirs(dir)
|
87
|
+
%x(cd #{dir};unzip #{zip_file})
|
88
|
+
else
|
89
|
+
retries = 0
|
90
|
+
begin
|
91
|
+
retries += 1
|
92
|
+
Zip::ZipFile::open(zip_file) do |zf|
|
93
|
+
zf.each do |e|
|
94
|
+
fpath = File.join(dir, e.name)
|
95
|
+
FileUtils.mkdir_p(File.dirname(fpath))
|
96
|
+
zf.extract(e, fpath)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
rescue StandardError => e
|
100
|
+
if(retries < 3)
|
101
|
+
puts ">> [ZIP ERROR ENCOUNTERED] trying again with: #{dir}"
|
102
|
+
FileUtils.rm_rf(dir)
|
103
|
+
FileUtils.makedirs(dir)
|
104
|
+
retry
|
105
|
+
end
|
106
|
+
raise e
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def unpack_targz(tgz_file, dir)
|
112
|
+
tar = Zlib::GzipReader.new(File.open(tgz_file, 'rb'))
|
113
|
+
Minitar.unpack(tar, dir)
|
114
|
+
end
|
115
|
+
|
116
|
+
# This is actually not unpacking the FlashPlayer
|
117
|
+
# Binary file as expected...
|
118
|
+
# OSX is treated the player binary as if it is
|
119
|
+
# a regular text file, but if it is copied manually,
|
120
|
+
# the command works fine!?
|
121
|
+
def unpack_dmg(dmg_file, dir)
|
122
|
+
# 1) Mount the dmg in place
|
123
|
+
# 2) Recursively Copy it's contents to asproject_home
|
124
|
+
# 3) Unmount the dmg
|
125
|
+
if(mounted_path.nil?)
|
126
|
+
raise StandardError.new('DMG file downloaded, but the RemoteFileTask needs a mounted_path in order to mount it')
|
127
|
+
end
|
128
|
+
|
129
|
+
if(!File.exists?(full_mounted_path))
|
130
|
+
system("hdiutil mount #{dmg_file}")
|
131
|
+
end
|
132
|
+
|
133
|
+
begin
|
134
|
+
mounted_target = File.join(full_mounted_path, extracted_file)
|
135
|
+
|
136
|
+
# Copy the DMG contents using system copy rather than ruby utils
|
137
|
+
# Because OS X does something special with .app files that the
|
138
|
+
# Ruby FileUtils and File classes break...
|
139
|
+
Log.puts '=================='
|
140
|
+
from = mounted_target
|
141
|
+
# from = File.join(full_mounted_path, extracted_file)
|
142
|
+
to = File.join(@user.downloads, @name.to_s, extracted_file)
|
143
|
+
Log.puts 'from: ' + from
|
144
|
+
Log.puts 'to: ' + to
|
145
|
+
FileUtils.makedirs(File.dirname(to))
|
146
|
+
|
147
|
+
if(File.exists?(from))
|
148
|
+
`ditto '#{from}' '#{to}'`
|
149
|
+
end
|
150
|
+
rescue
|
151
|
+
if(File.exists?(full_mounted_path))
|
152
|
+
system("hdiutil unmount -force \"#{full_mounted_path}\"")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def is_exe?(file)
|
158
|
+
return (file.split('.').pop == 'exe')
|
159
|
+
end
|
160
|
+
|
161
|
+
def is_zip?(file)
|
162
|
+
return (file.split('.').pop == 'zip')
|
163
|
+
end
|
164
|
+
|
165
|
+
def is_targz?(file)
|
166
|
+
parts = file.split('.')
|
167
|
+
return (parts.pop == 'gz' && parts.pop == 'tar')
|
168
|
+
end
|
169
|
+
|
170
|
+
def is_gzip?(file)
|
171
|
+
return (file.split('.').pop == 'gz')
|
172
|
+
end
|
173
|
+
|
174
|
+
def is_swc?(file)
|
175
|
+
return (file.split('.').pop == 'swc')
|
176
|
+
end
|
177
|
+
|
178
|
+
def is_rb?(file)
|
179
|
+
return (file.split('.').pop == 'rb')
|
180
|
+
end
|
181
|
+
|
182
|
+
def is_dmg?(file)
|
183
|
+
return (file.split('.').pop == 'dmg')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|