packaging 0.88.77

Sign up to get free protection for your applications and to get access to all the features.
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
+