fig 0.1.38-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/fig/os.rb ADDED
@@ -0,0 +1,396 @@
1
+ require 'fileutils'
2
+ # Must specify absolute path of ::Archive when using
3
+ # this module to avoid conflicts with Fig::Package::Archive
4
+ require 'libarchive_ruby' unless RUBY_PLATFORM == 'java'
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'net/ssh'
8
+ require 'net/sftp'
9
+ require 'net/netrc'
10
+ require 'tempfile'
11
+ require 'highline/import'
12
+
13
+ module Fig
14
+ class NotFoundException < Exception
15
+ end
16
+
17
+ class OS
18
+ def initialize(login)
19
+ @login = login
20
+ @username = ENV["FIG_USERNAME"]
21
+ @password = ENV["FIG_PASSWORD"]
22
+ end
23
+
24
+ def get_username()
25
+ @username ||= ask("Username: ") { |q| q.echo = true }
26
+ end
27
+
28
+ def get_password()
29
+ @password ||= ask("Password: ") { |q| q.echo = false }
30
+ end
31
+
32
+ def ftp_login(ftp, host)
33
+ if @login
34
+ rc = Net::Netrc.locate(host)
35
+ if rc
36
+ @username = rc.login
37
+ @password = rc.password
38
+ end
39
+ ftp.login(get_username, get_password)
40
+ else
41
+ ftp.login()
42
+ end
43
+ ftp.passive = true
44
+ end
45
+
46
+ def list(dir)
47
+ Dir.entries(dir) - ['.','..']
48
+ end
49
+
50
+ def exist?(path)
51
+ File.exist?(path)
52
+ end
53
+
54
+ def mtime(path)
55
+ File.mtime(path)
56
+ end
57
+
58
+ def read(path)
59
+ File.read(path)
60
+ end
61
+
62
+ def write(path, content)
63
+ File.open(path, "wb") { |f| f.binmode; f << content }
64
+ end
65
+
66
+ SUCCESS = 0
67
+ NOT_MODIFIED = 3
68
+ NOT_FOUND = 4
69
+
70
+ def download_list(url)
71
+ begin
72
+ uri = URI.parse(url)
73
+ rescue
74
+ $stderr.puts "Unable to parse url: '#{url}'"
75
+ exit 10
76
+ end
77
+ case uri.scheme
78
+ when "ftp"
79
+ ftp = Net::FTP.new(uri.host)
80
+ ftp_login(ftp, uri.host)
81
+ ftp.chdir(uri.path)
82
+ dirs = ftp.nlst
83
+ ftp.close
84
+
85
+ download_ftp_list(uri, dirs)
86
+ when "ssh"
87
+ packages = []
88
+ Net::SSH.start(uri.host, uri.user) do |ssh|
89
+ ls = ssh.exec!("[ -d #{uri.path} ] && find #{uri.path}")
90
+ if not ls.nil?
91
+ ls = ls.gsub(uri.path + "/", "").gsub(uri.path, "").split("\n")
92
+ ls.each do |line|
93
+ parts = line.gsub(/\\/, '/').sub(/^\.\//, '').sub(/:$/, '').chomp().split('/')
94
+ packages << parts.join('/') if parts.size == 2
95
+ end
96
+ end
97
+ end
98
+ packages
99
+ else
100
+ $stderr.puts "Protocol not supported: #{url}"
101
+ exit 10
102
+ end
103
+ end
104
+
105
+ def download_ftp_list(uri, dirs)
106
+ # Run a bunch of these in parallel since they're slow as hell
107
+ num_threads = (ENV["FIG_FTP_THREADS"] || "16").to_i
108
+ threads = []
109
+ all_packages = []
110
+ (0..num_threads-1).each { |num| all_packages[num] = [] }
111
+ (0..num_threads-1).each do |num|
112
+ threads << Thread.new do
113
+ packages = all_packages[num]
114
+ ftp = Net::FTP.new(uri.host)
115
+ ftp_login(ftp, uri.host)
116
+ ftp.chdir(uri.path)
117
+ pos = num
118
+ while pos < dirs.length
119
+ pkg = dirs[pos]
120
+ begin
121
+ ftp.nlst(dirs[pos]).each do |ver|
122
+ packages << pkg + '/' + ver
123
+ end
124
+ rescue Net::FTPPermError
125
+ # ignore
126
+ end
127
+ pos += num_threads
128
+ end
129
+ ftp.close
130
+ end
131
+ end
132
+ threads.each { |thread| thread.join }
133
+ all_packages.flatten.sort
134
+ end
135
+
136
+ def download(url, path)
137
+ FileUtils.mkdir_p(File.dirname(path))
138
+ uri = URI.parse(url)
139
+ case uri.scheme
140
+ when "ftp"
141
+ ftp = Net::FTP.new(uri.host)
142
+ ftp_login(ftp, uri.host)
143
+ begin
144
+ if File.exist?(path) && ftp.mtime(uri.path) <= File.mtime(path)
145
+ return false
146
+ else
147
+ $stderr.puts "downloading #{url}"
148
+ ftp.getbinaryfile(uri.path, path, 256*1024)
149
+ return true
150
+ end
151
+ rescue Net::FTPPermError
152
+ raise NotFoundException.new
153
+ end
154
+ when "http"
155
+ http = Net::HTTP.new(uri.host)
156
+ $stderr.puts "downloading #{url}"
157
+ File.open(path, "wb") do |file|
158
+ file.binmode
159
+ http.get(uri.path) do |block|
160
+ file.write(block)
161
+ end
162
+ end
163
+ when "ssh"
164
+ # TODO need better way to do conditional download
165
+ # timestamp = `ssh #{uri.user + '@' if uri.user}#{uri.host} "ruby -e 'puts File.mtime(\\"#{uri.path}\\").to_i'"`.to_i
166
+ timestamp = File.exist?(path) ? File.mtime(path).to_i : 0
167
+ cmd = `which fig-download`.strip + " #{timestamp} #{uri.path}"
168
+ ssh_download(uri.user, uri.host, path, cmd)
169
+ else
170
+ $stderr.puts "Unknown protocol: #{url}"
171
+ exit 10
172
+ end
173
+ end
174
+
175
+ def download_resource(url, dir)
176
+ FileUtils.mkdir_p(dir)
177
+ download(url, File.join(dir, URI.parse(url).path.split('/').last))
178
+ end
179
+
180
+ def download_archive(url, dir)
181
+ FileUtils.mkdir_p(dir)
182
+ basename = URI.parse(url).path.split('/').last
183
+ path = File.join(dir, basename)
184
+ download(url, path)
185
+ case basename
186
+ when /\.tar\.gz$/
187
+ unpack_archive(dir, path)
188
+ when /\.tgz$/
189
+ unpack_archive(dir, path)
190
+ when /\.tar\.bz2$/
191
+ unpack_archive(dir, path)
192
+ when /\.zip$/
193
+ unpack_archive(dir, path)
194
+ else
195
+ $stderr.puts "Unknown archive type: #{basename}"
196
+ exit 10
197
+ end
198
+ end
199
+
200
+ def upload(local_file, remote_file, user)
201
+ puts "uploading #{local_file} to #{remote_file}"
202
+ uri = URI.parse(remote_file)
203
+ case uri.scheme
204
+ when "ssh"
205
+ ssh_upload(uri.user, uri.host, local_file, remote_file)
206
+ when "ftp"
207
+ # fail unless system "curl -T #{local_file} --create-dirs --ftp-create-dirs #{remote_file}"
208
+ require 'net/ftp'
209
+ ftp_uri = URI.parse(ENV["FIG_REMOTE_URL"])
210
+ ftp_root_path = ftp_uri.path
211
+ ftp_root_dirs = ftp_uri.path.split("/")
212
+ remote_publish_path = uri.path[0, uri.path.rindex("/")]
213
+ remote_publish_dirs = remote_publish_path.split("/")
214
+ # Use array subtraction to deduce which project/version folder to upload to,
215
+ # i.e. [1,2,3] - [2,3,4] = [1]
216
+ remote_project_dirs = remote_publish_dirs - ftp_root_dirs
217
+ Net::FTP.open(uri.host) do |ftp|
218
+ ftp_login(ftp, uri.host)
219
+ # Assume that the FIG_REMOTE_URL path exists.
220
+ ftp.chdir(ftp_root_path)
221
+ remote_project_dirs.each do |dir|
222
+ # Can't automatically create parent directories, so do it manually.
223
+ if ftp.nlst().index(dir).nil?
224
+ ftp.mkdir(dir)
225
+ ftp.chdir(dir)
226
+ else
227
+ ftp.chdir(dir)
228
+ end
229
+ end
230
+ ftp.putbinaryfile(local_file)
231
+ end
232
+ end
233
+ end
234
+
235
+ def clear_directory(dir)
236
+ FileUtils.rm_rf(dir)
237
+ FileUtils.mkdir_p(dir)
238
+ end
239
+
240
+ def exec(dir,command)
241
+ Dir.chdir(dir) {
242
+ unless system command
243
+ $stderr.puts "Command failed"
244
+ exit 10
245
+ end
246
+ }
247
+ end
248
+
249
+ def copy(source, target, msg = nil)
250
+ if File.directory?(source)
251
+ FileUtils.mkdir_p(target)
252
+ Dir.foreach(source) do |child|
253
+ if child != "." and child != ".."
254
+ copy(File.join(source, child), File.join(target, child), msg)
255
+ end
256
+ end
257
+ else
258
+ if !File.exist?(target) || File.mtime(source) != File.mtime(target)
259
+ log_info "#{msg} #{target}" if msg
260
+ FileUtils.mkdir_p(File.dirname(target))
261
+ FileUtils.cp(source, target)
262
+ File.utime(File.atime(source), File.mtime(source), target)
263
+ end
264
+ end
265
+ end
266
+
267
+ def move_file(dir, from, to)
268
+ Dir.chdir(dir) { FileUtils.mv(from, to, :force => true) }
269
+ end
270
+
271
+ def log_info(msg)
272
+ $stderr.puts msg
273
+ end
274
+
275
+ # Expects files_to_archive as an Array of filenames.
276
+ def create_archive(archive_name, files_to_archive)
277
+ if OS.java?
278
+ `tar czvf #{archive_name} #{files_to_archive.join(' ')}`
279
+ else
280
+ # TODO: Need to verify files_to_archive exists.
281
+ ::Archive.write_open_filename(archive_name, ::Archive::COMPRESSION_GZIP, ::Archive::FORMAT_TAR) do |ar|
282
+ files_to_archive.each do |fn|
283
+ ar.new_entry do |entry|
284
+ entry.copy_stat(fn)
285
+ entry.pathname = fn
286
+ ar.write_header(entry)
287
+ if !entry.directory?
288
+ ar.write_data(open(fn) {|f| f.binmode; f.read })
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
294
+ end
295
+
296
+ # This method can handle the following archive types:
297
+ # .tar.bz2
298
+ # .tar.gz
299
+ # .tgz
300
+ # .zip
301
+ def unpack_archive(dir, file)
302
+ Dir.chdir(dir) do
303
+ if OS.java?
304
+ `tar xzvf #{file}`
305
+ else
306
+ ::Archive.read_open_filename(file) do |ar|
307
+ while entry = ar.next_header
308
+ ar.extract(entry)
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ def self.windows?
316
+ Config::CONFIG['host_os'] =~ /mswin|mingw/
317
+ end
318
+
319
+ def self.java?
320
+ RUBY_PLATFORM == 'java'
321
+ end
322
+
323
+ def self.unix?
324
+ !windows?
325
+ end
326
+
327
+ def shell_exec(cmd)
328
+ if OS.windows?
329
+ Windows.shell_exec_windows(cmd)
330
+ else
331
+ shell_exec_unix(cmd)
332
+ end
333
+ end
334
+
335
+ private
336
+
337
+ def shell_exec_unix(cmd)
338
+ Kernel.exec(ENV['SHELL'], '-c', cmd.join(' '))
339
+ end
340
+
341
+ def shell_exec_windows(cmd)
342
+ #command = ["C:/WINDOWS/system32/cmd.exe", "/C", "call"] + cmd
343
+ command = ["cmd.exe", "/C"] + cmd
344
+ command = command.join(' ')
345
+ Kernel.exec(command)
346
+ end
347
+
348
+ # path = The local path the file should be downloaded to.
349
+ # cmd = The command to be run on the remote host.
350
+ def ssh_download(user, host, path, cmd)
351
+ return_code = nil
352
+ tempfile = Tempfile.new("tmp")
353
+ Net::SSH.start(host, user) do |ssh|
354
+ ssh.open_channel do |channel|
355
+ channel.exec(cmd)
356
+ channel.on_data() { |ch, data| tempfile << data }
357
+ channel.on_extended_data() { |ch, type, data| $stderr.puts "SSH Download ERROR: #{data}" }
358
+ channel.on_request("exit-status") { |ch, request|
359
+ return_code = request.read_long
360
+ }
361
+ end
362
+ end
363
+
364
+ tempfile.close()
365
+
366
+ case return_code
367
+ when NOT_MODIFIED
368
+ tempfile.delete
369
+ return false
370
+ when NOT_FOUND
371
+ tempfile.delete
372
+ $stderr.puts "File not found: #{path}"
373
+ exit 10
374
+ when SUCCESS
375
+ FileUtils.mv(tempfile.path, path)
376
+ return true
377
+ else
378
+ tempfile.delete
379
+ $stderr.puts "Unable to download file: #{return_code}"
380
+ exit 1
381
+ end
382
+ end
383
+
384
+ def ssh_upload(user, host, local_file, remote_file)
385
+ uri = URI.parse(remote_file)
386
+ dir = uri.path[0, uri.path.rindex('/')]
387
+ Net::SSH.start(host, user) do |ssh|
388
+ ssh.exec!("mkdir -p #{dir}")
389
+ end
390
+ Net::SFTP.start(host, user) do |sftp|
391
+ sftp.upload!(local_file, uri.path)
392
+ end
393
+ end
394
+
395
+ end
396
+ end
@@ -0,0 +1,220 @@
1
+ module Fig
2
+ class Package
3
+ attr_reader :package_name, :version_name, :directory, :statements
4
+ attr_accessor :backtrace
5
+
6
+ def initialize(package_name, version_name, directory, statements)
7
+ @package_name = package_name
8
+ @version_name = version_name
9
+ @directory = directory
10
+ @statements = statements
11
+ @backtrace = nil
12
+ end
13
+
14
+ def [](config_name)
15
+ @statements.each do |stmt|
16
+ return stmt if stmt.is_a?(Configuration) && stmt.name == config_name
17
+ end
18
+ $stderr.puts "Configuration not found: #{@package_name}/#{@version_name}:#{config_name}"
19
+ exit 10
20
+ end
21
+
22
+ def configs
23
+ @statements.select { |statement| statement.is_a?(Configuration) }
24
+ end
25
+
26
+ def retrieves
27
+ retrieves = {}
28
+ statements.each { |statement| retrieves[statement.var] = statement.path if statement.is_a?(Retrieve) }
29
+ retrieves
30
+ end
31
+
32
+ def archive_urls
33
+ @statements.select{|s| s.is_a?(Archive)}.map{|s|s.url}
34
+ end
35
+
36
+ def resource_urls
37
+ @statements.select{|s| s.is_a?(Resource)}.map{|s|s.url}
38
+ end
39
+
40
+ def unparse
41
+ @statements.map { |statement| statement.unparse('') }.join("\n")
42
+ end
43
+
44
+ def ==(other)
45
+ @package_name == other.package_name && @version_name == other.version_name && @statements.to_yaml == other.statements.to_yaml
46
+ end
47
+
48
+ def to_s
49
+ @package_name + "/" + @version_name
50
+ end
51
+ end
52
+
53
+ class Archive
54
+ attr_reader :url
55
+
56
+ def initialize(url)
57
+ @url = url
58
+ end
59
+
60
+ def unparse(indent)
61
+ "#{indent}archive \"#{url}\""
62
+ end
63
+ end
64
+
65
+ class Resource
66
+ attr_reader :url
67
+
68
+ def initialize(url)
69
+ @url = url
70
+ end
71
+
72
+ def unparse(indent)
73
+ "#{indent}resource #{url}"
74
+ end
75
+ end
76
+
77
+ class Retrieve
78
+ attr_reader :var, :path
79
+
80
+ def initialize(var, path)
81
+ @var = var
82
+ @path = path
83
+ end
84
+
85
+ def unparse(indent)
86
+ "#{indent}retrieve #{var}->#{path}"
87
+ end
88
+ end
89
+
90
+ class Publish
91
+ attr_reader :local_name, :remote_name
92
+
93
+ def initialize(local_name, remote_name)
94
+ @local_name = local_name
95
+ @remote_name = remote_name
96
+ end
97
+
98
+ def unparse(indent)
99
+ "#{indent}publish #{@local_name}->#{@remote_name}"
100
+ end
101
+ end
102
+
103
+ class Install
104
+ def initialize(statements)
105
+ @statements = statements
106
+ end
107
+
108
+ def unparse(indent)
109
+ prefix = "\n#{indent}install"
110
+ body = @statements.map { |statement| statement.unparse(indent+' ') }.join("\n")
111
+ suffix = "#{indent}end"
112
+ return [prefix, body, suffix].join("\n")
113
+ end
114
+ end
115
+
116
+ class Configuration
117
+ attr_reader :name, :statements
118
+
119
+ def initialize(name, statements)
120
+ @name = name
121
+ @statements = statements
122
+ end
123
+
124
+ def with_name(name)
125
+ Configuration.new(name, statements)
126
+ end
127
+
128
+ def commands
129
+ result = statements.select { |statement| statement.is_a?(Command) }
130
+ # if result.empty?
131
+ # raise "No commands found for config: #{@name}"
132
+ # end
133
+ result
134
+ end
135
+
136
+ def unparse(indent)
137
+ unparse_statements(indent, "config #{@name}", @statements, "end")
138
+ end
139
+ end
140
+
141
+ class Path
142
+ attr_reader :name, :value
143
+
144
+ def initialize(name, value)
145
+ @name = name
146
+ @value = value
147
+ end
148
+
149
+ def unparse(indent)
150
+ "#{indent}append #{name}=#{value}"
151
+ end
152
+ end
153
+
154
+ class Set
155
+ attr_reader :name, :value
156
+
157
+ def initialize(name, value)
158
+ @name = name
159
+ @value = value
160
+ end
161
+
162
+ def unparse(indent)
163
+ "#{indent}set #{name}=#{value}"
164
+ end
165
+ end
166
+
167
+ class Include
168
+ attr_reader :package_name, :config_name, :version_name, :overrides
169
+
170
+ def initialize(package_name, config_name, version_name, overrides)
171
+ @package_name = package_name
172
+ @config_name = config_name
173
+ @version_name = version_name
174
+ @overrides = overrides
175
+ end
176
+
177
+ def unparse(indent)
178
+ descriptor = ""
179
+ descriptor += @package_name if @package_name
180
+ descriptor += "/#{@version_name}" if @version_name
181
+ descriptor += ":#{@config_name}" if @config_name
182
+ @overrides.each do |override|
183
+ descriptor += override.unparse
184
+ end
185
+ return "#{indent}include #{descriptor}"
186
+ end
187
+ end
188
+
189
+ class Override
190
+ attr_reader :package_name, :version_name
191
+
192
+ def initialize(package_name, version_name)
193
+ @package_name = package_name
194
+ @version_name = version_name
195
+ end
196
+
197
+ def unparse()
198
+ return " override " + @package_name + "/" + @version_name
199
+ end
200
+ end
201
+
202
+ class Command
203
+ attr_reader :command
204
+
205
+ def initialize(command)
206
+ @command = command
207
+ end
208
+
209
+ def unparse(indent)
210
+ "#{indent}command \"#{@command}\""
211
+ end
212
+ end
213
+
214
+ end
215
+
216
+ def unparse_statements(indent, prefix, statements, suffix)
217
+ body = @statements.map { |statement| statement.unparse(indent+' ') }.join("\n")
218
+ return ["\n#{indent}#{prefix}", body, "#{indent}#{suffix}"].join("\n")
219
+ end
220
+