omnibus 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.travis.yml +3 -11
  4. data/CHANGELOG.md +50 -0
  5. data/MAINTAINERS.md +26 -0
  6. data/README.md +61 -4
  7. data/appveyor.yml +35 -0
  8. data/docs/Build Cache.md +28 -3
  9. data/docs/Building on RHEL.md +1 -1
  10. data/features/commands/publish.feature +4 -9
  11. data/features/step_definitions/generator_steps.rb +14 -1
  12. data/features/support/env.rb +5 -3
  13. data/lib/omnibus.rb +10 -0
  14. data/lib/omnibus/build_version.rb +34 -25
  15. data/lib/omnibus/build_version_dsl.rb +43 -4
  16. data/lib/omnibus/builder.rb +30 -11
  17. data/lib/omnibus/changelog.rb +52 -0
  18. data/lib/omnibus/changelog_printer.rb +77 -0
  19. data/lib/omnibus/cli.rb +37 -2
  20. data/lib/omnibus/cli/changelog.rb +149 -0
  21. data/lib/omnibus/cli/publish.rb +30 -10
  22. data/lib/omnibus/config.rb +41 -2
  23. data/lib/omnibus/digestable.rb +6 -1
  24. data/lib/omnibus/exceptions.rb +15 -1
  25. data/lib/omnibus/fetcher.rb +78 -34
  26. data/lib/omnibus/fetchers/git_fetcher.rb +84 -42
  27. data/lib/omnibus/fetchers/net_fetcher.rb +64 -13
  28. data/lib/omnibus/fetchers/null_fetcher.rb +8 -1
  29. data/lib/omnibus/fetchers/path_fetcher.rb +24 -1
  30. data/lib/omnibus/file_syncer.rb +52 -1
  31. data/lib/omnibus/generator.rb +22 -21
  32. data/lib/omnibus/generator_files/.kitchen.yml.erb +8 -12
  33. data/lib/omnibus/generator_files/Berksfile.erb +4 -4
  34. data/lib/omnibus/generator_files/Gemfile.erb +3 -3
  35. data/lib/omnibus/generator_files/README.md.erb +17 -0
  36. data/lib/omnibus/generator_files/omnibus.rb.erb +6 -0
  37. data/lib/omnibus/git_repository.rb +43 -0
  38. data/lib/omnibus/health_check.rb +5 -1
  39. data/lib/omnibus/manifest.rb +134 -0
  40. data/lib/omnibus/manifest_diff.rb +88 -0
  41. data/lib/omnibus/manifest_entry.rb +43 -0
  42. data/lib/omnibus/metadata.rb +19 -1
  43. data/lib/omnibus/package.rb +9 -0
  44. data/lib/omnibus/packagers/base.rb +1 -1
  45. data/lib/omnibus/packagers/bff.rb +5 -5
  46. data/lib/omnibus/packagers/deb.rb +11 -4
  47. data/lib/omnibus/packagers/msi.rb +243 -2
  48. data/lib/omnibus/packagers/rpm.rb +68 -14
  49. data/lib/omnibus/packagers/solaris.rb +17 -23
  50. data/lib/omnibus/project.rb +129 -16
  51. data/lib/omnibus/publisher.rb +62 -49
  52. data/lib/omnibus/publishers/artifactory_publisher.rb +96 -5
  53. data/lib/omnibus/publishers/s3_publisher.rb +20 -25
  54. data/lib/omnibus/s3_cache.rb +13 -34
  55. data/lib/omnibus/s3_helpers.rb +119 -0
  56. data/lib/omnibus/semantic_version.rb +57 -0
  57. data/lib/omnibus/software.rb +87 -28
  58. data/lib/omnibus/sugarable.rb +18 -0
  59. data/lib/omnibus/templating.rb +8 -1
  60. data/lib/omnibus/version.rb +1 -1
  61. data/omnibus.gemspec +10 -7
  62. data/resources/bff/gen.template.erb +1 -1
  63. data/resources/msi/bundle.wxs.erb +17 -0
  64. data/resources/msi/localization-en-us.wxl.erb +1 -1
  65. data/resources/rpm/spec.erb +1 -1
  66. data/spec/functional/builder_spec.rb +15 -7
  67. data/spec/functional/fetchers/git_fetcher_spec.rb +44 -12
  68. data/spec/functional/fetchers/net_fetcher_spec.rb +171 -20
  69. data/spec/functional/fetchers/path_fetcher_spec.rb +16 -1
  70. data/spec/functional/file_syncer_spec.rb +58 -5
  71. data/spec/functional/templating_spec.rb +17 -6
  72. data/spec/spec_helper.rb +17 -0
  73. data/spec/support/file_helpers.rb +12 -2
  74. data/spec/support/git_helpers.rb +23 -18
  75. data/spec/support/matchers.rb +22 -0
  76. data/spec/support/output_helpers.rb +29 -0
  77. data/spec/unit/build_version_dsl_spec.rb +31 -4
  78. data/spec/unit/build_version_spec.rb +11 -4
  79. data/spec/unit/builder_spec.rb +33 -0
  80. data/spec/unit/changelog_spec.rb +55 -0
  81. data/spec/unit/cleanroom_spec.rb +1 -1
  82. data/spec/unit/compressors/dmg_spec.rb +3 -3
  83. data/spec/unit/compressors/tgz_spec.rb +3 -3
  84. data/spec/unit/config_spec.rb +3 -1
  85. data/spec/unit/fetcher_spec.rb +35 -0
  86. data/spec/unit/fetchers/git_fetcher_spec.rb +28 -14
  87. data/spec/unit/fetchers/net_fetcher_spec.rb +178 -24
  88. data/spec/unit/fetchers/path_fetcher_spec.rb +8 -7
  89. data/spec/unit/generator_spec.rb +22 -21
  90. data/spec/unit/git_repository_spec.rb +60 -0
  91. data/spec/unit/manifest_diff_spec.rb +75 -0
  92. data/spec/unit/manifest_spec.rb +116 -0
  93. data/spec/unit/metadata_spec.rb +11 -0
  94. data/spec/unit/omnibus_spec.rb +9 -6
  95. data/spec/unit/package_spec.rb +1 -1
  96. data/spec/unit/packagers/base_spec.rb +8 -18
  97. data/spec/unit/packagers/bff_spec.rb +9 -5
  98. data/spec/unit/packagers/deb_spec.rb +44 -12
  99. data/spec/unit/packagers/makeself_spec.rb +4 -4
  100. data/spec/unit/packagers/msi_spec.rb +122 -6
  101. data/spec/unit/packagers/pkg_spec.rb +3 -3
  102. data/spec/unit/packagers/rpm_spec.rb +37 -12
  103. data/spec/unit/project_spec.rb +18 -1
  104. data/spec/unit/publisher_spec.rb +65 -0
  105. data/spec/unit/publishers/artifactory_publisher_spec.rb +26 -20
  106. data/spec/unit/publishers/s3_publisher_spec.rb +14 -30
  107. data/spec/unit/s3_cacher_spec.rb +1 -1
  108. data/spec/unit/s3_helpers_spec.rb +32 -0
  109. data/spec/unit/semantic_version_spec.rb +55 -0
  110. data/spec/unit/software_spec.rb +112 -4
  111. metadata +86 -16
