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:
Mike McQuaid
2015-12-09 19:32:49 +00:00
parent c8d0a9075d
commit fdb4577be8
16 changed files with 69 additions and 1099 deletions
-118
View File
@@ -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
-364
View File
@@ -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"
+1 -1
View File
@@ -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
#
-191
View File
@@ -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
#