| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  | require "formula" | 
					
						
							| 
									
										
										
										
											2018-06-03 15:28:48 +05:30
										 |  |  | require "formula_creator" | 
					
						
							| 
									
										
										
										
											2017-03-18 17:02:08 +02:00
										 |  |  | require "missing_formula" | 
					
						
							| 
									
										
										
										
											2020-07-27 10:38:50 -04:00
										 |  |  | require "utils/pypi" | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | require "cask/cask_loader" | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 22:41:47 -05:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |   module DevCmd | 
					
						
							|  |  |  |     class Create < AbstractCommand | 
					
						
							|  |  |  |       cmd_args do | 
					
						
							|  |  |  |         description <<~EOS | 
					
						
							|  |  |  |           Generate a formula or, with `--cask`, a cask for the downloadable file at <URL> | 
					
						
							|  |  |  |           and open it in the editor. Homebrew will attempt to automatically derive the | 
					
						
							|  |  |  |           formula name and version, but if it fails, you'll have to make your own template. | 
					
						
							|  |  |  |           The `wget` formula serves as a simple example. For the complete API, see: | 
					
						
							|  |  |  |           <https://rubydoc.brew.sh/Formula> | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         switch "--autotools", | 
					
						
							|  |  |  |                description: "Create a basic template for an Autotools-style build." | 
					
						
							|  |  |  |         switch "--cask", | 
					
						
							|  |  |  |                description: "Create a basic template for a cask." | 
					
						
							|  |  |  |         switch "--cmake", | 
					
						
							|  |  |  |                description: "Create a basic template for a CMake-style build." | 
					
						
							|  |  |  |         switch "--crystal", | 
					
						
							|  |  |  |                description: "Create a basic template for a Crystal build." | 
					
						
							|  |  |  |         switch "--go", | 
					
						
							|  |  |  |                description: "Create a basic template for a Go build." | 
					
						
							|  |  |  |         switch "--meson", | 
					
						
							|  |  |  |                description: "Create a basic template for a Meson-style build." | 
					
						
							|  |  |  |         switch "--node", | 
					
						
							|  |  |  |                description: "Create a basic template for a Node build." | 
					
						
							|  |  |  |         switch "--perl", | 
					
						
							|  |  |  |                description: "Create a basic template for a Perl build." | 
					
						
							|  |  |  |         switch "--python", | 
					
						
							|  |  |  |                description: "Create a basic template for a Python build." | 
					
						
							|  |  |  |         switch "--ruby", | 
					
						
							|  |  |  |                description: "Create a basic template for a Ruby build." | 
					
						
							|  |  |  |         switch "--rust", | 
					
						
							|  |  |  |                description: "Create a basic template for a Rust build." | 
					
						
							| 
									
										
										
										
											2025-02-21 15:05:42 +01:00
										 |  |  |         switch "--zig", | 
					
						
							|  |  |  |                description: "Create a basic template for a Zig build." | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         switch "--no-fetch", | 
					
						
							|  |  |  |                description: "Homebrew will not download <URL> to the cache and will thus not add its SHA-256 " \ | 
					
						
							|  |  |  |                             "to the formula for you, nor will it check the GitHub API for GitHub projects " \ | 
					
						
							|  |  |  |                             "(to fill out its description and homepage)." | 
					
						
							|  |  |  |         switch "--HEAD", | 
					
						
							|  |  |  |                description: "Indicate that <URL> points to the package's repository rather than a file." | 
					
						
							|  |  |  |         flag   "--set-name=", | 
					
						
							|  |  |  |                description: "Explicitly set the <name> of the new formula or cask." | 
					
						
							|  |  |  |         flag   "--set-version=", | 
					
						
							|  |  |  |                description: "Explicitly set the <version> of the new formula or cask." | 
					
						
							|  |  |  |         flag   "--set-license=", | 
					
						
							|  |  |  |                description: "Explicitly set the <license> of the new formula." | 
					
						
							|  |  |  |         flag   "--tap=", | 
					
						
							|  |  |  |                description: "Generate the new formula within the given tap, specified as <user>`/`<repo>." | 
					
						
							|  |  |  |         switch "-f", "--force", | 
					
						
							|  |  |  |                description: "Ignore errors for disallowed formula names and names that shadow aliases." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts "--autotools", "--cmake", "--crystal", "--go", "--meson", "--node", | 
					
						
							| 
									
										
										
										
											2025-02-21 15:05:42 +01:00
										 |  |  |                   "--perl", "--python", "--ruby", "--rust", "--zig", "--cask" | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         conflicts "--cask", "--HEAD" | 
					
						
							|  |  |  |         conflicts "--cask", "--set-license" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         named_args :url, number: 1
 | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-07-30 18:25:38 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |       # Create a formula from a tarball URL. | 
					
						
							|  |  |  |       sig { override.void } | 
					
						
							|  |  |  |       def run | 
					
						
							|  |  |  |         path = if args.cask? | 
					
						
							|  |  |  |           create_cask | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           create_formula | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2018-07-30 18:25:38 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         exec_editor path | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { returns(Pathname) } | 
					
						
							|  |  |  |       def create_cask | 
					
						
							| 
									
										
										
										
											2024-12-03 17:43:22 -08:00
										 |  |  |         url = args.named.fetch(0) | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         name = if args.set_name.blank? | 
					
						
							|  |  |  |           stem = Pathname.new(url).stem.rpartition("=").last | 
					
						
							|  |  |  |           print "Cask name [#{stem}]: " | 
					
						
							|  |  |  |           __gets || stem | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           args.set_name | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         token = Cask::Utils.token_from(T.must(name)) | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         cask_tap = Tap.fetch(args.tap || "homebrew/cask") | 
					
						
							|  |  |  |         raise TapUnavailableError, cask_tap.name unless cask_tap.installed? | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         cask_path = cask_tap.new_cask_path(token) | 
					
						
							|  |  |  |         cask_path.dirname.mkpath unless cask_path.dirname.exist? | 
					
						
							|  |  |  |         raise Cask::CaskAlreadyCreatedError, token if cask_path.exist? | 
					
						
							| 
									
										
										
										
											2020-12-15 12:55:07 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         version = if args.set_version | 
					
						
							|  |  |  |           Version.new(T.must(args.set_version)) | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           Version.detect(url.gsub(token, "").gsub(/x86(_64)?/, "")) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         interpolated_url, sha256 = if version.null? | 
					
						
							|  |  |  |           [url, ""] | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           sha256 = if args.no_fetch? | 
					
						
							|  |  |  |             "" | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             strategy = DownloadStrategyDetector.detect(url) | 
					
						
							|  |  |  |             downloader = strategy.new(url, token, version.to_s, cache: Cask::Cache.path) | 
					
						
							|  |  |  |             downloader.fetch | 
					
						
							|  |  |  |             downloader.cached_location.sha256 | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           [url.gsub(version.to_s, "\#{version}"), sha256] | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         cask_path.atomic_write <<~RUBY | 
					
						
							|  |  |  |           # Documentation: https://docs.brew.sh/Cask-Cookbook | 
					
						
							|  |  |  |           #                https://docs.brew.sh/Adding-Software-to-Homebrew#cask-stanzas | 
					
						
							|  |  |  |           # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST! | 
					
						
							|  |  |  |           cask "#{token}" do | 
					
						
							|  |  |  |             version "#{version}" | 
					
						
							|  |  |  |             sha256 "#{sha256}" | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |             url "#{interpolated_url}" | 
					
						
							|  |  |  |             name "#{name}" | 
					
						
							|  |  |  |             desc "" | 
					
						
							|  |  |  |             homepage "" | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |             # Documentation: https://docs.brew.sh/Brew-Livecheck | 
					
						
							|  |  |  |             livecheck do | 
					
						
							|  |  |  |               url "" | 
					
						
							|  |  |  |               strategy "" | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2023-12-15 15:34:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |             depends_on macos: "" | 
					
						
							| 
									
										
										
										
											2023-12-15 15:34:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |             app "" | 
					
						
							| 
									
										
										
										
											2023-12-15 15:34:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |             # Documentation: https://docs.brew.sh/Cask-Cookbook#stanza-zap | 
					
						
							|  |  |  |             zap trash: "" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         RUBY | 
					
						
							| 
									
										
										
										
											2020-11-20 12:13:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         puts "Please run `brew audit --cask --new #{token}` before submitting, thanks." | 
					
						
							|  |  |  |         cask_path | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |       sig { returns(Pathname) } | 
					
						
							|  |  |  |       def create_formula | 
					
						
							|  |  |  |         mode = if args.autotools? | 
					
						
							|  |  |  |           :autotools | 
					
						
							|  |  |  |         elsif args.cmake? | 
					
						
							|  |  |  |           :cmake | 
					
						
							|  |  |  |         elsif args.crystal? | 
					
						
							|  |  |  |           :crystal | 
					
						
							|  |  |  |         elsif args.go? | 
					
						
							|  |  |  |           :go | 
					
						
							|  |  |  |         elsif args.meson? | 
					
						
							|  |  |  |           :meson | 
					
						
							|  |  |  |         elsif args.node? | 
					
						
							|  |  |  |           :node | 
					
						
							|  |  |  |         elsif args.perl? | 
					
						
							|  |  |  |           :perl | 
					
						
							|  |  |  |         elsif args.python? | 
					
						
							|  |  |  |           :python | 
					
						
							|  |  |  |         elsif args.ruby? | 
					
						
							|  |  |  |           :ruby | 
					
						
							|  |  |  |         elsif args.rust? | 
					
						
							|  |  |  |           :rust | 
					
						
							| 
									
										
										
										
											2025-02-21 15:05:42 +01:00
										 |  |  |         elsif args.zig? | 
					
						
							|  |  |  |           :zig | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         fc = FormulaCreator.new( | 
					
						
							|  |  |  |           args.set_name, | 
					
						
							|  |  |  |           args.set_version, | 
					
						
							|  |  |  |           tap:     args.tap, | 
					
						
							| 
									
										
										
										
											2024-12-03 17:43:22 -08:00
										 |  |  |           url:     args.named.fetch(0), | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |           mode:, | 
					
						
							|  |  |  |           license: args.set_license, | 
					
						
							|  |  |  |           fetch:   !args.no_fetch?, | 
					
						
							|  |  |  |           head:    args.HEAD?, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         fc.parse_url | 
					
						
							|  |  |  |         # ask for confirmation if name wasn't passed explicitly | 
					
						
							|  |  |  |         if args.set_name.blank? | 
					
						
							|  |  |  |           print "Formula name [#{fc.name}]: " | 
					
						
							|  |  |  |           fc.name = __gets || fc.name | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-11-28 18:07:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         fc.verify | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Check for disallowed formula, or names that shadow aliases, | 
					
						
							|  |  |  |         # unless --force is specified. | 
					
						
							|  |  |  |         unless args.force? | 
					
						
							|  |  |  |           if (reason = MissingFormula.disallowed_reason(fc.name)) | 
					
						
							|  |  |  |             odie <<~EOS | 
					
						
							|  |  |  |               The formula '#{fc.name}' is not allowed to be created. | 
					
						
							|  |  |  |               #{reason} | 
					
						
							|  |  |  |               If you really want to create this formula use `--force`. | 
					
						
							|  |  |  |             EOS | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           Homebrew.with_no_api_env do | 
					
						
							|  |  |  |             if Formula.aliases.include? fc.name | 
					
						
							|  |  |  |               realname = Formulary.canonical_name(fc.name) | 
					
						
							|  |  |  |               odie <<~EOS | 
					
						
							|  |  |  |                 The formula '#{realname}' is already aliased to '#{fc.name}'. | 
					
						
							|  |  |  |                 Please check that you are not creating a duplicate. | 
					
						
							|  |  |  |                 To force creation use `--force`. | 
					
						
							|  |  |  |               EOS | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-11-29 18:57:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         path = fc.write_formula! | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         formula = Homebrew.with_no_api_env do | 
					
						
							| 
									
										
										
										
											2025-02-10 14:55:20 +08:00
										 |  |  |           CoreTap.instance.clear_cache | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |           Formula[fc.name] | 
					
						
							| 
									
										
										
										
											2023-06-22 16:53:46 +01:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         PyPI.update_python_resources! formula, ignore_non_pypi_packages: true if args.python? | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-26 09:06:50 +03:00
										 |  |  |         puts <<~EOS | 
					
						
							| 
									
										
										
										
											2025-03-26 21:12:00 +03:00
										 |  |  |           Please audit and test formula before submitting: | 
					
						
							| 
									
										
										
										
											2024-09-26 09:06:50 +03:00
										 |  |  |             HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new #{fc.name} | 
					
						
							| 
									
										
										
										
											2025-03-26 21:12:00 +03:00
										 |  |  |             HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug #{fc.name} | 
					
						
							| 
									
										
										
										
											2025-03-26 21:32:05 +03:00
										 |  |  |             HOMEBREW_NO_INSTALL_FROM_API=1 brew test #{fc.name} | 
					
						
							| 
									
										
										
										
											2024-09-26 09:06:50 +03:00
										 |  |  |         EOS | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |         path | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |       sig { returns(T.nilable(String)) } | 
					
						
							|  |  |  |       def __gets | 
					
						
							| 
									
										
										
										
											2025-04-10 21:17:09 -03:00
										 |  |  |         $stdin.gets&.presence&.chomp | 
					
						
							| 
									
										
										
										
											2024-03-21 08:08:53 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-06-22 16:53:46 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  |   end | 
					
						
							|  |  |  | end |