@@ -164,7 +164,7 @@ module Omnibus
164
164
  # @return [String]
165
165
  #
166
166
  def package_path
167
- File.join(Config.package_dir, package_name)
167
+ File.expand_path(File.join(Config.package_dir, package_name))
168
168
  end
169
169
 
170
170
  #
@@ -61,7 +61,7 @@ module Omnibus
61
61
  # @return [String]
62
62
  #
63
63
  def scripts_install_dir
64
- File.expand_path("#{project.install_dir}/embedded/share/installp")
64
+ File.expand_path(File.join(project.install_dir, 'embedded/share/installp'))
65
65
  end
66
66
 
67
67
  #
@@ -70,7 +70,7 @@ module Omnibus
70
70
  # @return [String]
71
71
  #
72
72
  def scripts_staging_dir
73
- File.expand_path("#{staging_dir}#{scripts_install_dir}")
73
+ File.expand_path(File.join(staging_dir, scripts_install_dir))
74
74
  end
75
75
 
76
76
  #
@@ -173,16 +173,16 @@ module Omnibus
173
173
  # This implies that if we are in /tmp/staging/project/dir/things,
174
174
  # we will chown from 'project' on, rather than 'project/dir', which leaves
175
175
  # project owned by the build user (which is incorrect)
176
- shellout!("sudo chown -R 0:0 #{staging_dir}/#{project.install_dir.match(/^\/?(\w+)/)}")
176
+ shellout!("sudo chown -R 0:0 #{File.join(staging_dir, project.install_dir)}")
177
177
  log.info(log_key) { "Creating .bff file" }
