vanagon 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@ class Vanagon
22
22
  # @return [Makefile::Rule] The $1 rule
23
23
  def self.rule(target, &block)
24
24
  define_method("#{target}_rule") do
25
- Makefile::Rule.new("#{component.name}-#{target}", environment: component.environment) do |rule|
25
+ Makefile::Rule.new("#{component.name}-#{target}") do |rule|
26
26
  instance_exec(rule, &block)
27
27
  end
28
28
  end
@@ -70,7 +70,7 @@ class Vanagon
70
70
  #
71
71
  # @return [Makefile::Rule]
72
72
  def component_rule
73
- Makefile::Rule.new(component.name, environment: component.environment) do |rule|
73
+ Makefile::Rule.new(component.name) do |rule|
74
74
  rule.dependencies = ["#{component.name}-install"]
75
75
  end
76
76
  end
@@ -81,7 +81,7 @@ class Vanagon
81
81
  # @see [Vanagon::Component::Source]
82
82
  rule("unpack") do |r|
83
83
  r.dependencies = ['file-list-before-build']
84
- r.recipe << component.extract_with
84
+ r.recipe << andand_multiline(component.environment_variables, component.extract_with)
85
85
  r.recipe << "touch #{r.target}"
86
86
  end
87
87
 
@@ -109,6 +109,7 @@ class Vanagon
109
109
 
110
110
  unless component.configure.empty?
111
111
  r.recipe << andand_multiline(
112
+ component.environment_variables,
112
113
  "cd #{component.get_build_dir}",
113
114
  component.configure
114
115
  )
@@ -122,6 +123,7 @@ class Vanagon
122
123
  r.dependencies = ["#{component.name}-configure"]
123
124
  unless component.build.empty?
124
125
  r.recipe << andand_multiline(
126
+ component.environment_variables,
125
127
  "cd #{component.get_build_dir}",
126
128
  component.build
127
129
  )
@@ -135,6 +137,7 @@ class Vanagon
135
137
  r.dependencies = ["#{component.name}-build"]
136
138
  unless component.check.empty? || project.settings[:skipcheck]
137
139
  r.recipe << andand_multiline(
140
+ component.environment_variables,
138
141
  "cd #{component.get_build_dir}",
139
142
  component.check
140
143
  )
@@ -148,6 +151,7 @@ class Vanagon
148
151
  r.dependencies = ["#{component.name}-check"]
149
152
  unless component.install.empty?
150
153
  r.recipe << andand_multiline(
154
+ component.environment_variables,
151
155
  "cd #{component.get_build_dir}",
152
156
  component.install
153
157
  )
@@ -108,7 +108,7 @@ class Vanagon
108
108
  when "xz"
109
109
  %(unxz "#{file}")
110
110
  when "zip"
111
- "unzip '#{file}' || 7za x -r -tzip -o'#{File.basename(file, '.zip')}' '#{file}'"
111
+ "unzip -d '#{File.basename(file, '.zip')}' '#{file}' || 7za x -r -tzip -o'#{File.basename(file, '.zip')}' '#{file}'"
112
112
  else
113
113
  raise Vanagon::Error, "Don't know how to decompress #{extension} archives"
114
114
  end
@@ -31,7 +31,7 @@ class Vanagon
31
31
  filter_out_components(only_build) if only_build
32
32
  loginit('vanagon_hosts.log')
33
33
 
34
- @remote_workdir = options[:remote_workdir]
34
+ @remote_workdir = options[:"remote-workdir"]
35
35
 
36
36
  load_engine(engine, @platform, target)
37
37
  rescue LoadError => e
@@ -120,14 +120,18 @@ class Vanagon
120
120
  puts "Target is #{@engine.target}"
121
121
  retry_task { install_build_dependencies }
122
122
  retry_task { @project.fetch_sources(@workdir) }
123
+
123
124
  @project.make_makefile(@workdir)
124
125
  @project.make_bill_of_materials(@workdir)
125
126
  @project.generate_packaging_artifacts(@workdir)
126
127
  @engine.ship_workdir(@workdir)
