mirror of
https://github.com/wavetermdev/homebrew-cask.git
synced 2026-08-05 13:43:24 -07:00
brew-cask: move to using tap cmd directory.
This provides a few benefits: - faster `brew cask` execution times as another Ruby process is not needed. Cask can instead be loaded in-process with Homebrew. This will also make it easier to use some of Homebrew's core code and ease moving code from Cask into Homebrew core. - Users do not need to `brew upgrade` Cask any more: it's done automatically on any `brew update` or `git pull` of the Cask tap.
This commit is contained in:
-170
@@ -1,170 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# brew-cask
|
||||
#
|
||||
# bash shim to invoke brew-cask-cmd.rb
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
set +o histexpand
|
||||
set -o nounset
|
||||
shopt -s nocasematch
|
||||
shopt -s nullglob
|
||||
shopt -s dotglob
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$@"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%"${message##*[![:space:]]}"}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
resolve_dir () {
|
||||
local resolved="$(for dir; do cd "$dir"; done && /bin/pwd -P)"
|
||||
if [[ -d "$resolved" ]]; then
|
||||
printf "%s" "$resolved"
|
||||
else
|
||||
die "cannot resolve: '$@'"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_dir () {
|
||||
local dir="$1"
|
||||
local message
|
||||
shift
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
message="$@"
|
||||
else
|
||||
message="brew-cask: no such directory: '$dir'"
|
||||
fi
|
||||
if ! [[ -d "$dir" ]]; then
|
||||
die "$message"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_file () {
|
||||
local file="$1"
|
||||
local message
|
||||
shift
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
message="$@"
|
||||
else
|
||||
message="brew-cask: no such file: '$file'"
|
||||
fi
|
||||
if ! [[ -f "$file" ]]; then
|
||||
die "$message"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_executable () {
|
||||
local executable="$1"
|
||||
local message
|
||||
shift
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
message="$@"
|
||||
else
|
||||
message="brew-cask: no such executable: '$executable'"
|
||||
fi
|
||||
if ! [[ -f "$executable" ]] || ! [[ -x "$executable" ]]; then
|
||||
die "$message"
|
||||
fi
|
||||
}
|
||||
|
||||
# NOTE: Keep in sync with `Ruby20Requirement` in `/brew-cask.rb`.
|
||||
find_ruby_2_plus () {
|
||||
declare -a rubies
|
||||
local favorite_ruby="/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby"
|
||||
local version_str
|
||||
|
||||
if [[ -x "$favorite_ruby" ]]; then
|
||||
printf "%s" "$favorite_ruby"
|
||||
else
|
||||
IFS=$'\n' rubies=( $(/usr/bin/type -aP ruby) \
|
||||
"/usr/local/bin/ruby" \
|
||||
"$(brew --repository 2>/dev/null)/bin/ruby" )
|
||||
for ruby in "${rubies[@]}"; do
|
||||
version_str="$("$ruby" --version 2>/dev/null)"
|
||||
if [[ "$version_str" =~ ^ruby.2 ]]; then
|
||||
printf "%s" "$ruby"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_brew_cask () {
|
||||
local script_dir
|
||||
local symlink_target
|
||||
local symlink_target_dir
|
||||
local brewcask_lib_dir
|
||||
local brewcask_command
|
||||
local interpreter
|
||||
declare -a ruby_opts
|
||||
|
||||
ruby_opts=( "-W0" "-EUTF-8:UTF-8" )
|
||||
|
||||
script_dir="$(resolve_dir "${0%/*}")"
|
||||
ensure_dir "$script_dir" \
|
||||
"brew-cask: could not resolve script directory"
|
||||
|
||||
# return "." in case we are not a link
|
||||
symlink_target="$(/usr/bin/readlink "$0" || echo ".")"
|
||||
|
||||
# redefine script_dir because we are likely to be a relative link
|
||||
symlink_target_dir="$(/usr/bin/dirname "$symlink_target")"
|
||||
script_dir="$(resolve_dir "$script_dir" "$symlink_target_dir")"
|
||||
ensure_dir "$script_dir" \
|
||||
"brew-cask: could not resolve script directory"
|
||||
|
||||
# The Homebrew install process replaces the lib element below with rubylib
|
||||
brewcask_lib_dir="$(resolve_dir "$script_dir"/../lib)"
|
||||
ensure_dir "$brewcask_lib_dir" \
|
||||
"brew-cask: could not resolve homebrew-cask library directory"
|
||||
|
||||
brewcask_command="$brewcask_lib_dir/brew-cask-cmd.rb"
|
||||
ensure_file "$brewcask_command" \
|
||||
"brew-cask: could not find brew-cask-cmd.rb in '$brewcask_lib_dir'"
|
||||
|
||||
interpreter="$(find_ruby_2_plus)"
|
||||
ensure_executable "$interpreter" \
|
||||
"brew-cask: could not find Ruby 2.0 or greater. Try 'brew install ruby'."
|
||||
|
||||
exec "$interpreter" "${ruby_opts[@]}" "$brewcask_command" "${@}"
|
||||
}
|
||||
|
||||
###
|
||||
### initialization
|
||||
###
|
||||
|
||||
unset GEM_HOME
|
||||
unset GEM_PATH
|
||||
|
||||
###
|
||||
### dispatch
|
||||
###
|
||||
|
||||
_brew_cask "${@:-}"
|
||||
|
||||
#
|
||||
+9
-62
@@ -1,73 +1,20 @@
|
||||
begin
|
||||
require Pathname(__FILE__).realpath.dirname.join("lib", "hbc", "version")
|
||||
rescue
|
||||
# todo: transitional, defensive, should not be needed.
|
||||
# remove the begin/rescue logic after 1 Feb 2015
|
||||
require Pathname(__FILE__).realpath.dirname.join("lib", "cask", "version")
|
||||
HBC_VERSION = HOMEBREW_CASK_VERSION
|
||||
end
|
||||
|
||||
# NOTE: Keep in sync with `find_ruby_2_plus` in `/bin/brew-cask`.
|
||||
class Ruby20Requirement < Requirement
|
||||
fatal true
|
||||
default_formula "ruby"
|
||||
|
||||
satisfy :build_env => false do
|
||||
result = false
|
||||
favorite_ruby =
|
||||
"/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby"
|
||||
|
||||
if File.executable?(favorite_ruby)
|
||||
result = true
|
||||
else
|
||||
rubies = `/usr/bin/type -aP ruby`.split("\n")
|
||||
rubies += [
|
||||
"/usr/local/bin/ruby",
|
||||
"#{`brew --repository 2>/dev/null`.strip}/bin/ruby",
|
||||
]
|
||||
|
||||
rubies.uniq.each do |ruby|
|
||||
version = /\d\.\d/.match(`#{ruby} --version 2>/dev/null`)
|
||||
|
||||
if version && Version.new(version.to_s) >= Version.new("2.0")
|
||||
result = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
env do
|
||||
ENV.prepend_path "PATH", which("ruby").dirname
|
||||
end
|
||||
|
||||
def message; <<-EOS.undent
|
||||
brew-cask needs Ruby >=2.0
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
class BrewCask < Formula
|
||||
homepage "https://github.com/caskroom/homebrew-cask/"
|
||||
url "https://github.com/caskroom/homebrew-cask.git", :tag => "v#{HBC_VERSION}"
|
||||
head "https://github.com/caskroom/homebrew-cask.git", :branch => "master"
|
||||
url "https://github.com/caskroom/homebrew-cask.git", :tag => "v0.60.0"
|
||||
|
||||
skip_clean "bin"
|
||||
|
||||
depends_on Ruby20Requirement
|
||||
depends_on :ruby => "2.0"
|
||||
|
||||
def install
|
||||
man1.install "doc/man/brew-cask.1"
|
||||
prefix.install "lib" => "rubylib"
|
||||
inreplace "bin/brew-cask", "/lib", "/rubylib"
|
||||
end
|
||||
|
||||
prefix.install "Casks", "bin"
|
||||
(bin+"brew-cask").chmod 0755
|
||||
def caveats
|
||||
<<-EOS.undent
|
||||
You can uninstall this formula as `brew tap Caskroom/cask` is now all that's
|
||||
needed to install Homebrew Cask and keep it up to date.
|
||||
EOS
|
||||
end
|
||||
|
||||
test do
|
||||
system "#{bin}/brew-cask", "cask", "info", "google-chrome"
|
||||
system "brew", "cask", "info", "google-chrome"
|
||||
end
|
||||
end
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby -W0 -EUTF-8:UTF-8
|
||||
# encoding: UTF-8
|
||||
|
||||
# Ruby version check
|
||||
unless RUBY_VERSION.split(".").first.to_i >= 2
|
||||
alt_ruby = which "ruby"
|
||||
alt_ruby_version = `#{alt_ruby} --version`.chomp[/\d\.\d/, 0] if alt_ruby
|
||||
|
||||
unless alt_ruby && alt_ruby_version.split(".").first.to_i >= 2
|
||||
abort "Ruby 2.0 or above is required. You can install it with `brew install ruby`."
|
||||
end
|
||||
|
||||
exec alt_ruby, "-W0", "-I#{HOMEBREW_LIBRARY_PATH}", "-rglobal", __FILE__, *ARGV
|
||||
end
|
||||
|
||||
require 'pathname'
|
||||
|
||||
$LOAD_PATH.unshift(File.expand_path('../../lib', Pathname.new(__FILE__).realpath))
|
||||
|
||||
# todo remove internal Homebrew dependencies and remove this line
|
||||
require 'vendor/homebrew-fork/global'
|
||||
|
||||
require 'hbc'
|
||||
|
||||
begin
|
||||
Hbc::CLI.process(ARGV)
|
||||
rescue Interrupt => e
|
||||
puts
|
||||
exit 130
|
||||
end
|
||||
exit 0
|
||||
@@ -1,118 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# bump_version
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require 'open3'
|
||||
require 'rubygems'
|
||||
|
||||
###
|
||||
### configurable constants
|
||||
###
|
||||
|
||||
VERSION_FILE = 'lib/hbc/version.rb'
|
||||
VERSION_PAT = %r[\d+\.\d+\.\d+]i
|
||||
VERSION_CONSTANT_NAME = 'HBC_VERSION'
|
||||
|
||||
###
|
||||
### methods
|
||||
###
|
||||
|
||||
def cd_to_project_root
|
||||
Dir.chdir File.dirname(File.expand_path(__FILE__))
|
||||
@git_root ||= Open3.popen3(*%w[
|
||||
git rev-parse --show-toplevel
|
||||
]) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
Dir.chdir @git_root
|
||||
@git_root
|
||||
end
|
||||
|
||||
def git_diff
|
||||
Open3.popen3(*%w[
|
||||
git diff --no-color --
|
||||
],
|
||||
VERSION_FILE) do |stdin, stdout, stderr|
|
||||
stdout.each_line.map(&:chomp)
|
||||
end
|
||||
end
|
||||
|
||||
def file_contents_pat
|
||||
%r{\A(#{VERSION_CONSTANT_NAME}\s+=\s+)'(#{VERSION_PAT})'\s*\Z}s
|
||||
end
|
||||
|
||||
def current_file_contents
|
||||
@current_file_contents ||= File.read(VERSION_FILE)
|
||||
end
|
||||
|
||||
def current_file_version
|
||||
if file_contents_pat.match(current_file_contents)
|
||||
$2
|
||||
else
|
||||
raise "Could not parse file '#{VERSION_FILE}'"
|
||||
end
|
||||
end
|
||||
|
||||
def sanity_check
|
||||
unless %r{\A#{VERSION_PAT}\Z}.match(proposed_version)
|
||||
raise "Proposed version '#{proposed_version}' does not look like a semantic version string"
|
||||
end
|
||||
unless %r{\A#{VERSION_PAT}\Z}.match(current_file_version)
|
||||
raise "Current version '#{current_file_version}' does not look like a semantic version string"
|
||||
end
|
||||
unless Gem::Version.new(proposed_version) > Gem::Version.new(current_file_version)
|
||||
raise "Proposed version '#{proposed_version}' is not greater than current version #{current_file_version}"
|
||||
end
|
||||
end
|
||||
|
||||
def usage
|
||||
<<EOT
|
||||
bump_version <new-version>
|
||||
|
||||
Bump the version number in #{VERSION_FILE} to match the
|
||||
number given on the command line.
|
||||
|
||||
EOT
|
||||
end
|
||||
|
||||
def proposed_version
|
||||
@proposed_version ||= ARGV.first.sub(/^v/i, '')
|
||||
end
|
||||
|
||||
def rewrite_version
|
||||
new_file_contents = current_file_contents
|
||||
if new_file_contents.sub!(file_contents_pat, "\\1'#{proposed_version}'\n")
|
||||
File.open(VERSION_FILE, 'w') {|f| f.write(new_file_contents) }
|
||||
else
|
||||
raise "Could not parse file '#{VERSION_FILE}'"
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
# process args
|
||||
if %r{\A-+h(?:elp)?}i.match(ARGV.first)
|
||||
puts usage
|
||||
exit
|
||||
elsif ARGV.length != 1 or ! %r{\Av?#{VERSION_PAT}\Z}.match(ARGV.first)
|
||||
puts usage
|
||||
exit 1
|
||||
end
|
||||
|
||||
# initialize
|
||||
cd_to_project_root
|
||||
|
||||
# dispatch
|
||||
sanity_check
|
||||
rewrite_version
|
||||
puts git_diff
|
||||
@@ -1,364 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# generate_changelog
|
||||
#
|
||||
|
||||
###
|
||||
### dependencies
|
||||
###
|
||||
|
||||
require 'open3'
|
||||
require 'set'
|
||||
|
||||
###
|
||||
### configurable constants
|
||||
###
|
||||
|
||||
PROJECT_URL = 'https://github.com/caskroom/homebrew-cask'
|
||||
|
||||
MAINTAINERS = %w[
|
||||
phinze
|
||||
fanquake
|
||||
vitorgalvao
|
||||
alebcay
|
||||
ndr-qef
|
||||
jawshooah
|
||||
sebroeder
|
||||
adityadalal924
|
||||
caskroom
|
||||
]
|
||||
|
||||
CODE_PATHS = %w[
|
||||
bin
|
||||
developer
|
||||
lib
|
||||
spec
|
||||
test
|
||||
brew-cask.rb
|
||||
Rakefile
|
||||
Gemfile
|
||||
Gemfile.lock
|
||||
.travis.yml
|
||||
.gitignore
|
||||
]
|
||||
|
||||
SHA_PAT = '[\da-f]{40}'
|
||||
|
||||
###
|
||||
### monkeypatching
|
||||
###
|
||||
|
||||
class Array
|
||||
def to_h
|
||||
Hash[*self.flatten]
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
### git methods
|
||||
###
|
||||
|
||||
def end_object
|
||||
'HEAD'
|
||||
end
|
||||
|
||||
def matches_sha(sha)
|
||||
%r{\A#{SHA_PAT}\Z}.match(sha)
|
||||
end
|
||||
|
||||
def cd_to_project_root
|
||||
Dir.chdir File.dirname(File.expand_path(__FILE__))
|
||||
@git_root ||= Open3.popen3(*%w[
|
||||
git rev-parse --show-toplevel
|
||||
]) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
Dir.chdir @git_root
|
||||
@git_root
|
||||
end
|
||||
|
||||
def warn_if_off_branch(wanted_branch='master')
|
||||
current_branch = Open3.popen3(*%w[
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
]) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
unless current_branch == wanted_branch
|
||||
$stderr.puts "\nWARNING: you are running from branch '#{current_branch}', not '#{wanted_branch}'\n\n"
|
||||
end
|
||||
end
|
||||
|
||||
def last_release
|
||||
@last_release ||= Open3.popen3(
|
||||
'./developer/bin/get_release_tag'
|
||||
) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def next_release
|
||||
if @next_release.nil?
|
||||
if ENV.key?('NEW_RELEASE_TAG')
|
||||
@next_release = ENV['NEW_RELEASE_TAG']
|
||||
else
|
||||
@next_release = Open3.popen3(
|
||||
'./developer/bin/get_release_tag', '-next'
|
||||
) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
@next_release
|
||||
end
|
||||
end
|
||||
|
||||
def verify_git_object(object)
|
||||
sha = Open3.popen3(*%w[
|
||||
git rev-parse -q --verify
|
||||
],
|
||||
object, '--'
|
||||
) do |stdin, stdout, stderr|
|
||||
begin
|
||||
stdout.gets.chomp
|
||||
rescue
|
||||
end
|
||||
end
|
||||
raise "'#{object}' is not a git object" unless matches_sha sha
|
||||
sha
|
||||
end
|
||||
|
||||
# constrained to last_release..HEAD
|
||||
def all_shas
|
||||
@all_shas ||= Open3.popen3(*%w[
|
||||
git rev-list --topo-order
|
||||
],
|
||||
"#{last_release}..#{end_object}"
|
||||
) do |stdin, stdout, stderr|
|
||||
stdout.each_line.map(&:chomp)
|
||||
end
|
||||
end
|
||||
|
||||
# not constrained
|
||||
def tag_commits
|
||||
@tag_commits ||= Open3.popen3(*%w[
|
||||
git show-ref -s --tags --dereference
|
||||
]) do |stdin, stdout, stderr|
|
||||
stdout.each_line.collect do |line|
|
||||
line.chomp!
|
||||
if ! %r{\^\{\}\Z}.match(line)
|
||||
nil
|
||||
elsif %r{\A(#{SHA_PAT}) }.match(line)
|
||||
[$1, true]
|
||||
else
|
||||
raise "'#{line}' does not contain an SHA"
|
||||
end
|
||||
end.compact.to_h
|
||||
end
|
||||
end
|
||||
|
||||
# Collect merge commits separately because "git log" does not always
|
||||
# return related merge commits when using a path constraint. There
|
||||
# might be a clever way to do this in a single step already built into
|
||||
# git. In any case (in the opinion of the author) git's default
|
||||
# behavior is a bug.
|
||||
#
|
||||
# constrained to last_release..HEAD
|
||||
def merge_commits
|
||||
@merge_commits ||= Open3.popen3(*%w[
|
||||
git rev-list --pretty=oneline --topo-order --min-parents=2 --max-parents=2 --parents
|
||||
],
|
||||
"#{last_release}..#{end_object}"
|
||||
) do |stdin, stdout, stderr|
|
||||
stdout.each_line.collect do |line|
|
||||
line.chomp!
|
||||
# intentionally limited to the simple case of two parents
|
||||
if %r{\A(#{SHA_PAT}) (#{SHA_PAT}) (#{SHA_PAT}) (.*)}.match(line)
|
||||
[$1, {
|
||||
:trunk_parent => $2,
|
||||
:branch_parent => $3,
|
||||
:log => $4,
|
||||
}]
|
||||
else
|
||||
raise "could not parse '#{line}'"
|
||||
end
|
||||
end.compact.to_h
|
||||
end
|
||||
end
|
||||
|
||||
# constrained to last_release..HEAD
|
||||
# also constrained to CODE_PATHS
|
||||
def ordinary_code_commits
|
||||
@ordinary_code_commits ||= Open3.popen3(*%w[
|
||||
git rev-list --pretty=oneline --topo-order --max-parents=1 --parents
|
||||
],
|
||||
"#{last_release}..#{end_object}",
|
||||
'--', *CODE_PATHS
|
||||
) do |stdin, stdout, stderr|
|
||||
stdout.each_line.collect do |line|
|
||||
line.chomp!
|
||||
if %r{\A(#{SHA_PAT}) (#{SHA_PAT}) (.*)}.match(line)
|
||||
[$1, {
|
||||
:trunk_parent => $2,
|
||||
:log => $3,
|
||||
}]
|
||||
else
|
||||
raise "could not parse '#{line}'"
|
||||
end
|
||||
end.compact.to_h
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
### report/analysis methods
|
||||
###
|
||||
|
||||
# todo: read the release date from the tag
|
||||
def header
|
||||
<<EOT
|
||||
## #{next_release.sub(/^v/,'')}
|
||||
|
||||
* __Casks__
|
||||
- N Casks added ...
|
||||
- N total Casks
|
||||
* __Features__
|
||||
- none
|
||||
* __Breaking Changes__
|
||||
- none
|
||||
* __Fixes__
|
||||
- none
|
||||
* __Internal Changes__
|
||||
- none
|
||||
* __Documentation__
|
||||
- N doc commits since ...
|
||||
* __Contributors__
|
||||
- N new contributors since ...
|
||||
- N total contributors
|
||||
* __Release Date__
|
||||
- YYYY-MM-DD HH:MM:SS UTC
|
||||
EOT
|
||||
end
|
||||
|
||||
def footer
|
||||
@footer ||= Set.new
|
||||
@footer.to_a.sort
|
||||
end
|
||||
|
||||
def add_to_footer(line)
|
||||
@footer ||= Set.new
|
||||
@footer.add line
|
||||
end
|
||||
|
||||
def seen(sha)
|
||||
@seen ||= {}
|
||||
if @seen[sha]
|
||||
return true
|
||||
else
|
||||
@seen[sha] = true
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def log_ordinary_commit(sha)
|
||||
# indent ordinary commits
|
||||
" - #{ordinary_code_commits[sha][:log]}"
|
||||
end
|
||||
|
||||
def read_pull_request(sha)
|
||||
branch_parent = merge_commits[sha][:branch_parent]
|
||||
if ordinary_code_commits[branch_parent] and
|
||||
%r{\AMerge pull request \#(\d+) from ([^\s/]+)}.match(merge_commits[sha][:log]) then
|
||||
{
|
||||
:num => $1,
|
||||
:gh_user => MAINTAINERS.include?($2) ? '' : $2
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def log_merge_commit(sha)
|
||||
branch_parent = merge_commits[sha][:branch_parent]
|
||||
pr = read_pull_request sha
|
||||
if pr then
|
||||
# munge a GitHub PR commit log entry into Markdown links
|
||||
# plus log content from the first parent commit
|
||||
log = "[##{pr[:num]}][]"
|
||||
log.concat " #{ordinary_code_commits[branch_parent][:log]}"
|
||||
add_to_footer "[##{pr[:num]}]: #{PROJECT_URL}/issues/#{pr[:num]}"
|
||||
seen branch_parent
|
||||
if pr[:gh_user].length > 0
|
||||
log.concat " <3 [@#{pr[:gh_user]}][]"
|
||||
add_to_footer "[@#{pr[:gh_user]}]: https://github.com/#{pr[:gh_user]}"
|
||||
end
|
||||
" - #{log}"
|
||||
elsif ordinary_code_commits[branch_parent]
|
||||
# non-PR merge, just pass the log msg unmodified
|
||||
" - #{merge_commits[sha][:log]}"
|
||||
else
|
||||
# drop this merge, it does not relate to CODE_PATHS
|
||||
end
|
||||
end
|
||||
|
||||
def changelog
|
||||
# follows topological order
|
||||
all_shas.collect do |sha|
|
||||
if tag_commits[sha]
|
||||
nil
|
||||
elsif seen sha
|
||||
nil
|
||||
elsif ordinary_code_commits[sha]
|
||||
log_ordinary_commit sha
|
||||
elsif merge_commits[sha]
|
||||
log_merge_commit sha
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
# process args
|
||||
if %r{\A-+h(?:elp)?}i.match(ARGV.first)
|
||||
puts <<EOT
|
||||
generate_changelog [ <release-tag> ]
|
||||
|
||||
Generate a rough-draft changelog in Markdown format for changes since
|
||||
<release-tag>, which defaults to the most recent release.
|
||||
|
||||
The output is only a draft. Changelog items still need to be edited,
|
||||
removed, and/or added.
|
||||
|
||||
All changelog items must also be moved to within one of the given
|
||||
category sections.
|
||||
|
||||
EOT
|
||||
exit
|
||||
end
|
||||
|
||||
if ARGV.length
|
||||
@last_release = ARGV.shift
|
||||
end
|
||||
|
||||
# initialize
|
||||
cd_to_project_root
|
||||
verify_git_object last_release
|
||||
warn_if_off_branch 'master'
|
||||
|
||||
# report
|
||||
puts header
|
||||
puts "\n"
|
||||
puts changelog
|
||||
puts "\n"
|
||||
puts footer
|
||||
puts "\n"
|
||||
@@ -50,6 +50,6 @@ if ! /usr/bin/which ronn >/dev/null 2>&1; then
|
||||
die "ERROR: The 'ronn' gem must be installed"
|
||||
fi
|
||||
|
||||
ronn --roff --pipe --organization='Homebrew-cask' --manual='brew-cask' doc/src/brew-cask.1.md > doc/man/brew-cask.1
|
||||
ronn --roff --pipe --organization='Homebrew-cask' --manual='brew-cask' doc/src/brew-cask.1.md > man/man1/brew-cask.1
|
||||
|
||||
#
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# get_release_tag
|
||||
#
|
||||
|
||||
###
|
||||
### settings
|
||||
###
|
||||
|
||||
set -e # exit on any uncaught error
|
||||
set +o histexpand # don't expand history expressions
|
||||
shopt -s nocasematch # case-insensitive regular expressions
|
||||
|
||||
###
|
||||
### global variables
|
||||
###
|
||||
|
||||
opt_next=''
|
||||
opt_latest=''
|
||||
opt_verbose=''
|
||||
|
||||
###
|
||||
### functions
|
||||
###
|
||||
|
||||
warn () {
|
||||
local message="$@"
|
||||
message="${message//\\t/$'\011'}"
|
||||
message="${message//\\n/$'\012'}"
|
||||
message="${message%"${message##*[![:space:]]}"}"
|
||||
printf "%s\n" "$message" 1>&2
|
||||
}
|
||||
|
||||
die () {
|
||||
warn "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd_to_project_root () {
|
||||
local script_dir="$(/usr/bin/dirname "$0")"
|
||||
cd "$script_dir"
|
||||
local git_root="$(git rev-parse --show-toplevel)"
|
||||
if [[ -z "$git_root" ]]; then
|
||||
die "ERROR: Could not find git project root"
|
||||
fi
|
||||
cd "$git_root"
|
||||
}
|
||||
|
||||
verify_git_object_is_new () {
|
||||
if git rev-parse --verify "$1" >/dev/null 2>&1; then
|
||||
die "\nERROR: Proposed new tag: '$1' already exists as a commit object\n\n"
|
||||
fi
|
||||
}
|
||||
|
||||
sanity_check_parsed_version () {
|
||||
if [[ $# -ne 3 ]]; then
|
||||
die "ERROR: Could not parse version tag: wrong number of elements"
|
||||
fi
|
||||
if ! [[ $1 =~ ^v[0-9]+$ ]]; then
|
||||
die "ERROR: Could not parse version tag: does not start with v[0-9]"
|
||||
fi
|
||||
}
|
||||
|
||||
output_proposed_tag () {
|
||||
local new_tag="$1.$2.$3"
|
||||
sanity_check_parsed_version "$@"
|
||||
verify_git_object_is_new "$new_tag"
|
||||
if [[ -n "$opt_verbose" ]]; then
|
||||
printf "Latest tag\t%s\n" "$latest_tag"
|
||||
printf "Proposed new tag\t%s\n" "$new_tag"
|
||||
else
|
||||
printf "%s\n" "$new_tag"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_next_major_tag () {
|
||||
local -a version_elts
|
||||
IFS='.' read -a version_elts <<< "$1"
|
||||
sanity_check_parsed_version "${version_elts[@]}"
|
||||
version_elts[0]="${version_elts[0]#v}" # mangle v<digit> into number
|
||||
(( version_elts[0] += 1 )) # increment version field
|
||||
version_elts[0]="v${version_elts[0]}" # restore text v<digit>
|
||||
version_elts[1]='0' # reset minor field
|
||||
version_elts[2]='0' # reset patch field
|
||||
output_proposed_tag "${version_elts[@]}"
|
||||
}
|
||||
|
||||
generate_next_minor_tag () {
|
||||
local -a version_elts
|
||||
IFS='.' read -a version_elts <<< "$1"
|
||||
sanity_check_parsed_version "${version_elts[@]}"
|
||||
(( version_elts[1] += 1 )) # increment minor field
|
||||
version_elts[2]='0' # reset patch field
|
||||
output_proposed_tag "${version_elts[@]}"
|
||||
}
|
||||
|
||||
generate_next_patch_tag () {
|
||||
local -a version_elts
|
||||
IFS='.' read -a version_elts <<< "$1"
|
||||
sanity_check_parsed_version "${version_elts[@]}"
|
||||
(( version_elts[2] += 1 )) # increment patch field
|
||||
output_proposed_tag "${version_elts[@]}"
|
||||
}
|
||||
|
||||
process_args () {
|
||||
local arg
|
||||
for arg in "$@"; do
|
||||
if [[ $arg =~ ^-+h(elp)?$ ]]; then
|
||||
printf "get_release_tag [ -latest | -next | -patch | -major | -verbose | -help ]
|
||||
|
||||
Retrieve or calculate a release tag.
|
||||
|
||||
Arguments:
|
||||
|
||||
-latest Show the most recent tag in the repository, which is typically
|
||||
the designation of the latest release. This is the default
|
||||
when invoked with no arguments.
|
||||
|
||||
-next Calculate the next minor-release tag bump and return it.
|
||||
|
||||
-patch Calculate the next patch-release tag bump and return it.
|
||||
Overrides -next if both are given.
|
||||
|
||||
-major Calculate the next major-release tag bump and return it.
|
||||
Overrides -next if both are given.
|
||||
|
||||
-verbose Output a table, possibly including both latest existing and
|
||||
proposed new tags.
|
||||
|
||||
See doc/releasing.md for more information.
|
||||
|
||||
"
|
||||
exit
|
||||
elif [[ $arg =~ ^-+v(erbose)?$ ]]; then
|
||||
opt_verbose='true'
|
||||
elif [[ $arg =~ ^-+next$ ]]; then
|
||||
if [[ -z "$opt_next" ]]; then
|
||||
opt_next='minor'
|
||||
fi
|
||||
elif [[ $arg =~ ^-+patch$ ]]; then
|
||||
if [[ "$opt_next" == 'major' ]]; then
|
||||
die "ERROR: -patch is incompatible with -major"
|
||||
fi
|
||||
opt_next='patch'
|
||||
elif [[ $arg =~ ^-+major$ ]]; then
|
||||
if [[ "$opt_next" == 'patch' ]]; then
|
||||
die "ERROR: -patch is incompatible with -major"
|
||||
fi
|
||||
opt_next='major'
|
||||
elif [[ $arg =~ ^-+latest$ ]]; then
|
||||
opt_latest='true'
|
||||
else
|
||||
die "ERROR: Unknown argument '$arg'"
|
||||
fi
|
||||
if [[ -n "$opt_latest" && -n "$opt_next" ]]; then
|
||||
die "ERROR: -latest is incompatible with -next/-patch/-major"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
###
|
||||
### main
|
||||
###
|
||||
|
||||
_get_release_tag () {
|
||||
cd_to_project_root
|
||||
local latest_tag="$(git describe --tags --abbrev=0 2>/dev/null)"
|
||||
if [[ -z "$latest_tag" ]]; then
|
||||
die "ERROR: No recent tag found"
|
||||
elif [[ -z "$opt_next" ]]; then
|
||||
if [[ -n "$opt_verbose" ]]; then
|
||||
printf "Latest tag\t"
|
||||
fi
|
||||
printf "%s\n" "$latest_tag"
|
||||
elif [[ "$opt_next" == 'major' ]]; then
|
||||
generate_next_major_tag "$latest_tag"
|
||||
elif [[ "$opt_next" == 'minor' ]]; then
|
||||
generate_next_minor_tag "$latest_tag"
|
||||
elif [[ "$opt_next" == 'patch' ]]; then
|
||||
generate_next_patch_tag "$latest_tag"
|
||||
else
|
||||
die "ERROR: Should not happen. Unknown argument?"
|
||||
fi
|
||||
}
|
||||
|
||||
process_args "${@}"
|
||||
|
||||
# dispatch main
|
||||
_get_release_tag
|
||||
|
||||
#
|
||||
@@ -1,154 +0,0 @@
|
||||
# Release Standards
|
||||
|
||||
Here’s where we document how homebrew-cask is released.
|
||||
|
||||
## Versioning
|
||||
|
||||
We attempt to follow [Semantic Versioning](http://semver.org/) as much as possible.
|
||||
|
||||
Since we are still pre-1.0, this essentially means that we bump the PATCH number when we fix bugs, and we bump the MINOR number when we add features. Pretty simple.
|
||||
|
||||
The script `./developer/bin/get_release_tag` can tell you the latest release tag that exists and/or calculate the proposed next release tag. Docs are at `get_release_tag -help`.
|
||||
|
||||
## Release Process
|
||||
|
||||
This is partially scripted now. The most time-consuming step is editing the changelog.
|
||||
|
||||
1. Be running on a checkout of `master` which is up to date and `git status`
|
||||
clean:
|
||||
|
||||
```bash
|
||||
$ git checkout master && git status
|
||||
```
|
||||
|
||||
2. `cd` to the project root:
|
||||
|
||||
```bash
|
||||
$ cd "$(git rev-parse --show-toplevel)"
|
||||
```
|
||||
|
||||
3. Pull in the latest `master`:
|
||||
|
||||
```bash
|
||||
$ git pull https://github.com/caskroom/homebrew-cask master
|
||||
```
|
||||
|
||||
4. Compile the man page and check the result by running:
|
||||
|
||||
```bash
|
||||
$ ./developer/bin/generate_man_pages; git --no-pager diff ./doc/man/brew-cask.1
|
||||
```
|
||||
|
||||
If the newly-compiled man page has no changes other than the datestamp, you may wish to discard the changes as follows:
|
||||
|
||||
```bash
|
||||
$ git checkout -- ./doc/man/brew-cask.1 # discard changes
|
||||
```
|
||||
|
||||
5. Do a `git log` to see what changed since the last release. You can scope it to only code changes:
|
||||
|
||||
```bash
|
||||
$ git log "$(./developer/bin/get_release_tag)"..HEAD -- lib spec test developer bin Gemfile Gemfile.lock Rakefile brew-cask.rb
|
||||
```
|
||||
|
||||
6. Decide whether to bump the minor or patch field in the next release tag, based on whether or not features were added. For a feature release, run the shell command:
|
||||
|
||||
```bash
|
||||
$ export NEW_RELEASE_TAG="$(./developer/bin/get_release_tag -next)"; echo "$NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
or for a patch release, add `-patch` to the command:
|
||||
|
||||
```bash
|
||||
$ export NEW_RELEASE_TAG="$(./developer/bin/get_release_tag -next -patch)"; echo "$NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
7. Make sure the value in `$NEW_RELEASE_TAG` is what you want.
|
||||
|
||||
8. Bump the `HBC_VERSION` string which is stored in the file `lib/hbc/version.rb`:
|
||||
|
||||
```bash
|
||||
$ ./developer/bin/bump_version "$NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
The version string in the Ruby code should match `$NEW_RELEASE_TAG`, except that the Ruby version should lack the leading `v` character.
|
||||
|
||||
9. Generate a draft changelog for the new release by running:
|
||||
|
||||
```bash
|
||||
$ ./developer/bin/project_stats release >| /var/tmp/draft_release_changelog.md
|
||||
$ ./developer/bin/generate_changelog >> /var/tmp/draft_release_changelog.md
|
||||
```
|
||||
|
||||
10. Edit the draft changelog, following the patterns used in `doc/CHANGELOG.md`. Some of the items for the changelog should be extracted from the statistics section at the start of the file, after which the statistics section can be deleted.
|
||||
|
||||
11. When complete, insert the new release changelog near the beginning of `doc/CHANGELOG.md`, just after the first line.
|
||||
|
||||
12. Make a commit on `master` with the modifications to `doc/CHANGELOG.md`, `lib/hbc/version.rb`, and/or `doc/man/brew-cask.1`:
|
||||
|
||||
```bash
|
||||
$ git add doc/CHANGELOG.md lib/hbc/version.rb doc/man/brew-cask.1
|
||||
$ git commit -m "cut $NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
13. Pull to get changes since you started working on the changelog:
|
||||
|
||||
```bash
|
||||
$ git pull https://github.com/caskroom/homebrew-cask master
|
||||
```
|
||||
|
||||
14. Tag the tip commit. Make certain to provide a `-m` message so that we get an annotated tag in the git history:
|
||||
|
||||
```bash
|
||||
$ git tag -m "$NEW_RELEASE_TAG" "$NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
15. Push that commit and the tag:
|
||||
|
||||
```bash
|
||||
$ git push https://github.com/caskroom/homebrew-cask master && git push https://github.com/caskroom/homebrew-cask tag "$NEW_RELEASE_TAG" && echo "new release $NEW_RELEASE_TAG was successfully pushed"
|
||||
```
|
||||
|
||||
If you don’t see a success message, that probably means someone updated master while you were working on the changelog. You must pull and resolve.
|
||||
|
||||
16. Open your browser to the relevant release page on GitHub:
|
||||
|
||||
```bash
|
||||
$ open "https://github.com/caskroom/homebrew-cask/releases/new?tag=$NEW_RELEASE_TAG"
|
||||
```
|
||||
|
||||
17. On the release page:
|
||||
|
||||
* If the `Tag version` field does not auto-fill, manually select the tag
|
||||
you just created (shell variable `$NEW_RELEASE_TAG`).
|
||||
* Paste the Markdown summary for the new release from `doc/CHANGELOG.md`
|
||||
into the main textarea.
|
||||
* Do not include the `## <version number>` heading line from the changelog
|
||||
in the pasted text.
|
||||
* The `Release title` field may be left blank.
|
||||
|
||||
18. Click `Publish Release`.
|
||||
|
||||
19. Unset the shell variable `$NEW_RELEASE_TAG`; you don’t need it anymore:
|
||||
|
||||
```bash
|
||||
$ unset NEW_RELEASE_TAG
|
||||
```
|
||||
|
||||
20. Announce the release on IRC.
|
||||
|
||||
21. Respond to any pending GitHub issues which may be resolved after users upgrade.
|
||||
|
||||
22. Rejoice! Have a :cookie:.
|
||||
|
||||
## Things to Consider
|
||||
|
||||
The way `brew update` works, users will always be tracking `HEAD` in their Tap. This means that the latest updates to Casks are always propagated ahead of code releases. We need to be thoughtful about how we push out new or breaking functionality. As a pre-1.0 project we can still break backwards compatibility, but sometimes there might be decisions we can make about releasing to make things easier on our users.
|
||||
|
||||
In general: go easy on the users!
|
||||
|
||||
## Notes
|
||||
|
||||
* In steps 3 and 14:
|
||||
- The full URL is given for the repo because that does not change depending on your local `.git/config`. Equivalent commands may be `git push`, `git push origin master`, or `git push upstream master`.
|
||||
- We push the commits *before* pushing the tag to ensure that there are no conflicts. The default behavior of `git push --follow-tags` is to push tags to the public repo before commits, which caused the “lost” tag v0.39.0.
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby -W0 -EUTF-8:UTF-8
|
||||
# encoding: UTF-8
|
||||
|
||||
# just in case
|
||||
if RUBY_VERSION.to_i < 2
|
||||
raise 'brew-cask: Ruby 2.0 or greater is required.'
|
||||
end
|
||||
|
||||
require 'pathname'
|
||||
|
||||
$LOAD_PATH.unshift(File.expand_path('..', Pathname.new(__FILE__).realpath))
|
||||
|
||||
# todo remove internal Homebrew dependencies and remove this line
|
||||
require 'vendor/homebrew-fork/global'
|
||||
|
||||
require 'hbc'
|
||||
|
||||
begin
|
||||
Hbc::CLI.process(ARGV)
|
||||
rescue Interrupt => e
|
||||
puts
|
||||
exit 130
|
||||
end
|
||||
exit 0
|
||||
+1
-1
@@ -229,7 +229,7 @@ class Hbc::CLI
|
||||
|
||||
def run(*args)
|
||||
if args.include?('--version') or @attempted_verb == '--version'
|
||||
puts HBC_VERSION
|
||||
puts Hbc.full_version
|
||||
else
|
||||
purpose
|
||||
usage
|
||||
|
||||
+7
-11
@@ -11,7 +11,7 @@ class Hbc::CLI::Doctor < Hbc::CLI::Base
|
||||
ohai 'Homebrew Cellar Path:', render_with_none_as_error( homebrew_cellar )
|
||||
ohai 'Homebrew Repository Path:', render_with_none_as_error( homebrew_repository )
|
||||
ohai 'Homebrew Origin:', render_with_none_as_error( homebrew_origin )
|
||||
ohai 'Homebrew-cask Version:', render_with_none_as_error( HBC_VERSION )
|
||||
ohai 'Homebrew-cask Version:', render_with_none_as_error( Hbc.full_version )
|
||||
ohai 'Homebrew-cask Install Location:', render_install_location( HBC_VERSION )
|
||||
ohai 'Homebrew-cask Staging Location:', render_staging_location( Hbc.caskroom )
|
||||
ohai 'Homebrew-cask Cached Downloads:', render_cached_downloads
|
||||
@@ -93,9 +93,9 @@ class Hbc::CLI::Doctor < Hbc::CLI::Base
|
||||
homebrew_constants('version')
|
||||
end
|
||||
|
||||
def self.homebrew_libdir
|
||||
@homebrew_libdir ||= if homebrew_repository.respond_to?(:join)
|
||||
homebrew_repository.join('Library', 'Homebrew')
|
||||
def self.homebrew_taps
|
||||
@homebrew_taps ||= if homebrew_repository.respond_to?(:join)
|
||||
homebrew_repository.join('Library', 'Taps')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -206,14 +206,10 @@ class Hbc::CLI::Doctor < Hbc::CLI::Base
|
||||
return "#{none_string} #{error_string}"
|
||||
end
|
||||
copy = Array.new(paths)
|
||||
unless Hbc::Utils.file_is_descendant(copy[0], homebrew_cellar)
|
||||
copy[0] = "#{copy[0]} #{error_string %Q{error: should be descendant of Homebrew Cellar}}"
|
||||
end
|
||||
copy.map! do |elt|
|
||||
elt = (homebrew_libdir and Hbc::Utils.file_is_descendant(elt, homebrew_libdir)) ?
|
||||
"#{elt} #{error_string %Q{error: should not be descendant of Homebrew Library dir}}" :
|
||||
elt
|
||||
unless Hbc::Utils.file_is_descendant(copy[0], homebrew_taps)
|
||||
copy[0] = "#{copy[0]} #{error_string %Q{error: should be descendant of Homebrew taps directory}}"
|
||||
end
|
||||
copy
|
||||
end
|
||||
|
||||
def self.render_cached_downloads
|
||||
|
||||
@@ -100,6 +100,10 @@ module Hbc::Locations
|
||||
@default_tap = _tap
|
||||
end
|
||||
|
||||
def default_tappath
|
||||
@default_tappath ||= homebrew_tapspath.join(default_tap)
|
||||
end
|
||||
|
||||
def path(query)
|
||||
if query.include?('/')
|
||||
token_with_tap = query
|
||||
|
||||
+13
-1
@@ -1 +1,13 @@
|
||||
HBC_VERSION = '0.59.0'
|
||||
HBC_VERSION = '0.60.0'
|
||||
|
||||
module Hbc
|
||||
def self.full_version
|
||||
@full_version ||= begin
|
||||
revision, commit = Dir.chdir(Hbc.default_tappath) do
|
||||
[`git rev-parse --short=4 --verify -q HEAD 2>/dev/null`.chomp,
|
||||
`git show -s --format="%cr" HEAD 2>/dev/null`.chomp]
|
||||
end
|
||||
"#{HBC_VERSION} (git revision #{revision}; last commit #{commit})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,6 +4,6 @@ describe 'brew cask --version' do
|
||||
it 'respects the --version argument' do
|
||||
lambda {
|
||||
Hbc::CLI::NullCommand.new('--version').run
|
||||
}.must_output "#{HBC_VERSION}\n"
|
||||
}.must_output "#{Hbc.full_version}\n"
|
||||
end
|
||||
end
|
||||
|
||||
+2
-1
@@ -26,10 +26,11 @@ describe "Repo layout" do
|
||||
TOPLEVEL_DIRS = %w{
|
||||
.git
|
||||
Casks
|
||||
bin
|
||||
cmd
|
||||
developer
|
||||
doc
|
||||
lib
|
||||
man
|
||||
spec
|
||||
test
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user