packaging 0.88.77

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.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -0
  3. data/README-Solaris.md +117 -0
  4. data/README.md +977 -0
  5. data/lib/packaging.rb +32 -0
  6. data/lib/packaging/archive.rb +126 -0
  7. data/lib/packaging/artifactory.rb +651 -0
  8. data/lib/packaging/artifactory/extensions.rb +94 -0
  9. data/lib/packaging/config.rb +492 -0
  10. data/lib/packaging/config/params.rb +387 -0
  11. data/lib/packaging/config/validations.rb +13 -0
  12. data/lib/packaging/deb.rb +28 -0
  13. data/lib/packaging/deb/repo.rb +264 -0
  14. data/lib/packaging/gem.rb +70 -0
  15. data/lib/packaging/metrics.rb +15 -0
  16. data/lib/packaging/nuget.rb +39 -0
  17. data/lib/packaging/paths.rb +376 -0
  18. data/lib/packaging/platforms.rb +507 -0
  19. data/lib/packaging/repo.rb +155 -0
  20. data/lib/packaging/retrieve.rb +75 -0
  21. data/lib/packaging/rpm.rb +5 -0
  22. data/lib/packaging/rpm/repo.rb +254 -0
  23. data/lib/packaging/sign.rb +8 -0
  24. data/lib/packaging/sign/deb.rb +9 -0
  25. data/lib/packaging/sign/dmg.rb +41 -0
  26. data/lib/packaging/sign/ips.rb +57 -0
  27. data/lib/packaging/sign/msi.rb +124 -0
  28. data/lib/packaging/sign/rpm.rb +115 -0
  29. data/lib/packaging/tar.rb +163 -0
  30. data/lib/packaging/util.rb +146 -0
  31. data/lib/packaging/util/date.rb +20 -0
  32. data/lib/packaging/util/execution.rb +85 -0
  33. data/lib/packaging/util/file.rb +125 -0
  34. data/lib/packaging/util/git.rb +174 -0
  35. data/lib/packaging/util/git_tags.rb +73 -0
  36. data/lib/packaging/util/gpg.rb +66 -0
  37. data/lib/packaging/util/jenkins.rb +95 -0
  38. data/lib/packaging/util/misc.rb +69 -0
  39. data/lib/packaging/util/net.rb +410 -0
  40. data/lib/packaging/util/os.rb +17 -0
  41. data/lib/packaging/util/platform.rb +40 -0
  42. data/lib/packaging/util/rake_utils.rb +112 -0
  43. data/lib/packaging/util/serialization.rb +19 -0
  44. data/lib/packaging/util/ship.rb +300 -0
  45. data/lib/packaging/util/tool.rb +41 -0
  46. data/lib/packaging/util/version.rb +334 -0
  47. data/spec/fixtures/config/ext/build_defaults.yaml +2 -0
  48. data/spec/fixtures/config/ext/project_data.yaml +2 -0
  49. data/spec/fixtures/configs/components/test_file.json +1 -0
  50. data/spec/fixtures/configs/components/test_file_2.json +0 -0
  51. data/spec/fixtures/configs/components/test_file_not_tagged.json +1 -0
  52. data/spec/fixtures/configs/components/test_file_wrong_ext.txt +0 -0
  53. data/spec/fixtures/configs/components/test_file_wrong_ext.wrong +0 -0
  54. data/spec/fixtures/util/pre_tasks.yaml +4 -0
  55. data/spec/lib/packaging/artifactory_spec.rb +221 -0
  56. data/spec/lib/packaging/config_spec.rb +576 -0
  57. data/spec/lib/packaging/deb/repo_spec.rb +157 -0
  58. data/spec/lib/packaging/deb_spec.rb +52 -0
  59. data/spec/lib/packaging/gem_spec.rb +86 -0
  60. data/spec/lib/packaging/paths_spec.rb +418 -0
  61. data/spec/lib/packaging/platforms_spec.rb +178 -0
  62. data/spec/lib/packaging/repo_spec.rb +135 -0
  63. data/spec/lib/packaging/retrieve_spec.rb +100 -0
  64. data/spec/lib/packaging/rpm/repo_spec.rb +133 -0
  65. data/spec/lib/packaging/sign_spec.rb +133 -0
  66. data/spec/lib/packaging/tar_spec.rb +116 -0
  67. data/spec/lib/packaging/util/execution_spec.rb +56 -0
  68. data/spec/lib/packaging/util/file_spec.rb +139 -0
  69. data/spec/lib/packaging/util/git_spec.rb +160 -0
  70. data/spec/lib/packaging/util/git_tag_spec.rb +36 -0
  71. data/spec/lib/packaging/util/gpg_spec.rb +64 -0
  72. data/spec/lib/packaging/util/jenkins_spec.rb +112 -0
  73. data/spec/lib/packaging/util/misc_spec.rb +31 -0
  74. data/spec/lib/packaging/util/net_spec.rb +259 -0
  75. data/spec/lib/packaging/util/os_spec.rb +31 -0
  76. data/spec/lib/packaging/util/rake_utils_spec.rb +70 -0
  77. data/spec/lib/packaging/util/ship_spec.rb +199 -0
  78. data/spec/lib/packaging/util/version_spec.rb +123 -0
  79. data/spec/lib/packaging_spec.rb +19 -0
  80. data/spec/spec_helper.rb +22 -0
  81. data/static_artifacts/PackageInfo.plist +3 -0
  82. data/tasks/00_utils.rake +214 -0
  83. data/tasks/30_metrics.rake +33 -0
  84. data/tasks/apple.rake +268 -0
  85. data/tasks/archive.rake +69 -0
  86. data/tasks/build.rake +12 -0
  87. data/tasks/clean.rake +5 -0
  88. data/tasks/config.rake +35 -0
  89. data/tasks/deb.rake +129 -0
  90. data/tasks/deb_repos.rake +28 -0
  91. data/tasks/deprecated.rake +130 -0
  92. data/tasks/doc.rake +20 -0
  93. data/tasks/education.rake +57 -0
  94. data/tasks/fetch.rake +60 -0
  95. data/tasks/gem.rake +159 -0
  96. data/tasks/jenkins.rake +538 -0
  97. data/tasks/jenkins_dynamic.rake +202 -0
  98. data/tasks/load_extras.rake +21 -0
  99. data/tasks/mock.rake +348 -0
  100. data/tasks/nightly_repos.rake +286 -0
  101. data/tasks/pe_deb.rake +12 -0
  102. data/tasks/pe_rpm.rake +13 -0
  103. data/tasks/pe_ship.rake +226 -0
  104. data/tasks/pe_sign.rake +13 -0
  105. data/tasks/pe_tar.rake +5 -0
  106. data/tasks/retrieve.rake +52 -0
  107. data/tasks/rpm.rake +66 -0
  108. data/tasks/rpm_repos.rake +29 -0
  109. data/tasks/ship.rake +692 -0
  110. data/tasks/sign.rake +154 -0
  111. data/tasks/tag.rake +8 -0
  112. data/tasks/tar.rake +28 -0
  113. data/tasks/update.rake +16 -0
  114. data/tasks/vanagon.rake +35 -0
  115. data/tasks/vendor_gems.rake +117 -0
  116. data/tasks/version.rake +33 -0
  117. data/tasks/z_data_dump.rake +65 -0
  118. data/templates/README +1 -0
  119. data/templates/downstream.xml.erb +47 -0
  120. data/templates/msi.xml.erb +197 -0
  121. data/templates/packaging.xml.erb +346 -0
  122. data/templates/repo.xml.erb +117 -0
  123. metadata +287 -0
