| 
									
										
										
										
											2023-03-09 20:32:46 -08:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "cli/parser" | 
					
						
							| 
									
										
										
										
											2023-07-21 22:18:00 +08:00
										 |  |  | require "formula" | 
					
						
							| 
									
										
										
										
											2021-03-11 15:15:35 +00:00
										 |  |  | require "github_packages" | 
					
						
							| 
									
										
										
										
											2021-03-10 16:08:45 +00:00
										 |  |  | require "github_releases" | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | module Homebrew | 
					
						
							|  |  |  |   module_function | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |   sig { returns(CLI::Parser) } | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |   def pr_upload_args | 
					
						
							|  |  |  |     Homebrew::CLI::Parser.new do | 
					
						
							| 
									
										
										
										
											2021-01-15 15:04:02 -05:00
										 |  |  |       description <<~EOS | 
					
						
							| 
									
										
										
										
											2021-03-10 16:08:45 +00:00
										 |  |  |         Apply the bottle commit and publish bottles to a host. | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |       EOS | 
					
						
							| 
									
										
										
										
											2020-07-06 17:41:07 +02:00
										 |  |  |       switch "--keep-old", | 
					
						
							|  |  |  |              description: "If the formula specifies a rebuild version, " \ | 
					
						
							|  |  |  |                           "attempt to preserve its value in the generated DSL." | 
					
						
							| 
									
										
										
										
											2020-06-25 12:01:52 -04:00
										 |  |  |       switch "-n", "--dry-run", | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |              description: "Print what would be done rather than doing it." | 
					
						
							| 
									
										
										
										
											2020-10-03 12:33:47 -04:00
										 |  |  |       switch "--no-commit", | 
					
						
							|  |  |  |              description: "Do not generate a new commit before uploading." | 
					
						
							| 
									
										
										
										
											2020-07-02 00:11:55 +10:00
										 |  |  |       switch "--warn-on-upload-failure", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "Warn instead of raising an error if the bottle upload fails. " \ | 
					
						
							| 
									
										
										
										
											2020-07-02 00:11:55 +10:00
										 |  |  |                           "Useful for repairing bottle uploads that previously failed." | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       switch "--upload-only", | 
					
						
							|  |  |  |              description: "Skip running `brew bottle` before uploading." | 
					
						
							| 
									
										
										
										
											2021-04-01 16:23:39 +05:30
										 |  |  |       flag   "--committer=", | 
					
						
							|  |  |  |              description: "Specify a committer name and email in `git`'s standard author format." | 
					
						
							| 
									
										
										
										
											2020-06-25 12:01:52 -04:00
										 |  |  |       flag   "--root-url=", | 
					
						
							|  |  |  |              description: "Use the specified <URL> as the root of the bottle's URL instead of Homebrew's default." | 
					
						
							| 
									
										
										
										
											2021-04-28 14:57:41 -04:00
										 |  |  |       flag   "--root-url-using=", | 
					
						
							| 
									
										
										
										
											2022-06-28 10:09:59 +01:00
										 |  |  |              description: "Use the specified download strategy class for downloading the bottle's URL instead of " \ | 
					
						
							| 
									
										
										
										
											2021-04-29 12:51:15 -04:00
										 |  |  |                           "Homebrew's default." | 
					
						
							| 
									
										
										
										
											2021-01-10 14:26:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       conflicts "--upload-only", "--keep-old" | 
					
						
							|  |  |  |       conflicts "--upload-only", "--no-commit" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-10 14:26:40 -05:00
										 |  |  |       named_args :none | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-21 17:10:05 +01:00
										 |  |  |   def check_bottled_formulae!(bottles_hash) | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |     bottles_hash.each do |name, bottle_hash| | 
					
						
							|  |  |  |       formula_path = HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"] | 
					
						
							| 
									
										
										
										
											2020-07-29 09:22:09 +02:00
										 |  |  |       formula_version = Formulary.factory(formula_path).pkg_version | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |       bottle_version = PkgVersion.parse bottle_hash["formula"]["pkg_version"] | 
					
						
							| 
									
										
										
										
											2020-07-26 21:46:37 +10:00
										 |  |  |       next if formula_version == bottle_version | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       odie "Bottles are for #{name} #{bottle_version} but formula is version #{formula_version}!" | 
					
						
							| 
									
										
										
										
											2020-07-26 19:03:02 +10:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |   def github_releases?(bottles_hash) | 
					
						
							|  |  |  |     @github_releases ||= bottles_hash.values.all? do |bottle_hash| | 
					
						
							|  |  |  |       root_url = bottle_hash["bottle"]["root_url"] | 
					
						
							| 
									
										
										
										
											2021-03-10 16:08:45 +00:00
										 |  |  |       url_match = root_url.match GitHubReleases::URL_REGEX | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |       _, _, _, tag = *url_match | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tag | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-11 15:15:35 +00:00
										 |  |  |   def github_packages?(bottles_hash) | 
					
						
							|  |  |  |     @github_packages ||= bottles_hash.values.all? do |bottle_hash| | 
					
						
							|  |  |  |       bottle_hash["bottle"]["root_url"].match? GitHubPackages::URL_REGEX | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 14:48:45 +01:00
										 |  |  |   def bottles_hash_from_json_files(json_files, args) | 
					
						
							| 
									
										
										
										
											2021-04-28 12:48:24 +01:00
										 |  |  |     puts "Reading JSON files: #{json_files.join(", ")}" if args.verbose? | 
					
						
							| 
									
										
										
										
											2020-07-26 19:03:02 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |     bottles_hash = json_files.reduce({}) do |hash, json_file| | 
					
						
							| 
									
										
										
										
											2021-04-14 12:42:26 +01:00
										 |  |  |       hash.deep_merge(JSON.parse(File.read(json_file))) | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-28 12:48:24 +01:00
										 |  |  |     if args.root_url | 
					
						
							| 
									
										
										
										
											2021-03-30 17:35:13 +01:00
										 |  |  |       bottles_hash.each_value do |bottle_hash| | 
					
						
							| 
									
										
										
										
											2021-04-28 12:48:24 +01:00
										 |  |  |         bottle_hash["bottle"]["root_url"] = args.root_url | 
					
						
							| 
									
										
										
										
											2021-03-30 17:35:13 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 14:48:45 +01:00
										 |  |  |     bottles_hash | 
					
						
							| 
									
										
										
										
											2021-04-21 17:10:05 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def pr_upload | 
					
						
							|  |  |  |     args = pr_upload_args.parse | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 14:48:45 +01:00
										 |  |  |     json_files = Dir["*.bottle.json"] | 
					
						
							|  |  |  |     odie "No bottle JSON files found in the current working directory" if json_files.blank? | 
					
						
							|  |  |  |     bottles_hash = bottles_hash_from_json_files(json_files, args) | 
					
						
							| 
									
										
										
										
											2021-04-21 17:10:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-26 20:20:53 +01:00
										 |  |  |     Homebrew.install_bundler_gems!(groups: ["pr_upload"]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |     unless args.upload_only? | 
					
						
							|  |  |  |       bottle_args = ["bottle", "--merge", "--write"] | 
					
						
							|  |  |  |       bottle_args << "--verbose" if args.verbose? | 
					
						
							|  |  |  |       bottle_args << "--debug" if args.debug? | 
					
						
							|  |  |  |       bottle_args << "--keep-old" if args.keep_old? | 
					
						
							|  |  |  |       bottle_args << "--root-url=#{args.root_url}" if args.root_url | 
					
						
							|  |  |  |       bottle_args << "--committer=#{args.committer}" if args.committer | 
					
						
							|  |  |  |       bottle_args << "--no-commit" if args.no_commit? | 
					
						
							|  |  |  |       bottle_args << "--root-url-using=#{args.root_url_using}" if args.root_url_using | 
					
						
							|  |  |  |       bottle_args += json_files | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if args.dry_run? | 
					
						
							|  |  |  |         dry_run_service = if github_packages?(bottles_hash) | 
					
						
							|  |  |  |           # GitHub Packages has its own --dry-run handling. | 
					
						
							|  |  |  |           nil | 
					
						
							|  |  |  |         elsif github_releases?(bottles_hash) | 
					
						
							|  |  |  |           "GitHub Releases" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           odie "Service specified by root_url is not recognized" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if dry_run_service | 
					
						
							|  |  |  |           puts <<~EOS | 
					
						
							|  |  |  |             brew #{bottle_args.join " "} | 
					
						
							|  |  |  |             Upload bottles described by these JSON files to #{dry_run_service}: | 
					
						
							|  |  |  |               #{json_files.join("\n  ")} | 
					
						
							|  |  |  |           EOS | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2021-03-30 08:42:15 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-08-20 14:21:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       check_bottled_formulae!(bottles_hash) | 
					
						
							| 
									
										
										
										
											2021-04-30 12:00:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       safe_system HOMEBREW_BREW_FILE, *bottle_args | 
					
						
							| 
									
										
										
										
											2021-04-29 14:48:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       json_files = Dir["*.bottle.json"] | 
					
						
							|  |  |  |       if json_files.blank? | 
					
						
							|  |  |  |         puts "No bottle JSON files after merge, no upload needed!" | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-04-21 17:10:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-21 02:39:27 +01:00
										 |  |  |       # Reload the JSON files (in case `brew bottle --merge` generated | 
					
						
							|  |  |  |       # `all: $SHA256` bottles) | 
					
						
							|  |  |  |       bottles_hash = bottles_hash_from_json_files(json_files, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Check the bottle commits did not break `brew audit` | 
					
						
							|  |  |  |       unless args.no_commit? | 
					
						
							|  |  |  |         audit_args = ["audit", "--skip-style"] | 
					
						
							|  |  |  |         audit_args << "--verbose" if args.verbose? | 
					
						
							|  |  |  |         audit_args << "--debug" if args.debug? | 
					
						
							|  |  |  |         audit_args += bottles_hash.keys | 
					
						
							|  |  |  |         safe_system HOMEBREW_BREW_FILE, *audit_args | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-11-09 09:59:59 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-30 09:50:04 -07:00
										 |  |  |     if github_releases?(bottles_hash) | 
					
						
							| 
									
										
										
										
											2021-03-10 16:08:45 +00:00
										 |  |  |       github_releases = GitHubReleases.new | 
					
						
							|  |  |  |       github_releases.upload_bottles(bottles_hash) | 
					
						
							| 
									
										
										
										
											2021-03-11 15:15:35 +00:00
										 |  |  |     elsif github_packages?(bottles_hash) | 
					
						
							| 
									
										
										
										
											2021-11-19 11:48:23 -08:00
										 |  |  |       github_packages = GitHubPackages.new | 
					
						
							| 
									
										
										
										
											2021-04-07 12:48:31 +01:00
										 |  |  |       github_packages.upload_bottles(bottles_hash, | 
					
						
							| 
									
										
										
										
											2021-04-09 16:39:28 +01:00
										 |  |  |                                      keep_old:      args.keep_old?, | 
					
						
							| 
									
										
										
										
											2021-04-07 12:48:31 +01:00
										 |  |  |                                      dry_run:       args.dry_run?, | 
					
						
							|  |  |  |                                      warn_on_error: args.warn_on_upload_failure?) | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2021-02-21 22:12:17 -08:00
										 |  |  |       odie "Service specified by root_url is not recognized" | 
					
						
							| 
									
										
										
										
											2020-04-20 10:17:42 +02:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |