File: uninstall

package info (click to toggle)
linuxbrew-wrapper 20180923-1
  • links: PTS, VCS
  • area: contrib
  • in suites: buster
  • size: 160 kB
  • sloc: ruby: 677; sh: 73; makefile: 6
file content (336 lines) | stat: -rwxr-xr-x 8,679 bytes parent folder | download
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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
#!/usr/bin/env ruby

require "English"
require "fileutils"
require "optparse"
require "pathname"

# Default options
options = {
  :force => false,
  :quiet => false,
  :dry_run => false,
  :skip_cache_and_logs => false
}

# global status to indicate whether there is anything wrong.
@failed = false

module Tty
  module_function

  def blue
    bold 34
  end

  def red
    bold 31
  end

  def reset
    escape 0
  end

  def bold(code = 39)
    escape "1;#{code}"
  end

  def escape(code)
    "\033[#{code}m" if STDOUT.tty?
  end
end

class Array
  def shell_s
    cp = dup
    first = cp.shift
    cp.map { |arg| arg.gsub " ", "\\ " }.unshift(first).join(" ")
  end
end

class Pathname
  def resolved_path
    symlink? ? dirname+readlink : self
  end

  def /(other)
    self + other.to_s
  end

  def pretty_print
    if symlink?
      puts to_s + " -> " + resolved_path.to_s
    elsif directory?
      puts to_s + "/"
    else
      puts to_s
    end
  end
end

def ohai(*args)
  puts "#{Tty.blue}==>#{Tty.bold} #{args.shell_s}#{Tty.reset}"
end

def warn(warning)
  puts "#{Tty.red}Warning#{Tty.reset}: #{warning.chomp}"
end

def system(*args)
  return if Kernel.system(*args)

  warn "Failed during: #{args.shell_s}"
  @failed = true
end

####################################################################### script

homebrew_prefix_candidates = []

OptionParser.new do |opts|
  opts.banner = "Homebrew Uninstaller\nUsage: ./uninstall [options]"
  opts.summary_width = 16
  opts.on("-pPATH", "--path=PATH", "Sets Homebrew prefix. Defaults to /usr/local.") { |p| homebrew_prefix_candidates << Pathname.new(p) }
  opts.on("--skip-cache-and-logs", "Skips removal of HOMEBREW_CACHE and HOMEBREW_LOGS.") { |_p| options[:skip_cache_and_logs] = true }
  opts.on("-f", "--force", "Uninstall without prompting.") { options[:force] = true }
  opts.on("-q", "--quiet", "Suppress all output.") { options[:quiet] = true }
  opts.on("-d", "--dry-run", "Simulate uninstall but don't remove anything.") { options[:dry_run] = true }
  opts.on_tail("-h", "--help", "Display this message.") do
    puts opts
    exit
  end
end.parse!

if homebrew_prefix_candidates.empty? # Attempt to locate Homebrew unless `--path` is passed
  prefix =
    begin
      `brew --prefix`
    rescue
      ""
    end
  homebrew_prefix_candidates << Pathname.new(prefix.strip) unless prefix.empty?
  prefix =
    begin
      begin
        `command -v brew`
      rescue
        `which brew`
      end
    rescue
      ""
    end
  homebrew_prefix_candidates << Pathname.new(prefix.strip).dirname.parent unless prefix.empty?
  homebrew_prefix_candidates << Pathname.new("/usr/local") # Homebrew default path
  homebrew_prefix_candidates << Pathname.new("#{ENV["HOME"]}/.linuxbrew")
  homebrew_prefix_candidates << Pathname.new("/home/linuxbrew/.linuxbrew") # Linuxbrew default path
end

HOMEBREW_PREFIX = homebrew_prefix_candidates.find do |p|
  next unless p.directory?
  if p.to_s == "/usr/local" && File.exist?("/usr/local/Homebrew/.git")
    next true
  end

  (p/".git").exist? || (p/"bin/brew").executable?
end
abort "Failed to locate Homebrew!" if HOMEBREW_PREFIX.nil?

HOMEBREW_REPOSITORY = if (HOMEBREW_PREFIX/".git").exist?
  (HOMEBREW_PREFIX/".git").realpath.dirname
elsif (HOMEBREW_PREFIX/"bin/brew").exist?
  (HOMEBREW_PREFIX/"bin/brew").realpath.dirname.parent
end
abort "Failed to locate Homebrew!" if HOMEBREW_REPOSITORY.nil?

HOMEBREW_CELLAR = if (HOMEBREW_PREFIX/"Cellar").exist?
  HOMEBREW_PREFIX/"Cellar"
else
  HOMEBREW_REPOSITORY/"Cellar"
end

gitignore =
  begin
    (HOMEBREW_REPOSITORY/".gitignore").read
  rescue Errno::ENOENT
    `curl -fsSL https://raw.githubusercontent.com/Homebrew/brew/master/.gitignore`
  end
abort "Failed to fetch Homebrew .gitignore!" if gitignore.empty?

homebrew_files = gitignore.split("\n").
                 select { |line| line.start_with? "!" }.
                 map { |line| line.chomp("/").gsub(%r{^!?/}, "") }.
                 reject { |line| %w[bin share share/doc].include?(line) }.
                 map { |p| HOMEBREW_REPOSITORY/p }
if HOMEBREW_PREFIX.to_s != HOMEBREW_REPOSITORY.to_s
  homebrew_files << HOMEBREW_REPOSITORY
  homebrew_files += %w[
    bin/brew
    etc/bash_completion.d/brew
    share/doc/homebrew
    share/man/man1/brew.1
    share/man/man1/brew-cask.1
    share/zsh/site-functions/_brew
    share/zsh/site-functions/_brew_cask
    var/homebrew
  ].map { |p| HOMEBREW_PREFIX/p }