178
178
 
179
179
  # Since we want the owner to be root, we need to sudo the mkinstallp
180
180
  # command, otherwise it will not have access to the previously chowned
181
181
  # directory.
182
- shellout!("sudo /usr/sbin/mkinstallp -d #{staging_dir} -T #{staging_dir}/gen.template")
182
+ shellout!("sudo /usr/sbin/mkinstallp -d #{staging_dir} -T #{File.join(staging_dir, 'gen.template')}")
183
183
 
184
184
  # Copy the resulting package up to the package_dir
185
- FileSyncer.glob("#{staging_dir}/tmp/*.bff").each do |bff|
185
+ FileSyncer.glob(File.join(staging_dir, 'tmp/*.bff')).each do |bff|
186
186
  copy_file(bff, File.join(Config.package_dir, create_bff_file_name))
187
187
  end
188
188
  end
@@ -246,8 +246,10 @@ module Omnibus
246
246
  path = File.join(project.package_scripts_path, script)
247
247
 
248
248
  if File.file?(path)
249
- log.debug(log_key) { "Adding script `#{script}' to `#{debian_dir}'" }
249
+ log.debug(log_key) { "Adding script `#{script}' to `#{debian_dir}' from #{path}" }
250
250
  copy_file(path, debian_dir)
251
+ log.debug(log_key) { "SCRIPT FILE: #{debian_dir}/#{script}" }
252
+ FileUtils.chmod(0755, File.join(debian_dir, script))
251
253
  end
252
254
  end
253
255
  end
@@ -400,12 +402,17 @@ module Omnibus
400
402
  'amd64'
401
403
  when 'i686'
402
404
  'i386'
403
- when 'armv6l'
404
- if Ohai['platform'] == 'raspbian'
405
+ when /armv\dl/
406
+ if Ohai['platform'] == 'raspbian' || Ohai['platform'] == 'ubuntu'
405
407
  'armhf'
406
408
  else
407
- 'armv6l'
409
+ Ohai['kernel']['machine']
408
410
  end
411
+ when 'ppc64le'
412
+ # Debian prefers to use ppc64el for little endian architecture name
413
+ # where as others like gnutools/rhel use ppc64le( note the last 2 chars)
414
+ # see http://linux.debian.ports.powerpc.narkive.com/8eeWSBtZ/switching-ppc64el-port-name-to-ppc64le
415
+ 'ppc64el' #dpkg --print-architecture = ppc64el
409
416
  else
410
417
  Ohai['kernel']['machine']
411
418
  end
@@ -16,6 +16,8 @@
16
16
 
17
17
  module Omnibus
18
18
  class Packager::MSI < Packager::Base
19
+ DEFAULT_TIMESTAMP_SERVERS = ['http://timestamp.digicert.com',
20
+ 'http://timestamp.verisign.com/scripts/timestamp.dll']
19
21
  id :msi
20
22
 
21
23
  setup do
@@ -28,6 +30,9 @@ module Omnibus
28
30
  # Render the source file
29
31
  write_source_file
30
32
 
33
+ # Optionally, render the bundle file
34
+ write_bundle_file if bundle_msi
35
+
31
36
  # Copy all the staging assets from vendored Omnibus into the resources
32
37
  # directory.
33
38
  create_directory("#{resources_dir}/assets")
@@ -55,9 +60,12 @@ module Omnibus
55
60
  EOH
56
61
 
57
62
  # Compile with candle.exe
63
+ log.debug(log_key) { "wix_candle_flags: #{wix_candle_flags}" }
64
+
58
65
  shellout! <<-EOH.split.join(' ').squeeze(' ').strip
59
66
  candle.exe
60
67
  -nologo
68
+ #{wix_candle_flags}
61
69
  #{wix_extension_switches(wix_candle_extensions)}
