mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

Deprecate more methods. Internal APIs have been verified to be unused elsewhere and removed. External APIs have had deprecation methods added. Existing deprecations have been either upgraded to produce warnings or no longer deprecated and the reasoning documented.
242 lines
7.6 KiB
Ruby
242 lines
7.6 KiB
Ruby
#: * `create` <URL> [`--autotools`|`--cmake`|`--meson`] [`--no-fetch`] [`--set-name` <name>] [`--set-version` <version>] [`--tap` <user>`/`<repo>]:
|
|
#: Generate a formula 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 have a look at
|
|
#: <http://www.rubydoc.info/github/Homebrew/brew/master/Formula>.
|
|
#:
|
|
#: If `--autotools` is passed, create a basic template for an Autotools-style build.
|
|
#: If `--cmake` is passed, create a basic template for a CMake-style build.
|
|
#: If `--meson` is passed, create a basic template for a Meson-style build.
|
|
#:
|
|
#: If `--no-fetch` is passed, Homebrew will not download <URL> to the cache and
|
|
#: will thus not add the SHA256 to the formula for you. It will also not check
|
|
#: the GitHub API for GitHub projects (to fill out the description and homepage).
|
|
#:
|
|
#: The options `--set-name` and `--set-version` each take an argument and allow
|
|
#: you to explicitly set the name and version of the package you are creating.
|
|
#:
|
|
#: The option `--tap` takes a tap as its argument and generates the formula in
|
|
#: the specified tap.
|
|
|
|
require "formula"
|
|
require "missing_formula"
|
|
require "digest"
|
|
require "erb"
|
|
|
|
module Homebrew
|
|
module_function
|
|
|
|
# Create a formula from a tarball URL
|
|
def create
|
|
raise UsageError if ARGV.named.empty?
|
|
|
|
# Ensure that the cache exists so we can fetch the tarball
|
|
HOMEBREW_CACHE.mkpath
|
|
|
|
url = ARGV.named.first # Pull the first (and only) url from ARGV
|
|
|
|
version = ARGV.next if ARGV.include? "--set-version"
|
|
name = ARGV.next if ARGV.include? "--set-name"
|
|
tap = ARGV.next if ARGV.include? "--tap"
|
|
|
|
fc = FormulaCreator.new
|
|
fc.name = name
|
|
fc.version = version
|
|
fc.tap = Tap.fetch(tap || "homebrew/core")
|
|
raise TapUnavailableError, tap unless fc.tap.installed?
|
|
fc.url = url
|
|
|
|
fc.mode = if ARGV.include? "--cmake"
|
|
:cmake
|
|
elsif ARGV.include? "--autotools"
|
|
:autotools
|
|
elsif ARGV.include? "--meson"
|
|
:meson
|
|
end
|
|
|
|
if fc.name.nil? || fc.name.strip.empty?
|
|
stem = Pathname.new(url).stem
|
|
print "Formula name [#{stem}]: "
|
|
fc.name = __gets || stem
|
|
fc.update_path
|
|
end
|
|
|
|
# Don't allow blacklisted formula, or names that shadow aliases,
|
|
# unless --force is specified.
|
|
unless ARGV.force?
|
|
if reason = Homebrew::MissingFormula.blacklisted_reason(fc.name)
|
|
raise "#{fc.name} is blacklisted for creation.\n#{reason}\nIf you really want to create this formula use --force."
|
|
end
|
|
|
|
if Formula.aliases.include? fc.name
|
|
realname = Formulary.canonical_name(fc.name)
|
|
raise <<-EOS.undent
|
|
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
|
|
|
|
fc.generate!
|
|
|
|
puts "Please `brew audit --new-formula #{fc.name}` before submitting, thanks."
|
|
exec_editor fc.path
|
|
end
|
|
|
|
def __gets
|
|
gots = $stdin.gets.chomp
|
|
gots.empty? ? nil : gots
|
|
end
|
|
end
|
|
|
|
class FormulaCreator
|
|
attr_reader :url, :sha256, :desc, :homepage
|
|
attr_accessor :name, :version, :tap, :path, :mode
|
|
|
|
def url=(url)
|
|
@url = url
|
|
path = Pathname.new(url)
|
|
if @name.nil?
|
|
case url
|
|
when %r{github\.com/(\S+)/(\S+)\.git}
|
|
@user = $1
|
|
@name = $2
|
|
@head = true
|
|
@github = true
|
|
when %r{github\.com/(\S+)/(\S+)/(archive|releases)/}
|
|
@user = $1
|
|
@name = $2
|
|
@github = true
|
|
else
|
|
@name = path.basename.to_s[/(.*?)[-_.]?#{Regexp.escape(path.version.to_s)}/, 1]
|
|
end
|
|
end
|
|
update_path
|
|
if @version
|
|
@version = Version.create(@version)
|
|
else
|
|
@version = Version.detect(url, {})
|
|
end
|
|
end
|
|
|
|
def update_path
|
|
return if @name.nil? || @tap.nil?
|
|
@path = Formulary.path "#{@tap}/#{@name}"
|
|
end
|
|
|
|
def fetch?
|
|
!ARGV.include?("--no-fetch")
|
|
end
|
|
|
|
def head?
|
|
@head || ARGV.build_head?
|
|
end
|
|
|
|
def generate!
|
|
raise "#{path} already exists" if path.exist?
|
|
|
|
if version.nil? || version.null?
|
|
opoo "Version cannot be determined from URL."
|
|
puts "You'll need to add an explicit 'version' to the formula."
|
|
elsif fetch?
|
|
unless head?
|
|
r = Resource.new
|
|
r.url(url)
|
|
r.version(version)
|
|
r.owner = self
|
|
@sha256 = r.fetch.sha256 if r.download_strategy == CurlDownloadStrategy
|
|
end
|
|
|
|
if @user && @name
|
|
begin
|
|
metadata = GitHub.repository(@user, @name)
|
|
@desc = metadata["description"]
|
|
@homepage = metadata["homepage"]
|
|
rescue GitHub::HTTPNotFoundError
|
|
# If there was no repository found assume the network connection is at
|
|
# fault rather than the input URL.
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
|
|
path.write ERB.new(template, nil, ">").result(binding)
|
|
end
|
|
|
|
def template; <<-EOS.undent
|
|
# Documentation: http://docs.brew.sh/Formula-Cookbook.html
|
|
# http://www.rubydoc.info/github/Homebrew/brew/master/Formula
|
|
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
|
|
|
|
class #{Formulary.class_s(name)} < Formula
|
|
desc "#{desc}"
|
|
homepage "#{homepage}"
|
|
<% if head? %>
|
|
head "#{url}"
|
|
<% else %>
|
|
url "#{url}"
|
|
<% unless version.nil? or version.detected_from_url? %>
|
|
version "#{version}"
|
|
<% end %>
|
|
sha256 "#{sha256}"
|
|
<% end %>
|
|
|
|
<% if mode == :cmake %>
|
|
depends_on "cmake" => :build
|
|
<% elsif mode == :meson %>
|
|
depends_on "meson" => :build
|
|
depends_on "ninja" => :build
|
|
<% elsif mode.nil? %>
|
|
# depends_on "cmake" => :build
|
|
<% end %>
|
|
|
|
def install
|
|
# ENV.deparallelize # if your formula fails when building in parallel
|
|
|
|
<% if mode == :cmake %>
|
|
system "cmake", ".", *std_cmake_args
|
|
<% elsif mode == :autotools %>
|
|
# Remove unrecognized options if warned by configure
|
|
system "./configure", "--disable-debug",
|
|
"--disable-dependency-tracking",
|
|
"--disable-silent-rules",
|
|
"--prefix=\#{prefix}"
|
|
<% elsif mode == :meson %>
|
|
mkdir "build" do
|
|
system "meson", "--prefix=\#{prefix}", ".."
|
|
system "ninja"
|
|
system "ninja", "test"
|
|
system "ninja", "install"
|
|
end
|
|
<% else %>
|
|
# Remove unrecognized options if warned by configure
|
|
system "./configure", "--disable-debug",
|
|
"--disable-dependency-tracking",
|
|
"--disable-silent-rules",
|
|
"--prefix=\#{prefix}"
|
|
# system "cmake", ".", *std_cmake_args
|
|
<% end %>
|
|
<% if mode != :meson %>
|
|
system "make", "install" # if this fails, try separate make/make install steps
|
|
<% end %>
|
|
end
|
|
|
|
test do
|
|
# `test do` will create, run in and delete a temporary directory.
|
|
#
|
|
# This test will fail and we won't accept that! It's enough to just replace
|
|
# "false" with the main program this formula installs, but it'd be nice if you
|
|
# were more thorough. Run the test with `brew test #{name}`. Options passed
|
|
# to `brew install` such as `--HEAD` also need to be provided to `brew test`.
|
|
#
|
|
# The installed folder is not in the path, so use the entire path to any
|
|
# executables being tested: `system "\#{bin}/program", "do", "something"`.
|
|
system "false"
|
|
end
|
|
end
|
|
EOS
|
|
end
|
|
end
|