aboutsummaryrefslogtreecommitdiffstats
path: root/bin/brew
blob: bb89d371207290bddcdc0ecae23245ce84d0b052 (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
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#!/usr/bin/ruby
$:.unshift __FILE__+'/../../Library/Homebrew'
require 'env'
require 'find'

# often causes Ruby to throw exception ffs
Dir.chdir '/' unless File.directory? ENV['PWD']

######################################################################## funcs
def prune
  n=0
  dirs=Array.new
  HOMEBREW_PREFIX.find do |path|
    if path.directory?
      name=path.relative_path_from(HOMEBREW_PREFIX).to_s
      if name == '.git' or name == 'Cellar' or name == 'Library'
        Find.prune
      else
        dirs<<path
      end
    elsif path.symlink?
      resolved_path=path.dirname+path.readlink
      unless resolved_path.exist?
        path.unlink
        n+=1
      end
    end
  end
  dirs.sort.reverse_each do |d|
    if d.children.length == 0
      d.rmdir
      n+=1
    end
  end
  return n
end

# we actually remove formulae from ARGV so that any other analysis of ARGV
# only includes relevent arguments
# TODO require will throw if no formula, so we should catch no?
def extract_named_args
  args=Array.new
  ARGV.delete_if do |arg|
    if arg[0,1] == '-'
      false
    else
      args<<arg
      true
    end
  end
  return args
end

def extract_kegs
  require 'keg'
  kegs=extract_named_args.collect {|name| Keg.new name}
  raise "Expecting the name of a keg or formula, eg:\n\tbrew #{ARGV.join ' '} wget" if kegs.empty?
  return kegs
end

def abv keg=nil
  path=keg ? keg.path : HOMEBREW_CELLAR
  if path.directory?
    `find #{path} -type f | wc -l`.strip+' files, '+`du -hd0 #{path} | cut -d"\t" -f1`.strip
  else
    ''
  end
end

def install formula
  require 'keg'
  
  beginning = Time.now

  formula.brew do
    if ARGV.include? '--interactive'
      ohai "Entering interactive mode"
      puts "Type `exit' to return and finalize the installation"
      puts "Install to this prefix: #{formula.prefix}"
      pid=fork
      if pid.nil?
        exec 'bash'
      else
        Process.wait pid
      end
    elsif ARGV.include? '--help'
      ohai './configure --help'
      puts `./configure --help`
      exit
    else
      formula.prefix.mkpath
      formula.install
      %w[README ChangeLog COPYING LICENSE COPYRIGHT AUTHORS].each do |file|
        formula.prefix.install file if File.file? file
      end
    end
  end
  
  raise "Nothing installed" unless formula.installed?
  
  ohai 'Finishing up'
  keg=Keg.new formula
  keg.clean
  keg.ln
  if formula.caveats
    ohai "Caveats"
    puts formula.caveats
    ohai "Summary"
  end
  puts "#{keg.path}: "+abv(keg)+", built in #{pretty_duration Time.now-beginning}"
rescue Exception
  formula.prefix.rmtree if formula.prefix.directory?
  raise
end

def mk url, mode='make'
  require 'formula'
  path=Pathname.new(url)

  /(.*?)[-_.]?#{path.version}/.match path.basename
  raise "Couldn't parse name from #{url}" if $1.nil? or $1.empty?

  path=Formula.path $1
  raise "#{path} already exists!" if File.exist? path

  f=File.new path, 'w'
  f.puts "require 'brewkit'"
  f.puts
  f.puts "class #{Formula.class $1} <Formula"
  f.puts "  @url='#{url}'"
  f.puts "  @homepage=''" # second because you fill in these two first
  f.puts "  @md5=''"
  f.puts

  if mode == "cmake"
    f.puts "  def deps"
    f.puts "    BinaryDep.new 'cmake'"
    f.puts "  end"
    f.puts
  end

  f.puts "  def install"
  
  if mode == "make"
    f.puts "    system \"./configure --disable-debug --prefix='\#{prefix}'\""
    f.puts "    system \"make install\""
  elsif mode == "cmake"
    f.puts "    system \"cmake -G 'Unix Makefiles' -DCMAKE_INSTALL_PREFIX=\#{prefix}\""
    f.puts "    system \"make\""
    f.puts "    system \"make install\""
  end
  
  f.puts "  end"
  f.print "end"
  f.close

  return path
end

def prefix
  Pathname.new(__FILE__).dirname.parent.expand_path
end

def usage
  name=File.basename $0
  <<-EOS
Usage: #{name} command [formula] ...
Usage: #{name} [--prefix] [--cache] [--version]
Usage: #{name} [--verbose]

Commands:
  install formula ... [--debug] [--interactive]
  rm formula ...
  list formula ...
  ln formula ...
  info [formula]
  mk url
  prune
EOS
end


######################################################################## utils
def pretty_duration s
  return "#{(s*1000).to_i} milliseconds" if s < 3
  return "#{s.to_i} seconds" if s < 10*60
  return "#{(s/60).to_i} minutes"
end

######################################################################### impl
begin
  case ARGV.shift
    when '--prefix' then puts prefix
    when '--cache' then puts Homebrew::cache
    when '-h', '--help', '--usage', '-?' then puts usage
    when '-v', '--version' then puts HOMEBREW_VERSION
    when 'macports' then exec "open 'http://www.macports.org/ports.php?by=name&substr=#{ARGV.shift}'"

    when 'ls', 'list'
      dirs=extract_kegs.collect {|keg| keg.path}
      exec "find #{dirs.join' '} -not -type d -print"

    when 'edit'
      if ARGV.empty?
        r=HOMEBREW_PREFIX
        exec "mate #{r}/Library/Formula #{r}/Library/Homebrew #{r}/bin/brew #{r}/README"
      else
        require 'formula'
        paths=extract_named_args.collect {|name| Formula.path(name).to_s.gsub ' ', '\\ '}
        exec "mate #{paths.join ' '}"
      end

    when 'install'
      require 'formula'
      extract_named_args.each do |name|
        f=Formula.create(name)
        raise "#{f.name} already installed!\n\t#{f.prefix}" if f.installed?
        install f
      end

    when 'ln', 'link'
      n=0
      (kegs=extract_kegs).each do |keg|
        n+=nn=keg.ln
        puts "Created #{nn} links for #{keg.name}" if kegs.length > 1
      end
      puts "Created #{n} links"

    when 'rm', 'uninstall'
      extract_kegs.each do |keg|
        puts "Removing #{keg.name}..."
        keg.rm
      end
      print "Pruning #{prefix}/..."
      puts " #{prune} symbolic links pruned"

    when 'prune'
      puts "Pruned #{prune} symbolic links"

    when 'mk', 'make'
      mode = "make"
      if ARGV.length > 0
        if ARGV[0] == '--cmake'
          ARGV.shift
          mode = "cmake"
        end
      end
      
      paths=ARGV.collect {|arg| mk arg, mode}
      if paths.empty?
        raise "Invalid URL"
      elsif Kernel.system "which mate > /dev/null" and $? == 0
        paths=paths.collect {|path| path.to_s.gsub " ", "\\ "}
        exec "mate #{paths.join ' '}"
      else
        puts paths.join("\n")
      end

    when 'info', 'abv'
      if ARGV.empty?
        puts `ls #{HOMEBREW_CELLAR} | wc -l`.strip+" kegs, "+abv
      elsif ARGV[0][0..6] == 'http://'
        puts Pathname.new(ARGV.shift).version
      else
        #TODO show outdated status and that
        keg=extract_kegs[0]
        frm=Formula.create keg.name
        puts "#{keg.name} #{keg.version}"
        puts frm.homepage
        if frm.installed?
          puts "#{abv keg} (installed to #{keg.path})"
        end
        if frm.caveats
          ohai 'Caveats'
          puts frm.caveats
        end
      end

    else
      puts usage
  end

rescue StandardError, Interrupt => e
  if ARGV.include? '--verbose' or ENV['HOMEBREW_DEBUG']
    raise
  elsif e.kind_of? Interrupt
    puts # seeimgly a newline is typical
    exit 130
  elsif e.kind_of? StandardError and not e.kind_of? NameError
    puts "\033[1;31mError\033[0;0m: #{e}"
    exit 1
  else
    raise
  end
end