62
70
  -dProjectSourceDir="#{windows_safe_path(project.install_dir)}" "project-files.wxs"
63
71
  "#{windows_safe_path(staging_dir, 'source.wxs')}"
@@ -65,6 +73,9 @@ module Omnibus
65
73
 
66
74
  # Create the msi, ignoring the 204 return code from light.exe since it is
67
75
  # about some expected warnings
76
+
77
+ msi_file = windows_safe_path(Config.package_dir, msi_name)
78
+
68
79
  light_command = <<-EOH.split.join(' ').squeeze(' ').strip
69
80
  light.exe
70
81
  -nologo
@@ -73,9 +84,47 @@ module Omnibus
73
84
  -cultures:en-us
74
85
  -loc "#{windows_safe_path(staging_dir, 'localization-en-us.wxl')}"
75
86
  project-files.wixobj source.wixobj
76
- -out "#{windows_safe_path(Config.package_dir, package_name)}"
87
+ -out "#{msi_file}"
77
88
  EOH
78
89
  shellout!(light_command, returns: [0, 204])
90
+
91
+ if signing_identity
92
+ sign_package(msi_file)
93
+ end
94
+
95
+ # This assumes, rightly or wrongly, that any installers we want to bundle
96
+ # into our installer will be downloaded by omnibus and put in the cache dir
97
+
98
+ if bundle_msi
99
+ shellout! <<-EOH.split.join(' ').squeeze(' ').strip
100
+ candle.exe
101
+ -nologo
102
+ #{wix_candle_flags}
103
+ -ext WixBalExtension
104
+ #{wix_extension_switches(wix_candle_extensions)}
105
+ -dOmnibusCacheDir="#{windows_safe_path(File.expand_path(Config.cache_dir))}"
106
+ "#{windows_safe_path(staging_dir, 'bundle.wxs')}"
107
+ EOH
108
+
109
+ bundle_file = windows_safe_path(Config.package_dir, bundle_name)
110
+
111
+ bundle_light_command = <<-EOH.split.join(' ').squeeze(' ').strip
112
+ light.exe
113
+ -nologo
114
+ -ext WixUIExtension
115
+ -ext WixBalExtension
116
+ #{wix_extension_switches(wix_light_extensions)}
117
+ -cultures:en-us
118
+ -loc "#{windows_safe_path(staging_dir, 'localization-en-us.wxl')}"
119
+ bundle.wixobj
120
+ -out "#{bundle_file}"
121
+ EOH
122
+ shellout!(bundle_light_command, returns: [0, 204])
123
+
124
+ if signing_identity
125
+ sign_package(bundle_file)
126
+ end
127
+ end
79
128
  end
80
129
  end
81
130
 
@@ -177,13 +226,106 @@ module Omnibus
177
226
  end
178
227
  expose :wix_candle_extension
179
228
 
