vanagon 0.13.1 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,40 +2,86 @@ require 'optparse'
2
2
 
3
3
  class Vanagon
4
4
  class OptParse
5
- FLAGS = {
6
- :workdir => ['-w DIR', '--workdir DIR', "Working directory where build source should be put (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
- :configdir => ['-c', '--configdir DIR', 'Configs dir (defaults to $pwd/configs)'],
9
- :target => ['-t HOST', '--target HOST', 'Configure a target machine for build and packaging (defaults to grabbing one from the pooler)'],
10
- :engine => ['-e ENGINE', '--engine ENGINE', "A custom engine to use (defaults to the pooler) [base, local, docker, pooler currently supported]"],
11
- :skipcheck => ['--skipcheck', 'Skip the `check` stage when building components'],
12
- :preserve => ['-p', '--preserve', 'Whether to tear down the VM on success or not (defaults to false)'],
13
- :verbose => ['-v', '--verbose', 'Verbose output (does nothing)'],
14
- :only_build => ["--only-build COMPONENT,COMPONENT,...", Array, 'Only build this array of components']
15
- }.freeze
16
-
17
- def initialize(banner, options = [])
18
- @options = Hash[options.map { |v| [v, nil] }]
19
- @optparse = OptionParser.new do |opts|
5
+ def initialize(banner, symbols = []) # rubocop:disable Metrics/AbcSize
6
+ ## symbols array kept for backward compatibility but ignored
7
+
8
+ @options = Hash.new
9
+ @options[:preserve] = :'on-failure'
10
+
11
+ @option_parser = OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
20
12
  opts.banner = banner
13
+ opts.separator ""
14
+ opts.separator "Options:"
15
+
16
+ opts.on("-h",
17
+ "--help",
18
+ "Display help") do
19
+ $stdout.puts opts
20
+ exit 1
21
+ end
22
+
23
+ opts.on("-v",
24
+ "--verbose",
25
+ "Verbose output (does nothing)") do |verbose|
26
+ @options[:verbose] = verbose
27
+ end
28
+
29
+ opts.on("-w DIRECTORY",
30
+ "--workdir DIRECTORY",
31
+ "Working directory on the local host (defaults to calling mktemp)") do |workdir|
32
+ @options[:workdir] = workdir
33
+ end
34
+
35
+ opts.on("-r DIRECTORY",
36
+ "--remote-workdir DIRECTORY",
37
+ "Working directory on the remote host (defaults to calling mktemp)") do |remote|
38
+ @options[:"remote-workdir"] = remote
39
+ end
40
+
41
+ opts.on("-c DIRECTORY",
42
+ "--configdir DIRECTORY",
43
+ "Configuration directory (defaults to $CWD/configs)") do |configuration_directory|
44
+ @options[:configdir] = configuration_directory
45
+ end
21
46
 
22
- FLAGS.each_pair do |name, args|
23
- if @options.include?(name)
24
- opts.on(*args) do |value|
25
- @options[name] = value
26
- end
47
+ opts.on("-t HOST",
48
+ "--target HOST",
49
+ "Name of target machine for build and packaging (defaults to requesting from the pooler)") do |target|
50
+ @options[:target] = target
51
+ end
52
+
53
+ opts.on("-e ENGINE",
54
+ "--engine ENGINE",
55
+ "Custom engine to use [base, local, docker, pooler] (defaults to \"pooler\")") do |engine|
56
+ @options[:engine] = engine
57
+ end
58
+
59
+ opts.on("--skipcheck",
60
+ "Skip the \"check\" stage when building components") do |skipcheck|
61
+ @options[:skipcheck] = skipcheck
62
+ end
63
+
64
+ opts.on("-p [RULE]",
65
+ "--preserve [RULE]",
66
+ ["never", "on-failure", "always"],
67
+ "Rule for VM preservation. [never, on-failure, always]") do |rule|
68
+ if rule.nil?
69
+ @options[:preserve] = :always
70
+ else
71
+ @options[:preserve] = rule.to_sym
27
72
  end
28
73
  end
29
74
 
30
- opts.on('-h', '--help', 'Display help') do
31
- $stdout.puts opts
32
- exit 1
75
+ opts.on("--only-build COMPONENT,COMPONENT,...",
76
+ Array,
77
+ "Only build listed COMPONENTs") do |components|
78
+ @options[:only_build] = components
33
79
  end
34
80
  end
35
81
  end
36
82
 
37
83
  def parse!(args)
38
- @optparse.parse!(args)
84
+ @option_parser.parse!(args)
39
85
  @options
40
86
  end
41
87
 
@@ -37,6 +37,7 @@ class Vanagon
37
37
  attr_accessor :rpmbuild # This is RedHat/EL/Fedora/SLES specific
38
38
  attr_accessor :sort
39
39
  attr_accessor :tar
40
+ attr_accessor :shasum
40
41
 
41
42
  # Hold a string containing the values that a given platform
42
43
  # should use when a Makefile is run - resolves to the CFLAGS
@@ -215,6 +216,7 @@ class Vanagon
215
216
  @find ||= "find"
216
217
  @sort ||= "sort"
217
218
  @copy ||= "cp"
219
+ @shasum ||= "sha1sum"
218
220
 
219
221
  # Our first attempt at defining metadata about a platform
220
222
  @cross_compiled ||= false
@@ -435,6 +437,34 @@ class Vanagon
435
437
  end
436
438
  end
437
439
 
440
+ # Save the generic compiled archive and relevant metadata as packaging
441
+ # output. This will include a json file with all of the components/versions
442
+ # that were built and a bill of materials when relevant. The archive will be
443
+ # a gzipped tarball.
444
+ #
445
+ # @param project The Vanagon::Project to run this on
446
+ # @return array of commands to be run
447
+ def generate_compiled_archive(project)
448
+ name_and_version = "#{project.name}-#{project.version}"
449
+ name_and_version_and_platform = "#{name_and_version}.#{name}"
450
+ final_archive = "output/#{name_and_version_and_platform}.tar.gz"
451
+ archive_directory = "#{project.name}-archive"
452
+ metadata = project.build_manifest_json(true)
453
+ metadata.gsub!(/\n/, '\n')
454
+ [
455
+ "mkdir output",
456
+ "mkdir #{archive_directory}",
457
+ "gunzip -c #{name_and_version}.tar.gz | '#{tar}' -C #{archive_directory} -xf -",
458
+ "rm #{name_and_version}.tar.gz",
459
+ "cd #{archive_directory}/#{name_and_version}; rm -f bill-of-materials; #{tar} cf ../../#{name_and_version_and_platform}.tar *",
460
+ "gzip -9c #{name_and_version_and_platform}.tar > #{name_and_version_and_platform}.tar.gz",
461
+ "echo -e \"#{metadata}\" > output/#{name_and_version_and_platform}.json",
462
+ "cp bill-of-materials output/#{name_and_version_and_platform}-bill-of-materials ||:",
463
+ "cp #{name_and_version_and_platform}.tar.gz output",
464
+ "#{shasum} #{final_archive} > #{final_archive}.sha1"
465
+ ]
466
+ end
467
+
438
468
  # Set the command to turn the target machine into a builder for vanagon
439
469
  #
440
470
  # @param command [String] Command to enable the target machine to build packages for the platform
@@ -29,10 +29,15 @@ class Vanagon
29
29
  # @param workdir [String] working directory to stage the evaluated templates in
30
30
  # @param name [String] name of the project
31
31
  # @param binding [Binding] binding to use in evaluating the packaging templates
32
- def generate_packaging_artifacts(workdir, name, binding)
32
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
33
+ def generate_packaging_artifacts(workdir, name, binding, project) # rubocop:disable Metrics/AbcSize
33
34
  deb_dir = File.join(workdir, "debian")
34
35
  FileUtils.mkdir_p(deb_dir)
35
36
 
37
+ unless project.get_interest_triggers("install").empty? && project.get_interest_triggers("upgrade").empty? && project.get_activate_triggers.empty?
38
+ erb_file(File.join(VANAGON_ROOT, "resources/deb/triggers.erb"), File.join(deb_dir, "#{name}.triggers"), false, { :binding => binding })
39
+ end
40
+
36
41
  # Lots of templates here
37
42
  ["changelog", "conffiles", "control", "docs", "dirs", "install", "preinst", "postinst", "postrm", "prerm", "rules"].each do |deb_file|
38
43
  erb_file(File.join(VANAGON_ROOT, "resources/deb/#{deb_file}.erb"), File.join(deb_dir, deb_file), false, { :binding => binding })
@@ -111,6 +111,10 @@ class Vanagon
111
111
  @platform.tar = tar_cmd
112
112
  end
113
113
 
114
+ def shasum(sha1sum_command)
115
+ @platform.shasum = sha1sum_command
116
+ end
117
+
114
118
  # Set the type of package we are going to build for this platform
115
119
  #
116
120
  # @param pkg_type [String] The type of package we are going to build for this platform
@@ -64,7 +64,8 @@ class Vanagon
64
64
  # @param workdir [String] working directory to stage the evaluated templates in
65
65
  # @param name [String] name of the project
66
66
  # @param binding [Binding] binding to use in evaluating the packaging templates
67
- def generate_packaging_artifacts(workdir, name, binding) # rubocop:disable Metrics/AbcSize
67
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
68
+ def generate_packaging_artifacts(workdir, name, binding, project) # rubocop:disable Metrics/AbcSize
68
69
  resources_dir = File.join(workdir, "resources", "osx")
69
70
  FileUtils.mkdir_p(resources_dir)
70
71
  script_dir = File.join(workdir, "scripts")
@@ -100,6 +101,7 @@ class Vanagon
100
101
  @name = name
101
102
  @make = "/usr/bin/make"
102
103
  @tar = "tar"
104
+ @shasum = "/usr/bin/shasum"
103
105
  @pkgbuild = "/usr/bin/pkgbuild"
104
106
  @productbuild = "/usr/bin/productbuild"
105
107
  @hdiutil = "/usr/bin/hdiutil"
@@ -33,7 +33,8 @@ class Vanagon
33
33
  # @param workdir [String] working directory to stage the evaluated templates in
34
34
  # @param name [String] name of the project
35
35
  # @param binding [Binding] binding to use in evaluating the packaging templates
36
- def generate_packaging_artifacts(workdir, name, binding)
36
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
37
+ def generate_packaging_artifacts(workdir, name, binding, project)
37
38
  erb_file(File.join(VANAGON_ROOT, "resources/rpm/project.spec.erb"), File.join(workdir, "#{name}.spec"), false, { :binding => binding })
38
39
  end
39
40
 
@@ -17,6 +17,7 @@ class Vanagon
17
17
  @make = "/usr/bin/gmake"
18
18
  @tar = "/opt/freeware/bin/tar"
19
19
  @patch = "/opt/freeware/bin/patch"
20
+ @shasum = "/opt/freeware/bin/sha1sum"
20
21
  @num_cores = "lsdev -Cc processor |wc -l"
21
22
  @install = "/opt/freeware/bin/install"
22
23
  @rpmbuild = "/usr/bin/rpm"
@@ -48,7 +48,6 @@ class Vanagon
48
48
 
49
49
  bom_install,
50
50
 
51
- "rm #{name_and_version}.tar.gz",
52
51
  "cp -r packaging $(tempdir)/",
53
52
 
54
53
  # Here we are tweaking file/dir ownership and perms in the following ways
@@ -81,7 +80,8 @@ class Vanagon
81
80
  # @param workdir [String] working directory to stage the evaluated templates in
82
81
  # @param name [String] name of the project
83
82
  # @param binding [Binding] binding to use in evaluating the packaging templates
84
- def generate_packaging_artifacts(workdir, name, binding)
83
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
84
+ def generate_packaging_artifacts(workdir, name, binding, project)
85
85
  ["pkginfo", "depend", "preinstall", "preremove", "postinstall", "proto"].each do |template|
86
86
  target_dir = File.join(workdir, 'packaging')
87
87
  FileUtils.mkdir_p(target_dir)
@@ -185,6 +185,7 @@ class Vanagon
185
185
  @make = "/opt/csw/bin/gmake"
186
186
  @tar = "/usr/sfw/bin/gtar"
187
187
  @patch = "/usr/bin/gpatch"
188
+ @shasum = "/opt/csw/bin/shasum"
188
189
  # solaris 10
189
190
  @num_cores = "/usr/bin/kstat cpu_info | awk '{print $$1}' | grep '^core_id$$' | wc -l"
190
191
  super(name)
@@ -40,7 +40,8 @@ class Vanagon
40
40
  # @param workdir [String] working directory to stage the evaluated templates in
41
41
  # @param name [String] name of the project
42
42
  # @param binding [Binding] binding to use in evaluating the packaging templates
43
- def generate_packaging_artifacts(workdir, name, binding)
43
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
44
+ def generate_packaging_artifacts(workdir, name, binding, project)
44
45
  target_dir = File.join(workdir, 'packaging')
45
46
  FileUtils.mkdir_p(target_dir)
46
47
  erb_file(File.join(VANAGON_ROOT, "resources/solaris/11/p5m.erb"), File.join(target_dir, "#{name}.p5m"), false, { :binding => binding })
@@ -11,6 +11,10 @@ class Vanagon
11
11
  return generate_msi_package(project)
12
12
  when "nuget"
13
13
  return generate_nuget_package(project)
14
+ when "archive"
15
+ # We don't need to generate the package for archives, return an
16
+ # empty array
17
+ return []
14
18
  else
15
19
  raise Vanagon::Error, "I don't know how to build package type '#{project.platform.package_type}' for Windows. Teach me?"
16
20
  end
@@ -26,6 +30,8 @@ class Vanagon
26
30
  return msi_package_name(project)
27
31
  when "nuget"
28
32
  return nuget_package_name(project)
33
+ when "archive"
34
+ return "#{project.name}-#{project.version}-archive"
29
35
  else
30
36
  raise Vanagon::Error, "I don't know how to name package type '#{project.platform.package_type}' for Windows. Teach me?"
31
37
  end
@@ -36,12 +42,16 @@ class Vanagon
36
42
  # @param workdir [String] working directory to stage the evaluated templates in
37
43
  # @param name [String] name of the project
38
44
  # @param binding [Binding] binding to use in evaluating the packaging templates
39
- def generate_packaging_artifacts(workdir, name, binding)
45
+ # @param project [Vanagon::Project] Vanagon::Project we are building for
46
+ def generate_packaging_artifacts(workdir, name, binding, project)
40
47
  case @package_type
41
48
  when "msi"
42
49
  return generate_msi_packaging_artifacts(workdir, name, binding)
43
50
  when "nuget"
44
51
  return generate_nuget_packaging_artifacts(workdir, name, binding)
52
+ when "archive"
53
+ # We don't need to generate packaging artifacts if this is an archive
54
+ return
45
55
  else
46
56
  raise Vanagon::Error, "I don't know how create packaging artifacts for package type '#{project.platform.package_type}' for Windows. Teach me?"
47
57
  end
@@ -83,6 +83,13 @@ class Vanagon
83
83
  # Should we include source packages?
84
84
  attr_accessor :source_artifacts
85
85
 
86
+ # Should we include platform-specific archives as final outputs
87
+ # probably gzipped tarball for *nix, and probably 7z for win
88
+ attr_accessor :compiled_archive
89
+
90
+ # Should we generate platform-specific packages (rpm, deb, dmg, msi, etc)
91
+ attr_accessor :generate_packages
92
+
86
93
  # Loads a given project from the configdir
87
94
  #
88
95
  # @param name [String] the name of the project
@@ -109,7 +116,7 @@ class Vanagon
109
116
  # @param name [String] name of the project
110
117
  # @param platform [Vanagon::Platform] platform for the project to be built for
111
118
  # @return [Vanagon::Project] the project with the given name and platform
112
- def initialize(name, platform)
119
+ def initialize(name, platform) # rubocop:disable Metrics/AbcSize
113
120
  @name = name
114
121
  @components = []
115
122
  @requires = []
@@ -125,6 +132,8 @@ class Vanagon
125
132
  @conflicts = []
126
133
  @package_overrides = []
127
134
  @source_artifacts = false
135
+ @compiled_archive = false
136
+ @generate_packages = true
128
137
  end
129
138
 
130
139
  # Magic getter to retrieve settings in the project
@@ -168,7 +177,7 @@ class Vanagon
168
177
  def get_files
169
178
  files = []
170
179
  files.push @version_file if @version_file
171
- files.push @components.map(&:files).flatten
180
+ files.push components.flat_map(&:files)
172
181
  files.flatten.uniq
173
182
  end
174
183
 
@@ -210,7 +219,7 @@ class Vanagon
210
219
  # @return [Array] array of runtime requirements for the project
211
220
  def get_requires
212
221
  req = []
213
- req << @components.map(&:requires).flatten
222
+ req << components.flat_map(&:requires)
214
223
  req << @requires
215
224
  req.flatten.uniq
216
225
  end
@@ -221,7 +230,7 @@ class Vanagon
221
230
  def get_replaces
222
231
  replaces = []
223
232
  replaces.push @replaces.flatten
224
- replaces.push @components.map(&:replaces).flatten
233
+ replaces.push components.flat_map(&:replaces)
225
234
  replaces.flatten.uniq
226
235
  end
227
236
 
@@ -231,7 +240,7 @@ class Vanagon
231
240
 
232
241
  # Collects all of the conflicts for the project and its components
233
242
  def get_conflicts
234
- conflicts = @components.flat_map(&:conflicts) + @conflicts
243
+ conflicts = components.flat_map(&:conflicts) + @conflicts
235
244
  # Mash the whole thing down into a flat Array
236
245
  conflicts.flatten.uniq
237
246
  end
@@ -248,7 +257,7 @@ class Vanagon
248
257
  # @param [string] name of service to grab
249
258
  # @return [@component.service obj] specific service
250
259
  def get_service(name)
251
- @components.each do |component|
260
+ components.each do |component|
252
261
  if component.name == name
253
262
  return component.service
254
263
  end
@@ -262,7 +271,7 @@ class Vanagon
262
271
  def get_provides
263
272
  provides = []
264
273
  provides.push @provides.flatten
265
- provides.push @components.map(&:provides).flatten
274
+ provides.push components.flat_map(&:provides)
266
275
  provides.flatten.uniq
267
276
  end
268
277
 
@@ -270,15 +279,26 @@ class Vanagon
270
279
  !get_provides.empty?
271
280
  end
272
281
 
273
- # Collects the preinstall packaging actions for the project and it's components
274
- # for the specified packaging state
282
+ # Checks that the string pkg_state is valid (install OR upgrade).
283
+ # Return vanagon error if invalid
284
+ #
285
+ # @param pkg_state [String] package state input
286
+ def check_pkg_state_string(pkg_state)
287
+ unless ["install", "upgrade"].include? pkg_state
288
+ raise Vanagon::Error, "#{pkg_state} should be a string containing one of 'install' or 'upgrade'"
289
+ end
290
+ end
291
+
292
+ # Collects the preinstall packaging actions for the project and its components
293
+ # for the specified packaging state
275
294
  #
276
295
  # @param pkg_state [String] the package state we want to run the given scripts for.
277
- # Can be one or more of 'install' or 'upgrade'
296
+ # Can be one of 'install' or 'upgrade'
278
297
  # @return [String] string of Bourne shell compatible scriptlets to execute during the preinstall
279
298
  # phase of packaging during the state of the system defined by pkg_state (either install or upgrade)
280
299
  def get_preinstall_actions(pkg_state)
281
- scripts = @components.map(&:preinstall_actions).flatten.compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
300
+ check_pkg_state_string(pkg_state)
301
+ scripts = components.flat_map(&:preinstall_actions).compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
282
302
  if scripts.empty?
283
303
  return ': no preinstall scripts provided'
284
304
  else
@@ -286,16 +306,81 @@ class Vanagon
286
306
  end
287
307
  end
288
308
 
309
+ # Collects the install trigger scripts for the project for the specified packing state
310
+ #
311
+ # @param pkg_state [String] the package state we want to run the given scripts for.
312
+ # Can be one of the 'install' or 'upgrade'
313
+ # @return [Hash] of scriptlets to execute during the pkg_state (install or upgrade)
314
+ # there can be more than one script for each package (key)
315
+ def get_trigger_scripts(pkg_state)
316
+ triggers = Hash.new { |hsh, key| hsh[key] = [] }
317
+ check_pkg_state_string(pkg_state)
318
+ pkgs = components.flat_map(&:install_triggers).compact.select { |s| s.pkg_state.include? pkg_state }
319
+ pkgs.each do |package|
320
+ triggers[package.pkg].push package.scripts
321
+ end
322
+ triggers
323
+ end
324
+
325
+ # Grabs the install trigger scripts for the specified pkg
326
+ #
327
+ # @param pkg [String] the pkg we watch for being installed
328
+ def get_install_trigger_scripts(pkg)
329
+ scripts = get_trigger_scripts("install")
330
+ return scripts[pkg].join("\n")
331
+ end
332
+
333
+ # Grabs the upgrade trigger scripts for the specified pkg
334
+ #
335
+ # @param pkg [String] the pkg we watch for being upgraded
336
+ def get_upgrade_trigger_scripts(pkg)
337
+ scripts = get_trigger_scripts("upgrade")
338
+ return scripts[pkg].join("\n")
339
+ end
340
+
341
+ # Grabs all pkgs that have trigger scripts for 'install' and 'upgrade'
342
+ #
343
+ # @return [Array] a list of all the pkgs that have trigger scripts
344
+ def get_all_trigger_pkgs()
345
+ install_triggers = get_trigger_scripts("install")
346
+ upgrade_triggers = get_trigger_scripts("upgrade")
347
+ packages = (install_triggers.keys + upgrade_triggers.keys).uniq
348
+ return packages
349
+ end
350
+
351
+ # Collects the interest triggers for the project and its scripts for the
352
+ # specified packaging state
353
+ #
354
+ # @param pkg_state [String] the package state we want to run the given scripts for.
355
+ # Can be one of 'install' or 'upgrade'
356
+ # @return [Array] of OpenStructs of all interest triggers for the pkg_state
357
+ # Use array of openstructs because we need both interest_name and the scripts
358
+ def get_interest_triggers(pkg_state)
359
+ interest_triggers = []
360
+ check_pkg_state_string(pkg_state)
361
+ interests = components.flat_map(&:interest_triggers).compact.select { |s| s.pkg_state.include? pkg_state }
362
+ interests.each do |interest|
363
+ interest_triggers.push(interest)
364
+ end
365
+ interest_triggers.flatten.compact
366
+ end
367
+
368
+ # Collects activate triggers for the project and its components
369
+ #
370
+ # @return [Array] of activate triggers
371
+ def get_activate_triggers()
372
+ components.flat_map(&:activate_triggers).compact.map(&:activate_name)
373
+ end
289
374
 
290
375
  # Collects the postinstall packaging actions for the project and it's components
291
- # for the specified packaging state
376
+ # for the specified packaging state
292
377
  #
293
378
  # @param pkg_state [String] the package state we want to run the given scripts for.
294
- # Can be one or more of 'install' or 'upgrade'
379
+ # Can be one of 'install' or 'upgrade'
295
380
  # @return [String] string of Bourne shell compatible scriptlets to execute during the postinstall
296
381
  # phase of packaging during the state of the system defined by pkg_state (either install or upgrade)
297
382
  def get_postinstall_actions(pkg_state)
298
- scripts = @components.map(&:postinstall_actions).flatten.compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
383
+ scripts = components.flat_map(&:postinstall_actions).compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
299
384
  if scripts.empty?
300
385
  return ': no postinstall scripts provided'
301
386
  else
@@ -311,7 +396,7 @@ class Vanagon
311
396
  # @return [String] string of Bourne shell compatible scriptlets to execute during the preremove
312
397
  # phase of packaging during the state of the system defined by pkg_state (either removal or upgrade)
313
398
  def get_preremove_actions(pkg_state)
314
- scripts = @components.map(&:preremove_actions).flatten.compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
399
+ scripts = components.flat_map(&:preremove_actions).compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
315
400
  if scripts.empty?
316
401
  return ': no preremove scripts provided'
317
402
  else
@@ -327,7 +412,7 @@ class Vanagon
327
412
  # @return [String] string of Bourne shell compatible scriptlets to execute during the postremove
328
413
  # phase of packaging during the state of the system defined by pkg_state (either removal or upgrade)
329
414
  def get_postremove_actions(pkg_state)
330
- scripts = @components.map(&:postremove_actions).flatten.compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
415
+ scripts = components.flat_map(&:postremove_actions).compact.select { |s| s.pkg_state.include? pkg_state }.map(&:scripts)
331
416
  if scripts.empty?
332
417
  return ': no postremove scripts provided'
333
418
  else
@@ -339,7 +424,7 @@ class Vanagon
339
424
  #
340
425
  # @return [Array] array of configfiles installed by components of the project
341
426
  def get_configfiles
342
- @components.map(&:configfiles).flatten.uniq
427
+ components.flat_map(&:configfiles).uniq
343
428
  end
344
429
 
345
430
  def has_configfiles?
@@ -352,7 +437,7 @@ class Vanagon
352
437
  def get_directories
353
438
  dirs = []
354
439
  dirs.push @directories
355
- dirs.push @components.map(&:directories).flatten
440
+ dirs.push components.flat_map(&:directories)
356
441
  dirs.flatten.uniq
357
442
  end
358
443
 
@@ -384,7 +469,7 @@ class Vanagon
384
469
  #
385
470
  # @return [Array] the services provided by components in the project
386
471
  def get_services
387
- @components.map(&:service).flatten.compact
472
+ components.flat_map(&:service).compact
388
473
  end
389
474
 
390
475
  # Simple utility for determining if the components in the project declare
@@ -415,7 +500,7 @@ class Vanagon
415
500
  #
416
501
  # @return [Array] a listing of component names and versions
417
502
  def generate_bill_of_materials
418
- @components.map { |comp| "#{comp.name} #{comp.version}" }.sort
503
+ components.map { |comp| "#{comp.name} #{comp.version}" }.sort
419
504
  end
420
505
 
421
506
  # Method to generate the command to create a tarball of the project
@@ -451,7 +536,7 @@ class Vanagon
451
536
  # @param component [Vanagon::Component] component to check for already satisfied build dependencies
452
537
  # @return [Array] a list of the build dependencies for the given component that are satisfied by other components in the project
453
538
  def list_component_dependencies(component)
454
- component.build_requires.select { |dep| @components.map(&:name).include?(dep) }
539
+ component.build_requires.select { |dep| components.map(&:name).include?(dep) }
455
540
  end
456
541
 
457
542
  # Get the package name for the project on the current platform
@@ -465,7 +550,14 @@ class Vanagon
465
550
  #
466
551
  # @return [String, Array] commands to build a package for the current project as defined by the platform
467
552
  def generate_package
468
- @platform.generate_package(self)
553
+ cmds = []
554
+ if generate_packages
555
+ cmds << @platform.generate_package(self)
556
+ end
557
+ if compiled_archive
558
+ cmds << @platform.generate_compiled_archive(self)
559
+ end
560
+ cmds.flatten
469
561
  end
470
562
 
471
563
  # Generate any required files to build a package for this project on the
@@ -473,7 +565,7 @@ class Vanagon
473
565
  #
474
566
  # @param workdir [String] workdir to put the packaging files into
475
567
  def generate_packaging_artifacts(workdir)
476
- @platform.generate_packaging_artifacts(workdir, @name, binding)
568
+ @platform.generate_packaging_artifacts(workdir, @name, binding, self)
477
569
  end
478
570
 
479
571
  # Generate a json hash which lists all of the dependant components of the
@@ -482,7 +574,7 @@ class Vanagon
482
574
  # @return [Hash] where the top level keys are components and their values
483
575
  # are hashes with additional information on the component.
484
576
  def generate_dependencies_info
485
- @components.each_with_object({}) do |component, hsh|
577
+ components.each_with_object({}) do |component, hsh|
486
578
  hsh.merge!(component.get_dependency_hash)
487
579
  end
488
580
  end
@@ -493,7 +585,7 @@ class Vanagon
493
585
  #
494
586
  # @return [Hash] of information which is useful to know about how a package
495
587
  # was built and what went into the package.
496
- def build_manifest_json
588
+ def build_manifest_json(pretty = false)
497
589
  manifest = {
498
590
  "packaging_type" => {
499
591
  "vanagon" => VANAGON_VERSION,
@@ -502,6 +594,11 @@ class Vanagon
502
594
  "components" => generate_dependencies_info,
503
595
  "build_time" => BUILD_TIME,
504
596
  }
597
+ if pretty
598
+ JSON.pretty_generate(manifest)
599
+ else
600
+ manifest
601
+ end
505
602
  end
506
603
 
507
604
  # Writes a json file at `ext/build_metadata.json` containing information
@@ -509,9 +606,37 @@ class Vanagon
509
606
  #
510
607
  # @return [Hash] of build information
511
608
  def save_manifest_json
512
- manifest = build_manifest_json
609
+ manifest = build_manifest_json(true)
513
610
  File.open(File.join('ext', 'build_metadata.json'), 'w') do |f|
514
- f.write(JSON.pretty_generate(manifest))
611
+ f.write(manifest)
612
+ end
613
+ end
614
+
615
+ # Load the settings hash from an upstream vanagon project.
616
+ # This will clone a git repo at a specified branch and load the specified
617
+ # vanagon project (with no components). The settings hash of the upstream
618
+ # project will be merged with the existing settings hash, overriding any
619
+ # duplicates at the time of calling with the value from upstream. To
620
+ # override settings from upstream, you need to set the `proj.setting` after
621
+ # `proj.inherit_settings`.
622
+ #
623
+ # As the settings are not lazy-loaded, if you need to override a setting
624
+ # from upstream that is used in later settings, you'll need to override all
625
+ # of the settings based on the one you're overriding.
626
+ #
627
+ # @param upstream_project_name [String] The name of the vanagon project to load
628
+ # @param upstream_git_url [URI] The URL to clone this vanagon project from
629
+ # @param upstream_git_branch [String] The branch of the vanagon project to clone from
630
+ def load_upstream_settings(upstream_project_name, upstream_git_url, upstream_git_branch)
631
+ Dir.mktmpdir do |working_directory|
632
+ upstream_source = Vanagon::Component::Source::Git.new(upstream_git_url, workdir: working_directory, ref: upstream_git_branch)
633
+ upstream_source.fetch
634
+ # We don't want to load any of the upstream components, so we're going to
635
+ # pass an array with an empty string as the component list for load_project
636
+ no_components = ['']
637
+ upstream_project = Vanagon::Project.load_project(upstream_project_name, File.join(working_directory, upstream_source.dirname, "configs", "projects"), platform, no_components)
638
+ @settings.merge!(upstream_project.settings)
639
+ upstream_project.cleanup
515
640
  end
516
641
  end
517
642
  end