packaging 0.99.0

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 (114) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -0
  3. data/README-Solaris.md +117 -0
  4. data/README.md +1031 -0
  5. data/lib/packaging.rb +32 -0
  6. data/lib/packaging/artifactory.rb +278 -0
  7. data/lib/packaging/config.rb +392 -0
  8. data/lib/packaging/config/params.rb +366 -0
  9. data/lib/packaging/deb.rb +28 -0
  10. data/lib/packaging/deb/repo.rb +263 -0
  11. data/lib/packaging/gem.rb +112 -0
  12. data/lib/packaging/ips.rb +57 -0
  13. data/lib/packaging/msi.rb +89 -0
  14. data/lib/packaging/nuget.rb +39 -0
  15. data/lib/packaging/osx.rb +36 -0
  16. data/lib/packaging/paths.rb +238 -0
  17. data/lib/packaging/platforms.rb +480 -0
  18. data/lib/packaging/repo.rb +55 -0
  19. data/lib/packaging/retrieve.rb +46 -0
  20. data/lib/packaging/rpm.rb +5 -0
  21. data/lib/packaging/rpm/repo.rb +257 -0
  22. data/lib/packaging/tar.rb +154 -0
  23. data/lib/packaging/util.rb +146 -0
  24. data/lib/packaging/util/date.rb +15 -0
  25. data/lib/packaging/util/execution.rb +85 -0
  26. data/lib/packaging/util/file.rb +125 -0
  27. data/lib/packaging/util/git.rb +174 -0
  28. data/lib/packaging/util/git_tags.rb +73 -0
  29. data/lib/packaging/util/gpg.rb +62 -0
  30. data/lib/packaging/util/jenkins.rb +95 -0
  31. data/lib/packaging/util/misc.rb +69 -0
  32. data/lib/packaging/util/net.rb +368 -0
  33. data/lib/packaging/util/os.rb +17 -0
  34. data/lib/packaging/util/platform.rb +40 -0
  35. data/lib/packaging/util/rake_utils.rb +111 -0
  36. data/lib/packaging/util/serialization.rb +19 -0
  37. data/lib/packaging/util/ship.rb +171 -0
  38. data/lib/packaging/util/tool.rb +41 -0
  39. data/lib/packaging/util/version.rb +326 -0
  40. data/spec/fixtures/config/ext/build_defaults.yaml +2 -0
  41. data/spec/fixtures/config/ext/project_data.yaml +2 -0
  42. data/spec/fixtures/config/params.yaml +2 -0
  43. data/spec/fixtures/configs/components/test_file.json +1 -0
  44. data/spec/fixtures/configs/components/test_file_2.json +0 -0
  45. data/spec/fixtures/configs/components/test_file_not_tagged.json +1 -0
  46. data/spec/fixtures/configs/components/test_file_wrong_ext.txt +0 -0
  47. data/spec/fixtures/configs/components/test_file_wrong_ext.wrong +0 -0
  48. data/spec/fixtures/util/pre_tasks.yaml +4 -0
  49. data/spec/lib/packaging/artifactory_spec.rb +171 -0
  50. data/spec/lib/packaging/config_spec.rb +556 -0
  51. data/spec/lib/packaging/deb/repo_spec.rb +148 -0
  52. data/spec/lib/packaging/deb_spec.rb +52 -0
  53. data/spec/lib/packaging/paths_spec.rb +153 -0
  54. data/spec/lib/packaging/platforms_spec.rb +153 -0
  55. data/spec/lib/packaging/repo_spec.rb +97 -0
  56. data/spec/lib/packaging/retrieve_spec.rb +61 -0
  57. data/spec/lib/packaging/rpm/repo_spec.rb +133 -0
  58. data/spec/lib/packaging/tar_spec.rb +122 -0
  59. data/spec/lib/packaging/util/execution_spec.rb +56 -0
  60. data/spec/lib/packaging/util/file_spec.rb +139 -0
  61. data/spec/lib/packaging/util/git_spec.rb +160 -0
  62. data/spec/lib/packaging/util/git_tag_spec.rb +36 -0
  63. data/spec/lib/packaging/util/gpg_spec.rb +64 -0
  64. data/spec/lib/packaging/util/jenkins_spec.rb +112 -0
  65. data/spec/lib/packaging/util/misc_spec.rb +31 -0
  66. data/spec/lib/packaging/util/net_spec.rb +239 -0
  67. data/spec/lib/packaging/util/os_spec.rb +31 -0
  68. data/spec/lib/packaging/util/rake_utils_spec.rb +70 -0
  69. data/spec/lib/packaging/util/ship_spec.rb +117 -0
  70. data/spec/lib/packaging/util/version_spec.rb +123 -0
  71. data/spec/lib/packaging_spec.rb +19 -0
  72. data/spec/spec_helper.rb +36 -0
  73. data/static_artifacts/PackageInfo.plist +3 -0
  74. data/tasks/00_utils.rake +216 -0
  75. data/tasks/30_metrics.rake +33 -0
  76. data/tasks/apple.rake +266 -0
  77. data/tasks/build.rake +12 -0
  78. data/tasks/clean.rake +5 -0
  79. data/tasks/config.rake +30 -0
  80. data/tasks/deb.rake +129 -0
  81. data/tasks/deb_repos.rake +28 -0
  82. data/tasks/deprecated.rake +130 -0
  83. data/tasks/doc.rake +20 -0
  84. data/tasks/education.rake +57 -0
  85. data/tasks/fetch.rake +57 -0
  86. data/tasks/gem.rake +146 -0
  87. data/tasks/jenkins.rake +494 -0
  88. data/tasks/jenkins_dynamic.rake +202 -0
  89. data/tasks/load_extras.rake +21 -0
  90. data/tasks/mock.rake +348 -0
  91. data/tasks/nightly_repos.rake +335 -0
  92. data/tasks/pe_deb.rake +12 -0
  93. data/tasks/pe_rpm.rake +13 -0
  94. data/tasks/pe_ship.rake +221 -0
  95. data/tasks/pe_sign.rake +13 -0
  96. data/tasks/pe_tar.rake +5 -0
  97. data/tasks/retrieve.rake +45 -0
  98. data/tasks/rpm.rake +66 -0
  99. data/tasks/rpm_repos.rake +29 -0
  100. data/tasks/ship.rake +752 -0
  101. data/tasks/sign.rake +226 -0
  102. data/tasks/tag.rake +8 -0
  103. data/tasks/tar.rake +34 -0
  104. data/tasks/update.rake +16 -0
  105. data/tasks/vanagon.rake +35 -0
  106. data/tasks/vendor_gems.rake +117 -0
  107. data/tasks/version.rake +33 -0
  108. data/tasks/z_data_dump.rake +65 -0
  109. data/templates/README +1 -0
  110. data/templates/downstream.xml.erb +47 -0
  111. data/templates/msi.xml.erb +197 -0
  112. data/templates/packaging.xml.erb +344 -0
  113. data/templates/repo.xml.erb +114 -0
  114. metadata +234 -0