229
+ #
230
+ # Signal that we're building a bundle rather than a single package
231
+ #
232
+ # @example
233
+ # bundle_msi true
234
+ #
235
+ # @param [TrueClass, FalseClass] value
236
+ # whether we're a bundle or not
237
+ #
238
+ # @return [TrueClass, FalseClass]
239
+ # whether we're a bundle or not
240
+ def bundle_msi(val = false)
241
+ unless (val.is_a?(TrueClass) || val.is_a?(FalseClass))
242
+ raise InvalidValue.new(:bundle_msi, 'be TrueClass or FalseClass')
243
+ end
244
+ @bundle_msi ||= val
245
+ end
246
+ expose :bundle_msi
247
+
248
+ #
249
+ # Set the signing certificate name
250
+ #
251
+ # @example
252
+ # signing_identity 'FooCert'
253
+ # signing_identity 'FooCert', store: 'BarStore'
254
+ #
255
+ # @param [String] thumbprint
256
+ # the thumbprint of the certificate in the certificate store
257
+ # @param [Hash<Symbol, String>] params
258
+ # an optional hash that defines the parameters for the singing identity
259
+ #
260
+ # @option params [String] :store (My)
261
+ # The name of the certificate store which contains the certificate
262
+ # @option params [Array<String>, String] :timestamp_servers
263
+ # A trusted timestamp server or a list of truested timestamp servers to
264
+ # be tried. They are tried in the order provided.
265
+ # @option params [TrueClass, FalseClass] :machine_store (false)
266
+ # If set to true, the local machine store will be searched for a valid
267
+ # certificate. Otherwise, the current user store is used
268
+ #
269
+ # Setting nothing will default to trying ['http://timestamp.digicert.com',
270
+ # 'http://timestamp.verisign.com/scripts/timestamp.dll']
271
+ #
272
+ # @return [Hash{:thumbprint => String, :store => String, :timestamp_servers => Array[String]}]
273
+ #
274
+ def signing_identity(thumbprint= NULL, params = NULL)
275
+ unless null?(thumbprint)
276
+ @signing_identity = {}
277
+ unless thumbprint.is_a?(String)
278
+ raise InvalidValue.new(:signing_identity, 'be a String')
279
+ end
280
+
281
+ @signing_identity[:thumbprint] = thumbprint
282
+
283
+ if !null?(params)
284
+ unless params.is_a?(Hash)
285
+ raise InvalidValue.new(:params, 'be a Hash')
286
+ end
287
+
288
+ valid_keys = [:store, :timestamp_servers, :machine_store]
289
+ invalid_keys = params.keys - valid_keys
290
+ unless invalid_keys.empty?
291
+ raise InvalidValue.new(:params, "contain keys from [#{valid_keys.join(', ')}]. "\
292
+ "Found invalid keys [#{invalid_keys.join(', ')}]")
293
+ end
294
+
295
+ if !params[:machine_store].nil? && !(
296
+ params[:machine_store].is_a?(TrueClass) ||
297
+ params[:machine_store].is_a?(FalseClass))
298
+ raise InvalidValue.new(:params, 'contain key :machine_store of type TrueClass or FalseClass')
299
+ end
300
+ else
301
+ params = {}
302
+ end
303
+
304
+ @signing_identity[:store] = params[:store] || 'My'
305
+ servers = params[:timestamp_servers] || DEFAULT_TIMESTAMP_SERVERS
306
+ @signing_identity[:timestamp_servers] = [servers].flatten
307
+ @signing_identity[:machine_store] = params[:machine_store] || false
308
+ end
309
+
310
+ @signing_identity
311
+ end
312
+ expose :signing_identity
313
+
180
314
  #
181
315
  # @!endgroup
182
316
  # --------------------------------------------------
183
317
 
184
318
  # @see Base#package_name
185
319
  def package_name
186
- "#{project.package_name}-#{project.build_version}-#{project.build_iteration}.msi"
320
+ bundle_msi ? bundle_name : msi_name
321
+ end
322
+
323
+ def msi_name
324
+ "#{project.package_name}-#{project.build_version}-#{project.build_iteration}-#{Config.windows_arch}.msi"
325
+ end
326
+
327
+ def bundle_name
328
+ "#{project.package_name}-#{project.build_version}-#{project.build_iteration}-#{Config.windows_arch}.exe"
187
329
  end
188
330
 
189
331
  #
@@ -279,6 +421,27 @@ module Omnibus
279
421
  )
280
422
  end
281
423
 
424
+ #
425
+ # Write the bundle file into the staging directory.
426
+ #
427
+ # @return [void]
428
+ #
429
+ def write_bundle_file
430
+ render_template(resource_path('bundle.wxs.erb'),
431
+ destination: "#{staging_dir}/bundle.wxs",
432
+ variables: {
433
+ name: project.package_name,
434
+ friendly_name: project.friendly_name,
435
+ maintainer: project.maintainer,
436
+ upgrade_code: upgrade_code,
437
+ parameters: parameters,
438
+ version: msi_version,
439
+ display_version: msi_display_version,
440
+ msi: windows_safe_path(Config.package_dir, msi_name),
441
+ }
442
+ )
443
+ end
444
+
282
445
  #
283
446
  # Parse and return the MSI version from the {Project#build_version}.
284
447
  #
@@ -331,6 +494,17 @@ module Omnibus
331
494
  @wix_candle_extensions ||= []
332
495
  end
333
496
 
497
+ #
498
+ # Returns the options to use for candle
499
+ #
500
+ # @return [Array]
501
+ # the extensions that will be loaded for candle
502
+ #
503
+ def wix_candle_flags
504
+ # we support x86 or x64. No Itanium support (ia64).
505
+ @wix_candle_flags ||= "-arch " + (Config.windows_arch.to_sym == :x86 ? "x86" : "x64")
506
+ end
507
+
334
508
  #