@@ -0,0 +1,8 @@
1
+ module Pkg::Sign
2
+ require 'packaging/sign/deb'
3
+ require 'packaging/sign/dmg'
4
+ require 'packaging/sign/ips'
5
+ require 'packaging/sign/msi'
6
+ require 'packaging/sign/rpm'
7
+ module_function
8
+ end
@@ -0,0 +1,9 @@
1
+ module Pkg::Sign::Deb
2
+ module_function
3
+
4
+ def sign_changes(file)
5
+ # Lazy lazy lazy lazy lazy
6
+ sign_program = "-p'gpg --use-agent --no-tty'" if ENV['RPM_GPG_AGENT']
7
+ Pkg::Util::Execution.capture3("debsign #{sign_program} --re-sign -k#{Pkg::Config.gpg_key} #{file}")
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ module Pkg::Sign::Dmg
2
+ module_function
3
+
4
+ def sign(target_dir = 'pkg')
5
+ use_identity = "-i #{Pkg::Config.osx_signing_ssh_key}" unless Pkg::Config.osx_signing_ssh_key.nil?
6
+
7
+ if Pkg::Config.osx_signing_server =~ /@/
8
+ host_string = "#{Pkg::Config.osx_signing_server}"
9
+ else
10
+ host_string = "#{ENV['USER']}@#{Pkg::Config.osx_signing_server}"
11
+ end
12
+ ssh_host_string = "#{use_identity} #{host_string}"
13
+ rsync_host_string = "-e 'ssh #{use_identity}' #{host_string}"
14
+
15
+ work_dir = "/tmp/#{Pkg::Util.rand_string}"
16
+ mount = File.join(work_dir, "mount")
17
+ signed = File.join(work_dir, "signed")
18
+ Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p #{mount} #{signed}")
19
+ dmgs = Dir.glob("#{target_dir}/apple/**/*.dmg")
20
+ Pkg::Util::Net.rsync_to(dmgs.join(" "), rsync_host_string, work_dir)
21
+ Pkg::Util::Net.remote_execute(ssh_host_string, %Q[for dmg in #{dmgs.map { |d| File.basename(d, ".dmg") }.join(" ")}; do
22
+ /usr/bin/hdiutil attach #{work_dir}/$dmg.dmg -mountpoint #{mount} -nobrowse -quiet ;
23
+ /usr/bin/security -q unlock-keychain -p "#{Pkg::Config.osx_signing_keychain_pw}" "#{Pkg::Config.osx_signing_keychain}" ;
24
+ for pkg in $(ls #{mount}/*.pkg | xargs -n 1 basename); do
25
+ if /usr/sbin/pkgutil --check-signature #{mount}/$pkg ; then
26
+ echo "$pkg is already signed, skipping . . ." ;
27
+ cp #{mount}/$pkg #{signed}/$pkg ;
28
+ else
29
+ /usr/bin/productsign --keychain "#{Pkg::Config.osx_signing_keychain}" --sign "#{Pkg::Config.osx_signing_cert}" #{mount}/$pkg #{signed}/$pkg ;
30
+ fi
31
+ done
32
+ /usr/bin/hdiutil detach #{mount} -quiet ;
33
+ /bin/rm #{work_dir}/$dmg.dmg ;
34
+ /usr/bin/hdiutil create -volname $dmg -srcfolder #{signed}/ #{work_dir}/$dmg.dmg ;
35
+ /bin/rm #{signed}/* ; done])
36
+ dmgs.each do | dmg |
37
+ Pkg::Util::Net.rsync_from("#{work_dir}/#{File.basename(dmg)}", rsync_host_string, File.dirname(dmg))
38
+ end
39
+ Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -d '#{work_dir}' ]; then rm -rf '#{work_dir}'; fi")
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ module Pkg::Sign::Ips
2
+ module_function
3
+
4
+ def sign(target_dir = 'pkg')
5
+ use_identity = "-i #{Pkg::Config.ips_signing_ssh_key}" unless Pkg::Config.ips_signing_ssh_key.nil?
6
+
7
+ ssh_host_string = "#{use_identity} #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
8
+ rsync_host_string = "-e 'ssh #{use_identity}' #{ENV['USER']}@#{Pkg::Config.ips_signing_server}"
9
+
10
+ p5ps = Dir.glob("#{target_dir}/solaris/11/**/*.p5p")
11
+
12
+ p5ps.each do |p5p|
13
+ work_dir = "/tmp/#{Pkg::Util.rand_string}"
14
+ unsigned_dir = "#{work_dir}/unsigned"
15
+ repo_dir = "#{work_dir}/repo"
16
+ signed_dir = "#{work_dir}/pkgs"
17
+
18
+ Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p #{repo_dir} #{unsigned_dir} #{signed_dir}")
19
+ Pkg::Util::Net.rsync_to(p5p, rsync_host_string, unsigned_dir)
20
+
21
+ # Before we can get started with signing packages we need to create a repo
22
+ Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrepo create #{repo_dir}")
23
+ Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrepo set -s #{repo_dir} publisher/prefix=puppetlabs.com")
24
+ # And import all the packages into the repo.
25
+ Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrecv -s #{unsigned_dir}/#{File.basename(p5p)} -d #{repo_dir} '*'")
26
+ # We are going to hard code the values for signing cert locations for now.
27
+ # This autmation will require an update to actually become reusable, but
28
+ # for now these values will stay this way so solaris signing will stop
29
+ # failing. Please update soon. 06/23/16
30
+ #
31
+ # - Sean P. McDonald
32
+ #
33
+ # We sign the entire repo
34
+ sign_cmd = "sudo -E /usr/bin/pkgsign -c /root/signing/signing_cert_2020.pem \
35
+ -i /root/signing/Thawte_SHA256_Code_Signing_CA.pem \
36
+ -i /root/signing/Thawte_Primary_Root_CA.pem \
37
+ -k /root/signing/signing_key_2020.pem \
38
+ -s 'file://#{work_dir}/repo' '*'"
39
+ puts "About to sign #{p5p} with #{sign_cmd} in #{work_dir}"
40
+ Pkg::Util::Net.remote_execute(ssh_host_string, sign_cmd.squeeze(' '))
41
+ # pkgrecv with -a will pull packages out of the repo, so we need to do that too to actually get the packages we signed
42
+ Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkgrecv -d #{signed_dir}/#{File.basename(p5p)} -a -s #{repo_dir} '*'")
43
+ begin
44
+ # lets make sure we actually signed something?
45
+ # **NOTE** if we're repeatedly trying to sign the same version this
46
+ # might explode because I don't know how to reset the IPS cache.
47
+ # Everything is amazing.
48
+ Pkg::Util::Net.remote_execute(ssh_host_string, "sudo -E /usr/bin/pkg contents -m -g #{signed_dir}/#{File.basename(p5p)} '*' | grep '^signature '")
49
+ rescue RuntimeError
50
+ raise "Looks like #{File.basename(p5p)} was not signed correctly, quitting!"
51
+ end
52
+ # and pull the packages back.
53
+ Pkg::Util::Net.rsync_from("#{signed_dir}/#{File.basename(p5p)}", rsync_host_string, File.dirname(p5p))
54
+ Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -e '#{work_dir}' ] ; then sudo rm -r '#{work_dir}' ; fi")
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,124 @@
1
+ module Pkg::Sign::Msi
2
+ module_function
3
+
4
+ def sign(target_dir = 'pkg')
5
+ use_identity = "-i #{Pkg::Config.msi_signing_ssh_key}" if Pkg::Config.msi_signing_ssh_key
6
+
7
+ ssh_host_string = "#{use_identity} Administrator@#{Pkg::Config.msi_signing_server}"
8
+ rsync_host_string = "-e 'ssh #{use_identity}' Administrator@#{Pkg::Config.msi_signing_server}"
9
+
10
+ work_dir = "Windows/Temp/#{Pkg::Util.rand_string}"
11
+ Pkg::Util::Net.remote_execute(ssh_host_string, "mkdir -p C:/#{work_dir}")
12
+ msis = Dir.glob("#{target_dir}/windows*/**/*.msi")
13
+ Pkg::Util::Net.rsync_to(msis.join(" "), rsync_host_string, "/cygdrive/c/#{work_dir}",
14
+ extra_flags: ["--ignore-existing --relative"])
15
+
16
+ # Please Note:
17
+ # We are currently adding two signatures to the msi.
18
+ #
19
+ # Microsoft compatable Signatures are composed of three different
20
+ # elements.
21
+ # 1) The Certificate used to sign the package. This is the element that
22
+ # is attached to organization. The certificate has an associated
23
+ # algorithm. We recently (February 2016) had to switch from a sha1 to
24
+ # a sha256 certificate. Sha1 was deprecated by many Microsoft
25
+ # elements on 2016-01-01, which forced us to switch to a sha256 cert.
26
+ # This sha256 certificate is recognized by all currently supported
27
+ # windows platforms (Windows 8/Vista forward).
28
+ # 2) The signature used to attach the certificate to the package. This
29
+ # can be a done with a variety of digest algorithms. Older platforms
30
+ # (i.e., Windows 8 and Windows Vista) don't recognize later
31
+ # algorithms like sha256.
32
+ # 3) The timestamp used to validate when the package was signed. This
33
+ # comes from an external source and can be delivered with a variety
34
+ # of digest algorithms. Older platforms do not recognize newer
35
+ # algorithms like sha256.
36
+ #
37
+ # We could have only one signature with the Sha256 Cert, Sha1 Signature,
38
+ # and Sha1 Timestamp, but that would be too easy. The sha256 signature
39
+ # and timestamp add more security to our packages. We can't have only
40
+ # sha256 elements in our package signature, though, because Windows 8
41
+ # and Windows Vista just don't recognize them at all.
42
+ #
43
+ # In order to add two signatures to an MSI, we also need to change the
44
+ # tool we use to sign packages with. Previously, we were using SignTool
45
+ # which is the Microsoft blessed program used to sign packages. However,
46
+ # this tool isn't able to add two signatures to an MSI specifically. It
47
+ # can dual-sign an exe, just not an MSI. In order to get the dual-signed
48
+ # packages, we decided to switch over to using osslsigncode. The original
49
+ # project didn't have support to compile on a windows system, so we
50
+ # decided to use this fork. The binaries on the signer were pulled from
51
+ # https://sourceforge.net/u/keeely/osslsigncode/ci/master/tree/
52
+ #
53
+ # These are our signatures:
54
+ # The first signature:
55
+ # * Sha256 Certificate
56
+ # * Sha1 Signature
57
+ # * Sha1 Timestamp
58
+ #
59
+ # The second signature:
60
+ # * Sha256 Certificate
61
+ # * Sha256 Signature
62
+ # * Sha256 Timestamp
63
+ #
64
+ # Once we no longer support Windows 8/Windows Vista, we can remove the
65
+ # first Sha1 signature.
66
+ sign_command = <<-CMD
67
+ for msipath in #{msis.join(" ")}; do
68
+ msi="$(basename $msipath)"
69
+ msidir="C:/#{work_dir}/$(dirname $msipath)"
70
+ if "/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe" verify -in "$msidir/$msi" ; then
71
+ echo "$msi is already signed, skipping . . ." ;
72
+ else
73
+ tries=5
74
+ sha1Servers=(http://timestamp.digicert.com/sha1/timestamp
75
+ http://timestamp.comodoca.com/authenticode)
76
+ for timeserver in "${sha1Servers[@]}"; do
77
+ for ((try=1; try<=$tries; try++)) do
78
+ ret=$(/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe sign \
79
+ -n "Puppet" -i "http://www.puppet.com" \
80
+ -h sha1 \
81
+ -pkcs12 "#{Pkg::Config.msi_signing_cert}" \
82
+ -pass "#{Pkg::Config.msi_signing_cert_pw}" \
83
+ -t "$timeserver" \
84
+ -in "$msidir/$msi" \
85
+ -out "$msidir/signed-$msi")
86
+ if [[ $ret == *"Succeeded"* ]]; then break; fi
87
+ done;
88
+ if [[ $ret == *"Succeeded"* ]]; then break; fi
89
+ done;
90
+ echo $ret
91
+ if [[ $ret != *"Succeeded"* ]]; then exit 1; fi
92
+ sha256Servers=(http://timestamp.digicert.com/sha256/timestamp
93
+ http://timestamp.comodoca.com?td=sha256)
94
+ for timeserver in "${sha256Servers[@]}"; do
95
+ for ((try=1; try<=$tries; try++)) do
96
+ ret=$(/cygdrive/c/tools/osslsigncode-fork/osslsigncode.exe sign \
97
+ -n "Puppet" -i "http://www.puppet.com" \
98
+ -nest -h sha256 \
99
+ -pkcs12 "#{Pkg::Config.msi_signing_cert}" \
100
+ -pass "#{Pkg::Config.msi_signing_cert_pw}" \
101
+ -ts "$timeserver" \
102
+ -in "$msidir/signed-$msi" \
103
+ -out "$msidir/$msi")
104
+ if [[ $ret == *"Succeeded"* ]]; then break; fi
105
+ done;
106
+ if [[ $ret == *"Succeeded"* ]]; then break; fi
107
+ done;
108
+ echo $ret
109
+ if [[ $ret != *"Succeeded"* ]]; then exit 1; fi
110
+ fi
111
+ done
112
+ CMD
113
+
114
+ Pkg::Util::Net.remote_execute(
115
+ ssh_host_string,
116
+ sign_command,
117
+ { fail_fast: false }
118
+ )
119
+ msis.each do | msi |
120
+ Pkg::Util::Net.rsync_from("/cygdrive/c/#{work_dir}/#{msi}", rsync_host_string, File.dirname(msi))
121
+ end
122
+ Pkg::Util::Net.remote_execute(ssh_host_string, "if [ -d '/cygdrive/c/#{work_dir}' ]; then rm -rf '/cygdrive/c/#{work_dir}'; fi")
123
+ end
124
+ end
@@ -0,0 +1,115 @@
1
+ module Pkg::Sign::Rpm
2
+ module_function
3
+
4
+ def sign(rpm, sign_flags = nil)
5
+ # To enable support for wrappers around rpm and thus support for gpg-agent
6
+ # rpm signing, we have to be able to tell the packaging repo what binary to
7
+ # use as the rpm signing tool.
8
+ rpm_command = ENV['RPM'] || Pkg::Util::Tool.find_tool('rpm')
9
+
10
+ # If we're using the gpg agent for rpm signing, we don't want to specify the
11
+ # input for the passphrase, which is what '--passphrase-fd 3' does. However,
12
+ # if we're not using the gpg agent, this is required, and is part of the
13
+ # defaults on modern rpm. The fun part of gpg-agent signing of rpms is
14
+ # specifying that the gpg check command always return true
15
+ gpg_check_command = ''
16
+ input_flag = ''
17
+ if Pkg::Util.boolean_value(ENV['RPM_GPG_AGENT'])
18
+ gpg_check_command = "--define '%__gpg_check_password_cmd /bin/true'"
19
+ else
20
+ input_flag = "--passphrase-fd 3"
21
+ end
22
+
23
+ # Try this up to 5 times, to allow for incorrect passwords
24
+ Pkg::Util::Execution.retry_on_fail(:times => 5) do
25
+ # This definition of %__gpg_sign_cmd is the default on modern rpm. We
26
+ # accept extra flags to override certain signing behavior for older
27
+ # versions of rpm, e.g. specifying V3 signatures instead of V4.
28
+ Pkg::Util::Execution.capture3("#{rpm_command} #{gpg_check_command} --define '%_gpg_name #{Pkg::Util::Gpg.key}' --define '%__gpg_sign_cmd %{__gpg} gpg #{sign_flags} #{input_flag} --batch --no-verbose --no-armor --no-secmem-warning -u %{_gpg_name} -sbo %{__signature_filename} %{__plaintext_filename}' --addsign #{rpm}")
29
+ end
30
+ end
31
+
32
+ def legacy_sign(rpm)
33
+ sign(rpm, "--force-v3-sigs --digest-algo=sha1")
34
+ end
35
+
36
+ def has_sig?(rpm)
37
+ # This should allow the `Pkg::Util::Gpg.key` method to fail if gpg_key is
38
+ # not set, before shelling out. We also only want the short key, all
39
+ # lowercase, since that's what the `rpm -Kv` output uses.
40
+ key = Pkg::Util::Gpg.key.downcase.chars.last(8).join
41
+ signature_check_output = %x(rpm --checksig --verbose #{rpm})
42
+ # If the signing key has not been loaded on the system this is running on,
43
+ # the check will exit 1, even if the rpm is signed, so we can't use capture3,
44
+ # which bails out with non-0 exit codes. Instead, check that the output
45
+ # looks more-or-less how we expect it to.
46
+ fail "Something went wrong checking the signature of #{rpm}." unless signature_check_output.include? "Header"
47
+ return signature_check_output.include? "key ID #{key}"
48
+ end
49
+
50
+ def sign_all(rpm_directory)
51
+ # Create a hash mapping full paths to basenames.
52
+ # This will allow us to keep track of the different paths that may be
53
+ # associated with a single basename, e.g. noarch packages.
54
+ all_rpms = {}
55
+ rpms_to_sign = Dir["#{rpm_directory}/**/*.rpm"]
56
+ rpms_to_sign.each do |rpm_path|
57
+ all_rpms[rpm_path] = File.basename(rpm_path)
58
+ end
59
+ # Delete a package, both from the signing server and from the rpm array, if
60
+ # there are other packages with the same basename so that we only sign the
61
+ # package once.
62
+ all_rpms.each do |rpm_path, rpm_filename|
63
+ if rpms_to_sign.map { |rpm| File.basename(rpm) }.count(rpm_filename) > 1
64
+ FileUtils.rm(rpm_path)
65
+ rpms_to_sign.delete(rpm_path)
66
+ end
67
+ end
68
+
69
+ v3_rpms = []
70
+ v4_rpms = []
71
+ rpms_to_sign.each do |rpm|
72
+ platform_tag = Pkg::Paths.tag_from_artifact_path(rpm)
73
+ platform, version, _ = Pkg::Platforms.parse_platform_tag(platform_tag)
74
+
75
+ # We don't sign AIX rpms
76
+ next if platform_tag.include?('aix')
77
+
78
+ if has_sig? rpm
79
+ puts "#{rpm} is already signed, skipping . . ."
80
+ next
81
+ end
82
+
83
+ case Pkg::Platforms.signature_format_for_platform_version(platform, version)
84
+ when 'v3'
85
+ v3_rpms << rpm
86
+ when 'v4'
87
+ v4_rpms << rpm
88
+ else
89
+ fail "Cannot find signature type for package '#{rpm}'"
90
+ end
91
+ end
92
+
93
+ unless v3_rpms.empty?
94
+ puts "Signing legacy (v3) rpms..."
95
+ legacy_sign(v3_rpms.join(' '))
96
+ end
97
+
98
+ unless v4_rpms.empty?
99
+ puts "Signing modern (v4) rpms..."
100
+ sign(v4_rpms.join(' '))
101
+ end
102
+
103
+ # Using the map of paths to basenames, we re-hardlink the rpms we deleted.
104
+ all_rpms.each do |link_path, rpm_filename|
105
+ next if File.exist? link_path
106
+ FileUtils.mkdir_p(File.dirname(link_path))
107
+ # Find paths where the signed rpm has the same basename, but different
108
+ # full path, as the one we need to link.
109
+ paths_to_link_to = rpms_to_sign.select { |rpm| File.basename(rpm) == rpm_filename && rpm != link_path }
110
+ paths_to_link_to.each do |path|
111
+ FileUtils.ln(path, link_path, :force => true, :verbose => true)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,163 @@
1
+ module Pkg
2
+ class Tar
3
+ require 'fileutils'
4
+ require 'pathname'
5
+ include FileUtils
6
+
7
+ attr_accessor :files, :project, :version, :excludes, :target, :templates
8
+ attr_reader :tar
9
+
10
+ def initialize
11
+ @tar = Pkg::Util::Tool.find_tool('tar', :required => true)
12
+ @project = Pkg::Config.project
13
+ @version = Pkg::Config.version
14
+ @files = Pkg::Config.files
15
+ @target = File.join(Pkg::Config.project_root, "pkg", "#{@project}-#{@version}.tar.gz")
16
+
17
+ # If the user did not specify any files, then archive the entire working directory
18
+ # instead
19
+ @files ||= Dir.glob('*')
20
+
21
+ # We require that the excludes list be a string (which is space
22
+ # separated, we hope)(deprecated) or an array.
23
+ #
24
+ if Pkg::Config.tar_excludes
25
+ if Pkg::Config.tar_excludes.is_a?(String)
26
+ warn "warning: `tar_excludes` should be an array, not a string"
27
+ @excludes = Pkg::Config.tar_excludes.split(' ')
28
+ elsif Pkg::Config.tar_excludes.is_a?(Array)
29
+ @excludes = Pkg::Config.tar_excludes
30
+ else
31
+ fail "Tarball excludes must either be an array or a string, not #{@excludes.class}"
32
+ end
33
+ else
34
+ @excludes = []
35
+ end
36
+
37
+ # If the user has specified things to exclude via config file, they will be
38
+ # honored by the tar class, but we also always exclude the packaging repo
39
+ # and 'pkg' directory.
40
+ @excludes += ['pkg', 'ext/packaging']
41
+
42
+ # On the other hand, support for explicit templates started with Arrays,
43
+ # so that's all we support.
44
+ #
45
+ if Pkg::Config.templates
46
+ @templates = Pkg::Config.templates.dup
47
+ fail "templates must be an array" unless @templates.is_a?(Array)
48
+ expand_templates
49
+ end
50
+ end
51
+
52
+ def install_files_to(workdir)
53
+ # It is nice to use arrays in YAML to represent array content, but we used
54
+ # to support a mode where a space-separated string was used. Support both
55
+ # to allow a gentle migration to a modern style...
56
+ patterns =
57
+ case @files
58
+ when String
59
+ $stderr.puts "warning: `files` should be an array, not a string"
60
+ @files.split(' ')
61
+ when Array
62
+ @files
63
+ else
64
+ raise "`files` must be a string or an array!"
65
+ end
66
+
67
+ Pkg::Util::File.install_files_into_dir(patterns, workdir)
68
+ end
69
+
70
+ # The templates of a project can include globs, which may expand to an
71
+ # arbitrary number of files. This method expands all of the templates using
72
+ # Dir.glob and then filters out any templates that live in the packaging
73
+ # tools themselves. If the template is a source/target combination, it is
74
+ # returned to the array untouched.
75
+ def expand_templates
76
+ @templates.map! do |tempfile|
77
+ if tempfile.is_a?(String)
78
+ # Expand possible globs to all matching entries
79
+ Dir.glob(File.join(Pkg::Config::project_root, tempfile))
80
+ elsif tempfile.is_a?(Hash)
81
+ tempfile
82
+ end
83
+ end
84
+ @templates.flatten!
85
+
86
+ # Reject matches that are templates from packaging itself. These will contain the packaging root.
87
+ # These tend to come from the current tar.rake implementation.
88
+ @templates.reject! { |temp| temp.is_a?(String) && temp.match(/#{Pkg::Config::packaging_root}/) }
89
+ end
90
+
91
+ # Given the tar object's template files (assumed to be in Pkg::Config.project_root), transform
92
+ # them, removing the originals. If workdir is passed, assume Pkg::Config.project_root
93
+ # exists in workdir
94
+ def template(workdir = nil)
95
+ workdir ||= Pkg::Config.project_root
96
+ root = Pathname.new(Pkg::Config.project_root)
97
+
98
+ # Templates can be either a string or a hash of source and target. If it
99
+ # is a string, the target is assumed to be the same path as the
100
+ # source,with the extension removed. If it is a hash, we assume nothing
101
+ # and use the provided source and target.
102
+ @templates.each do |cur_template|
103
+ if cur_template.is_a?(String)
104
+ template_file = File.expand_path(cur_template)
105
+ target_file = template_file.sub(File.extname(template_file), "")
106
+ elsif cur_template.is_a?(Hash)
107
+ template_file = File.expand_path(cur_template["source"])
108
+ target_file = File.expand_path(cur_template["target"])
109
+ end
110
+
111
+ # We construct paths to the erb template and its proposed target file
112
+ # relative to the project root, *not* fully qualified. This allows us
113
+ # to, given a temporary workdir containing a copy of the project,
114
+ # construct the full path to the erb and target file inside the
115
+ # temporary workdir.
116
+ #
117
+ rel_path_to_template = Pathname.new(template_file).relative_path_from(root).to_s
118
+ rel_path_to_target = Pathname.new(target_file).relative_path_from(root).to_s
119
+
120
+ # What we pass to Pkg::util::File.erb_file are the paths to the erb
121
+ # and target inside of a temporary project directory. We are, in
122
+ # essence, templating "in place." This is why we remove the original
123
+ # files - they're not the originals in the authoritative project
124
+ # directory, but the originals in the temporary working copy.
125
+ if File.exist?(File.join(workdir, rel_path_to_template))
126
+ mkpath(File.dirname(File.join(workdir, rel_path_to_target)), :verbose => false)
127
+ Pkg::Util::File.erb_file(File.join(workdir, rel_path_to_template), File.join(workdir, rel_path_to_target), true, :binding => Pkg::Config.get_binding)
128
+ elsif File.exist?(File.join(root, rel_path_to_template))
129
+ mkpath(File.dirname(File.join(workdir, rel_path_to_target)), :verbose => false)
130
+ Pkg::Util::File.erb_file(File.join(root, rel_path_to_template), File.join(workdir, rel_path_to_target), false, :binding => Pkg::Config.get_binding)
131
+ else
132
+ fail "Expected to find #{template_file} in #{root} for templating. But it was not there. Maybe you deleted it?"
133
+ end
134
+ end
135
+ end
136
+
137
+ def tar(target, source)
138
+ mkpath File.dirname(target)
139
+ cd File.dirname(source) do
140
+ %x(#{@tar} #{@excludes.map { |x| (" --exclude #{x} ") }.join if @excludes} -zcf '#{File.basename(target)}' '#{File.basename(source)}')
141
+ unless $?.success?
142
+ fail "Failed to create .tar.gz archive with #{@tar}. Please ensure the tar command in your path accepts the flags '-c', '-z', and '-f'"
143
+ end
144
+ mv File.basename(target), target
145
+ end
146
+ end
147
+
148
+ def clean_up(workdir)
149
+ rm_rf workdir
150
+ end
151
+
152
+ def pkg!
153
+ workdir = File.join(Pkg::Util::File.mktemp, "#{@project}-#{@version}")
154
+ mkpath workdir
155
+ self.install_files_to workdir
156
+ self.template(workdir)
157
+ self.tar(@target, workdir)
158
+ self.clean_up workdir
159
+ end
160
+
161
+ end
162
+ end
163
+