fig 0.1.39 → 0.1.41

Sign up to get free protection for your applications and to get access to all the features.
data/lib/fig.rb CHANGED
@@ -0,0 +1,222 @@
1
+ require 'rubygems'
2
+ require 'net/ftp'
3
+ require 'log4r'
4
+
5
+ require 'fig/environment'
6
+ require 'fig/figrc'
7
+ require 'fig/logging'
8
+ require 'fig/options'
9
+ require 'fig/os'
10
+ require 'fig/parser'
11
+ require 'fig/repository'
12
+ require 'fig/retriever'
13
+ require 'fig/userinputerror'
14
+ require 'fig/windows'
15
+
16
+ module Fig
17
+ DEFAULT_FIG_FILE = 'package.fig'
18
+
19
+ def parse_descriptor(descriptor)
20
+ # todo should use treetop for these:
21
+ package_name = descriptor =~ /^([^:\/]+)/ ? $1 : nil
22
+ config_name = descriptor =~ /:([^:\/]+)/ ? $1 : nil
23
+ version_name = descriptor =~ /\/([^:\/]+)/ ? $1 : nil
24
+ return package_name, config_name, version_name
25
+ end
26
+
27
+ def run_fig(argv)
28
+ shell_command = nil
29
+ argv.each_with_index do |arg, i|
30
+ if arg == '--'
31
+ shell_command = argv[(i+1)..-1]
32
+ argv.slice!(i..-1)
33
+ break
34
+ end
35
+ end
36
+
37
+ options, argv, exit_value = parse_options(argv)
38
+ if not exit_value.nil?
39
+ return exit_value
40
+ end
41
+
42
+ Logging.initialize_pre_configuration(options[:log_level])
43
+
44
+ vars = {}
45
+ ENV.each {|key,value| vars[key]=value }
46
+
47
+ remote_url = nil
48
+ if options[:update] || options[:publish] || options[:update_if_missing] || options[:list_remote]
49
+ remote_url = ENV['FIG_REMOTE_URL']
50
+ if remote_url.nil?
51
+ $stderr.puts 'Please define the FIG_REMOTE_URL environment variable.'
52
+ return 1
53
+ end
54
+ end
55
+
56
+ configuration = FigRC.find(
57
+ options[:figrc],
58
+ remote_url,
59
+ options[:login],
60
+ options[:home],
61
+ options[:no_figrc]
62
+ )
63
+
64
+ Logging.initialize_post_configuration(options[:log_config] || configuration['log configuration'], options[:log_level])
65
+
66
+ remote_user = nil
67
+
68
+ os = OS.new(options[:login])
69
+ repos = Repository.new(
70
+ os,
71
+ File.expand_path(File.join(options[:home], 'repos')),
72
+ remote_url,
73
+ configuration,
74
+ remote_user,
75
+ options[:update],
76
+ options[:update_if_missing]
77
+ )
78
+ retriever = Retriever.new('.')
79
+ # Check to see if this is still happening with the new layers of abstraction.
80
+ at_exit { retriever.save }
81
+ env = Environment.new(os, repos, vars, retriever)
82
+
83
+ options[:modifiers].each do |modifier|
84
+ env.apply_config_statement(nil, modifier, nil)
85
+ end
86
+
87
+ input = nil
88
+ if options[:input] == :none
89
+ # ignore
90
+ elsif options[:input] == '-'
91
+ input = $stdin.read
92
+ elsif options[:input].nil?
93
+ input = os.read(DEFAULT_FIG_FILE) if os.exist?(DEFAULT_FIG_FILE)
94
+ else
95
+ if os.exist?(options[:input])
96
+ input = os.read(options[:input])
97
+ else
98
+ $stderr.puts %Q<File not found: "#{options[:input]}".>
99
+ return 1
100
+ end
101
+ end
102
+
103
+ options[:cleans].each do |descriptor|
104
+ package_name, version_name = descriptor.split('/')
105
+ repos.clean(package_name, version_name)
106
+ end
107
+ if options[:list]
108
+ repos.list_packages.sort.each do |item|
109
+ puts item
110
+ end
111
+ return 0
112
+ end
113
+
114
+ if options[:list_remote]
115
+ repos.list_remote_packages.sort.each do |item|
116
+ puts item
117
+ end
118
+ return 0
119
+ end
120
+
121
+ if not options[:list_configs].empty?
122
+ options[:list_configs].each do |descriptor|
123
+ package_name, version_name = descriptor.split('/')
124
+ repos.read_local_package(package_name, version_name).configs.each do |config|
125
+ puts config.name
126
+ end
127
+ end
128
+ return 0
129
+ end
130
+
131
+ if input
132
+ package = Parser.new.parse_package(nil, nil, '.', input)
133
+ direct_retrieves=[]
134
+ if options[:retrieve]
135
+ package.retrieves.each do |var, path|
136
+ if var =~ /^@([^\/]+)(.*)/
137
+ direct_retrieves << [$1, $2, path]
138
+ else
139
+ env.add_retrieve(var, path)
140
+ end
141
+ end
142
+ end
143
+ unless options[:publish] || options[:list] || options[:publish_local]
144
+ env.register_package(package)
145
+ env.apply_config(package, options[:config], nil)
146
+ direct_retrieves.each do |info|
147
+ env.direct_retrieve(info[0], info[1], info[2])
148
+ end
149
+ end
150
+ else
151
+ package = Package.new(nil, nil, '.', [])
152
+ end
153
+
154
+ if options[:publish] || options[:publish_local]
155
+ if !argv.empty?
156
+ $stderr.puts %Q<Unexpected arguments: #{argv.join(' ')}>
157
+ return 10
158
+ end
159
+ package_name, config_name, version_name = parse_descriptor(options[:publish] || options[:publish_local])
160
+ if package_name.nil? || version_name.nil?
161
+ $stderr.puts 'Please specify a package name and a version name.'
162
+ return 10
163
+ end
164
+ if not options[:modifiers].empty?
165
+ publish_statements = options[:resources] + options[:archives] + [Configuration.new('default', options[:modifiers])]
166
+ publish_statements << Publish.new('default','default')
167
+ elsif not package.statements.empty?
168
+ publish_statements = package.statements
169
+ else
170
+ $stderr.puts 'Nothing to publish.'
171
+ return 1
172
+ end
173
+ if options[:publish]
174
+ Logging.info "Checking status of #{package_name}/#{version_name}..."
175
+ if repos.list_remote_packages.include?("#{package_name}/#{version_name}")
176
+ Logging.info "#{package_name}/#{version_name} has already been published."
177
+ if not options[:force]
178
+ Logging.fatal 'Use the --force option if you really want to overwrite, or use --publish-local for testing.'
179
+ return 1
180
+ else
181
+ Logging.info 'Overwriting...'
182
+ end
183
+ end
184
+ end
185
+ Logging.info "Publishing #{package_name}/#{version_name}."
186
+ repos.publish_package(publish_statements, package_name, version_name, options[:publish_local])
187
+ elsif options[:echo]
188
+ puts env[options[:echo]]
189
+ elsif shell_command
190
+ argv.shift
191
+ env.execute_shell(shell_command) { |cmd| os.shell_exec cmd }
192
+ elsif argv[0]
193
+ package_name, config_name, version_name = parse_descriptor(argv.shift)
194
+ env.include_config(package, package_name, config_name, version_name, {}, nil)
195
+ env.execute_config(package, package_name, config_name, nil, argv) { |cmd| os.shell_exec cmd }
196
+ elsif input
197
+ env.execute_config(package, nil, options[:config], nil, argv) { |cmd| os.shell_exec cmd }
198
+ elsif !repos.updating?
199
+ $stderr.puts USAGE
200
+ $stderr.puts %q<Run "fig --help" for a full list of commands.>
201
+ end
202
+
203
+ return 0
204
+ end
205
+
206
+ def run_with_exception_handling(argv)
207
+ begin
208
+ return_code = run_fig(argv)
209
+ return return_code
210
+ rescue URLAccessError => exception
211
+ $stderr.puts "Access to #{exception.url} not allowed."
212
+ return 1
213
+ rescue UserInputError => exception
214
+ # If there's no message, we assume that the cause has already been logged.
215
+ if not exception.message.nil?
216
+ $stderr.puts exception.to_s
217
+ end
218
+
219
+ return 1
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,52 @@
1
+
2
+ module Fig
3
+ class ApplicationConfiguration
4
+ def initialize(remote_repository_url)
5
+ @data = []
6
+ @remote_repository_url = remote_repository_url
7
+ clear_cached_data
8
+ end
9
+
10
+ def ensure_url_whitelist_initialized()
11
+ return if not @whitelist.nil?
12
+ whitelist = self['url_whitelist']
13
+ if whitelist.nil?
14
+ @whitelist = []
15
+ else
16
+ @whitelist = [@remote_repository_url, whitelist].flatten
17
+ end
18
+ end
19
+
20
+ def [](key)
21
+ @data.each do |dataset|
22
+ if dataset.has_key?(key)
23
+ return dataset[key]
24
+ end
25
+ end
26
+ return nil
27
+ end
28
+
29
+ def push_dataset(dataset)
30
+ @data.push(dataset)
31
+ end
32
+
33
+ def unshift_dataset(dataset)
34
+ @data.unshift(dataset)
35
+ end
36
+
37
+ # after push_dataset or unshift_dataset, call clear_cached, and lazy initialize as far as the list of things to exclude
38
+
39
+ def clear_cached_data()
40
+ @whitelist = nil
41
+ end
42
+
43
+ def url_access_allowed?(url)
44
+ ensure_url_whitelist_initialized
45
+ return true if @whitelist.empty?
46
+ @whitelist.each do |allowed_url|
47
+ return true if url.match(/\A#{Regexp.quote(allowed_url)}\b/)
48
+ end
49
+ return false
50
+ end
51
+ end
52
+ end
@@ -5,7 +5,7 @@ class Backtrace
5
5
  @parent = parent
6
6
  @package_name = package_name
7
7
  @version_name = version_name
8
- @config_name = config_name || "default"
8
+ @config_name = config_name || 'default'
9
9
  @overrides = {}
10
10
  end
11
11
 
@@ -13,15 +13,15 @@ class Backtrace
13
13
  if @parent
14
14
  @parent.collect(stack)
15
15
  end
16
- elem = ""
16
+ elem = ''
17
17
  if @package_name
18
18
  elem = @package_name
19
19
  end
20
20
  if @version_name
21
- elem += "/" + @version_name
21
+ elem += '/' + @version_name
22
22
  end
23
23
  if @config_name
24
- elem += ":" + @config_name
24
+ elem += ':' + @config_name
25
25
  end
26
26
  stack << elem
27
27
  end
@@ -41,8 +41,8 @@ class Backtrace
41
41
  collect(stack)
42
42
  i=0
43
43
  for elem in stack
44
- indent=""
45
- i.times { indent += " " }
44
+ indent=''
45
+ i.times { indent += ' ' }
46
46
  out.puts indent+elem
47
47
  i += 1
48
48
  end
@@ -0,0 +1,15 @@
1
+ require 'fig/userinputerror'
2
+
3
+ module Fig
4
+ # Could not determine some kind of information from a configuration file,
5
+ # whether .figrc, log4r, package.fig, etc.
6
+ class ConfigFileError < UserInputError
7
+ def initialize(message, file)
8
+ super(message)
9
+
10
+ @file = file
11
+
12
+ return
13
+ end
14
+ end
15
+ end
@@ -1,11 +1,14 @@
1
+ require 'stringio'
2
+
1
3
  require 'fig/backtrace'
4
+ require 'fig/logging'
5
+ require 'fig/repositoryerror'
2
6
 
3
7
  module Fig
4
-
5
- # This class manages the program's state, including the value of all environment
6
- # variables, and which packages have already been applied
8
+ # This class manages the program's state, including the value of all
9
+ # environment variables, and which packages have already been applied.
7
10
  class Environment
8
- DEFAULT_VERSION_NAME = "current"
11
+ DEFAULT_VERSION_NAME = 'current'
9
12
 
10
13
  def initialize(os, repository, variables, retriever)
11
14
  @os = os
@@ -22,8 +25,8 @@ module Fig
22
25
  @variables[name]
23
26
  end
24
27
 
25
- # Indicates that the values from a particular envrionment variable path should
26
- # be copied to a local directory
28
+ # Indicates that the values from a particular envrionment variable path
29
+
27
30
  def add_retrieve(name, path)
28
31
  @retrieve_vars[name] = path
29
32
  end
@@ -31,8 +34,8 @@ module Fig
31
34
  def register_package(package)
32
35
  name = package.package_name
33
36
  if @packages[name]
34
- $stderr.puts "Package already exists with name: #{name}"
35
- exit 10
37
+ Fig::Logging.fatal %Q<There is already a package with the name "#{name}".>
38
+ raise RepositoryError.new
36
39
  end
37
40
  @packages[name] = package
38
41
  end
@@ -41,7 +44,7 @@ module Fig
41
44
  if (@applied_configs[package.package_name] ||= []).member?(config_name)
42
45
  return
43
46
  end
44
- new_backtrace = backtrace #Backtrace.new(backtrace, package.package_name, package.version_name, config_name)
47
+ new_backtrace = backtrace
45
48
 
46
49
  config = package[config_name]
47
50
  config.statements.each { |stmt| apply_config_statement(package, stmt, new_backtrace) }
@@ -57,11 +60,11 @@ module Fig
57
60
  def execute_config(base_package, package_name, config_name, version_name, args)
58
61
  package = lookup_package(package_name || base_package.package_name, version_name, Backtrace.new(nil, package_name, version_name, config_name))
59
62
  result = nil
60
- commands = package[config_name || "default"].commands
63
+ commands = package[config_name || 'default'].commands
61
64
  with_environment do
62
- # todo nil check
65
+ # TODO nil check
63
66
  commands.each do |command|
64
- result = yield expand_arg("#{command.command} #{args.join(' ')}").gsub("@",package.directory).split(" ")
67
+ result = yield expand_arg("#{command.command} #{args.join(' ')}").gsub('@',package.directory).split(' ')
65
68
  end
66
69
  end
67
70
  result
@@ -83,7 +86,7 @@ module Fig
83
86
  end
84
87
 
85
88
  def include_config(base_package, package_name, config_name, version_name, overrides, backtrace)
86
- # Check to see if this include has been overridden
89
+ # Check to see if this include has been overridden.
87
90
  if backtrace
88
91
  override = backtrace.get_override(package_name || base_package.package_name)
89
92
  if override
@@ -95,7 +98,7 @@ module Fig
95
98
  new_backtrace.add_override(override.package_name, override.version_name)
96
99
  end
97
100
  package = lookup_package(package_name || base_package.package_name, version_name, new_backtrace)
98
- apply_config(package, config_name || "default", new_backtrace)
101
+ apply_config(package, config_name || 'default', new_backtrace)
99
102
  end
100
103
 
101
104
  def direct_retrieve(package_name, source_path, target_path)
@@ -104,7 +107,7 @@ module Fig
104
107
  FileUtils.cp_r(File.join(package.directory, source_path, '.'), target_path)
105
108
  end
106
109
 
107
- private
110
+ private
108
111
 
109
112
  def set_variable(base_package, name, value)
110
113
  @variables[name] = expand_value(base_package, name, value)
@@ -146,10 +149,14 @@ module Fig
146
149
  package.backtrace = backtrace
147
150
  @packages[package_name] = package
148
151
  elsif version_name && version_name != package.version_name
149
- $stderr.puts "Version mismatch: #{package_name}"
150
- backtrace.dump($stderr) if backtrace
151
- package.backtrace.dump($stderr) if package.backtrace
152
- exit 10
152
+ string_handle = StringIO.new
153
+ backtrace.dump(string_handle) if backtrace
154
+ package.backtrace.dump(string_handle) if package.backtrace
155
+ stacktrace = string_handle.to_s
156
+ Fig::Logging.fatal \
157
+ "Version mismatch: #{package_name}" \
158
+ + stacktrace.empty? ? '' : "\n#{stacktrace}"
159
+ raise RepositoryError.new
153
160
  end
154
161
  package
155
162
  end
@@ -159,18 +166,31 @@ module Fig
159
166
  return value unless base_package && base_package.package_name
160
167
  file = value.gsub(/\@/, base_package.directory)
161
168
  if @retrieve_vars.member?(name)
162
- # A '//' in the source file's path tells us to preserve path information
163
- # after the '//' when doing a retrieve.
169
+ # A '//' in the source file's path tells us to preserve path
170
+ # information after the '//' when doing a retrieve.
164
171
  if file.split('//').size > 1
165
172
  preserved_path = file.split('//').last
166
- target = File.join(@retrieve_vars[name].gsub(/\[package\]/, base_package.package_name), preserved_path)
173
+ target = File.join(
174
+ @retrieve_vars[name].gsub(
175
+ /\[package\]/,
176
+ base_package.package_name
177
+ ),
178
+ preserved_path
179
+ )
167
180
  else
168
- target = File.join(@retrieve_vars[name].gsub(/\[package\]/, base_package.package_name))
181
+ target = File.join(
182
+ @retrieve_vars[name].gsub(
183
+ /\[package\]/,
184
+ base_package.package_name
185
+ )
186
+ )
169
187
  if not File.directory?(file)
170
188
  target = File.join(target, File.basename(file))
171
189
  end
172
190
  end
173
- @retriever.with_config(base_package.package_name, base_package.version_name) do
191
+ @retriever.with_package_config(
192
+ base_package.package_name, base_package.version_name
193
+ ) do
174
194
  @retriever.retrieve(file, target)
175
195
  end
176
196
  file = target
@@ -182,8 +202,8 @@ module Fig
182
202
  arg.gsub(/\@([a-zA-Z0-9\-\.]+)/) do |match|
183
203
  package = @packages[$1]
184
204
  if package.nil?
185
- $stderr.puts "Package not found: #{$1}"
186
- exit 10
205
+ Fig::Logging.fatal "Package not found: #{$1}"
206
+ raise RepositoryError.new
187
207
  end
188
208
  package.directory
189
209
  end