335
509
  # Takes an array of wix extension names and creates a string
336
510
  # that can be passed to wix to load those.
@@ -343,5 +517,72 @@ module Omnibus
343
517
  def wix_extension_switches(arr)
344
518
  "#{arr.map {|e| "-ext '#{e}'"}.join(' ')}"
345
519
  end
520
+
521
+ def thumbprint
522
+ signing_identity[:thumbprint]
523
+ end
524
+
525
+ def cert_store_name
526
+ signing_identity[:store]
527
+ end
528
+
529
+ def timestamp_servers
530
+ signing_identity[:timestamp_servers]
531
+ end
532
+
533
+ def machine_store?
534
+ signing_identity[:machine_store]
535
+ end
536
+
537
+ #
538
+ # Takes a path to a msi and uses the set certificate store and
539
+ # certificate name
540
+ #
541
+ def sign_package(msi_file)
542
+ cmd = Array.new.tap do |arr|
543
+ arr << 'signtool.exe'
544
+ arr << 'sign /v'
545
+ arr << '/sm' if machine_store?
546
+ arr << "/s #{cert_store_name}"
547
+ arr << "/sha1 #{thumbprint}"
548
+ arr << "\"#{msi_file}\""
549
+ end
550
+ shellout!(cmd.join(" "))
551
+ add_timestamp(msi_file)
552
+ end
553
+
554
+ #
555
+ # Iterates through available timestamp servers and tries to timestamp
556
+ # the file. If non succeed, an exception is raised.
557
+ #
558
+ def add_timestamp(msi_file)
559
+ success = false
560
+ timestamp_servers.each do |ts|
561
+ success = try_timestamp(msi_file, ts)
562
+ break if success
563
+ end
564
+ raise FailedToTimestampMSI.new if !success
565
+ end
566
+
567
+ def try_timestamp(msi_file, url)
568
+ timestamp_command = "signtool.exe timestamp -t #{url} \"#{msi_file}\""
569
+ status = shellout(timestamp_command)
570
+ if status.exitstatus != 0
571
+ log.warn(log_key) do
572
+ <<-EOH.strip
573
+ Failed to add timestamp with timeserver #{url}
574
+
575
+ STDOUT
576
+ ------
577
+ #{status.stdout}
578
+
579
+ STDERR
580
+ ------
581
+ #{status.stderr}
582
+ EOH
583
+ end
584
+ end
585
+ status.exitstatus == 0
586
+ end
346
587
  end
347
588
  end
@@ -210,7 +210,7 @@ module Omnibus
210
210
  # @return [String]
211
211
  #
212
212
  def package_name
213
- "#{safe_base_package_name}-#{safe_version}-#{safe_build_iteration}.#{safe_architecture}.rpm"
213
+ "#{safe_base_package_name}-#{safe_version}-#{safe_build_iteration}#{dist_tag}.#{safe_architecture}.rpm"
214
214
  end
215
215
 
216
216
  #
@@ -222,6 +222,41 @@ module Omnibus
222
222
  @build_dir ||= File.join(staging_dir, 'BUILD')
223
223
  end
224
224
 
225
+ #
226
+ # Get a list of user-declared config files
227
+ #
228
+ # @return [Array]
229
+ #
230
+ def config_files
231
+ @config_files ||= project.config_files.map { |file| rpm_safe(file) }
232
+ end
233
+
234
+ #
235
+ # Directories owned by the filesystem package:
236
+ # http://fedoraproject.org/wiki/Packaging:Guidelines#File_and_Directory_Ownership
237
+ #
238
+ # @return [Array]
239
+ #
240
+ def filesystem_directories
241
+ @filesystem_directories ||= IO.readlines(resource_path('filesystem_list')).map { |f| f.chomp }
242
+ end
243
+
244
+ #
245
+ # Mark filesystem directories with ownership and permissions specified in the filesystem package
246
+ # https://git.fedorahosted.org/cgit/filesystem.git/plain/filesystem.spec
247
+ #
248
+ # @return [String]
249
+ #
250
+ def mark_filesystem_directories(fsdir)
251
+ if fsdir.eql?('/') || fsdir.eql?('/usr/lib') || fsdir.eql?('/usr/share/empty')
252
+ return "%dir %attr(0555,root,root) #{fsdir}"
253
+ elsif filesystem_directories.include?(fsdir)
254
+ return "%dir %attr(0755,root,root) #{fsdir}"
255
+ else
256
+ return "%dir #{fsdir}"
257
+ end
258
+ end
259
+
225
260
  #
