vanagon 0.13.1 → 0.14.1

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.
@@ -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