sprout 0.7.191-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,158 @@
1
+ =begin
2
+ Copyright (c) 2007 Pattern Park
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ =end
23
+
24
+ require 'zip/zipfilesystem'
25
+
26
+ # TODO: Make this task more like a rake FileTask
27
+ # The output should be the task name and the input
28
+ # files should be added as prerequisites
29
+
30
+ module Sprout
31
+ class ZipError < StandardError #:nodoc:
32
+ end
33
+
34
+ # The ZipTask should accept any directory as input and either
35
+ # an expected zip file name or directory where one will be created
36
+ # for output.
37
+ # The resulting zip file will only be generated if a file in the
38
+ # input directory has a newer timestamp than the existing zip file
39
+ class ZipTask < Rake::FileTask
40
+
41
+ # Array of file names that should not be added to the zip archive.
42
+ # The default value of this property is:
43
+ # @excludes = ['.', '..', '.svn', '.cvs', '.DS_Store', '.git', 'CVS', 'Thumbs.db']
44
+ attr_writer :excludes
45
+ # The file or folder that should be archived.
46
+ #
47
+ # If input is a directory, all of it's contents
48
+ # will be recursively added to the archive (excluding any files that match +excludes+ of course).
49
+ #
50
+ # If input is a file, a new archive will be created with a similar file name and only that file
51
+ # will be added to the archive.
52
+ attr_writer :input
53
+ # Zip archive file to create. Usually, the name of the zip task will be used for this property,
54
+ # but in cases where you want a particular task name and a different output file, you can set
55
+ # this parameter.
56
+ attr_writer :output
57
+
58
+ def self.define_task(args, &block) # :nodoc:
59
+ t = super
60
+ yield t if block_given?
61
+ t.define
62
+ end
63
+
64
+ def define # :nodoc:
65
+ @input = define_input(input)
66
+ @output = define_output(output || name)
67
+ end
68
+
69
+ def output
70
+ @output ||= nil
71
+ end
72
+
73
+ def input
74
+ @input ||= nil
75
+ end
76
+
77
+ def execute(*args) # :nodoc:
78
+ create_archive
79
+ end
80
+
81
+ def excludes
82
+ @excludes ||= ['.', '..', '.svn', '.cvs', '.DS_Store', '.git', 'CVS', 'Thumbs.db']
83
+ end
84
+
85
+ private
86
+
87
+ def create_archive(force=false) # :nodoc:
88
+ return unless (force || name == output)
89
+
90
+ start = Dir.pwd
91
+ begin
92
+ full_output = File.expand_path(output)
93
+ full_input = File.expand_path(input)
94
+ Dir.chdir(File.dirname(full_input))
95
+ masked_input = full_input.gsub("#{Dir.pwd}/", '')
96
+
97
+ # Create the containing folder for output
98
+ if(!File.directory?(File.dirname(full_output)))
99
+ FileUtils.mkdir_p(File.dirname(full_output))
100
+ end
101
+
102
+ ZipUtil.pack(masked_input, full_output, excludes)
103
+
104
+ ensure
105
+ Dir.chdir(start)
106
+ end
107
+
108
+ end
109
+
110
+ def define_input(input)
111
+ file input do |t|
112
+ raise ZipError.new("ZipTask '#{name}' could not find valid input at: #{input}") unless (File.exists?(input))
113
+ end
114
+
115
+ input_files = FileList["#{input}/**/**/*"]
116
+ input_files.each do |f|
117
+ prerequisites << f
118
+ end
119
+ prerequisites << input
120
+ return input
121
+ end
122
+
123
+ def define_output(out)
124
+
125
+ # If the provided parent dir doesn't
126
+ # exist, create it
127
+ if(!File.exists?(File.dirname(out)))
128
+ FileUtils.mkdir_p(File.dirname(out))
129
+ end
130
+
131
+ # If the provided output is just a directory
132
+ # and it's parent doesn't yet exist, create the
133
+ # provided output directory before appending
134
+ # the real zip file name
135
+ if(!File.basename(out).index('.'))
136
+ FileUtils.mkdir_p(out)
137
+ end
138
+
139
+ # If out is just a directory, append input's basename
140
+ # to create the zip file
141
+ if(File.directory?(out))
142
+ out = File.join(out, File.basename(input) + '.zip')
143
+ end
144
+
145
+ if(out != name)
146
+ file out do
147
+ create_archive(true)
148
+ end
149
+ prerequisites << out
150
+ end
151
+ return out
152
+ end
153
+ end
154
+ end
155
+
156
+ def zip(args, &block)
157
+ Sprout::ZipTask.define_task(args, &block)
158
+ end
@@ -0,0 +1,207 @@
1
+
2
+ module Sprout
3
+
4
+ class TemplateResolver < Hash #:nodoc:
5
+ include Singleton
6
+
7
+ attr_accessor :replace_all,
8
+ :ignore_all
9
+
10
+ @@SPROUT_FILE_NAME = 'Sprout'
11
+ @@RENDER_IGNORE_FILES = ['asclass_config.rb', 'SWFMillTemplate.erb', 'Template.erb']
12
+ @@BINARY_EXTENSIONS = ['.jpg', '.png', '.gif', '.doc', '.xls', '.exe', '.swf', 'fla', '.psd']
13
+ @@LOG_PREFIX = ">> Created file: "
14
+ @@DELETE_PREFIX = ">> Deleted file: "
15
+
16
+ def initialize
17
+ super
18
+ @replace_all = false
19
+ @ignore_all = false
20
+ end
21
+
22
+ def copy_files(from, to, render=false)
23
+ created_files = Array.new
24
+ if(!File.exists? from)
25
+ raise UsageError.new('TemplateResolver attempted to copy files from (' + from + ') but it does not exist...')
26
+ end
27
+ if(File.directory? from)
28
+ Dir.open(from).each do |filename|
29
+ if(!Sprout.ignore_file? filename)
30
+ fullname = File.join(from, filename)
31
+ new_fullname = File.join(to, filename)
32
+ cleaned_filename = clean_file_name(filename)
33
+ cleaned_fullname = File.join(to, cleaned_filename)
34
+ if(File.directory? fullname)
35
+ Dir.mkdir(new_fullname) unless File.exists? new_fullname
36
+ puts new_fullname
37
+ copy_files(fullname, new_fullname, render)
38
+ else
39
+ file = copy_file(fullname, cleaned_fullname, render)
40
+ end
41
+ end
42
+ end
43
+ else
44
+ raise UsageError.new("copy_files called with a file (" + from + ") instead of a directory!")
45
+ end
46
+
47
+ return created_files
48
+ end
49
+
50
+ def puts(file, is_delete=false)
51
+ prefix = (is_delete) ? @@DELETE_PREFIX : @@LOG_PREFIX
52
+ Log.puts(prefix + file.gsub(Dir.pwd + '/', ''))
53
+ end
54
+
55
+ def b(path)
56
+ (is_binary?(path)) ? 'b' : ''
57
+ end
58
+
59
+ def copy_file(from, to, render=false, delegate=nil)
60
+ if(write_file?(to))
61
+ content = nil
62
+ File.open(from, 'r' + b(from)) do |f|
63
+ content = f.read
64
+ end
65
+ if(render && should_render?(from))
66
+ begin
67
+ bind = (delegate.nil?) ? binding : delegate.get_binding
68
+ content = ERB.new(content, nil, '>').result(bind)
69
+ rescue NameError => e
70
+ Log.puts '>> Template ' + from + ' references a value that is not defined'
71
+ raise e
72
+ end
73
+ end
74
+ FileUtils.makedirs(File.dirname(to))
75
+ File.open(to, 'w' + b(to)) do |f|
76
+ f.write(content)
77
+ end
78
+ puts to
79
+ return to
80
+ end
81
+ return nil
82
+ end
83
+
84
+ def should_render?(file)
85
+ if(is_binary?(file) || @@RENDER_IGNORE_FILES.index(File.basename(file)))
86
+ return false
87
+ end
88
+ return true
89
+ end
90
+
91
+ def write_file?(file)
92
+ if(!File.exists?(file))
93
+ return true
94
+ elsif(@replace_all)
95
+ puts(file, true)
96
+ File.delete(file)
97
+ return true
98
+ elsif(@ignore_all)
99
+ return false
100
+ end
101
+
102
+ relative = file.gsub(Dir.pwd, '')
103
+ msg = <<EOF
104
+
105
+ [WARNING] Sprout Encountered an existing file at [#{relative}], what would you like to do?
106
+ (r)eplace, (i)gnore, (R)eplace all or (I)gnore all?
107
+
108
+ EOF
109
+ if(Log.debug)
110
+ return false
111
+ end
112
+
113
+ $stdout.puts msg
114
+ answer = $stdin.gets.chomp
115
+ if(answer == 'r')
116
+ return true
117
+ elsif(answer == 'i')
118
+ return false
119
+ elsif(answer == 'R')
120
+ msg = <<EOF
121
+
122
+ Are you sure you want to replace ALL duplicate files?
123
+ (y)es or (n)o
124
+
125
+ EOF
126
+ $stdout.puts msg
127
+ answer = $stdin.gets.chomp
128
+ if(answer == 'y')
129
+ @replace_all = true
130
+ else
131
+ write_file?(file)
132
+ end
133
+ elsif(answer == 'I')
134
+ @ignore_all = true
135
+ return false
136
+ else
137
+ $stdout.puts "I didn't understand that response... Please choose from the following choices:\n\n"
138
+ write_file?(file)
139
+ end
140
+ end
141
+
142
+ def render_file filename
143
+ file = File.open(filename, 'r')
144
+ resolved = ERB.new(file.read, nil, '>').result(binding)
145
+ file.close
146
+ file = File.open(filename, 'w')
147
+ file.write(resolved)
148
+ file.close
149
+ end
150
+
151
+ def clean_file_name name
152
+ return name.gsub(@@SPROUT_FILE_NAME, project_name)
153
+ end
154
+
155
+ def project_name
156
+ return Sprout.project_name
157
+ end
158
+
159
+ def instance_name
160
+ return project_name[0,1].downcase + project_name[1,project_name.size]
161
+ end
162
+
163
+ #TODO: Figure out if the file is plain text or not... Possible?
164
+ def is_binary? file
165
+ file_extension = File.extname(file).downcase
166
+ @@BINARY_EXTENSIONS.each do |ext|
167
+ if(file_extension == ext)
168
+ return true
169
+ end
170
+ end
171
+ return false
172
+ end
173
+
174
+ =begin
175
+ Found this code for binary inspection here:
176
+ http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/44940
177
+ it's not 100%, but better than what I'm doing with extensions.
178
+ This should be tested and inserted above
179
+ if it works.
180
+
181
+ NON_ASCII_PRINTABLE = /[^\x20-\x7e\s]/
182
+
183
+ def nonbinary?(io, forbidden, size = 1024)
184
+ while buf = io.read(size)
185
+ return false if forbidden =~ buf
186
+ end
187
+ true
188
+ end
189
+
190
+ # usage: ruby this_script.rb filename ...
191
+ ARGV.each do |fn|
192
+ begin
193
+ open(fn) do |f|
194
+ if nonbinary?(f, NON_ASCII_PRINTABLE)
195
+ puts "#{fn}: ascii printable"
196
+ else
197
+ puts "#{fn}: binary"
198
+ end
199
+ end
200
+ rescue
201
+ puts "#$0: #$!"
202
+ end
203
+ end
204
+ =end
205
+
206
+ end
207
+ end
@@ -0,0 +1,370 @@
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
+ ["HOME", "USERPROFILE"].each do |homekey|
148
+ return @home = ENV[homekey] if ENV[homekey]
149
+ end
150
+
151
+ if ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
152
+ return @home = "#{ENV["HOMEDRIVE"]}:#{ENV["HOMEPATH"]}"
153
+ end
154
+
155
+ begin
156
+ return @home = File.expand_path("~")
157
+ rescue StandardError
158
+ if File::ALT_SEPARATOR
159
+ return @home = "C:\\"
160
+ else
161
+ return @home = "/"
162
+ end
163
+ end
164
+ end
165
+
166
+ def get_exe_path(executable)
167
+ paths = get_paths
168
+ file = nil
169
+ paths.each do |path|
170
+ file = File.join(path, executable)
171
+ if(File.exists?(file))
172
+ return file
173
+ end
174
+ end
175
+ return nil
176
+ end
177
+
178
+ def in_path?(executable)
179
+ return !get_exe_path(executable).nil?
180
+ end
181
+
182
+ def get_paths
183
+ return ENV['PATH'].split(':')
184
+ end
185
+
186
+ def library
187
+ return home
188
+ end
189
+
190
+ def platform
191
+ if(Platform::OS == :win32)
192
+ return :win32
193
+ elsif(Platform::IMPL == :macosx)
194
+ return :macosx
195
+ else
196
+ return Platform::IMPL
197
+ end
198
+ end
199
+
200
+ def get_process_runner(command)
201
+ return ProcessRunner.new(command)
202
+ end
203
+
204
+ def execute(tool, options='')
205
+ Log.puts(">> Execute: #{File.basename(tool)} #{options}")
206
+ tool = clean_path(tool)
207
+ runner = get_process_runner("#{tool} #{options}")
208
+
209
+ result = runner.read
210
+ error = runner.read_err
211
+ if(result.size > 0)
212
+ Log.puts result
213
+ end
214
+ if(error.size > 0)
215
+ raise ExecutionError.new("[ERROR] #{error}")
216
+ end
217
+ end
218
+
219
+ def execute_silent(tool, options='')
220
+ tool = clean_path(tool)
221
+ return get_process_runner("#{tool} #{options}")
222
+ end
223
+
224
+ def execute_thread(tool, options='')
225
+ return Thread.new {
226
+ execute(tool, options)
227
+ }
228
+ end
229
+
230
+ def clean_path(path)
231
+ if(path.index(' '))
232
+ # Changed 2/26/2008 in attempt to support
233
+ # ToolTask.PathsParam s that have spaces in the values
234
+ return path.split(' ').join('\ ')
235
+ # return %{'#{path}'}
236
+ end
237
+ return path
238
+ end
239
+
240
+ def application_home(name)
241
+ return File.join(library, format_application_name(name.to_s));
242
+ end
243
+
244
+ def format_application_name(name)
245
+ if(name.index('.') != 0)
246
+ name = '.' + name
247
+ end
248
+ return name.split(" ").join("_").downcase
249
+ end
250
+ end
251
+
252
+ class OSXUser < UnixUser # :nodoc:
253
+ @@LIBRARY = 'Library'
254
+
255
+ def library
256
+ lib = File.join(home, @@LIBRARY)
257
+ if(File.exists?(lib))
258
+ return lib
259
+ else
260
+ return super
261
+ end
262
+ end
263
+
264
+ def format_application_name(name)
265
+ return name.capitalize
266
+ end
267
+ end
268
+
269
+ class WinUser < UnixUser # :nodoc:
270
+ @@LOCAL_SETTINGS = "Local\ Settings"
271
+ @@APPLICATION_DATA = "Application\ Data"
272
+
273
+ def initialize
274
+ super
275
+ @home = nil
276
+ end
277
+
278
+ def setup_user
279
+ end
280
+
281
+ def home
282
+ usr = super
283
+ if(usr.index "My Documents")
284
+ usr = File.dirname(usr)
285
+ end
286
+ return usr
287
+ end
288
+
289
+ def get_paths
290
+ return ENV['PATH'].split(';')
291
+ end
292
+
293
+ def library
294
+ # For some reason, my homepath returns inside 'My Documents'...
295
+ application_data = File.join(home, @@LOCAL_SETTINGS, @@APPLICATION_DATA)
296
+ if(File.exists?(application_data))
297
+ return application_data
298
+ else
299
+ return super
300
+ end
301
+ end
302
+
303
+ def clean_path(path)
304
+ path = path.split('/').join("\\")
305
+ if(path.index(' '))
306
+ return %{"#{path}"}
307
+ end
308
+ return path
309
+ end
310
+
311
+ def format_application_name(name)
312
+ return name.capitalize
313
+ end
314
+ end
315
+
316
+ class CygwinUser < WinUser # :nodoc:
317
+
318
+ def initialize
319
+ super
320
+ @home = nil
321
+ @win_home = nil
322
+ @win_home_cyg_path = nil
323
+ end
324
+
325
+ def setup_user
326
+ end
327
+
328
+ def clean_path(path)
329
+ if(path.index(' '))
330
+ return %{'#{path}'}
331
+ end
332
+ return path
333
+ end
334
+
335
+ def win_home
336
+ if(@win_home.nil?)
337
+ @win_home = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
338
+ end
339
+ return @win_home
340
+ end
341
+
342
+ def home
343
+ if(@home.nil?)
344
+ path = win_home.split('\\').join("/")
345
+ path = path.split(":").join("")
346
+ parts = path.split("/")
347
+ path = parts.shift().downcase + "/" + parts.join("/")
348
+ @home = "/cygdrive/" + path
349
+ end
350
+ return @home
351
+ end
352
+
353
+ end
354
+
355
+ class VistaUser < WinUser # :nodoc:
356
+ def home
357
+ profile = ENV['USERPROFILE']
358
+ if(profile)
359
+ return profile
360
+ end
361
+ return super
362
+ end
363
+ end
364
+
365
+ class ThreadMock # :nodoc:
366
+ def alive?
367
+ return false
368
+ end
369
+ end
370
+ end