226
261
  # Render an rpm spec file in +SPECS/#{name}.spec+ using the supplied ERB
227
262
  # template.
@@ -240,21 +275,9 @@ module Omnibus
240
275
  hash
241
276
  end
242
277
 
243
- # Exclude directories from the spec that are owned by the filesystem package:
244
- # http://fedoraproject.org/wiki/Packaging:Guidelines#File_and_Directory_Ownership
245
- filesystem_directories = IO.readlines(resource_path('filesystem_list'))
246
- filesystem_directories.map! { |dirname| dirname.chomp }
247
-
248
- # Get a list of user-declared config files
249
- config_files = project.config_files.map { |file| rpm_safe(file) }
250
-
251
278
  # Get a list of all files
252
279
  files = FileSyncer.glob("#{build_dir}/**/*")
253
- .map { |path| path.gsub("#{build_dir}/", '') }
254
- .map { |path| "/#{path}" }
255
- .map { |path| rpm_safe(path) }
256
- .reject { |path| config_files.include?(path) }
257
- .reject { |path| filesystem_directories.include?(path) }
280
+ .map { |path| build_filepath(path) }
258
281
 
259
282
  render_template(resource_path('spec.erb'),
260
283
  destination: spec_file,
@@ -264,6 +287,7 @@ module Omnibus
264
287
  iteration: safe_build_iteration,
265
288
  vendor: vendor,
266
289
  license: license,
290
+ dist_tag: dist_tag,
267
291
  architecture: safe_architecture,
268
292
  maintainer: project.maintainer,
269
293
  homepage: project.homepage,
@@ -278,6 +302,7 @@ module Omnibus
278
302
  scripts: scripts,
279
303
  config_files: config_files,
280
304
  files: files,
305
+ build_dir: build_dir,
281
306
  }
282
307
  )
283
308
  end
@@ -334,6 +359,22 @@ module Omnibus
334
359
  end
335
360
  end
336
361
 
362
+ #
363
+ # Convert the path of a file in the staging directory to an entry for use in the spec file.
364
+ #
365
+ # @return [String]
366
+ #
367
+ def build_filepath(path)
368
+ filepath = rpm_safe('/' + path.gsub("#{build_dir}/", ''))
369
+ return if config_files.include?(filepath)
370
+ full_path = build_dir + filepath.gsub('[%]','%')
371
+ # FileSyncer.glob quotes pathnames that contain spaces, which is a problem on el7
372
+ full_path.gsub!('"', '')
373
+ # Mark directories with the %dir directive to prevent rpmbuild from counting their contents twice.
374
+ return mark_filesystem_directories(filepath) if !File.symlink?(full_path) && File.directory?(full_path)
375
+ filepath
376
+ end
377
+
337
378
  #
338
379
  # The full path to this spec file on disk.
339
380
  #
@@ -393,6 +434,17 @@ module Omnibus
393
434
  .gsub("%", "[%]")
394
435
  end
395
436
 
437
+ #
438
+ # The Dist Tag for this RPM package per the Fedora packaging guidlines.
439
+ #
440
+ # @see http://fedoraproject.org/wiki/Packaging:DistTag
441
+ #
442
+ # @return [String]
443
+ #
444
+ def dist_tag
445
+ ".#{Omnibus::Metadata.platform_shortname}#{Omnibus::Metadata.platform_version}"
446
+ end
447
+
396
448
  #
397
449
  # Return the RPM-ready base package name, converting any invalid characters to
398
450
  # dashes (+-+).
@@ -478,6 +530,8 @@ module Omnibus
478
530
  #
479
531
  def safe_architecture
480
532
  case Ohai['kernel']['machine']
533
+ when 'i686'
534
+ 'i386'
481
535
  when 'armv6l'
482
536
  if Ohai['platform'] == 'pidora'
483
537
  'armv6hl'