aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cmd/create.rb
blob: 9ba3e72040ebe5701dbd5f04d28d1a3733fbf135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
require 'formula'
require 'blacklist'
require 'digest'
require 'erb'

module Homebrew

  # Create a formula from a tarball URL
  def create

    # Allow searching MacPorts or Fink.
    if ARGV.include? '--macports'
      exec_browser "http://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
    elsif ARGV.include? '--fink'
      exec_browser "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
    end

    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'

    fc = FormulaCreator.new
    fc.name = name
    fc.version = version
    fc.url = url

    fc.mode = if ARGV.include? '--cmake'
      :cmake
    elsif ARGV.include? '--autotools'
      :autotools
    end

    if fc.name.nil? || fc.name.strip.empty?
      stem = Pathname.new(url).stem
      print "Formula name [#{stem}]: "
      fc.name = __gets || stem
      fc.path = Formula.path(fc.name)
    end

    # Don't allow blacklisted formula, or names that shadow aliases,
    # unless --force is specified.
    unless ARGV.force?
      if msg = blacklisted?(fc.name)
        raise "#{fc.name} is blacklisted for creation.\n#{msg}\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 #{fc.name}` before submitting, thanks."
    exec_editor fc.path
  end

  def __gets
    gots = $stdin.gets.chomp
    if gots.empty? then nil else gots end
  end
end

class FormulaCreator
  attr_reader :url, :sha1
  attr_accessor :name, :version, :path, :mode

  def url= url
    @url = url
    path = Pathname.new(url)
    if @name.nil?
      %r{github.com/\S+/(\S+)/archive/}.match url
      @name ||= $1
      /(.*?)[-_.]?#{path.version}/.match path.basename
      @name ||= $1
      @path = Formula.path @name unless @name.nil?
    else
      @path = Formula.path name
    end
    if @version
      @version = Version.new(@version)
    else
      @version = Pathname.new(url).version
    end
  end

  def fetch?
    !ARGV.include?("--no-fetch")
  end

  def generate!
    raise "#{path} already exists" if path.exist?

    if version.nil?
      opoo "Version cannot be determined from URL."
      puts "You'll need to add an explicit 'version' to the formula."
    end

    if fetch? && version
      r = Resource.new
      r.url, r.version, r.owner = url, version, self
      @sha1 = r.fetch.sha1 if r.download_strategy == CurlDownloadStrategy
    end

    path.write ERB.new(template, nil, '>').result(binding)
  end

  def template; <<-EOS.undent
    require "formula"

    # Documentation: https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/Formula-Cookbook.md
    #                #{HOMEBREW_CONTRIB}/example-formula.rb
    # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!

    class #{Formulary.class_s(name)} < Formula
      homepage ""
      url "#{url}"
    <% unless  version.nil? or version.detected_from_url? %>
      version "#{version}"
    <% end %>
      sha1 "#{sha1}"

    <% if  mode == :cmake %>
      depends_on "cmake" => :build
    <% elsif  mode.nil? %>
      # depends_on "cmake" => :build
    <% end  %>
      depends_on :x11 # if your formula requires any X11/XQuartz components

      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}"
    <% 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  %>
        system "make", "install" # if this fails, try separate make/make install steps
      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