Module: Xolo::Server::Helpers::FileTransfers
- Defined in:
- lib/xolo/server/helpers/file_transfers.rb
Constant Summary collapse
- UPLOAD_ACTION =
Constants
'Upload'- REUPLOAD_ACTION =
'Re-upload'- CLOUD_DP_NA =
Thes values in the cdnType field of the Cloud DP definition from the API indicate that there is no Cloud DP configured
[nil, Xolo::BLANK, 'NONE'].freeze
- CLOUD_DP_UPLOAD_TIMEOUT =
How long to wait for a pkg to appear on the Cloud DP when uploading via API before giving up and raising an error
1800
Class Method Summary collapse
-
.included(includer) ⇒ Object
when this module is included.
Instance Method Summary collapse
-
#cloud_dp_available? ⇒ Boolean
Is a cloud distribution point defined?.
-
#cloud_dp_data ⇒ Hash
TODO: Use ruby-jss when it implements could-distribution-point rsrc.
-
#cloud_dp_pkg_ready?(pkg_filename) ⇒ Boolean
TODO: Use ruby-jss when it implements could-distribution-point rsrc.
-
#cloud_dp_pkgs ⇒ Hash {String => String}
TODO: Use ruby-jss when it implements could-distribution-point rsrc.
-
#cloud_dp_principal? ⇒ Boolean
TODO: Use ruby-jss when it implements could-distribution-point rsrc.
-
#dist_pkg_filename(version) ⇒ String
What will be the name of the file on the dist point? For a first upload, it will be ‘xolo-<title>-<version>.pkg’.
-
#pkg_is_distribution?(pkg_file) ⇒ Boolean
Check if a package is a Distribution package, if not, it is a component package and can’t be used for MDM deployment.
-
#prep_pkg_for_upload(version, pkg_src) ⇒ Pathname
Prep a .pkg before we start uploading to the dist point.
-
#process_and_upload_autopkg_pkg(title, version, pkg_src) ⇒ void
upload a package from autopkg to Jamf Pro and do all the processing around that.
-
#process_and_upload_to_jamf(title, version, pkg_src:, orig_filename: nil) ⇒ void
Process a pkg installer and upload to jamf.
-
#process_and_upload_uploaded_pkg ⇒ Object
Upload an pkg installer from xadm to Jamf Pro, and do all the processing around that.
-
#process_incoming_ssvc_icon ⇒ Object
Store an uploaded self service icon in the title’s directory.
-
#process_incoming_testfile ⇒ Object
upload a file for testing …
-
#sign_and_stage(pkg_src, staged_pkg, version) ⇒ void
If this pkg needs signing, do so putting the signed pkg in the staged_pkg location, and delete the original pkg_src file.
-
#update_version_post_upload(version, staged_pkg, orig_filename) ⇒ void
After uploading a pkg, update the version with info about the pkg, like whether it’s a dist pkg or not, and save the manifest and checksum NOTE this is run as part of the upload thread.
-
#upload_pkg_in_thread(version, staged_pkg, orig_filename) ⇒ void
upload a prepped/staged pkg in a thread, and do the things that need to be done after upload, like setting the upload/reupload date and user, enabling the reinstall policy if it’s a reupload, etc.
-
#upload_to_dist_point(jpkg, pkg_file) ⇒ void
upload a staged pkg to the dist point(s) This will also update the checksum and manifest.
-
#upload_via_api? ⇒ Boolean
are Dist Point uploads configured to be done via the API, or with an upload tool defined in config?.
-
#upload_via_tool(jpkg, pkg_file) ⇒ void
upload the pkg with the uploader tool defined in config.
-
#validate_uploaded_pkg(filename) ⇒ String
Confirm and return the extension of the originally uplaoded file, as .pkg.
-
#wait_for_pkg_and_enable_reinstall_policy(version) ⇒ void
Wait for a re-uploaded pkg to appear on the Cloud DP after an API upload, then enable the reinstall policy.
-
#wrap_component_pkg_in_distribution(orig_pkg, version) ⇒ Pathname
Wrap a component pkg in a Distribution pkg, return the path to the Distribution pkg, which should be the same as the orig_pkg.
Class Method Details
.included(includer) ⇒ Object
when this module is included
39 40 41 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 39 def self.included(includer) Xolo.verbose_include includer, self end |
Instance Method Details
#cloud_dp_available? ⇒ Boolean
Returns Is a cloud distribution point defined?.
530 531 532 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 530 def cloud_dp_available? !CLOUD_DP_NA.include? cloud_dp_data[:cdnType] end |
#cloud_dp_data ⇒ Hash
TODO: Use ruby-jss when it implements could-distribution-point rsrc
514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 514 def cloud_dp_data return @cloud_dp_data if @cloud_dp_data @cloud_dp_data = jamf_cnx.jp_get '/v1/cloud-distribution-point' @cloud_dp_data.delete :privateKey @cloud_dp_data.delete :keyPairId @cloud_dp_data rescue Jamf::Connection::JamfProAPIError => e @cloud_dp_data = { cdnType: 'NONE', master: false } return @cloud_dp_data if jamf_cnx.last_http_response.status == 404 raise e end |
#cloud_dp_pkg_ready?(pkg_filename) ⇒ Boolean
TODO: Use ruby-jss when it implements could-distribution-point rsrc
Does a given pkg name exist on the cloud dp with ‘ready’ status?
549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 549 def cloud_dp_pkg_ready?(pkg_filename) return false unless cloud_dp_available? filt = CGI.escape "fileName=='#{pkg_filename}'" response = jamf_cnx.jp_get "/v1/cloud-distribution-point/files?filter=#{filt}" # No fileserver I know of will allow multiples of a single filename.... # so assume there's only zero or one data = response[:results].first return false unless data # once the status is ready, we should be good to go data[:status] == 'READY' end |
#cloud_dp_pkgs ⇒ Hash {String => String}
TODO: Use ruby-jss when it implements could-distribution-point rsrc
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 569 def cloud_dp_pkgs page = 0 page_size = 1000 pkgs = {} loop do response = jamf_cnx.jp_get "/v1/cloud-distribution-point/files?page=#{page}&page-size=#{page_size}" results = response[:results] break if results.empty? results.each do |f| next unless f[:type] == 'PACKAGE' && f[:status] == 'READY' # fileObjectId is the Jamf ID of the Package object for this DP file pkgs[f[:fileObjectId]] = f[:fileName] end page += 1 end pkgs end |
#cloud_dp_principal? ⇒ Boolean
TODO: Use ruby-jss when it implements could-distribution-point rsrc
537 538 539 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 537 def cloud_dp_principal? cloud_dp_available? && cloud_dp_data[:master] end |
#dist_pkg_filename(version) ⇒ String
What will be the name of the file on the dist point? For a first upload, it will be ‘xolo-<title>-<version>.pkg’
If we are re-uploading, it will be ‘xolo-<title>-<version>N.pkg’ where N is an integer (starting with 2) that increments with each re-upload,
This is so that re-uploads don’t have the same filename on the Dist Point, which could be problematic. It also helps to visually see that this is a re-uploaded pkg and not the original one.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 321 def dist_pkg_filename(version) if version.upload_date.pix_empty? # no upload date, this is the first upload "#{version.jamf_pkg_name}#{Xolo::DOT_PKG}" elsif version.jamf_pkg_file.to_s =~ /_(\d+)_\.pkg$/ # this is a re-upload, does the filename indicat a previous re-upload with a _N_ in the name? next_num = Regexp.last_match[1].to_i + 1 "#{version.jamf_pkg_name}_#{next_num}_#{Xolo::DOT_PKG}" else # the first re-upload, just add _2_ before the extension "#{version.jamf_pkg_name}_2_#{Xolo::DOT_PKG}" end end |
#pkg_is_distribution?(pkg_file) ⇒ Boolean
Check if a package is a Distribution package, if not, it is a component package and can’t be used for MDM deployment.
365 366 367 368 369 370 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 365 def pkg_is_distribution?(pkg_file) pkg_file = Pathname.new(pkg_file) raise ArgumentError, "pkg_file does not exist or not a file: #{pkg_file}" unless pkg_file.file? `/usr/bin/xar -tf #{pkg_file.to_s.shellescape}`.split("\n").include? 'Distribution' end |
#prep_pkg_for_upload(version, pkg_src) ⇒ Pathname
Prep a .pkg before we start uploading to the dist point
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 146 def prep_pkg_for_upload(version, pkg_src) msg = "Jamf: Processing installer package '#{pkg_src}' (#{pkg_src.size.pix_humanize_bytes}) for Jamf Dist upload, title '#{version.title}' version '#{version.version}'" progress msg, log: :info version.jamf_pkg_file = dist_pkg_filename(version) log_debug "Jamf: Uploaded package filename will be '#{version.jamf_pkg_file}'" version.save_local_data # The pkg_src will be staged here before uploading to the Dist Point staged_pkg = Xolo::Server::Title.title_dir(version.title) + version.jamf_pkg_file # remove any old one that might be there staged_pkg.delete if staged_pkg.file? # This will move/copy the pkg_src into the staged_pkg, signing it on the way if needed, and # delete the original pkg_src file. sign_and_stage(pkg_src, staged_pkg, version) # Wrap component pkgs in a Distribution pkg if configured to do so staged_pkg = wrap_component_pkg_in_distribution(staged_pkg, version) if Xolo::Server.config.create_distribution_pkgs staged_pkg end |
#process_and_upload_autopkg_pkg(title, version, pkg_src) ⇒ void
This method returns an undefined value.
upload a package from autopkg to Jamf Pro and do all the processing around that
105 106 107 108 109 110 111 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 105 def process_and_upload_autopkg_pkg(title, version, pkg_src) process_and_upload_to_jamf( title, version, pkg_src: pkg_src ) end |
#process_and_upload_to_jamf(title, version, pkg_src:, orig_filename: nil) ⇒ void
This method returns an undefined value.
Process a pkg installer and upload to jamf
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 123 def process_and_upload_to_jamf(title, version, pkg_src:, orig_filename: nil) pkg_src = Pathname.new pkg_src orig_filename ||= pkg_src.basename.to_s version = instantiate_version(title: title, version: version) if version.is_a?(String) staged_pkg = prep_pkg_for_upload(version, pkg_src) upload_pkg_in_thread(version, staged_pkg, orig_filename) rescue => e msg = "#{e.class}: #{e}" log_error msg e.backtrace.each { |line| log_error "..#{line}" } halt 400, { status: 400, error: msg } ensure pkg_src.delete if pkg_src.file? end |
#process_and_upload_uploaded_pkg ⇒ Object
Upload an pkg installer from xadm to Jamf Pro, and do all the processing around that
88 89 90 91 92 93 94 95 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 88 def process_and_upload_uploaded_pkg process_and_upload_to_jamf( params[:title], params[:version], pkg_src: params[:file][:tempfile].path, orig_filename: params[:file][:filename] ) end |
#process_incoming_ssvc_icon ⇒ Object
Store an uploaded self service icon in the title’s directory. It’ll be added to Policies and Patch Policies as needed (increasing the bloat in the database, of course)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 67 def process_incoming_ssvc_icon filename = params[:file][:filename] tempfile = Pathname.new params[:file][:tempfile].path log_info "Processing uploaded SelfService icon for #{params[:title]}" title = instantiate_title params[:title] title.save_ssvc_icon(tempfile, filename) # this will configure the ssvc settings but won't make it available # in ssvc - that happens elsewhere. title.configure_pol_for_self_service rescue => e msg = "#{e.class}: #{e}" log_error msg e.backtrace.each { |line| log_error "..#{line}" } halt 400, { status: 400, error: msg } end |
#process_incoming_testfile ⇒ Object
upload a file for testing … anything
49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 49 def process_incoming_testfile progress 'starting test file upload', log: :debug params[:file][:filename] tempfile = Pathname.new params[:file][:tempfile].path progress "1/3 TempFile is #{tempfile} size is #{tempfile.size}... is it still uploading?", log: :debug sleep 2 progress "2/3 TempFile is #{tempfile} size is #{tempfile.size}... is it still uploading?", log: :debug sleep 2 progress "3/3 TempFile is #{tempfile} size is #{tempfile.size}... is it still uploading?", log: :debug progress 'all done', log: :debug end |
#sign_and_stage(pkg_src, staged_pkg, version) ⇒ void
This method returns an undefined value.
If this pkg needs signing, do so putting the signed pkg in the staged_pkg location, and delete the original pkg_src file. If it doesn’t need signing, just move it to the staged_pkg location.
345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 345 def sign_and_stage(pkg_src, staged_pkg, version) if need_to_sign?(pkg_src, version) # This will put the signed pkg into the staged_pkg location sign_pkg(pkg_src, staged_pkg) log_debug "Signing complete, signed pkg is '#{staged_pkg}', deleting original file '#{pkg_src}'" pkg_src.delete if pkg_src.file? else log_debug "The .pkg file doesn't need signing, moving pkg_src to '#{staged_pkg}'" pkg_src.rename staged_pkg end end |
#update_version_post_upload(version, staged_pkg, orig_filename) ⇒ void
This method returns an undefined value.
After uploading a pkg, update the version with info about the pkg, like whether it’s a dist pkg or not, and save the manifest and checksum NOTE this is run as part of the upload thread.
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 284 def update_version_post_upload(version, staged_pkg, orig_filename) # make note if the pkg is a Distribution package version.dist_pkg = pkg_is_distribution?(staged_pkg) # save the manifest on the server, just in case # TODO: Support sha3_512 in manifests version.manifest_file.pix_atomic_write(version.jamf_package.manifest) # save the checksum just in case version.sha_512 = version.jamf_package.checksum # don't save the admins local path to the pkg, just the filename they uploaded version.pkg_to_upload = orig_filename # save/update the local data file, since we've done stuff to update it version.save_local_data # log the upload version.log_change msg: "Uploaded pkg file '#{staged_pkg.basename}' to dist point" ensure staged_pkg.delete if staged_pkg.file? end |
#upload_pkg_in_thread(version, staged_pkg, orig_filename) ⇒ void
This method returns an undefined value.
upload a prepped/staged pkg in a thread, and do the things that need to be done after upload, like setting the upload/reupload date and user, enabling the reinstall policy if it’s a reupload, etc
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 177 def upload_pkg_in_thread(version, staged_pkg, orig_filename) if @pkg_upload_thread&.alive? msg = "A pkg upload is already in progress for version '#{version}' - can't start another one until it's done" log_error msg raise msg end @pkg_upload_thread = Thread.new do begin # is this a re-upload? The jamf_pkg_file will have already # been updated to reflect the new filename with the _N_ if it's a re-upload re_uploading = version.jamf_pkg_file =~ /_(\d+)_\.pkg$/ # disable reinstall policy if re-uploading, # will be re-enabled after the upload if re_uploading action = REUPLOAD_ACTION pol = version.jamf_auto_reinstall_policy pol.disable pol.save else action = UPLOAD_ACTION end upload_to_dist_point(version.jamf_package, staged_pkg) uploaded_by = if version.title_object.autopkg_enabled? Xolo::Server::Helpers::AutoPkg::AUTOPKG_UPLOADED_BY elsif defined?(session) session[:admin] end if re_uploading version.reupload_date = Time.now version.reuploaded_by = uploaded_by # if upload via API, wait for pkg to appear then enable the policy if upload_via_api? wait_for_pkg_and_enable_reinstall_policy(version) # otherwise notify someone to confirm upload is complete before enabling the policy else msg = "Please confirm that re-uploaded pkg '#{version.jamf_pkg_file}' is on the dist point and ready to go, then enable the reinstall policy '#{pol.name}' at #{jamf_auto_reinstall_policy_url}" log_info msg, alert: true end # if upload_via_api? # update the dist filename in the jamf package object version.jamf_package.fileName = version.jamf_pkg_file version.jamf_package.packageName = version.jamf_pkg_name version.jamf_package.save # if this is a first-time upload, just set the upload date and user else version.upload_date = Time.now version.uploaded_by = uploaded_by end # if re_uploading version.save_local_data version.log_change msg: "#{action}ed pkg file '#{staged_pkg.basename}' to Jamf Pro dist point(s)" rescue => e msg = "Error in pkg upload thread: #{e.class}: #{e}" log_error msg e.backtrace.each { |line| log_error "..#{line}" } end # begin update_version_post_upload(version, staged_pkg, orig_filename) end # thread end |
#upload_to_dist_point(jpkg, pkg_file) ⇒ void
This method returns an undefined value.
upload a staged pkg to the dist point(s) This will also update the checksum and manifest.
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 442 def upload_to_dist_point(jpkg, pkg_file) # via API if upload_via_api? log_debug 'Jamf: increasing the API timeout to 30 minutes for the pkg upload' jpkg.cnx.jp_cnx..timeout = 1800 log_debug "Jamf: Attempting upload of #{pkg_file.basename} to primary dist point via API" # this will update the checksum and manifest automatically, and save back to the jamf pro server jpkg.upload pkg_file log_info "Jamf: Uploaded #{pkg_file.basename} to primary dist point via API, with new checksum and manifest" # via upload tool defined in config else log_debug "Jamf: Regenerating manifest for package '#{jpkg.packageName}' from #{pkg_file.basename}" jpkg.generate_manifest(pkg_file) log_debug "Jamf: Recalculating checksum for package '#{jpkg.packageName}' from #{pkg_file.basename}" jpkg.recalculate_checksum(pkg_file) log_info "Jamf: Saving package '#{jpkg.packageName}' with new checksum and manifest" jpkg.save upload_via_tool(jpkg, pkg_file) end end |
#upload_via_api? ⇒ Boolean
are Dist Point uploads configured to be done via the API, or with an upload tool defined in config?
430 431 432 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 430 def upload_via_api? Xolo::Server.config.upload_tool.to_s.downcase == 'api' end |
#upload_via_tool(jpkg, pkg_file) ⇒ void
This method returns an undefined value.
upload the pkg with the uploader tool defined in config
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 474 def upload_via_tool(jpkg, pkg_file) log_info "Jamf: Uploading #{pkg_file.basename} to dist point(s) via upload tool" tool = Shellwords.escape Xolo::Server.config.upload_tool.to_s jpkg_name = Shellwords.escape jpkg.packageName pkg = Shellwords.escape pkg_file.to_s cmd = "#{tool} #{jpkg_name} #{pkg}" stdouterr, exit_status = Open3.capture2e(cmd) if exit_status.success? log_debug "Jamf: upload tool succeeded in uploading #{pkg_file.basename} to dist point(s)." return end msg = "Uploader tool failed to upload #{pkg_file.basename} to dist point(s): #{stdouterr}" log_error msg raise msg end |
#validate_uploaded_pkg(filename) ⇒ String
Confirm and return the extension of the originally uplaoded file, as .pkg
500 501 502 503 504 505 506 507 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 500 def validate_uploaded_pkg(filename) log_debug "Validating pkg file ext for '#{filename}'" file_extname = Pathname.new(filename).extname return file_extname if Xolo::OK_PKG_EXTS.include? file_extname raise "Bad filename '#{filename}'. Package files must end in #{Xolo::OK_PKG_EXTS.join(', or ')}" end |
#wait_for_pkg_and_enable_reinstall_policy(version) ⇒ void
This method returns an undefined value.
Wait for a re-uploaded pkg to appear on the Cloud DP after an API upload, then enable the reinstall policy
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 253 def wait_for_pkg_and_enable_reinstall_policy(version) start_time = Time.now until cloud_dp_pkg_ready?(version.jamf_pkg_file) if Time.now - start_time > CLOUD_DP_UPLOAD_TIMEOUT msg = "Timed out waiting for pkg '#{version.jamf_pkg_file}' to appear on Cloud DP after upload via API" log_error msg raise msg end log_debug "Checking every minute for pkg '#{version.jamf_pkg_file}' to appear on Cloud DP after upload via API..." sleep 60 end # until log_debug "Pkg '#{version.jamf_pkg_file}' is now on Cloud DP, enabling reinstall policy" pol = version.jamf_auto_reinstall_policy pol.enable pol.save msg = "Re-uploaded pkg '#{version.jamf_pkg_file}' is on the dist point and ready to go, reinstall policy '#{pol.name}' has been enabled" log_info msg, alert: true end |
#wrap_component_pkg_in_distribution(orig_pkg, version) ⇒ Pathname
Wrap a component pkg in a Distribution pkg, return the path to the Distribution pkg, which should be the same as the orig_pkg
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
# File 'lib/xolo/server/helpers/file_transfers.rb', line 380 def wrap_component_pkg_in_distribution(orig_pkg, version) orig_pkg = Pathname.new(orig_pkg) raise ArgumentError, "pkg_file does not exist or not a file: #{orig_pkg}" unless orig_pkg.file? if pkg_is_distribution?(orig_pkg) log_debug "Package '#{orig_pkg.basename}' is already a Distribution pkg, not wrapping" return orig_pkg end log_info "Wrapping component pkg '#{orig_pkg.basename}' in a Distribution pkg" out_dir = orig_pkg.parent out_file = out_dir + "#{orig_pkg.basename(Xolo::DOT_PKG)}_dist#{Xolo::DOT_PKG}" # the productbuild command, with signing if needed prodbuild_cmd = +"/usr/bin/productbuild --package #{orig_pkg.to_s.shellescape} " signing_reason = if version.pkg_is_from_autopkg && Xolo::Server.config.sign_autopkg_pkgs 'autopkg' elsif !version.pkg_is_from_autopkg && Xolo::Server.config.sign_pkgs 'uploaded' end if signing_reason log_info "Signing is enabled for #{signing_reason} pkgs, will sign the Distribution pkg as part of wrapping process" sh_kch = Shellwords.escape Xolo::Server::Configuration::PKG_SIGNING_KEYCHAIN.to_s sh_ident = Shellwords.escape Xolo::Server.config.pkg_signing_identity unlock_signing_keychain prodbuild_cmd << "--sign #{sh_ident} --keychain #{sh_kch} " end prodbuild_cmd << out_file.to_s.shellescape log_debug "Wrapping component pkg in Distribution pkg with this command: #{prodbuild_cmd}" if system prodbuild_cmd # remove the component pkg orig_pkg.delete # rename the dist pkg to the original pkg name, out_file.rename orig_pkg return orig_pkg end raise "Failed to wrap component pkg '#{orig_pkg.basename}' in a Distribution pkg" end |