@@ -0,0 +1,202 @@
1
+ # Rake Task to dynamically create a Jenkins job to model the
2
+ # pl:jenkins:uber_build set of tasks in a Matrix job where each cell is an
3
+ # individual build to be run. This would be nice if we only had to create one job,
4
+ # but alas, we're actually creating three jobs.
5
+ # 1) a packaging job that builds the packages
6
+ # |
7
+ # V
8
+ # 2) a repo creation job that creates repos from those packages
9
+ # |
10
+ # V
11
+ # 3) (optional) a job to proxy the downstream job passed in via DOWNSTREAM_JOB
12
+ #
13
+
14
+ namespace :pl do
15
+ namespace :jenkins do
16
+ desc "Dynamic Jenkins UBER build: Build all the things with ONE job"
17
+ task :uber_build, [:poll_interval] => "pl:fetch" do |t, args|
18
+ args.with_defaults(:poll_interval => 0)
19
+ poll_interval = args.poll_interval.to_i
20
+
21
+ # If we have a dirty source, bail, because changes won't get reflected in
22
+ # the package builds
23
+ Pkg::Util::Git.fail_on_dirty_source
24
+
25
+ # Use JSON to parse the json part of the submission, so we want to fail
26
+ # here also if JSON isn't available
27
+ Pkg::Util.require_library_or_fail 'json'
28
+
29
+ # The uber_build.xml.erb file is an XML erb template that will define a
30
+ # job in Jenkins with all of the appropriate tasks
31
+ work_dir = Pkg::Util::File.mktemp
32
+ template_dir = File.join(File.dirname(__FILE__), '..', 'templates')
33
+ templates = ['repo.xml.erb', 'packaging.xml.erb']
34
+ templates << ('msi.xml.erb') if Pkg::Config.build_msi
35
+ templates << ('downstream.xml.erb') if ENV['DOWNSTREAM_JOB']
36
+
37
+ # Generate an XML file for every job configuration erb and attempt to
38
+ # create a jenkins job from that XML config
39
+ templates.each do |t|
40
+ erb_template = File.join(template_dir, t)
41
+ xml_file = File.join(work_dir, t.gsub('.erb', ''))
42
+ Pkg::Util::File.erb_file(erb_template, xml_file, nil, :binding => Pkg::Config.get_binding)
43
+ # If we're creating a job meant to run on a windows box, we need to limit the path length
44
+ # Max path length allowed is 260 chars, which we manage to exceed with this job name. Luckily,
45
+ # simply using the short sha rather than the long sha gets us just under the length limit. Gross fix,
46
+ # I know, but hey, it works for now.
47
+ if t == "msi.xml.erb"
48
+ ref = Pkg::Config.short_ref
49
+ else
50
+ ref = Pkg::Config.ref
51
+ end
52
+ job_name = "#{Pkg::Config.project}-#{t.gsub('.xml.erb', '')}-#{Pkg::Config.build_date}-#{ref}"
53
+ puts "Checking for existence of #{job_name}..."
54
+ if Pkg::Util::Jenkins.jenkins_job_exists?(job_name)
55
+ raise "Job #{job_name} already exists on #{Pkg::Config.jenkins_build_host}"
56
+ else
57
+ Pkg::Util::Execution.retry_on_fail(:times => 3) do
58
+ url = Pkg::Util::Jenkins.create_jenkins_job(job_name, xml_file)
59
+ if t == "packaging.xml.erb"
60
+ ENV["PACKAGE_BUILD_URL"] = url
61
+ end
62
+ puts "Verifying job created successfully..."
63
+ unless Pkg::Util::Jenkins.jenkins_job_exists?(job_name)
64
+ raise "Unable to verify Jenkins job, trying again..."
65
+ end
66
+ puts "Jenkins job created at #{url}"
67
+ end
68
+ end
69
+ end
70
+ rm_r work_dir
71
+ packaging_name = "#{Pkg::Config.project}-packaging-#{Pkg::Config.build_date}-#{Pkg::Config.ref}"
72
+ Pkg::Util::RakeUtils.invoke_task("pl:jenkins:trigger_dynamic_job", packaging_name)
73
+
74
+ if poll_interval > 0
75
+ ##
76
+ # Wait for the '*packaging*' job to finish.
77
+ #
78
+ name = "#{Pkg::Config.project}-packaging-#{Pkg::Config.build_date}-#{Pkg::Config.ref}"
79
+ packaging_job_url = "http://#{Pkg::Config.jenkins_build_host}/job/#{name}"
80
+
81
+ packaging_build_hash = nil
82
+ Pkg::Util::Execution.retry_on_fail(:times => 10, :delay => 1) do
83
+ packaging_build_hash = Pkg::Util::Jenkins.poll_jenkins_job(packaging_job_url)
84
+ end
85
+
86
+ ##
87
+ # Output status of packaging build for cli consumption
88
+ #
89
+ puts "Packaging #{packaging_build_hash['result']}"
90
+
91
+ if packaging_build_hash['result'] == 'FAILURE'
92
+ fail "Please see #{packaging_job_url} for failure details."
93
+ end
94
+
95
+ if Pkg::Config.build_msi
96
+ ##
97
+ # Wait for the '*msi*' job to finish.
98
+ #
99
+ name = "#{Pkg::Config.project}-msi-#{Pkg::Config.build_date}-#{Pkg::Config.short_ref}"
100
+ msi_job_url = "http://#{Pkg::Config.jenkins_build_host}/job/#{name}"
101
+
102
+ msi_build_hash = nil
103
+ Pkg::Util::Execution.retry_on_fail(:times => 10, :delay => 1) do
104
+ msi_build_hash = Pkg::Util::Jenkins.poll_jenkins_job(msi_job_url)
105
+ end
106
+
107
+ ##
108
+ # Output status of msi build for cli consumption
109
+ #
110
+ puts "MSI #{msi_build_hash['result']}"
111
+
112
+ if msi_build_hash['result'] == 'FAILURE'
113
+ fail "Please see #{msi_job_url} for failure details."
114
+ end
115
+ end
116
+
117
+ ##
118
+ # Wait for the '*repo*' job to finish.
119
+ #
120
+ name = "#{Pkg::Config.project}-repo-#{Pkg::Config.build_date}-#{Pkg::Config.ref}"
121
+ repo_job_url = "http://#{Pkg::Config.jenkins_build_host}/job/#{name}"
122
+
123
+ repo_build_hash = nil
124
+ Pkg::Util::Execution.retry_on_fail(:times => 10, :delay => 1) do
125
+ repo_build_hash = Pkg::Util::Jenkins.poll_jenkins_job(repo_job_url)
126
+ end
127
+
128
+ ##
129
+ # Output status of repo build for cli consumption
130
+ #
131
+ puts "Repo Creation #{repo_build_hash['result']}"
132
+
133
+ if repo_build_hash['result'] == 'FAILURE'
134
+ fail "Please see #{repo_job_url} for failure details."
135
+ end
136
+ end
137
+ end
138
+
139
+ # Task to trigger the jenkins job we just created. This uses a lot of the
140
+ # same logic in jenkins.rake, with different parameters.
141
+ # TODO make all this replicated code a better, more abstract method
142
+ task :trigger_dynamic_job, :name do |t, args|
143
+ name = args.name
144
+
145
+ properties = Pkg::Config.config_to_yaml
146
+ bundle = Pkg::Util::Git.bundle('HEAD')
147
+
148
+ # Create a string of metrics to send to Jenkins for data analysis
149
+ if Pkg::Config.pe_version
150
+ metrics = "#{ENV['USER']}~#{Pkg::Config.version}~#{Pkg::Config.pe_version}~#{Pkg::Config.team}"
151
+ else
152
+ metrics = "#{ENV['USER']}~#{Pkg::Config.version}~N/A~#{Pkg::Config.team}"
153
+ end
154
+
155
+ # Construct the parameters, which is an array of hashes we turn into JSON
156
+ parameters = [{ "name" => "BUILD_PROPERTIES", "file" => "file0" },
157
+ { "name" => "PROJECT_BUNDLE", "file" => "file1" },
158
+ { "name" => "PROJECT", "value" => "#{Pkg::Config.project}" },
159
+ { "name" => "METRICS", "value" => "#{metrics}" }]
160
+
161
+ # Contruct the json string
162
+ json = JSON.generate("parameter" => parameters)
163
+
164
+ # The args array that holds all of the arguments we pass
165
+ # to the curl utility method.
166
+ curl_args = [
167
+ "-Fname=BUILD_PROPERTIES", "-Ffile0=@#{properties}",
168
+ "-Fname=PROJECT_BUNDLE", "-Ffile1=@#{bundle}",
169
+ "-Fname=PROJECT", "-Fvalue=#{Pkg::Config.project}",
170
+ "-Fname=METRICS", "-Fvalue=#{metrics}",
171
+ "-FSubmit=Build",
172
+ "-Fjson=#{json.to_json}",
173
+ ]
174
+
175
+ # Contstruct the job url
176
+ trigger_url = "#{Pkg::Config.jenkins_build_host}/job/#{name}/build"
177
+
178
+ _, retval = Pkg::Util::Net.curl_form_data(trigger_url, curl_args)
179
+ if Pkg::Util::Execution.success?(retval)
180
+ Pkg::Util::Net.print_url_info("http://#{Pkg::Config.jenkins_build_host}/job/#{name}")
181
+ puts "Your packages will be available at http://#{Pkg::Config.builds_server}/#{Pkg::Config.project}/#{Pkg::Config.ref}"
182
+ else
183
+ fail "An error occurred submitting the job to jenkins. Take a look at the preceding http response for more info."
184
+ end
185
+
186
+ # Clean up after ourselves
187
+ rm bundle
188
+ rm properties
189
+ end
190
+ end
191
+ end
192
+
193
+ namespace :pe do
194
+ namespace :jenkins do
195
+ desc "Dynamic Jenkins UBER build: Build all the things with ONE job"
196
+ task :uber_build, [:poll_interval] do |t, args|
197
+ Pkg::Util.check_var("PE_VER", Pkg::Config.pe_version)
198
+ args.with_defaults(:poll_interval => 0)
199
+ Rake::Task["pl:jenkins:uber_build"].invoke(args.poll_interval)
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,21 @@
1
+ # The pl:load_extras tasks is intended to load variables
2
+ # from the extra yaml file downloaded by the pl:fetch task.
3
+ # The goal is to be able to augment/override settings in the
4
+ # source project's build_data.yaml and project_data.yaml with
5
+ # Puppet Labs-specific data, rather than having to clutter the
6
+ # generic tasks with data not generally useful outside the
7
+ # PL Release team
8
+ namespace :pl do
9
+ task :load_extras, :tempdir do |t, args|
10
+ unless ENV['PARAMS_FILE'] && ENV['PARAMS_FILE'] != ''
11
+ tempdir = args.tempdir
12
+ raise "pl:load_extras requires a directory containing extras data" if tempdir.nil?
13
+ Pkg::Config.config_from_yaml("#{tempdir}/#{Pkg::Config.builder_data_file}")
14
+
15
+ # Environment variables take precedence over those loaded from configs,
16
+ # so we make sure that any we clobbered are reset.
17
+ Pkg::Config.load_envvars
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,348 @@
1
+ # The mock methods/tasks are fairly specific to puppetlabs infrastructure, e.g., the mock configs
2
+ # have to be named in a format like the PL mocks, e.g. dist-version-architecture, such as:
3
+ # el-5-i386
4
+ # fedora-17-i386
5
+ # as well as the oddly formatted exception, 'pl-5-i386' which is the default puppetlabs FOSS mock
6
+ # format for 'el-5-i386' (note swap 'pl' for 'el')
7
+ #
8
+ # The mock-built rpms are placed in a directory structure under 'pkg' based on how the Puppet Labs
9
+ # repo structure is laid out in order to facilitate easy shipping from the local repository to the
10
+ # Puppet Labs repos. For open source, the directory structure mirrors that of yum.puppetlabs.com:
11
+ # pkg/<dist>/<version>/{products,devel,dependencies}/<arch>/*.rpm
12
+ # e.g.,
13
+ # pkg/el/5/products/i386/*.rpm
14
+ # pkg/fedora/f16/products/i386/*.rpm
15
+ #
16
+ # For PE, the directory structure is flatter:
17
+ # pkg/<dist>-<version>-<arch>/*.rpm
18
+ # e.g.,
19
+ # pkg/el-5-i386/*.rpm
20
+ def mock_artifact(mock_config, cmd_args, mockfile)
21
+ unless mock = Pkg::Util::Tool.find_tool('mock')
22
+ raise "mock is required for building srpms with mock. Please install mock and try again."
23
+ end
24
+ randomize = Pkg::Config.random_mockroot
25
+ configdir = nil
26
+ basedir = File.join('var', 'lib', 'mock')
27
+
28
+ if randomize
29
+ basedir, configdir = randomize_mock_config_dir(mock_config, mockfile)
30
+ configdir_arg = " --configdir #{configdir}"
31
+ end
32
+ result_dir = Pkg::Util::File.mktemp
33
+ resultdir_arg = " --resultdir #{result_dir}"
34
+
35
+ begin
36
+ sh "#{mock} -r #{mock_config} #{resultdir_arg} #{configdir_arg} #{cmd_args}"
37
+
38
+ # Return a FileList of the build artifacts
39
+ return FileList[File.join(result_dir, '*.rpm')]
40
+
41
+ rescue RuntimeError => error
42
+ build_log = File.join(result_dir, 'build.log')
43
+ root_log = File.join(result_dir, 'root.log')
44
+ content = File.read(build_log) if File.readable?(build_log)
45
+
46
+ if File.readable?(root_log)
47
+ $stderr.puts File.read(root_log)
48
+ end
49
+ if content and content.lines.count > 2
50
+ $stderr.puts content
51
+ end
52
+
53
+ # Any useful info has now been gleaned from the logs in the case of a
54
+ # failure, so we can safely remove basedir if this is a randomized mockroot
55
+ # build. Scarily enough, because of mock permissions, we can't actually
56
+ # just remove it, we have to sudo remove it.
57
+
58
+ if randomize and basedir and File.directory?(basedir)
59
+ sh "sudo -n rm -r #{basedir}"
60
+ sh "sudo -n rm -r #{result_dir}"
61
+ end
62
+
63
+ raise error
64
+ ensure
65
+ # Unlike basedir, which we keep in the success case, we don't need
66
+ # configdir anymore either way, so we always clean it up if we're using
67
+ # randomized mockroots.
68
+ #
69
+ rm_r configdir if randomize
70
+ end
71
+ end
72
+
73
+ # Use mock to build an SRPM
74
+ # Return the path to the srpm
75
+ def mock_srpm(mock_config, spec, sources, mockfile, defines = nil)
76
+ cmd_args = "--buildsrpm #{defines} --sources #{sources} --spec #{spec}"
77
+ srpms = mock_artifact(mock_config, cmd_args, mockfile)
78
+
79
+ unless srpms.size == 1
80
+ fail "#{srpms} contains an unexpected number of artifacts."
81
+ end
82
+ srpms[0]
83
+ end
84
+
85
+ # Use mock to build rpms from an srpm
86
+ # Return a FileList containing the built RPMs
87
+ def mock_rpm(mock_config, srpm, mockfile)
88
+ cmd_args = " #{srpm}"
89
+ mock_artifact(mock_config, cmd_args, mockfile)
90
+ end
91
+
92
+ # Determine the "family" of the target distribution based on the mock config name,
93
+ # e.g. pupent-3.0-el5-i386 = "el"
94
+ # and pl-fedora-17-i386 = "fedora"
95
+ #
96
+ def mock_el_family(mock_config)
97
+ if Pkg::Config.build_pe
98
+ # This uses a regex capture instead of splitting to allow the now defunct PE version component to be optional
99
+ family = mock_config.match(/^pupent-(\d\.\d-)?([a-z]+)([0-9]+)-(.*)$/)[2]
100
+ else
101
+ first, second = mock_config.split('-')
102
+ if first == 'el' || first == 'fedora'
103
+ family = first
104
+ elsif first == 'pl'
105
+ if second.match(/^\d+$/)
106
+ family = 'el'
107
+ else
108
+ family = second
109
+ end
110
+ end
111
+ end
112
+ family
113
+ end
114
+
115
+ # Determine the major version of the target distribution based on the mock config name,
116
+ # e.g. pupent-3.0-el5-i386 = "5"
117
+ # and "pl-fedora-17-i386" = "17"
118
+ #
119
+ def mock_el_ver(mock_config)
120
+ if Pkg::Config.build_pe
121
+ # This uses a regex capture instead of splitting to allow the now defunct PE version component to be optional
122
+ version = mock_config.match(/^pupent-(\d\.\d-)?([a-z]+)([0-9]+)-(.*)$/)[3]
123
+ else
124
+ first, second, third = mock_config.split('-')
125
+ if (first == 'el' || first == 'fedora') || (first == 'pl' && second.match(/^\d+$/))
126
+ version = second
127
+ else
128
+ version = third
129
+ end
130
+ end
131
+ if [first, second].include?('fedora')
132
+ version = "f#{version}"
133
+ end
134
+ version
135
+ end
136
+
137
+ # Return the RPM family and version for a Vanagon or Packaging repo built project.
138
+ def rpm_family_and_version
139
+ if Pkg::Config.vanagon_project
140
+ Pkg::Config.rpm_targets.split(' ').map do |target|
141
+ rpm_el_family, rpm_el_version, arch = target.split('-')
142
+ "#{rpm_el_family}-#{rpm_el_version}"
143
+ end
144
+ else
145
+ Pkg::Config.final_mocks.split.map { |mock| "#{mock_el_family(mock)}-#{mock_el_ver(mock) }" }
146
+ end
147
+ end
148
+
149
+
150
+ # Checks to see if the pe agnostic config template is in place.
151
+ # If it is then the mock config is set to point to the generated config file.
152
+ # The generated config file is formed by substituting the pe_version into the erb
153
+ #
154
+ def mock_template(mock_config)
155
+ Pkg::Util.check_var("PE version, ENV[PE_VER]", Pkg::Config.pe_version)
156
+ # pe_version is used in the erb template
157
+ pe_version = Pkg::Config.pe_version
158
+ # This bit is fun, here we remove any x.y version in the PE version location in the string from the mock_config
159
+ # for example, pupent-3.4-el5-i386.cfg would become pupent-el5-i386 while pupent-el7-x86_64 would remain unmodified.
160
+ template = mock_config.sub(/([^-]*)-\d\.\d-([^-]*)-([^-]*)/, '\1-\2-\3')
161
+ template_location = File.join(File::SEPARATOR, "etc", "mock", "#{template}.cfg.erb")
162
+ if File.exists?(template_location)
163
+ return template, Pkg::Util::File.erb_file(template_location, nil, false, { :binding => binding })
164
+ else
165
+ return mock_config
166
+ end
167
+ end
168
+
169
+ # Determine the appropriate rpm macro definitions based on the mock config name
170
+ # Return a string of space separated macros prefixed with --define
171
+ #
172
+ def mock_defines(mock_config)
173
+ family = mock_el_family(mock_config)
174
+ version = mock_el_ver(mock_config)
175
+ defines = ""
176
+ if version =~ /^(4|5)$/ or family == "sles"
177
+ defines = %Q(--define "dist .#{family}#{version}" \
178
+ --define "_source_filedigest_algorithm 1" \
179
+ --define "_binary_filedigest_algorithm 1" \
180
+ --define "_binary_payload w9.gzdio" \
181
+ --define "_source_payload w9.gzdio" \
182
+ --define "_default_patch_fuzz 2")
183
+ end
184
+ defines
185
+ end
186
+
187
+ def build_rpm_with_mock(mocks)
188
+ mocks.split(' ').each do |mock_config|
189
+ family = mock_el_family(mock_config)
190
+ version = mock_el_ver(mock_config)
191
+ subdir = if Pkg::Config.yum_repo_name
192
+ Pkg::Config.yum_repo_name
193
+ else
194
+ Pkg::Util::Version.is_final? ? 'products' : 'devel'
195
+ end
196
+ bench = Benchmark.realtime do
197
+ # Set up the rpmbuild dir in a temp space, with our tarball and spec
198
+ workdir = prep_rpm_build_dir
199
+ spec = Dir.glob(File.join(workdir, "SPECS", "*.spec"))[0]
200
+ sources = File.join(workdir, "SOURCES")
201
+ defines = mock_defines(mock_config)
202
+ if Pkg::Config.build_pe
203
+ mock_config, mockfile = mock_template(mock_config)
204
+ end
205
+ # Build the srpm inside a mock chroot
206
+ srpm = mock_srpm(mock_config, spec, sources, mockfile, defines)
207
+
208
+ # Now that we have the srpm, build the rpm in a mock chroot
209
+ rpms = mock_rpm(mock_config, srpm, mockfile)
210
+
211
+ rpms.each do |rpm|
212
+ rpm.strip!
213
+
214
+ if Pkg::Config.build_pe
215
+ %x(mkdir -p pkg/pe/rpm/#{family}-#{version}-{srpms,i386,x86_64})
216
+ case File.basename(rpm)
217
+ when /debuginfo/
218
+ rm_rf(rpm)
219
+ when /src\.rpm/
220
+ FileUtils.cp_r(rpm, "pkg/pe/rpm/#{family}-#{version}-srpms", { :preserve => true })
221
+ when /i.?86/
222
+ FileUtils.cp_r(rpm, "pkg/pe/rpm/#{family}-#{version}-i386", { :preserve => true })
223
+ when /x86_64/
224
+ FileUtils.cp_r(rpm, "pkg/pe/rpm/#{family}-#{version}-x86_64", { :preserve => true })
225
+ when /noarch/
226
+ FileUtils.cp_r(rpm, "pkg/pe/rpm/#{family}-#{version}-i386", { :preserve => true })
227
+ FileUtils.ln("pkg/pe/rpm/#{family}-#{version}-i386/#{File.basename(rpm)}", "pkg/pe/rpm/#{family}-#{version}-x86_64/", :force => true, :verbose => true)
228
+ end
229
+ elsif subdir == 'PC1' || !Pkg::Config.yum_repo_name
230
+ %x(mkdir -p pkg/#{family}/#{version}/#{subdir}/{SRPMS,i386,x86_64})
231
+ case File.basename(rpm)
232
+ when /debuginfo/
233
+ rm_rf(rpm)
234
+ when /src\.rpm/
235
+ FileUtils.cp_r(rpm, "pkg/#{family}/#{version}/#{subdir}/SRPMS", { :preserve => true })
236
+ when /i.?86/
237
+ FileUtils.cp_r(rpm, "pkg/#{family}/#{version}/#{subdir}/i386", { :preserve => true })
238
+ when /x86_64/
239
+ FileUtils.cp_r(rpm, "pkg/#{family}/#{version}/#{subdir}/x86_64", { :preserve => true })
240
+ when /noarch/
241
+ FileUtils.cp_r(rpm, "pkg/#{family}/#{version}/#{subdir}/i386", { :preserve => true })
242
+ FileUtils.ln("pkg/#{family}/#{version}/#{subdir}/i386/#{File.basename(rpm)}", "pkg/#{family}/#{version}/#{subdir}/x86_64/", :force => true, :verbose => true)
243
+ end
244
+ else
245
+ %x(mkdir -p pkg/#{subdir}/#{family}/#{version}/{SRPMS,i386,x86_64})
246
+ case File.basename(rpm)
247
+ when /debuginfo/
248
+ rm_rf(rpm)
249
+ when /src\.rpm/
250
+ FileUtils.cp_r(rpm, "pkg/#{subdir}/#{family}/#{version}/SRPMS", { :preserve => true })
251
+ when /i.?86/
252
+ FileUtils.cp_r(rpm, "pkg/#{subdir}/#{family}/#{version}/i386", { :preserve => true })
253
+ when /x86_64/
254
+ FileUtils.cp_r(rpm, "pkg/#{subdir}/#{family}/#{version}/x86_64", { :preserve => true })
255
+ when /noarch/
256
+ FileUtils.cp_r(rpm, "pkg/#{subdir}/#{family}/#{version}/i386", { :preserve => true })
257
+ FileUtils.ln("pkg/#{subdir}/#{family}/#{version}/i386/#{File.basename(rpm)}", "pkg/#{subdir}/#{family}/#{version}/x86_64/", :force => true, :verbose => true)
258
+ end
259
+ end
260
+ end
261
+ # To avoid filling up the system with our random mockroots, we should
262
+ # clean up. However, this requires sudo. If we don't have sudo, we'll
263
+ # just fail and not clean up, but warn the user about it.
264
+ if Pkg::Config.random_mockroot
265
+ %x(sudo -n echo 'Cleaning build root.')
266
+ if $?.success?
267
+ sh "sudo -n rm -r #{File.dirname(srpm)}" unless File.dirname(srpm).nil?
268
+ sh "sudo -n rm -r #{File.dirname(rpms[0])}" unless File.dirname(rpms[0]).nil?
269
+ sh "sudo -n rm -r #{workdir}" unless workdir.nil?
270
+ else
271
+ warn "Couldn't clean rpm build areas without sudo. Leaving."
272
+ end
273
+ end
274
+ end
275
+ puts "Finished building in: #{bench}"
276
+ end
277
+ end
278
+
279
+ # With the advent of using Jenkins to parallelize builds, it becomes critical
280
+ # that we be able to use the same mock at the same time for > 1 builds without
281
+ # clobbering the mock root every time. Here we add a method that takes the full
282
+ # path to a mock configuration and a path, and adds a base directory
283
+ # configuration directive to the mock to use the path as the directory for the
284
+ # mock build root. The new mock config is written to a temporary space, and its
285
+ # location is returned. This allows us to create mock configs with randomized
286
+ # temporary mock roots.
287
+ #
288
+ def mock_with_basedir(mock, basedir)
289
+ config = IO.readlines(mock)
290
+ basedir = "config_opts['basedir'] = '#{basedir}'"
291
+ config.unshift(basedir)
292
+ tempdir = Pkg::Util::File.mktemp
293
+ newmock = File.join(tempdir, File.basename(mock))
294
+ File.open(newmock, 'w') { |f| f.puts config }
295
+ newmock
296
+ end
297
+
298
+ # Mock accepts an alternate configuration directory to /etc/mock for mock
299
+ # configs, but the directory has to include both site-defaults.cfg and
300
+ # logging.ini. This is a simple utility method to set a mock configuration dir
301
+ # by copying a mock and the required defaults to a temporary directory and
302
+ # returning that directory. This method takes the full path to a mock
303
+ # configuration file and returns the path to the new configuration dir.
304
+ #
305
+ def setup_mock_config_dir(mock)
306
+ tempdir = Pkg::Util::File.mktemp
307
+ cp File.join('/', 'etc', 'mock', 'site-defaults.cfg'), tempdir
308
+ cp File.join('/', 'etc', 'mock', 'logging.ini'), tempdir
309
+ cp mock, tempdir
310
+ tempdir
311
+ end
312
+
313
+ # Create a mock config file from an existing one, except insert the 'basedir'
314
+ # option. 'basedir' will be set to a random directory we create. Move the new
315
+ # mock config and the required default mock settings files into a new config
316
+ # dir to pass to mock. Return the path to the config dir.
317
+ #
318
+ def randomize_mock_config_dir(mock_config, mockfile)
319
+ # basedir will be the location of our temporary mock root
320
+ basedir = Pkg::Util::File.mktemp
321
+ chown("#{ENV['USER']}", "mock", basedir)
322
+ # Mock requires the sticky bit be set on the basedir
323
+ chmod(02775, basedir)
324
+ mockfile ||= File.join('/', 'etc', 'mock', "#{mock_config}.cfg")
325
+ puts "Setting mock basedir to #{basedir}"
326
+ # Create a new mock config file with 'basedir' set to our basedir
327
+ config = mock_with_basedir(mockfile, basedir)
328
+ # Setup a mock config dir, copying in our mock config and logging.ini etc
329
+ configdir = setup_mock_config_dir(config)
330
+ # Clean up the directory with the temporary mock config
331
+ rm_r File.dirname(config)
332
+ return basedir, configdir
333
+ end
334
+
335
+
336
+ namespace :pl do
337
+ desc "Use default mock to make a final rpm, keyed to PL infrastructure, pass MOCK to specify config"
338
+ task :mock => "package:tar" do
339
+ # If default mock isn't specified, just take the first one in the Pkg::Config.final_mocks list
340
+ Pkg::Config.default_mock ||= Pkg::Config.final_mocks.split(' ')[0]
341
+ build_rpm_with_mock(Pkg::Config.default_mock)
342
+ end
343
+
344
+ desc "Use specified mocks to make rpms, keyed to PL infrastructure, pass MOCK to specifiy config"
345
+ task :mock_all => "package:tar" do
346
+ build_rpm_with_mock(Pkg::Config.final_mocks)
347
+ end
348
+ end