From 775c4eedd7f6342ccfe7fe802a5935cb78ab050d Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Fri, 12 Feb 2016 13:25:37 +0000 Subject: Promote update-bash to the default updater. Also, rename the existing updater to `update-ruby` to allow using as a fallback. It will eventually be removed. Closes Homebrew/homebrew#49109. Signed-off-by: Mike McQuaid --- Library/Homebrew/cmd/update-bash.sh | 355 ------------------------ Library/Homebrew/cmd/update-ruby.rb | 492 ++++++++++++++++++++++++++++++++++ Library/Homebrew/cmd/update.rb | 492 ---------------------------------- Library/Homebrew/cmd/update.sh | 355 ++++++++++++++++++++++++ Library/Homebrew/test/test_updater.rb | 2 +- 5 files changed, 848 insertions(+), 848 deletions(-) delete mode 100644 Library/Homebrew/cmd/update-bash.sh create mode 100644 Library/Homebrew/cmd/update-ruby.rb delete mode 100644 Library/Homebrew/cmd/update.rb create mode 100644 Library/Homebrew/cmd/update.sh (limited to 'Library/Homebrew') diff --git a/Library/Homebrew/cmd/update-bash.sh b/Library/Homebrew/cmd/update-bash.sh deleted file mode 100644 index 4a0a2699c..000000000 --- a/Library/Homebrew/cmd/update-bash.sh +++ /dev/null @@ -1,355 +0,0 @@ -brew() { - "$HOMEBREW_BREW_FILE" "$@" -} - -git() { - [[ -n "$HOMEBREW_GIT" ]] || odie "HOMEBREW_GIT is unset!" - "$HOMEBREW_GIT" "$@" -} - -which_git() { - local git_path - local active_developer_dir - - if [[ -n "$HOMEBREW_GIT" ]] - then - git_path="$HOMEBREW_GIT" - elif [[ -n "$GIT" ]] - then - git_path="$GIT" - else - git_path="git" - fi - - git_path="$(which "$git_path" 2>/dev/null)" - - if [[ -n "$git_path" ]] - then - git_path="$(chdir "${git_path%/*}" && pwd -P)/${git_path##*/}" - fi - - if [[ -n "$HOMEBREW_OSX" && "$git_path" = "/usr/bin/git" ]] - then - active_developer_dir="$('/usr/bin/xcode-select' -print-path 2>/dev/null)" - if [[ -n "$active_developer_dir" && -x "$active_developer_dir/usr/bin/git" ]] - then - git_path="$active_developer_dir/usr/bin/git" - else - git_path="" - fi - fi - echo "$git_path" -} - -git_init_if_necessary() { - set -e - trap '{ rm -rf .git; exit 1; }' EXIT - - if [[ ! -d ".git" ]] - then - git init - git config --bool core.autocrlf false - git config remote.origin.url https://github.com/Homebrew/homebrew.git - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin - git reset --hard origin/master - SKIP_FETCH_HOMEBREW_REPOSITORY=1 - fi - - set +e - trap - EXIT - - if [[ "$(git remote show origin -n)" = *"mxcl/homebrew"* ]] - then - git remote set-url origin https://github.com/Homebrew/homebrew.git && - git remote set-url --delete origin ".*mxcl\/homebrew.*" - fi -} - -rename_taps_dir_if_necessary() { - local tap_dir - local tap_dir_basename - local user - local repo - - for tap_dir in "$HOMEBREW_LIBRARY"/Taps/* - do - [[ -d "$tap_dir/.git" ]] || continue - tap_dir_basename="${tap_dir##*/}" - if [[ "$tap_dir_basename" = *"-"* ]] - then - # only replace the *last* dash: yes, tap filenames suck - user="$(echo "${tap_dir_basename%-*}" | tr "[:upper:]" "[:lower:]")" - repo="$(echo "${tap_dir_basename:${#user}+1}" | tr "[:upper:]" "[:lower:]")" - mkdir -p "$HOMEBREW_LIBRARY/Taps/$user" - mv "$tap_dir", "$HOMEBREW_LIBRARY/Taps/$user/homebrew-$repo" - - if [[ ${#${tap_dir_basename//[^\-]}} -gt 1 ]] - then - echo "Homebrew changed the structure of Taps like /." >&2 - echo "So you may need to rename $HOMEBREW_LIBRARY/Taps/$user/homebrew-$repo manually." >&2 - fi - else - echo "Homebrew changed the structure of Taps like /. " >&2 - echo "$tap_dir is an incorrect Tap path." >&2 - echo "So you may need to rename it to $HOMEBREW_LIBRARY/Taps//homebrew- manually." >&2 - fi - done -} - -repo_var() { - local repo_var - - repo_var="$1" - if [[ "$repo_var" = "$HOMEBREW_REPOSITORY" ]] - then - repo_var="" - else - repo_var="${repo_var#"$HOMEBREW_LIBRARY/Taps"}" - repo_var="$(echo -n "$repo_var" | tr -C "A-Za-z0-9" "_" | tr "[:lower:]" "[:upper:]")" - fi - echo "$repo_var" -} - -upstream_branch() { - local upstream_branch - - upstream_branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null)" - upstream_branch="${upstream_branch#refs/remotes/origin/}" - [[ -z "$upstream_branch" ]] && upstream_branch="master" - echo "$upstream_branch" -} - -read_current_revision() { - git rev-parse -q --verify HEAD -} - -pop_stash() { - [[ -z "$STASHED" ]] && return - git stash pop "${QUIET_ARGS[@]}" - if [[ -n "$HOMEBREW_VERBOSE" ]] - then - echo "Restoring your stashed changes to $DIR:" - git status --short --untracked-files - fi - unset STASHED -} - -pop_stash_message() { - [[ -z "$STASHED" ]] && return - echo "To restore the stashed changes to $DIR run:" - echo " 'cd $DIR && git stash pop'" - unset STASHED -} - -reset_on_interrupt() { - if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] - then - git checkout "$INITIAL_BRANCH" - fi - - if [[ -n "$INITIAL_REVISION" ]] - then - git reset --hard "$INITIAL_REVISION" "${QUIET_ARGS[@]}" - fi - - if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] - then - pop_stash - else - pop_stash_message - fi - - exit 130 -} - -pull() { - local DIR - local TAP_VAR - - DIR="$1" - cd "$DIR" || return - TAP_VAR=$(repo_var "$DIR") - unset STASHED - - # The upstream repository's default branch may not be master; - # check refs/remotes/origin/HEAD to see what the default - # origin branch name is, and use that. If not set, fall back to "master". - INITIAL_BRANCH="$(git symbolic-ref --short HEAD 2>/dev/null)" - UPSTREAM_BRANCH="$(upstream_branch)" - - # Used for testing purposes, e.g., for testing formula migration after - # renaming it in the currently checked-out branch. To test run - # "brew update --simulate-from-current-branch" - if [[ -n "$HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH" ]] - then - INITIAL_REVISION="$(git rev-parse -q --verify "$UPSTREAM_BRANCH")" - CURRENT_REVISION="$(read_current_revision)" - export HOMEBREW_UPDATE_BEFORE"$TAP_VAR"="$INITIAL_REVISION" - export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$CURRENT_REVISION" - if ! git merge-base --is-ancestor "$INITIAL_REVISION" "$CURRENT_REVISION" - then - odie "Your $DIR HEAD is not a descendant of $UPSTREAM_BRANCH!" - fi - return - fi - - trap reset_on_interrupt SIGINT - - if [[ -n "$(git status --untracked-files=all --porcelain 2>/dev/null)" ]] - then - if [[ -n "$HOMEBREW_VERBOSE" ]] - then - echo "Stashing uncommitted changes to $DIR." - git status --short --untracked-files=all - fi - git -c "user.email=brew-update@localhost" \ - -c "user.name=brew update" \ - stash save --include-untracked "${QUIET_ARGS[@]}" - git reset --hard "${QUIET_ARGS[@]}" - STASHED="1" - fi - - if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] - then - # Recreate and check out `#{upstream_branch}` if unable to fast-forward - # it to `origin/#{@upstream_branch}`. Otherwise, just check it out. - if git merge-base --is-ancestor "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" &>/dev/null - then - git checkout --force "$UPSTREAM_BRANCH" "${QUIET_ARGS[@]}" - else - git checkout --force -B "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" "${QUIET_ARGS[@]}" - fi - fi - - INITIAL_REVISION="$(read_current_revision)" - export HOMEBREW_UPDATE_BEFORE"$TAP_VAR"="$INITIAL_REVISION" - - # ensure we don't munge line endings on checkout - git config core.autocrlf false - - if [[ -n "$HOMEBREW_REBASE" ]] - then - git rebase "${QUIET_ARGS[@]}" "origin/$UPSTREAM_BRANCH" - else - git merge --no-edit --ff "${QUIET_ARGS[@]}" "origin/$UPSTREAM_BRANCH" - fi - - export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$(read_current_revision)" - - trap '' SIGINT - - if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] - then - git checkout "$INITIAL_BRANCH" "${QUIET_ARGS[@]}" - pop_stash - else - pop_stash_message - fi - - trap - SIGINT -} - -homebrew-update-bash() { - local option - local DIR - local UPSTREAM_BRANCH - - for option in "$@" - do - case "$option" in - --help) brew update --help; exit $? ;; - --verbose) HOMEBREW_VERBOSE=1 ;; - --debug) HOMEBREW_DEBUG=1;; - --rebase) HOMEBREW_REBASE=1 ;; - --simulate-from-current-branch) HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH=1 ;; - --*) ;; - -*) - [[ "$option" = *v* ]] && HOMEBREW_VERBOSE=1; - [[ "$option" = *d* ]] && HOMEBREW_DEBUG=1; - ;; - *) - odie <<-EOS -This command updates brew itself, and does not take formula names. -Use 'brew upgrade '. -EOS - ;; - esac - done - - if [[ -n "$HOMEBREW_DEBUG" ]] - then - set -x - fi - - # check permissions - if [[ "$HOMEBREW_PREFIX" = "/usr/local" && ! -w /usr/local ]] - then - odie "/usr/local must be writable!" - fi - - if [[ ! -w "$HOMEBREW_REPOSITORY" ]] - then - odie "$HOMEBREW_REPOSITORY must be writable!" - fi - - HOMEBREW_GIT="$(which_git)" - if [[ -z "$HOMEBREW_GIT" ]] - then - brew install git - HOMEBREW_GIT="$(which_git)" - if [[ -z "$HOMEBREW_GIT" ]] - then - odie "Git must be installed and in your PATH!" - fi - fi - export GIT_TERMINAL_PROMPT="0" - export GIT_ASKPASS="false" - export GIT_SSH_COMMAND="ssh -oBatchMode=yes" - - if [[ -z "$HOMEBREW_VERBOSE" ]] - then - QUIET_ARGS=(-q) - else - QUIET_ARGS=() - fi - - # ensure GIT_CONFIG is unset as we need to operate on .git/config - unset GIT_CONFIG - - chdir "$HOMEBREW_REPOSITORY" - git_init_if_necessary - # rename Taps directories - # this procedure will be removed in the future if it seems unnecessary - rename_taps_dir_if_necessary - - # kill all of subprocess on interrupt - trap '{ pkill -P $$; wait; exit 130; }' SIGINT - - for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/* - do - [[ -d "$DIR/.git" ]] || continue - [[ -n "$SKIP_FETCH_HOMEBREW_REPOSITORY" && "$DIR" = "$HOMEBREW_REPOSITORY" ]] && continue - cd "$DIR" || continue - UPSTREAM_BRANCH="$(upstream_branch)" - # the refspec ensures that the default upstream branch gets updated - ( - git fetch "${QUIET_ARGS[@]}" origin \ - "refs/heads/$UPSTREAM_BRANCH:refs/remotes/origin/$UPSTREAM_BRANCH" || \ - odie "Fetching $DIR failed!" - ) & - done - - wait - trap - SIGINT - - for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/* - do - [[ -d "$DIR/.git" ]] || continue - pull "$DIR" - done - - chdir "$HOMEBREW_REPOSITORY" - brew update-report "$@" - return $? -} diff --git a/Library/Homebrew/cmd/update-ruby.rb b/Library/Homebrew/cmd/update-ruby.rb new file mode 100644 index 000000000..98294bca8 --- /dev/null +++ b/Library/Homebrew/cmd/update-ruby.rb @@ -0,0 +1,492 @@ +require "cmd/tap" +require "diagnostic" +require "formula_versions" +require "migrator" +require "formulary" +require "descriptions" + +module Homebrew + def update_ruby + unless ARGV.named.empty? + abort <<-EOS.undent + This command updates brew itself, and does not take formula names. + Use `brew upgrade `. + EOS + end + + # check permissions + checks = Diagnostic::Checks.new + %w[ + check_access_usr_local + check_access_homebrew_repository + ].each do |check| + out = checks.send(check) + odie out unless out.nil? + end + + # ensure git is installed + Utils.ensure_git_installed! + + # ensure GIT_CONFIG is unset as we need to operate on .git/config + ENV.delete("GIT_CONFIG") + + cd HOMEBREW_REPOSITORY + git_init_if_necessary + + # migrate to new directories based tap structure + migrate_taps + + report = Report.new + master_updater = Updater.new(HOMEBREW_REPOSITORY) + master_updater.pull! + master_updated = master_updater.updated? + if master_updated + initial_short = shorten_revision(master_updater.initial_revision) + current_short = shorten_revision(master_updater.current_revision) + puts "Updated Homebrew from #{initial_short} to #{current_short}." + end + report.update(master_updater.report) + + # rename Taps directories + # this procedure will be removed in the future if it seems unnecessasry + rename_taps_dir_if_necessary + + updated_taps = [] + Tap.each do |tap| + next unless tap.git? + + tap.path.cd do + updater = Updater.new(tap.path) + + begin + updater.pull! + rescue + onoe "Failed to update tap: #{tap}" + else + updated_taps << tap.name if updater.updated? + report.update(updater.report) do |_key, oldval, newval| + oldval.concat(newval) + end + end + end + end + unless updated_taps.empty? + puts "Updated #{updated_taps.size} tap#{plural(updated_taps.size)} " \ + "(#{updated_taps.join(", ")})." + end + puts "Already up-to-date." unless master_updated || !updated_taps.empty? + + Tap.clear_cache + Tap.each(&:link_manpages) + + # automatically tap any migrated formulae's new tap + report.select_formula(:D).each do |f| + next unless (dir = HOMEBREW_CELLAR/f).exist? + migration = TAP_MIGRATIONS[f] + next unless migration + tap = Tap.fetch(*migration.split("/")) + tap.install unless tap.installed? + + # update tap for each Tab + tabs = dir.subdirs.map { |d| Tab.for_keg(Keg.new(d)) } + next if tabs.first.source["tap"] != "Homebrew/homebrew" + tabs.each { |tab| tab.source["tap"] = "#{tap.user}/homebrew-#{tap.repo}" } + tabs.each(&:write) + end if load_tap_migrations + + load_formula_renames + report.update_renamed + + # Migrate installed renamed formulae from core and taps. + report.select_formula(:R).each do |oldname, newname| + if oldname.include?("/") + user, repo, oldname = oldname.split("/", 3) + newname = newname.split("/", 3).last + else + user = "homebrew" + repo = "homebrew" + end + + next unless (dir = HOMEBREW_CELLAR/oldname).directory? && !dir.subdirs.empty? + + begin + f = Formulary.factory("#{user}/#{repo}/#{newname}") + # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616 + rescue Exception + end + + next unless f + + begin + migrator = Migrator.new(f) + migrator.migrate + rescue Migrator::MigratorDifferentTapsError + end + end + + if report.empty? + puts "No changes to formulae." if master_updated || !updated_taps.empty? + else + report.dump + end + Descriptions.update_cache(report) + end + + private + + def shorten_revision(revision) + `git rev-parse --short #{revision}`.chomp + end + + def git_init_if_necessary + if Dir[".git/*"].empty? + safe_system "git", "init" + safe_system "git", "config", "core.autocrlf", "false" + safe_system "git", "config", "remote.origin.url", "https://github.com/Homebrew/homebrew.git" + safe_system "git", "config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*" + safe_system "git", "fetch", "origin" + safe_system "git", "reset", "--hard", "origin/master" + end + + if `git remote show origin -n` =~ /Fetch URL: \S+mxcl\/homebrew/ + safe_system "git", "remote", "set-url", "origin", "https://github.com/Homebrew/homebrew.git" + safe_system "git", "remote", "set-url", "--delete", "origin", ".*mxcl\/homebrew.*" + end + rescue Exception + FileUtils.rm_rf ".git" + raise + end + + def rename_taps_dir_if_necessary + Dir.glob("#{HOMEBREW_LIBRARY}/Taps/*/") do |tapd| + begin + if File.directory?(tapd + "/.git") + tapd_basename = File.basename(tapd) + if tapd_basename.include?("-") + # only replace the *last* dash: yes, tap filenames suck + user, repo = tapd_basename.reverse.sub("-", "/").reverse.split("/") + + FileUtils.mkdir_p("#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}") + FileUtils.mv(tapd, "#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase}") + + if tapd_basename.count("-") >= 2 + opoo "Homebrew changed the structure of Taps like /. "\ + + "So you may need to rename #{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase} manually." + end + else + opoo "Homebrew changed the structure of Taps like /. "\ + "#{tapd} is incorrect name format. You may need to rename it like / manually." + end + end + rescue => ex + onoe ex.message + next # next tap directory + end + end + end + + def load_tap_migrations + load "tap_migrations.rb" + rescue LoadError + false + end + + def load_formula_renames + load "formula_renames.rb" + rescue LoadError + false + end +end + +class Updater + attr_reader :initial_revision, :current_revision, :repository + + def initialize(repository) + @repository = repository + @stashed = false + @quiet_args = [] + @quiet_args << "--quiet" unless ARGV.verbose? + end + + def pull!(options = {}) + # The upstream repository's default branch may not be master; + # check refs/remotes/origin/HEAD to see what the default + # origin branch name is, and use that. If not set, fall back to "master". + begin + @upstream_branch = `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null` + @upstream_branch = @upstream_branch.chomp.sub('refs/remotes/origin/', '') + rescue ErrorDuringExecution + @upstream_branch = "master" + end + + begin + @initial_branch = `git symbolic-ref --short HEAD 2>/dev/null`.chomp + rescue ErrorDuringExecution + @initial_branch = "" + end + + unless `git status --untracked-files=all --porcelain 2>/dev/null`.chomp.empty? + if ARGV.verbose? + puts "Stashing uncommitted changes to #{repository}." + system "git", "status", "--short", "--untracked-files=all" + end + safe_system "git", "-c", "user.email=brew-update@localhost", + "-c", "user.name=brew update", + "stash", "save", "--include-untracked", *@quiet_args + safe_system "git", "reset", "--hard", *@quiet_args + @stashed = true + end + + # Used for testing purposes, e.g., for testing formula migration after + # renaming it in the currently checked-out branch. To test run + # "brew update --simulate-from-current-branch" + if ARGV.include?("--simulate-from-current-branch") + @initial_revision = `git rev-parse -q --verify #{@upstream_branch}`.chomp + @current_revision = read_current_revision + begin + safe_system "git", "merge-base", "--is-ancestor", @initial_revision, @current_revision + rescue ErrorDuringExecution + odie "Your HEAD is not a descendant of '#{@upstream_branch}'." + end + return + end + + if @initial_branch != @upstream_branch && !@initial_branch.empty? + # Recreate and check out `#{upstream_branch}` if unable to fast-forward + # it to `origin/#{@upstream_branch}`. Otherwise, just check it out. + if system("git", "merge-base", "--is-ancestor", @upstream_branch, "origin/#{@upstream_branch}") + safe_system "git", "checkout", "--force", @upstream_branch, *@quiet_args + else + safe_system "git", "checkout", "--force", "-B", @upstream_branch, "origin/#{@upstream_branch}", *@quiet_args + end + end + + @initial_revision = read_current_revision + + # ensure we don't munge line endings on checkout + safe_system "git", "config", "core.autocrlf", "false" + + args = ["pull"] + args << "--ff" + args << ((ARGV.include? "--rebase") ? "--rebase" : "--no-rebase") + args += @quiet_args + args << "origin" + # the refspec ensures that the default upstream branch gets updated + args << "refs/heads/#{@upstream_branch}:refs/remotes/origin/#{@upstream_branch}" + + reset_on_interrupt { safe_system "git", *args } + + @current_revision = read_current_revision + + if @initial_branch != @upstream_branch && !@initial_branch.empty? + safe_system "git", "checkout", @initial_branch, *@quiet_args + pop_stash + else + pop_stash_message + end + end + + def pop_stash + return unless @stashed + safe_system "git", "stash", "pop", *@quiet_args + if ARGV.verbose? + puts "Restoring your stashed changes to #{repository}:" + system "git", "status", "--short", "--untracked-files" + end + @stashed = false + end + + def pop_stash_message + return unless @stashed + puts "To restore the stashed changes to #{repository} run:" + puts " `cd #{repository} && git stash pop`" + @stashed = false + end + + def reset_on_interrupt + ignore_interrupts { yield } + ensure + if $?.signaled? && $?.termsig == 2 # SIGINT + safe_system "git", "checkout", @initial_branch unless @initial_branch.empty? + safe_system "git", "reset", "--hard", @initial_revision, *@quiet_args + if @initial_branch + pop_stash + else + pop_stash_message + end + end + end + + def report + map = Hash.new { |h, k| h[k] = [] } + + if initial_revision && initial_revision != current_revision + wc_revision = read_current_revision + + diff.each_line do |line| + status, *paths = line.split + src = paths.first + dst = paths.last + + next unless File.extname(dst) == ".rb" + next unless paths.any? { |p| File.dirname(p) == formula_directory } + + case status + when "A", "D" + map[status.to_sym] << repository.join(src) + when "M" + file = repository.join(src) + begin + formula = Formulary.factory(file) + new_version = if wc_revision == current_revision + formula.pkg_version + else + FormulaVersions.new(formula).formula_at_revision(@current_revision, &:pkg_version) + end + old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version) + next if new_version == old_version + # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616 + rescue Exception => e + onoe e if ARGV.homebrew_developer? + end + map[:M] << file + when /^R\d{0,3}/ + map[:D] << repository.join(src) if File.dirname(src) == formula_directory + map[:A] << repository.join(dst) if File.dirname(dst) == formula_directory + end + end + end + + map + end + + def updated? + initial_revision && initial_revision != current_revision + end + + private + + def formula_directory + if repository == HOMEBREW_REPOSITORY + "Library/Formula" + elsif repository.join("Formula").directory? + "Formula" + elsif repository.join("HomebrewFormula").directory? + "HomebrewFormula" + else + "." + end + end + + def read_current_revision + `git rev-parse -q --verify HEAD`.chomp + end + + def diff + Utils.popen_read( + "git", "diff-tree", "-r", "--name-status", "--diff-filter=AMDR", + "-M85%", initial_revision, current_revision + ) + end + + def `(cmd) + out = super + unless $?.success? + $stderr.puts(out) unless out.empty? + raise ErrorDuringExecution.new(cmd) + end + ohai(cmd, out) if ARGV.verbose? + out + end +end + +class Report + def initialize + @hash = {} + end + + def fetch(*args, &block) + @hash.fetch(*args, &block) + end + + def update(*args, &block) + @hash.update(*args, &block) + end + + def empty? + @hash.empty? + end + + def dump + # Key Legend: Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R) + + dump_formula_report :A, "New Formulae" + dump_formula_report :M, "Updated Formulae" + dump_formula_report :R, "Renamed Formulae" + dump_formula_report :D, "Deleted Formulae" + end + + def update_renamed + renamed_formulae = [] + + fetch(:D, []).each do |path| + case path.to_s + when HOMEBREW_TAP_PATH_REGEX + oldname = path.basename(".rb").to_s + next unless newname = Tap.fetch($1, $2).formula_renames[oldname] + else + oldname = path.basename(".rb").to_s + next unless newname = CoreFormulaRepository.instance.formula_renames[oldname] + end + + if fetch(:A, []).include?(newpath = path.dirname.join("#{newname}.rb")) + renamed_formulae << [path, newpath] + end + end + + unless renamed_formulae.empty? + @hash[:A] -= renamed_formulae.map(&:last) if @hash[:A] + @hash[:D] -= renamed_formulae.map(&:first) if @hash[:D] + @hash[:R] = renamed_formulae + end + end + + def select_formula(key) + fetch(key, []).map do |path, newpath| + if path.to_s =~ HOMEBREW_TAP_PATH_REGEX + tap = Tap.fetch($1, $2) + if newpath + ["#{tap}/#{path.basename(".rb")}", "#{tap}/#{newpath.basename(".rb")}"] + else + "#{tap}/#{path.basename(".rb")}" + end + elsif newpath + ["#{path.basename(".rb")}", "#{newpath.basename(".rb")}"] + else + path.basename(".rb").to_s + end + end.sort + end + + def dump_formula_report(key, title) + formula = select_formula(key).map do |name, new_name| + # Format list items of renamed formulae + if key == :R + new_name = pretty_installed(new_name) if installed?(name) + "#{name} -> #{new_name}" + else + installed?(name) ? pretty_installed(name) : name + end + end + + unless formula.empty? + # Dump formula list. + ohai title + puts_columns(formula) + end + end + + def installed?(formula) + (HOMEBREW_CELLAR/formula.split("/").last).directory? + end +end diff --git a/Library/Homebrew/cmd/update.rb b/Library/Homebrew/cmd/update.rb deleted file mode 100644 index f93224c8d..000000000 --- a/Library/Homebrew/cmd/update.rb +++ /dev/null @@ -1,492 +0,0 @@ -require "cmd/tap" -require "diagnostic" -require "formula_versions" -require "migrator" -require "formulary" -require "descriptions" - -module Homebrew - def update - unless ARGV.named.empty? - abort <<-EOS.undent - This command updates brew itself, and does not take formula names. - Use `brew upgrade `. - EOS - end - - # check permissions - checks = Diagnostic::Checks.new - %w[ - check_access_usr_local - check_access_homebrew_repository - ].each do |check| - out = checks.send(check) - odie out unless out.nil? - end - - # ensure git is installed - Utils.ensure_git_installed! - - # ensure GIT_CONFIG is unset as we need to operate on .git/config - ENV.delete("GIT_CONFIG") - - cd HOMEBREW_REPOSITORY - git_init_if_necessary - - # migrate to new directories based tap structure - migrate_taps - - report = Report.new - master_updater = Updater.new(HOMEBREW_REPOSITORY) - master_updater.pull! - master_updated = master_updater.updated? - if master_updated - initial_short = shorten_revision(master_updater.initial_revision) - current_short = shorten_revision(master_updater.current_revision) - puts "Updated Homebrew from #{initial_short} to #{current_short}." - end - report.update(master_updater.report) - - # rename Taps directories - # this procedure will be removed in the future if it seems unnecessasry - rename_taps_dir_if_necessary - - updated_taps = [] - Tap.each do |tap| - next unless tap.git? - - tap.path.cd do - updater = Updater.new(tap.path) - - begin - updater.pull! - rescue - onoe "Failed to update tap: #{tap}" - else - updated_taps << tap.name if updater.updated? - report.update(updater.report) do |_key, oldval, newval| - oldval.concat(newval) - end - end - end - end - unless updated_taps.empty? - puts "Updated #{updated_taps.size} tap#{plural(updated_taps.size)} " \ - "(#{updated_taps.join(", ")})." - end - puts "Already up-to-date." unless master_updated || !updated_taps.empty? - - Tap.clear_cache - Tap.each(&:link_manpages) - - # automatically tap any migrated formulae's new tap - report.select_formula(:D).each do |f| - next unless (dir = HOMEBREW_CELLAR/f).exist? - migration = TAP_MIGRATIONS[f] - next unless migration - tap = Tap.fetch(*migration.split("/")) - tap.install unless tap.installed? - - # update tap for each Tab - tabs = dir.subdirs.map { |d| Tab.for_keg(Keg.new(d)) } - next if tabs.first.source["tap"] != "Homebrew/homebrew" - tabs.each { |tab| tab.source["tap"] = "#{tap.user}/homebrew-#{tap.repo}" } - tabs.each(&:write) - end if load_tap_migrations - - load_formula_renames - report.update_renamed - - # Migrate installed renamed formulae from core and taps. - report.select_formula(:R).each do |oldname, newname| - if oldname.include?("/") - user, repo, oldname = oldname.split("/", 3) - newname = newname.split("/", 3).last - else - user = "homebrew" - repo = "homebrew" - end - - next unless (dir = HOMEBREW_CELLAR/oldname).directory? && !dir.subdirs.empty? - - begin - f = Formulary.factory("#{user}/#{repo}/#{newname}") - # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616 - rescue Exception - end - - next unless f - - begin - migrator = Migrator.new(f) - migrator.migrate - rescue Migrator::MigratorDifferentTapsError - end - end - - if report.empty? - puts "No changes to formulae." if master_updated || !updated_taps.empty? - else - report.dump - end - Descriptions.update_cache(report) - end - - private - - def shorten_revision(revision) - `git rev-parse --short #{revision}`.chomp - end - - def git_init_if_necessary - if Dir[".git/*"].empty? - safe_system "git", "init" - safe_system "git", "config", "core.autocrlf", "false" - safe_system "git", "config", "remote.origin.url", "https://github.com/Homebrew/homebrew.git" - safe_system "git", "config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*" - safe_system "git", "fetch", "origin" - safe_system "git", "reset", "--hard", "origin/master" - end - - if `git remote show origin -n` =~ /Fetch URL: \S+mxcl\/homebrew/ - safe_system "git", "remote", "set-url", "origin", "https://github.com/Homebrew/homebrew.git" - safe_system "git", "remote", "set-url", "--delete", "origin", ".*mxcl\/homebrew.*" - end - rescue Exception - FileUtils.rm_rf ".git" - raise - end - - def rename_taps_dir_if_necessary - Dir.glob("#{HOMEBREW_LIBRARY}/Taps/*/") do |tapd| - begin - if File.directory?(tapd + "/.git") - tapd_basename = File.basename(tapd) - if tapd_basename.include?("-") - # only replace the *last* dash: yes, tap filenames suck - user, repo = tapd_basename.reverse.sub("-", "/").reverse.split("/") - - FileUtils.mkdir_p("#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}") - FileUtils.mv(tapd, "#{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase}") - - if tapd_basename.count("-") >= 2 - opoo "Homebrew changed the structure of Taps like /. "\ - + "So you may need to rename #{HOMEBREW_LIBRARY}/Taps/#{user.downcase}/homebrew-#{repo.downcase} manually." - end - else - opoo "Homebrew changed the structure of Taps like /. "\ - "#{tapd} is incorrect name format. You may need to rename it like / manually." - end - end - rescue => ex - onoe ex.message - next # next tap directory - end - end - end - - def load_tap_migrations - load "tap_migrations.rb" - rescue LoadError - false - end - - def load_formula_renames - load "formula_renames.rb" - rescue LoadError - false - end -end - -class Updater - attr_reader :initial_revision, :current_revision, :repository - - def initialize(repository) - @repository = repository - @stashed = false - @quiet_args = [] - @quiet_args << "--quiet" unless ARGV.verbose? - end - - def pull!(options = {}) - # The upstream repository's default branch may not be master; - # check refs/remotes/origin/HEAD to see what the default - # origin branch name is, and use that. If not set, fall back to "master". - begin - @upstream_branch = `git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null` - @upstream_branch = @upstream_branch.chomp.sub('refs/remotes/origin/', '') - rescue ErrorDuringExecution - @upstream_branch = "master" - end - - begin - @initial_branch = `git symbolic-ref --short HEAD 2>/dev/null`.chomp - rescue ErrorDuringExecution - @initial_branch = "" - end - - unless `git status --untracked-files=all --porcelain 2>/dev/null`.chomp.empty? - if ARGV.verbose? - puts "Stashing uncommitted changes to #{repository}." - system "git", "status", "--short", "--untracked-files=all" - end - safe_system "git", "-c", "user.email=brew-update@localhost", - "-c", "user.name=brew update", - "stash", "save", "--include-untracked", *@quiet_args - safe_system "git", "reset", "--hard", *@quiet_args - @stashed = true - end - - # Used for testing purposes, e.g., for testing formula migration after - # renaming it in the currently checked-out branch. To test run - # "brew update --simulate-from-current-branch" - if ARGV.include?("--simulate-from-current-branch") - @initial_revision = `git rev-parse -q --verify #{@upstream_branch}`.chomp - @current_revision = read_current_revision - begin - safe_system "git", "merge-base", "--is-ancestor", @initial_revision, @current_revision - rescue ErrorDuringExecution - odie "Your HEAD is not a descendant of '#{@upstream_branch}'." - end - return - end - - if @initial_branch != @upstream_branch && !@initial_branch.empty? - # Recreate and check out `#{upstream_branch}` if unable to fast-forward - # it to `origin/#{@upstream_branch}`. Otherwise, just check it out. - if system("git", "merge-base", "--is-ancestor", @upstream_branch, "origin/#{@upstream_branch}") - safe_system "git", "checkout", "--force", @upstream_branch, *@quiet_args - else - safe_system "git", "checkout", "--force", "-B", @upstream_branch, "origin/#{@upstream_branch}", *@quiet_args - end - end - - @initial_revision = read_current_revision - - # ensure we don't munge line endings on checkout - safe_system "git", "config", "core.autocrlf", "false" - - args = ["pull"] - args << "--ff" - args << ((ARGV.include? "--rebase") ? "--rebase" : "--no-rebase") - args += @quiet_args - args << "origin" - # the refspec ensures that the default upstream branch gets updated - args << "refs/heads/#{@upstream_branch}:refs/remotes/origin/#{@upstream_branch}" - - reset_on_interrupt { safe_system "git", *args } - - @current_revision = read_current_revision - - if @initial_branch != @upstream_branch && !@initial_branch.empty? - safe_system "git", "checkout", @initial_branch, *@quiet_args - pop_stash - else - pop_stash_message - end - end - - def pop_stash - return unless @stashed - safe_system "git", "stash", "pop", *@quiet_args - if ARGV.verbose? - puts "Restoring your stashed changes to #{repository}:" - system "git", "status", "--short", "--untracked-files" - end - @stashed = false - end - - def pop_stash_message - return unless @stashed - puts "To restore the stashed changes to #{repository} run:" - puts " `cd #{repository} && git stash pop`" - @stashed = false - end - - def reset_on_interrupt - ignore_interrupts { yield } - ensure - if $?.signaled? && $?.termsig == 2 # SIGINT - safe_system "git", "checkout", @initial_branch unless @initial_branch.empty? - safe_system "git", "reset", "--hard", @initial_revision, *@quiet_args - if @initial_branch - pop_stash - else - pop_stash_message - end - end - end - - def report - map = Hash.new { |h, k| h[k] = [] } - - if initial_revision && initial_revision != current_revision - wc_revision = read_current_revision - - diff.each_line do |line| - status, *paths = line.split - src = paths.first - dst = paths.last - - next unless File.extname(dst) == ".rb" - next unless paths.any? { |p| File.dirname(p) == formula_directory } - - case status - when "A", "D" - map[status.to_sym] << repository.join(src) - when "M" - file = repository.join(src) - begin - formula = Formulary.factory(file) - new_version = if wc_revision == current_revision - formula.pkg_version - else - FormulaVersions.new(formula).formula_at_revision(@current_revision, &:pkg_version) - end - old_version = FormulaVersions.new(formula).formula_at_revision(@initial_revision, &:pkg_version) - next if new_version == old_version - # short term fix to prevent situation like https://github.com/Homebrew/homebrew/issues/45616 - rescue Exception => e - onoe e if ARGV.homebrew_developer? - end - map[:M] << file - when /^R\d{0,3}/ - map[:D] << repository.join(src) if File.dirname(src) == formula_directory - map[:A] << repository.join(dst) if File.dirname(dst) == formula_directory - end - end - end - - map - end - - def updated? - initial_revision && initial_revision != current_revision - end - - private - - def formula_directory - if repository == HOMEBREW_REPOSITORY - "Library/Formula" - elsif repository.join("Formula").directory? - "Formula" - elsif repository.join("HomebrewFormula").directory? - "HomebrewFormula" - else - "." - end - end - - def read_current_revision - `git rev-parse -q --verify HEAD`.chomp - end - - def diff - Utils.popen_read( - "git", "diff-tree", "-r", "--name-status", "--diff-filter=AMDR", - "-M85%", initial_revision, current_revision - ) - end - - def `(cmd) - out = super - unless $?.success? - $stderr.puts(out) unless out.empty? - raise ErrorDuringExecution.new(cmd) - end - ohai(cmd, out) if ARGV.verbose? - out - end -end - -class Report - def initialize - @hash = {} - end - - def fetch(*args, &block) - @hash.fetch(*args, &block) - end - - def update(*args, &block) - @hash.update(*args, &block) - end - - def empty? - @hash.empty? - end - - def dump - # Key Legend: Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R) - - dump_formula_report :A, "New Formulae" - dump_formula_report :M, "Updated Formulae" - dump_formula_report :R, "Renamed Formulae" - dump_formula_report :D, "Deleted Formulae" - end - - def update_renamed - renamed_formulae = [] - - fetch(:D, []).each do |path| - case path.to_s - when HOMEBREW_TAP_PATH_REGEX - oldname = path.basename(".rb").to_s - next unless newname = Tap.fetch($1, $2).formula_renames[oldname] - else - oldname = path.basename(".rb").to_s - next unless newname = CoreFormulaRepository.instance.formula_renames[oldname] - end - - if fetch(:A, []).include?(newpath = path.dirname.join("#{newname}.rb")) - renamed_formulae << [path, newpath] - end - end - - unless renamed_formulae.empty? - @hash[:A] -= renamed_formulae.map(&:last) if @hash[:A] - @hash[:D] -= renamed_formulae.map(&:first) if @hash[:D] - @hash[:R] = renamed_formulae - end - end - - def select_formula(key) - fetch(key, []).map do |path, newpath| - if path.to_s =~ HOMEBREW_TAP_PATH_REGEX - tap = Tap.fetch($1, $2) - if newpath - ["#{tap}/#{path.basename(".rb")}", "#{tap}/#{newpath.basename(".rb")}"] - else - "#{tap}/#{path.basename(".rb")}" - end - elsif newpath - ["#{path.basename(".rb")}", "#{newpath.basename(".rb")}"] - else - path.basename(".rb").to_s - end - end.sort - end - - def dump_formula_report(key, title) - formula = select_formula(key).map do |name, new_name| - # Format list items of renamed formulae - if key == :R - new_name = pretty_installed(new_name) if installed?(name) - "#{name} -> #{new_name}" - else - installed?(name) ? pretty_installed(name) : name - end - end - - unless formula.empty? - # Dump formula list. - ohai title - puts_columns(formula) - end - end - - def installed?(formula) - (HOMEBREW_CELLAR/formula.split("/").last).directory? - end -end diff --git a/Library/Homebrew/cmd/update.sh b/Library/Homebrew/cmd/update.sh new file mode 100644 index 000000000..d9226cfb9 --- /dev/null +++ b/Library/Homebrew/cmd/update.sh @@ -0,0 +1,355 @@ +brew() { + "$HOMEBREW_BREW_FILE" "$@" +} + +git() { + [[ -n "$HOMEBREW_GIT" ]] || odie "HOMEBREW_GIT is unset!" + "$HOMEBREW_GIT" "$@" +} + +which_git() { + local git_path + local active_developer_dir + + if [[ -n "$HOMEBREW_GIT" ]] + then + git_path="$HOMEBREW_GIT" + elif [[ -n "$GIT" ]] + then + git_path="$GIT" + else + git_path="git" + fi + + git_path="$(which "$git_path" 2>/dev/null)" + + if [[ -n "$git_path" ]] + then + git_path="$(chdir "${git_path%/*}" && pwd -P)/${git_path##*/}" + fi + + if [[ -n "$HOMEBREW_OSX" && "$git_path" = "/usr/bin/git" ]] + then + active_developer_dir="$('/usr/bin/xcode-select' -print-path 2>/dev/null)" + if [[ -n "$active_developer_dir" && -x "$active_developer_dir/usr/bin/git" ]] + then + git_path="$active_developer_dir/usr/bin/git" + else + git_path="" + fi + fi + echo "$git_path" +} + +git_init_if_necessary() { + set -e + trap '{ rm -rf .git; exit 1; }' EXIT + + if [[ ! -d ".git" ]] + then + git init + git config --bool core.autocrlf false + git config remote.origin.url https://github.com/Homebrew/homebrew.git + git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" + git fetch origin + git reset --hard origin/master + SKIP_FETCH_HOMEBREW_REPOSITORY=1 + fi + + set +e + trap - EXIT + + if [[ "$(git remote show origin -n)" = *"mxcl/homebrew"* ]] + then + git remote set-url origin https://github.com/Homebrew/homebrew.git && + git remote set-url --delete origin ".*mxcl\/homebrew.*" + fi +} + +rename_taps_dir_if_necessary() { + local tap_dir + local tap_dir_basename + local user + local repo + + for tap_dir in "$HOMEBREW_LIBRARY"/Taps/* + do + [[ -d "$tap_dir/.git" ]] || continue + tap_dir_basename="${tap_dir##*/}" + if [[ "$tap_dir_basename" = *"-"* ]] + then + # only replace the *last* dash: yes, tap filenames suck + user="$(echo "${tap_dir_basename%-*}" | tr "[:upper:]" "[:lower:]")" + repo="$(echo "${tap_dir_basename:${#user}+1}" | tr "[:upper:]" "[:lower:]")" + mkdir -p "$HOMEBREW_LIBRARY/Taps/$user" + mv "$tap_dir", "$HOMEBREW_LIBRARY/Taps/$user/homebrew-$repo" + + if [[ ${#${tap_dir_basename//[^\-]}} -gt 1 ]] + then + echo "Homebrew changed the structure of Taps like /." >&2 + echo "So you may need to rename $HOMEBREW_LIBRARY/Taps/$user/homebrew-$repo manually." >&2 + fi + else + echo "Homebrew changed the structure of Taps like /. " >&2 + echo "$tap_dir is an incorrect Tap path." >&2 + echo "So you may need to rename it to $HOMEBREW_LIBRARY/Taps//homebrew- manually." >&2 + fi + done +} + +repo_var() { + local repo_var + + repo_var="$1" + if [[ "$repo_var" = "$HOMEBREW_REPOSITORY" ]] + then + repo_var="" + else + repo_var="${repo_var#"$HOMEBREW_LIBRARY/Taps"}" + repo_var="$(echo -n "$repo_var" | tr -C "A-Za-z0-9" "_" | tr "[:lower:]" "[:upper:]")" + fi + echo "$repo_var" +} + +upstream_branch() { + local upstream_branch + + upstream_branch="$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null)" + upstream_branch="${upstream_branch#refs/remotes/origin/}" + [[ -z "$upstream_branch" ]] && upstream_branch="master" + echo "$upstream_branch" +} + +read_current_revision() { + git rev-parse -q --verify HEAD +} + +pop_stash() { + [[ -z "$STASHED" ]] && return + git stash pop "${QUIET_ARGS[@]}" + if [[ -n "$HOMEBREW_VERBOSE" ]] + then + echo "Restoring your stashed changes to $DIR:" + git status --short --untracked-files + fi + unset STASHED +} + +pop_stash_message() { + [[ -z "$STASHED" ]] && return + echo "To restore the stashed changes to $DIR run:" + echo " 'cd $DIR && git stash pop'" + unset STASHED +} + +reset_on_interrupt() { + if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] + then + git checkout "$INITIAL_BRANCH" + fi + + if [[ -n "$INITIAL_REVISION" ]] + then + git reset --hard "$INITIAL_REVISION" "${QUIET_ARGS[@]}" + fi + + if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] + then + pop_stash + else + pop_stash_message + fi + + exit 130 +} + +pull() { + local DIR + local TAP_VAR + + DIR="$1" + cd "$DIR" || return + TAP_VAR=$(repo_var "$DIR") + unset STASHED + + # The upstream repository's default branch may not be master; + # check refs/remotes/origin/HEAD to see what the default + # origin branch name is, and use that. If not set, fall back to "master". + INITIAL_BRANCH="$(git symbolic-ref --short HEAD 2>/dev/null)" + UPSTREAM_BRANCH="$(upstream_branch)" + + # Used for testing purposes, e.g., for testing formula migration after + # renaming it in the currently checked-out branch. To test run + # "brew update --simulate-from-current-branch" + if [[ -n "$HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH" ]] + then + INITIAL_REVISION="$(git rev-parse -q --verify "$UPSTREAM_BRANCH")" + CURRENT_REVISION="$(read_current_revision)" + export HOMEBREW_UPDATE_BEFORE"$TAP_VAR"="$INITIAL_REVISION" + export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$CURRENT_REVISION" + if ! git merge-base --is-ancestor "$INITIAL_REVISION" "$CURRENT_REVISION" + then + odie "Your $DIR HEAD is not a descendant of $UPSTREAM_BRANCH!" + fi + return + fi + + trap reset_on_interrupt SIGINT + + if [[ -n "$(git status --untracked-files=all --porcelain 2>/dev/null)" ]] + then + if [[ -n "$HOMEBREW_VERBOSE" ]] + then + echo "Stashing uncommitted changes to $DIR." + git status --short --untracked-files=all + fi + git -c "user.email=brew-update@localhost" \ + -c "user.name=brew update" \ + stash save --include-untracked "${QUIET_ARGS[@]}" + git reset --hard "${QUIET_ARGS[@]}" + STASHED="1" + fi + + if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] + then + # Recreate and check out `#{upstream_branch}` if unable to fast-forward + # it to `origin/#{@upstream_branch}`. Otherwise, just check it out. + if git merge-base --is-ancestor "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" &>/dev/null + then + git checkout --force "$UPSTREAM_BRANCH" "${QUIET_ARGS[@]}" + else + git checkout --force -B "$UPSTREAM_BRANCH" "origin/$UPSTREAM_BRANCH" "${QUIET_ARGS[@]}" + fi + fi + + INITIAL_REVISION="$(read_current_revision)" + export HOMEBREW_UPDATE_BEFORE"$TAP_VAR"="$INITIAL_REVISION" + + # ensure we don't munge line endings on checkout + git config core.autocrlf false + + if [[ -n "$HOMEBREW_REBASE" ]] + then + git rebase "${QUIET_ARGS[@]}" "origin/$UPSTREAM_BRANCH" + else + git merge --no-edit --ff "${QUIET_ARGS[@]}" "origin/$UPSTREAM_BRANCH" + fi + + export HOMEBREW_UPDATE_AFTER"$TAP_VAR"="$(read_current_revision)" + + trap '' SIGINT + + if [[ "$INITIAL_BRANCH" != "$UPSTREAM_BRANCH" && -n "$INITIAL_BRANCH" ]] + then + git checkout "$INITIAL_BRANCH" "${QUIET_ARGS[@]}" + pop_stash + else + pop_stash_message + fi + + trap - SIGINT +} + +homebrew-update() { + local option + local DIR + local UPSTREAM_BRANCH + + for option in "$@" + do + case "$option" in + --help) brew update --help; exit $? ;; + --verbose) HOMEBREW_VERBOSE=1 ;; + --debug) HOMEBREW_DEBUG=1;; + --rebase) HOMEBREW_REBASE=1 ;; + --simulate-from-current-branch) HOMEBREW_SIMULATE_FROM_CURRENT_BRANCH=1 ;; + --*) ;; + -*) + [[ "$option" = *v* ]] && HOMEBREW_VERBOSE=1; + [[ "$option" = *d* ]] && HOMEBREW_DEBUG=1; + ;; + *) + odie <<-EOS +This command updates brew itself, and does not take formula names. +Use 'brew upgrade '. +EOS + ;; + esac + done + + if [[ -n "$HOMEBREW_DEBUG" ]] + then + set -x + fi + + # check permissions + if [[ "$HOMEBREW_PREFIX" = "/usr/local" && ! -w /usr/local ]] + then + odie "/usr/local must be writable!" + fi + + if [[ ! -w "$HOMEBREW_REPOSITORY" ]] + then + odie "$HOMEBREW_REPOSITORY must be writable!" + fi + + HOMEBREW_GIT="$(which_git)" + if [[ -z "$HOMEBREW_GIT" ]] + then + brew install git + HOMEBREW_GIT="$(which_git)" + if [[ -z "$HOMEBREW_GIT" ]] + then + odie "Git must be installed and in your PATH!" + fi + fi + export GIT_TERMINAL_PROMPT="0" + export GIT_ASKPASS="false" + export GIT_SSH_COMMAND="ssh -oBatchMode=yes" + + if [[ -z "$HOMEBREW_VERBOSE" ]] + then + QUIET_ARGS=(-q) + else + QUIET_ARGS=() + fi + + # ensure GIT_CONFIG is unset as we need to operate on .git/config + unset GIT_CONFIG + + chdir "$HOMEBREW_REPOSITORY" + git_init_if_necessary + # rename Taps directories + # this procedure will be removed in the future if it seems unnecessary + rename_taps_dir_if_necessary + + # kill all of subprocess on interrupt + trap '{ pkill -P $$; wait; exit 130; }' SIGINT + + for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/* + do + [[ -d "$DIR/.git" ]] || continue + [[ -n "$SKIP_FETCH_HOMEBREW_REPOSITORY" && "$DIR" = "$HOMEBREW_REPOSITORY" ]] && continue + cd "$DIR" || continue + UPSTREAM_BRANCH="$(upstream_branch)" + # the refspec ensures that the default upstream branch gets updated + ( + git fetch "${QUIET_ARGS[@]}" origin \ + "refs/heads/$UPSTREAM_BRANCH:refs/remotes/origin/$UPSTREAM_BRANCH" || \ + odie "Fetching $DIR failed!" + ) & + done + + wait + trap - SIGINT + + for DIR in "$HOMEBREW_REPOSITORY" "$HOMEBREW_LIBRARY"/Taps/*/* + do + [[ -d "$DIR/.git" ]] || continue + pull "$DIR" + done + + chdir "$HOMEBREW_REPOSITORY" + brew update-report "$@" + return $? +} diff --git a/Library/Homebrew/test/test_updater.rb b/Library/Homebrew/test/test_updater.rb index 16efdaa1d..f84048b52 100644 --- a/Library/Homebrew/test/test_updater.rb +++ b/Library/Homebrew/test/test_updater.rb @@ -1,5 +1,5 @@ require "testing_env" -require "cmd/update" +require "cmd/update-ruby" require "formula_versions" require "yaml" -- cgit v1.2.3