127
128
  @engine.dispatch("(cd #{@engine.remote_workdir}; #{@platform.make})")
128
129
  @engine.retrieve_built_artifact
129
- @engine.teardown unless @preserve
130
- cleanup_workdir unless @preserve
130
+
131
+ unless @preserve
132
+ @engine.teardown
133
+ cleanup_workdir
134
+ end
131
135
  rescue => e
132
136
  puts e
133
137
  puts e.backtrace.join("\n")
@@ -146,6 +150,8 @@ class Vanagon
146
150
 
147
151
  puts "rendering Makefile"
148
152
  retry_task { @project.fetch_sources(@workdir) }
153
+ @project.make_bill_of_materials(@workdir)
154
+ @project.generate_packaging_artifacts(@workdir)
149
155
  @project.make_makefile(@workdir)
150
156
  end
151
157
 
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'vanagon/extensions/string'
2
3
 
3
4
  class Vanagon
4
5
  # Environment is a validating wrapper around a delegated Hash,
@@ -46,22 +47,21 @@ class Vanagon
46
47
  @data = {}
47
48
  end
48
49
 
49
- # Associates the value given by value with the key given by key. Keys must
50
- # be strings, and should conform to the Open Group's guidelines for portable
51
- # shell variable names:
50
+ # Associates the value given by value with the key given by key. Keys will
51
+ # be cast to Strings, and should conform to the Open Group's guidelines for
52
+ # portable shell variable names:
52
53
  # Environment variable names used by the utilities in the Shell and
53
54
  # Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
54
55
  # letters, digits, and the '_' (underscore) from the characters defined
55
56
  # in Portable Character Set and do not begin with a digit.
56
57
  #
57
- # Values must be Strings or Integers, and will be stored precisely as given,
58
+ # Values will be cast to Strings, and will be stored precisely as given,
58
59
  # so any escaped characters, single or double quotes, or whitespace will be
59
60
  # preserved exactly as passed during assignment.
60
61
  #
61
62
  # @param key [String]
62
63
  # @param value [String, Integer]
63
- # @raise [ArgumentError] if key is not a String, or if value is not a
64
- # String or an Integer
64
+ # @raise [ArgumentError] if key or value cannot be cast to a String
65
65
  def []=(key, value)
66
66
  @data.update({ validate_key(key) => validate_value(value) })
67
67
  end
@@ -133,32 +133,49 @@ class Vanagon
133
133
  end
134
134
  alias to_string to_s
135
135
 
136
- def sanitize_value(str)
137
- escaped_variables = str.scan(/\$\$([\w]+)/).flatten
136
+ def sanitize_subshells(str)
137
+ pattern = %r{\$\$\((.*?)\)}
138
+ escaped_variables = str.scan(pattern).flatten
138
139
  return str if escaped_variables.empty?
139
140
 