else
  homebrew_files << HOMEBREW_REPOSITORY/".git"
  homebrew_files += %w[
    CHANGELOG.md
    lib64
  ].map { |p| HOMEBREW_PREFIX/p }
end
homebrew_files << HOMEBREW_CELLAR
homebrew_files << HOMEBREW_PREFIX/"Caskroom"

unless options[:skip_cache_and_logs]
  homebrew_files += %W[
    #{ENV["HOME"]}/Library/Caches/Homebrew
    #{ENV["HOME"]}/Library/Logs/Homebrew
    /Library/Caches/Homebrew
    #{ENV["HOME"]}/.cache/Homebrew
    #{ENV["HOMEBREW_CACHE"]}
    #{ENV["HOMEBREW_LOGS"]}
  ].map { |p| Pathname.new(p) }
end

if RUBY_PLATFORM.to_s.downcase.include? "darwin"
  homebrew_files += %W[
    /Applications
    #{ENV["HOME"]}/Applications
  ].map { |p| Pathname.new(p) }.select(&:directory?).map do |p|
    p.children.select do |app|
      app.resolved_path.to_s.start_with? HOMEBREW_CELLAR.to_s
    end
  end.flatten
end

homebrew_files = homebrew_files.select(&:exist?).sort

unless options[:quiet]
  warn "This script #{options[:dry_run] ? "would" : "will"} remove:"
  homebrew_files.each(&:pretty_print)
end

if STDIN.tty? && (!options[:force] && !options[:dry_run])
  STDERR.print "Are you sure you want to uninstall Homebrew? This will remove your installed packages! [y/N] "
  abort unless gets.rstrip =~ /y|yes/i
end

ohai "Removing Homebrew installation..." unless options[:quiet]
paths = %w[Frameworks bin etc include lib opt sbin share var].
        map { |p| HOMEBREW_PREFIX/p }.
        select(&:exist?).
        map(&:to_s)
if paths.any?
  args = paths + %w[-regextype egrep -regex .*/info/([^.][^/]*\.info|dir)]
  if options[:dry_run]
    args << "-print"
  else
    args += %w[-exec /bin/bash -c]
    args << "/usr/bin/install-info --delete --quiet {} \"$(dirname {})/dir\""
    args << ";"
  end
  puts "Would delete:" if options[:dry_run]
  system "/usr/bin/find", *args
  args = paths + %w[-type l -lname */Cellar/*]
  if options[:dry_run]
    args << "-print"
  else
    args += %w[-exec unlink {} ;]
  end
  puts "Would delete:" if options[:dry_run]
  system "/usr/bin/find", *args
end

homebrew_files.each do |file|
  if options[:dry_run]
    puts "Would delete #{file}"
  else
    begin
      FileUtils.rm_rf(file)
    rescue => e
      warn "Failed to delete #{file}"
      puts e.message
      @failed = true
    end
  end
end

# Invalidate sudo timestamp before exiting
at_exit { Kernel.system "/usr/bin/sudo", "-k" }

def sudo?
  return @have_sudo unless @have_sudo.nil?

  Kernel.system "/usr/bin/sudo", "-v"
  @have_sudo = $CHILD_STATUS && $CHILD_STATUS.success?
end

def sudo(*args)
  if sudo?
    args.unshift("-A") unless ENV["SUDO_ASKPASS"].nil?
    ohai "/usr/bin/sudo", *args
    system "/usr/bin/sudo", *args
  else
    ohai *args
    system *args
  end
end

ohai "Removing empty directories..." unless options[:quiet]
paths = %w[bin etc include lib opt sbin share var
           Caskroom Cellar Homebrew Frameworks].
        map { |p| HOMEBREW_PREFIX/p }.
        select(&:exist?).
        map(&:to_s)
if paths.any?
  args = paths + %w[-name .DS_Store]
  if options[:dry_run]
    args << "-print"
  else
    args << "-delete"
  end
  puts "Would delete:" if options[:dry_run]
  sudo "/usr/bin/find", *args
  args = paths + %w[-depth -type d -empty]
  if options[:dry_run]
    args << "-print"
  else
    args += %w[-exec rmdir {} ;]
  end
  puts "Would remove directories:" if options[:dry_run]
  sudo "/usr/bin/find", *args
end

if options[:dry_run]
  exit
else
  if HOMEBREW_PREFIX.to_s != "/usr/local" && HOMEBREW_PREFIX.exist?
    sudo "rmdir", HOMEBREW_PREFIX.to_s
  end
  if HOMEBREW_PREFIX.to_s != HOMEBREW_REPOSITORY.to_s && HOMEBREW_REPOSITORY.exist?
    sudo "rmdir", HOMEBREW_REPOSITORY.to_s
  end
end

unless options[:quiet]
  if @failed
    warn "Homebrew partially uninstalled (but there were steps that failed)!"
  else
    ohai "Homebrew uninstalled!"
  end
end

residual_files = []
residual_files.concat(HOMEBREW_REPOSITORY.children) if HOMEBREW_REPOSITORY.exist?
residual_files.concat(HOMEBREW_PREFIX.children) if HOMEBREW_PREFIX.exist?
residual_files.uniq!

unless residual_files.empty? || options[:quiet]
  puts "The following possible Homebrew files were not deleted:"
  residual_files.each(&:pretty_print)
  puts "You may wish to remove them yourself.\n"
end

exit 1 if @failed