140
- warning = [%(Value "#{str}" looks like it's escaping one or more strings for shell interpolation.)]
141
- escaped_variables.each { |v| warning.push "\t$$#{v} (will be coerced to $(#{v})" }
141
+ warning = [%(Value "#{str}" looks like it's escaping one or more values for subshell interpolation.)]
142
+ escaped_variables.each { |v| warning.push %(\t"$$(#{v})" will be coerced to "$(shell #{v})") }
142
143
  warning.push <<-eos.undent
143
- All environment variables will be resolved by Make; these variables will
144
- be unesecaped for now, but you should update your projects parameters.
144
+ All environment variables will now be resolved by Make before they're executed
145
+ by the shell. These variables will be mangled for you for now, but you should
146
+ update your project's parameters.
145
147
  eos
146
148
 
147
149
  warn warning.join("\n")
148
- str.gsub(/\$\$([\w]+)/, '$(\1)')
150
+ str.gsub(pattern, '$(shell \1)')
149
151
  end
150
- private :sanitize_value
152
+ private :sanitize_subshells
151
153
 
152
- # Validate that a key is a String, that it does not contain invalid
154
+ def sanitize_variables(str)
155
+ pattern = %r{\$\$([\w]+)}
156
+ escaped_variables = str.scan(pattern).flatten
157
+ return str if escaped_variables.empty?
158
+
159
+ warning = [%(Value "#{str}" looks like it's escaping one or more shell variable names for shell interpolation.)]
160
+ escaped_variables.each { |v| warning.push %(\t"$$#{v}" will be coerced to "$(#{v})") }
161
+ warning.push <<-eos.undent
162
+ All environment variables will now be resolved by Make before they're executed
163
+ by the shell. These variables will be mangled for you for now, but you should
164
+ update your project's parameters.
165
+ eos
166
+
167
+ warn warning.join("\n")
168
+ str.gsub(pattern, '$(\1)')
169
+ end
170
+ private :sanitize_variables
171
+
172
+ # Cast key to a String, and validate that it does not contain invalid
153
173
  # characters, and that it does not begin with a digit
154
- # @param key [String]
174
+ # @param key [Object]
155
175
  # @raise [ArgumentError] if key is not a String, if key contains invalid
156
176
  # characters, or if key begins with a digit
157
177
  def validate_key(str)
158
- unless str.is_a?(String)
159
- raise ArgumentError,
160
- 'environment variable Name must be a String'
161
- end
178
+ str = str.to_s
162
179
 
163
180
  if str[0] =~ /\d/
164
181
  raise ArgumentError,
@@ -175,19 +192,13 @@ class Vanagon
175
192
  end
176
193
  private :validate_key
177
194
 
178
- # Validate that str is a String or an Integer, and that the value
195
+ # Cast str to a String, and validate that the value
179
196
  # of str cannot be split into more than a single String by #shellsplit.
180
- # @param value [String, Integer]
181
- # @raise [ArgumentError] if key is not a String or an Integer
197
+ # @param value [Object]
182
198
  def validate_value(str)
183
- unless str.is_a?(String) || str.is_a?(Integer)
184
- raise ArgumentError,
185
- 'Value must be a String or an Integer'
186
- end
187
-
188
199
  # sanitize the value, which should look for any Shell escaped
189
200
  # variable names inside of the value.
190
- str.is_a?(String) ? sanitize_value(str) : str
201
+ sanitize_variables(sanitize_subshells(str.to_s))
191
202
  end
192
203
  private :validate_value
193
204
  end
@@ -4,7 +4,7 @@ class Vanagon
4
4
  class OptParse
5
5
  FLAGS = {
6
6
  :workdir => ['-w DIR', '--workdir DIR', "Working directory where build source should be put (defaults to a tmpdir)"],
7
- :remote_workdir => ['--remote_workdir DIR', "Working directory where build source should be put on the remote host (defaults to a tmpdir)"],
7
+ :"remote-workdir" => ['-r DIR', '--remote-workdir DIR', "Working directory where build source should be put on the remote host (defaults to a tmpdir)"],
8
8
  :configdir => ['-c', '--configdir DIR', 'Configs dir (defaults to $pwd/configs)'],
9
9
  :target => ['-t HOST', '--target HOST', 'Configure a target machine for build and packaging (defaults to grabbing one from the pooler)'],
10
10
  :engine => ['-e ENGINE', '--engine ENGINE', "A custom engine to use (defaults to the pooler) [base, local, docker, pooler currently supported]"],
@@ -72,6 +72,11 @@ class Vanagon
72
72
  # cross-compiled or natively compiled.
73
73
  attr_accessor :cross_compiled
74
74
 
75
+ # Stores a string, pointing at the shell that should be used
76
+ # if a user needs to change the path or name of the shell that
77
+ # Make will run build recipes in.
78
+ attr_accessor :shell
79
+
75
80
  # A string, containing the script that will be executed on
76
81
  # the remote build target to determine how many CPU cores
77
82
  # are available on that platform. Vanagon will use that count
@@ -208,9 +213,15 @@ class Vanagon
208
213
  @find ||= "find"
209
214
  @sort ||= "sort"
210
215
  @copy ||= "cp"
216
+
217
+ # Our first attempt at defining metadata about a platform
211
218
  @cross_compiled ||= false
212
219
  end
213
220
 
221
+ def shell
222
+ @shell ||= "/bin/bash"
223
+ end
224
+
214
225
  # This allows instance variables to be accessed using the hash lookup syntax
215
226
  def [](key)
216
227
  if instance_variable_get("@#{key}")
@@ -389,5 +400,34 @@ class Vanagon
389
400
  def is_cross_compiled_linux?
390
401
  return (is_cross_compiled? && is_linux?)
391
402
  end
403
+
404
+ # Pass in a packaging override. This needs to be implemented for each
405
+ # individual platform so that this input ends up in the right place.
406
+ #
407
+ # @param project
408
+ # @param var the string that should be added to the build script.
409
+ def package_override(project, var)
410
+ fail "I don't know how to set package overrides for #{name}, teach me?"
411
+ end
412
+
413
+ # Generic adder for build repositories
414
+ #
415
+ # @param *args [Array<String>] List of arguments to pass on to the platform specific method
416
+ # @raise [Vanagon::Error] an arror is raised if the current platform does not define add_repository
417
+ def add_build_repository(*args)
418
+ if self.respond_to?(:add_repository)
419
+ self.provision_with self.send(:add_repository, *args)
420
+ else
421
+ raise Vanagon::Error, "Adding a build repository not defined for #{name}"
422
+ end
423
+ end
424
+
425
+ # Set the command to turn the target machine into a builder for vanagon
426
+ #
427
+ # @param command [String] Command to enable the target machine to build packages for the platform
428
+ def provision_with(command)
429
+ provisioning << command
430
+ provisioning.flatten!
431
+ end
392
432
  end
393
433
  end
@@ -102,6 +102,16 @@ class Vanagon
102
102
  provisioning << "apt-get -qq update"
103
103
  end
104
104
 
105
+
106
+ # Pass in a packaging override. This will get added to the rules file, and
107
+ # is a good way to pass in arbitrary environment variables
108
+ #
109
+ # @param project
110
+ # @param var the string that should be added to the build script.
111
+ def package_override(project, var)
112
+ project.package_overrides << var
113
+ end
114
+
105
115
  # Constructor. Sets up some defaults for the debian platform and calls the parent constructor
106
116
  #
107
117
  # @param name [String] name of the platform
@@ -26,7 +26,7 @@ class Vanagon
26
26
  #
27
27
  # @param name [String] name of the platform
28
28
  # @param block [Proc] DSL definition of the platform to call
29
- def platform(platform_name, &block) # rubocop:disable Metrics/AbcSize
29
+ def platform(platform_name, &block)
30
30
  @platform = case platform_name
31
31
  when /^aix-/
32
32
  Vanagon::Platform::RPM::AIX.new(@name)
@@ -51,7 +51,6 @@ class Vanagon
51
51
  end
52
52
 
53
53
  yield(self)
54
- environment 'VANAGON_PLATFORM', platform_name.tr('-', '.')
55
54
  @platform
56
55
  end
57
56
 
@@ -98,6 +97,13 @@ class Vanagon
98
97
  @platform.make = make_cmd
99
98
  end
100
99
 
100
+ # Set the path for Make's SHELL for the platform
101
+ #
102
+ # @param shell_path [String] Full path to the shell Make should use
103
+ def shell(shell_path)
104
+ @platform.shell = shell_path
105
+ end
106
+
101
107
  # Set the path to tar for the platform
102
108
  #
103
109
  # @param tar [String] Full path to the tar command for the platform
@@ -138,7 +144,6 @@ class Vanagon
138
144
  # @param xcc [Boolean] True if this is a cross-compiled platform
139
145
  def cross_compiled(xcc_flag)
140
146
  @platform.cross_compiled = !!xcc_flag
141
- environment 'VANAGON_PLATFORM_XCC', @platform.cross_compiled.to_s
142
147
  end
143
148
 
144
149
  # define an explicit Dist for the platform (most likely used for RPM platforms)
@@ -179,8 +184,7 @@ class Vanagon
179
184
  #
180
185
  # @param command [String] Command to enable the target machine to build packages for the platform
181
186
  def provision_with(command)
182
- @platform.provisioning << command
183
- @platform.provisioning.flatten!
187
+ @platform.provision_with(command)
184
188
  end
185
189
 
186
190
  # Set the command to install any needed build dependencies for the target machine
@@ -316,7 +320,6 @@ class Vanagon
316
320
  # @param user[String] a user string to login with.
317
321
  def target_user(user = "root")
318
322
  @platform.target_user = user
319
- environment 'VANAGON_PLATFORM_USER', user
320
323
  end
321
324
 
322
325
  # Set the target ip address or hostname to start build
@@ -339,7 +342,6 @@ class Vanagon
339
342
  # @param codename [String] codename for this platform (squeeze for example)
340
343
  def codename(codename)
341
344
  @platform.codename = codename
342
- environment 'VANAGON_PLATFORM_CODENAME', codename
343
345
  end
344
346
 
345
347
  def output_dir(directory)
@@ -379,11 +381,7 @@ class Vanagon
379
381
  # @param *args [Array<String>] List of arguments to pass on to the platform specific method
380
382
  # @raise [Vanagon::Error] an arror is raised if the current platform does not define add_repository
381
383
  def add_build_repository(*args)
382
- if @platform.respond_to?(:add_repository)
383
- self.provision_with @platform.send(:add_repository, *args)
384
- else
385
- raise Vanagon::Error, "Adding a build repository not defined for #{@platform.name}"
386
- end
384
+ @platform.add_build_repository(*args)
387
385
  end
388
386
  end
389
387
  end
@@ -69,6 +69,15 @@ class Vanagon
69
69
  commands
70
70
  end
71
71
 
72
+ # Pass in a packaging override. This will get added to the spec file, and
73
+ # is a good way to pass in arbitrary `%_define` or `%_global`
74
+ #
75
+ # @param project
76
+ # @param var the string that should be added to the build script.
77
+ def package_override(project, var)
78
+ project.package_overrides << var
79
+ end
80
+
72
81
  # Constructor. Sets up some defaults for the rpm platform and calls the parent constructor
73
82
  #
74
83
  # @param name [String] name of the platform
@@ -73,6 +73,13 @@ class Vanagon
73
73
  # project should pass to each platform
74
74
  attr_accessor :environment
75
75
 
76
+ # Extra vars to be set in the spec file or debian rules.
77
+ # Good for setting extra %define or %global things for RPM, or env
78
+ # variables needed in the debian rules file
79
+ # No extra munging will be performed, so these should be set as you want
80
+ # them to appear in your spec/rules files!
81
+ attr_accessor :package_overrides
82
+
76
83
  # Loads a given project from the configdir
77
84
  #
78
85
  # @param name [String] the name of the project
@@ -114,6 +121,7 @@ class Vanagon
114
121
  @replaces = []
115
122
  @provides = []
116
123
  @conflicts = []
124
+ @package_overrides = []
117
125
  end
118
126
 
119
127
  # Magic getter to retrieve settings in the project
@@ -393,7 +401,7 @@ class Vanagon
393
401
  files.push get_files.map(&:path)
394
402
  files.push get_configfiles.map(&:path)
395
403
  if @platform.is_windows?
396
- files.flatten.map { |f| "$$(cygpath --mixed --long-name '#{f}')" }
404
+ files.flatten.map { |f| "$(shell cygpath --mixed --long-name '#{f}')" }
397
405
  else
398
406
  files.flatten
399
407
  end
@@ -462,7 +470,6 @@ class Vanagon
462
470
  #
463
471
  # @param workdir [String] workdir to put the packaging files into
464
472
  def generate_packaging_artifacts(workdir)
465
- FileUtils.install File.join(VANAGON_ROOT, "resources", "metrics", "profiling_shell.sh"), File.join(workdir, "profiling_shell.sh"), :mode => 0775
466
473
  @platform.generate_packaging_artifacts(workdir, @name, binding)
467
474
  end
468
475
  end
@@ -24,7 +24,6 @@ class Vanagon
24
24
  # @param block [Proc] DSL definition of the project to call
25
25
  def project(name, &block)
26
26
  yield(self)
27
- environment 'VANAGON_PROJECT', @name
28
27
  end
29
28
 
30
29
  # Accessor for the project.
@@ -70,6 +69,10 @@ class Vanagon
70
69
  @project.settings[name] = value
71
70
  end
72
71
 
72
+ def settings
73
+ @project.settings
74
+ end
75
+
73
76
  # Sets the description of the project. Mainly for use in packaging.
74
77
  #
75
78
  # @param descr [String] description of the project
@@ -82,9 +85,6 @@ class Vanagon
82
85
  # @param the_name [String] name of the project
83
86
  def name(the_name)
84
87
  @project.name = the_name
85
- # Overwrite the environment variable name using the reset name
86
- # of the project.
87
- environment 'VANAGON_PROJECT_NAME', @project.name
88
88
  end
89
89
 
90
90
  # Sets the homepage for the project. Mainly for use in packaging.
@@ -99,7 +99,6 @@ class Vanagon
99
99
  # @param page [Integer] timeout in seconds
100
100
  def timeout(to)
101
101
  @project.timeout = to
102
- environment 'VANAGON_PROJECT_TIMEOUT', @project.timeout
103
102
  end
104
103
 
105
104
  # Sets the run time requirements for the project. Mainly for use in packaging.
@@ -140,7 +139,6 @@ class Vanagon
140
139
  # @param ver [String] version of the project
141
140
  def version(ver)
142
141
  @project.version = ver.tr('-', '.')
143
- environment 'VANAGON_PROJECT_VERSION', @project.version
144
142
  end
145
143
 
146
144
  # Sets the release for the project. Mainly for use in packaging.
@@ -148,7 +146,6 @@ class Vanagon
148
146
  # @param rel [String] release of the project
149
147
  def release(rel)
150
148
  @project.release = rel
151
- environment 'VANAGON_PROJECT_RELEASE', @project.release
152
149
  end
153
150
 
154
151
  # Sets the version for the project based on a git describe of the
@@ -162,12 +159,28 @@ class Vanagon
162
159
  warn "Directory '#{dirname}' cannot be versioned by git. Maybe it hasn't been tagged yet?"
163
160
  end
164
161
 
162
+ # Get the version string from a git branch name. This will look for a '.'
163
+ # delimited string of numbers of any length and return that as the version.
164
+ # For example, 'maint/1.7.0/fixing-some-bugs' will return '1.7.0' and '4.8.x'
165
+ # will return '4.8'.
166
+ #
167
+ # @return version string parsed from branch name, fails if unable to find version
168
+ def version_from_branch
169
+ branch = Git.open(File.expand_path("..", Vanagon::Driver.configdir)).current_branch
170
+ if branch =~ /(\d+(\.\d+)+)/
171
+ return $1
172
+ else
173
+ fail "Can't find a version in your branch, make sure it matches <number>.<number>, like maint/1.7.0/fixing-some-bugs"
174
+ end
175
+ rescue Git::GitExecuteError => e
176
+ fail "Something went wrong trying to find your git branch.\n#{e}"
177
+ end
178
+
165
179
  # Sets the vendor for the project. Used in packaging artifacts.
166
180
  #
167
181
  # @param vend [String] vendor or author of the project
168
182
  def vendor(vend)
169
183
  @project.vendor = vend
170
- environment 'VANAGON_PROJECT_VENDOR', @project.vendor
171
184
  end
172
185
 
173
186
  # Adds a directory to the list of directories provided by the project, to be included in any packages of the project
@@ -262,7 +275,15 @@ class Vanagon
262
275
  # Counter for the number of times a project should retry a task
263
276
  def retry_count(retry_count)
264
277
  @project.retry_count = retry_count
265
- environment 'VANAGON_PROJECT_RETRY_COUNT', @project.retry_count
278
+ end
279
+
280
+ # Set a package override. Will call the platform-specific implementation
281
+ # This will get set in the spec file, deb rules, etc.
282
+ #
283
+ # @param var the string to be included in the build script
284
+ def package_override(var)
285
+ platform = @project.platform
286
+ platform.package_override(self._project, var)
266
287
  end
267
288
  end
268
289
  end