Merge pull request #2724 from rolandwalker/devscript_bash_refactor

Devscript bash refactoring
This commit is contained in:
Roland Walker
2014-01-31 09:36:39 -08:00
8 changed files with 485 additions and 177 deletions
+59 -27
View File
@@ -3,17 +3,43 @@
# develop_brew_cask
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### configurable global variables
###
tap_subdir="Library/Taps/phinze-cask"
###
### functions
###
warn () {
local message="$@"
if ! [[ $message =~ "\n"$ ]]; then
message="${message}\n"
fi
printf "$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
printf "Could not find git project root"
exit 1;
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
@@ -22,15 +48,22 @@ cd_to_version_dir () {
local cellar_dir="$1"
local version_dir="$2"
if [[ -z "$version_dir" ]]; then
printf "Can't get version dir under $cellar_dir/\n";
exit 1;
die "ERROR: Could not find version dir under $cellar_dir/"
fi
cd "$cellar_dir/$version_dir"
}
not_inside_homebrew () {
local tap_dir="$1"
local git_root="$2"
if [[ "$(/usr/bin/stat -L -f '%i' "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' "$git_root")" ]]; then
die "\nERROR: Run this script in your private repo, not inside Homebrew.\n"
fi
}
create_dev_links () {
local git_root="$1"
local tap_dir="$2"
local tap_dir="$1"
local git_root="$2"
/bin/mv rubylib production_rubylib
/bin/mv Casks production_Casks
/bin/ln -s "$git_root/Casks" .
@@ -40,46 +73,44 @@ create_dev_links () {
/bin/mv Casks production_Casks
/bin/ln -s "$git_root/Casks" .
/bin/ln -s "$git_root/lib" .
printf "brew-cask is now in development mode\n"
printf "Note: it is not safe to run 'brew update' while in development mode\n"
}
###
### main
###
_develop_brew_cask () {
# configurable
local tap_subdir="Library/Taps/phinze-cask"
# initialization
cd_to_project_root;
local git_root="$(pwd)"
cd_to_project_root
local git_root="$(/bin/pwd)"
local brew_prefix="$(brew --prefix)"
local cellar_dir="$brew_prefix/Cellar/brew-cask"
local version_dir="$(/bin/ls "$cellar_dir/" | /usr/bin/sort | /usr/bin/tail -1)"
local tap_dir="$brew_prefix/$tap_subdir"
# sanity check
if [[ "$(/usr/bin/stat -L -f '%i' "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' "$git_root")" ]]; then
printf "\nERROR: run this script in your private repo, not inside Homebrew.\n";
exit 1;
fi
not_inside_homebrew "$tap_dir" "$git_root"
# action
cd_to_version_dir "$cellar_dir" "$version_dir";
cd_to_version_dir "$cellar_dir" "$version_dir"
if [[ -e "production_rubylib" ]]; then
printf "brew-cask is already set up for development\n";
exit 1
die "brew-cask is already set up for development"
else
create_dev_links "$git_root" "$tap_dir";
printf "brew-cask is now in development mode\n"
printf "Note: it is not safe to run 'brew update' while in development mode\n"
create_dev_links "$tap_dir" "$git_root"
fi
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "develop_brew_cask
Symlink private repo directories into Homebrew's Cellar, so
that the 'brew cask' command will use the current development
branch in your private repo.
that the 'brew cask' command will use code and Casks from
the current development branch in your private repo.
Saves the production Homebrew directories under new names.
@@ -92,6 +123,7 @@ mode is in effect.
exit
fi
_develop_brew_cask "$@";
# dispatch main
_develop_brew_cask "${@}"
#
+43 -22
View File
@@ -3,20 +3,36 @@
# get_release_tag
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
opt_next='';
opt_latest='';
opt_verbose='';
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
die () {
local message="$@";
###
### global variables
###
opt_next=''
opt_latest=''
opt_verbose=''
###
### functions
###
warn () {
local message="$@"
if ! [[ $message =~ "\n"$ ]]; then
message="${message}\n"
fi
printf "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
@@ -25,23 +41,23 @@ cd_to_project_root () {
cd "$script_dir"
local git_root="$(git rev-parse --show-toplevel)"
if [[ -z "$git_root" ]]; then
die "Could not find git project root"
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"
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: can't parse version tag, wrong number of elements"
die "ERROR: Could not parse version tag: wrong number of elements"
fi
if ! [[ $1 =~ ^v[0-9]+$ ]]; then
die "Error: can't parse version tag, does not start with v[0-9]"
die "ERROR: Could not parse version tag: does not start with v[0-9]"
fi
}
@@ -71,7 +87,7 @@ generate_next_major_tag () {
generate_next_minor_tag () {
local -a version_elts
IFS='.' read -a version_elts <<< "$1";
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
@@ -123,30 +139,34 @@ See RELEASING.md for more information.
fi
elif [[ $arg =~ ^-+patch$ ]]; then
if [[ "$opt_next" == 'major' ]]; then
die "Error: -patch is incompatible with -major";
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";
die "ERROR: -patch is incompatible with -major"
fi
opt_next='major'
elif [[ $arg =~ ^-+latest$ ]]; then
opt_latest='true'
else
die "Error: unknown argument '$arg'"
die "ERROR: Unknown argument '$arg'"
fi
if [[ -n "$opt_latest" && -n "$opt_next" ]]; then
die "Error: -latest is incompatible with -next/-patch/-major"
die "ERROR: -latest is incompatible with -next/-patch/-major"
fi
done
}
###
### main
###
_get_release_tag () {
cd_to_project_root;
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"
die "ERROR: No recent tag found"
elif [[ -z "$opt_next" ]]; then
if [[ -n "$opt_verbose" ]]; then
printf "Latest tag\t"
@@ -159,12 +179,13 @@ _get_release_tag () {
elif [[ "$opt_next" == 'patch' ]]; then
generate_next_patch_tag "$latest_tag"
else
die "Error: should not happen. Unknown argument?"
die "ERROR: Should not happen. Unknown argument?"
fi
}
process_args "$@";
process_args "${@}"
_get_release_tag;
# dispatch main
_get_release_tag
#
+114 -30
View File
@@ -3,41 +3,82 @@
# list_apps_in_pkg
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
_list_apps_in_pkg () {
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
local tmpdir=`/usr/bin/mktemp -d -t list_apps_in_pkg`
trap "/bin/rm -rf '$tmpdir'" EXIT
###
### global variables
###
/usr/sbin/pkgutil --expand "$1" "$tmpdir/unpack"
opt_lax=''
opt_pkg=''
tmpdir=''
{
# source 1
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/Applications".*?path\s*=\s*"([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }'; \
# source 2
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/".*?path\s*=\s*"./Applications/([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
# source 3
/usr/bin/find "$tmpdir" -type d -name '*.app' | \
perl -pe 's{\A.*/}{}'; \
} | \
# merge sources
/usr/bin/sort | /usr/bin/uniq | \
# markup
###
### functions
###
warn () {
local message="$@"
if ! [[ $message =~ "\n"$ ]]; then
message="${message}\n"
fi
printf "$message" 1>&2
}
die () {
warn "$@"
exit 1
}
app_source_1 () {
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/Applications".*?path\s*=\s*"([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
app_source_2 () {
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info[^\n]*install-location="/".*?path\s*=\s*"./Applications/([^"]+)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
app_source_3 () {
/usr/bin/find "$tmpdir" -type d -name '*.app' | \
perl -pe 's{\A.*/}{}';
}
app_source_4 () {
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{path\s*=\s*"([^"]+\.app)"}sg) { my $p = $1; $p =~ s{\A.*/}{}; print "$p\n" }';
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
/usr/bin/xargs -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /bin/test -n "$(/usr/bin/find /Applications -type d -maxdepth 3 -name "{}" -print0; /usr/bin/find ~/Applications -type d -maxdepth 3 -name "{}")" && printf " (+)"; printf "\n"'
}
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_apps_in_pkg <file.pkg>
process_args () {
local arg
if [[ "$#" -eq 0 ]]; then
die "ERROR: A file argument is required"
else
opt_pkg="${!#}" # last arg
fi
for arg in "$@"; do
if [[ $arg =~ ^-+h(elp)?$ ]]; then
printf "list_apps_in_pkg [ -lax ] <file.pkg>
Given a package file, extract a list of candidate App names from
inside the pkg, which may be useful for naming a Cask.
@@ -48,7 +89,12 @@ If an App of the listed name is already installed in /Applications
or ~/Applications, it will be followed by a plus symbol '(+)' in
the output. This can be verified via 'ls' or the Finder.
This script is imperfect.
Arguments
-lax Be less selective in looking for App names. Generate
more, but less accurate, guesses.
Bugs: This script is imperfect.
- It does not fully parse PackageInfo files
- An App can be hidden within a nested archive and not found
- Some pkg files simply don't contain any Apps
@@ -56,9 +102,47 @@ This script is imperfect.
See CONTRIBUTING.md and 'man pkgutil' for more information.
"
exit
fi
exit
elif [[ $arg =~ ^-+lax$ ]]; then
opt_lax='true'
elif [[ "$arg" = "$opt_pkg" ]]; then
opt_latest='true'
else
die "ERROR: Unknown argument '$arg'"
fi
done
if ! [[ -e "$opt_pkg" ]]; then
die "ERROR: No such pkg file: '$opt_pkg'"
fi
}
_list_apps_in_pkg "$@";
###
### main
###
_list_apps_in_pkg () {
tmpdir=`/usr/bin/mktemp -d -t list_apps_in_pkg`
trap "/bin/rm -rf '$tmpdir'" EXIT
/usr/sbin/pkgutil --expand "$opt_pkg" "$tmpdir/unpack"
{
# strings that look like App names (Something.app)
app_source_1;
app_source_2;
app_source_3;
if [[ -n "$opt_lax" ]]; then
app_source_4;
fi
} | \
merge_sources | \
mark_up_sources
}
process_args "${@}"
# dispatch main
_list_apps_in_pkg
#
+53 -14
View File
@@ -3,29 +3,67 @@
# list_ids_in_pkg
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### 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
###
tmpdir=''
###
### functions
###
bundle_id_source_1 () {
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info.*?\sid(?:entifier)?\s*=\s*"([^"]*?)"}sg) { print "$1\n" }'
}
merge_sources () {
/usr/bin/sort | /usr/bin/uniq
}
clean_sources () {
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/egrep -v 'sparkle\.finish-installation$'
}
mark_up_sources () {
/usr/bin/perl -pe 's{\n}{\000}sg' | \
/usr/bin/xargs -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /usr/sbin/pkgutil --pkg-info "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
}
###
### main
###
_list_ids_in_pkg () {
local tmpdir=`/usr/bin/mktemp -d -t list_ids_in_pkg`
tmpdir=`/usr/bin/mktemp -d -t list_ids_in_pkg`
trap "/bin/rm -rf '$tmpdir'" EXIT
/usr/sbin/pkgutil --expand "$1" "$tmpdir/unpack"
/usr/bin/find "$tmpdir" -name PackageInfo -print0 | \
/usr/bin/xargs -0 /usr/bin/perl -0777 -ne \
'while (m{<pkg-info.*?\sid(?:entifier)?\s*=\s*"([^"]*?)"}sg) { print "$1\n" }' | \
/usr/bin/sort | /usr/bin/uniq | \
/usr/bin/egrep -v '^com\.apple\.' | \
/usr/bin/egrep -v 'sparkle\.finish-installation$' | \
/usr/bin/perl -pe 's{\n}{\000}sg' | \
/usr/bin/xargs -0 -I{} -n1 /bin/bash -c \
'printf "{}"; /usr/sbin/pkgutil --pkg-info "{}" >/dev/null 2>&1 && printf " (+)"; printf "\n"'
{
# emit strings that look like bundle ids
bundle_id_source_1;
} | \
merge_sources | \
clean_sources | \
mark_up_sources
}
# process args
if [[ $1 =~ ^-+h(elp)?$ || -z "$1" ]]; then
printf "list_ids_in_pkg <file.pkg>
@@ -55,6 +93,7 @@ See CONTRIBUTING.md and 'man pkgutil' for more information.
exit
fi
_list_ids_in_pkg "$@";
# dispatch main
_list_ids_in_pkg "${@}"
#
+18 -5
View File
@@ -3,14 +3,26 @@
# list_loaded_kext_ids
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### main
###
_list_loaded_kext_ids () {
/usr/sbin/kextstat -kl | /usr/bin/cut -c53- | /usr/bin/cut -f1 -d' ' | /usr/bin/egrep -v '^com\.apple\.'
/usr/sbin/kextstat -kl | \
/usr/bin/cut -c53- | \
/usr/bin/cut -f1 -d' ' | \
/usr/bin/egrep -v '^com\.apple\.'
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_loaded_kext_ids
@@ -27,6 +39,7 @@ See CONTRIBUTING.md for more information.
exit
fi
_list_loaded_kext_ids "$@";
# dispatch main
_list_loaded_kext_ids "${@}"
#
+14 -4
View File
@@ -3,9 +3,17 @@
# list_recent_pkg_ids
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### main
###
_list_recent_pkg_ids () {
/bin/ls -t /var/db/receipts | \
@@ -15,6 +23,7 @@ _list_recent_pkg_ids () {
/usr/bin/head -10
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "list_recent_pkg_ids
@@ -31,6 +40,7 @@ See CONTRIBUTING.md for more information.
exit
fi
_list_recent_pkg_ids "$@";
# dispatch main
_list_recent_pkg_ids "${@}"
#
+61 -27
View File
@@ -3,17 +3,43 @@
# production_brew_cask
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### configurable global variables
###
tap_subdir="Library/Taps/phinze-cask"
###
### functions
###
warn () {
local message="$@"
if ! [[ $message =~ "\n"$ ]]; then
message="${message}\n"
fi
printf "$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
printf "Could not find git project root"
exit 1;
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
@@ -22,12 +48,19 @@ cd_to_version_dir () {
local cellar_dir="$1"
local version_dir="$2"
if [[ -z "$version_dir" ]]; then
printf "Can't get version dir under $cellar_dir/\n";
exit 1;
die "ERROR: Could not find version dir under $cellar_dir/"
fi
cd "$cellar_dir/$version_dir"
}
not_inside_homebrew () {
local tap_dir="$1"
local git_root="$2"
if [[ "$(/usr/bin/stat -L -f '%i' "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' "$git_root")" ]]; then
die "\nERROR: Run this script in your private repo, not inside Homebrew.\n"
fi
}
remove_dev_links () {
local tap_dir="$1"
/bin/rm rubylib Casks
@@ -37,53 +70,54 @@ remove_dev_links () {
/bin/rm lib Casks
/bin/mv production_lib lib
/bin/mv production_Casks Casks
printf "brew-cask is now in production mode\n"
printf "It is safe to run 'brew update' if you are in production mode for all Caskroom repos.\n"
}
###
### main
###
_production_brew_cask () {
# configurable
local tap_subdir="Library/Taps/phinze-cask"
# initialization
cd_to_project_root;
local git_root="$(pwd)"
cd_to_project_root
local git_root="$(/bin/pwd)"
local brew_prefix="$(brew --prefix)"
local cellar_dir="$brew_prefix/Cellar/brew-cask"
local version_dir="$(/bin/ls "$cellar_dir/" | /usr/bin/sort | /usr/bin/tail -1)"
local tap_dir="$brew_prefix/$tap_subdir"
# sanity check
if [[ "$(/usr/bin/stat -L -f '%i' "$tap_dir")" -eq "$(/usr/bin/stat -L -f '%i' "$git_root")" ]]; then
printf "\nERROR: run this script in your private repo, not inside Homebrew.\n"
exit 1;
fi
not_inside_homebrew "$tap_dir" "$git_root"
# action
cd_to_version_dir "$cellar_dir" "$version_dir";
cd_to_version_dir "$cellar_dir" "$version_dir"
if [[ -e "production_rubylib" ]]; then
remove_dev_links "$tap_dir";
printf "brew-cask is now in production mode\n"
printf "It is safe to run 'brew update'\n"
remove_dev_links "$tap_dir"
else
printf "brew-cask is already set up for production\n"
exit 1
die "brew-cask is already set up for production"
fi
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "production_brew_cask
Undo all symlinks created by 'develop_brew_cask' so that
the 'brew cask' command will use only released code within
Homebrew.
Undo all symlinks created by 'develop_brew_cask' so that the
'brew cask' command will use only released code and Casks
within Homebrew.
After running this command it is safe to run 'brew update'.
After running this command it is safe to run 'brew update',
unless you are using similar scripts to create symlinks into
other Caskroom development repos.
"
exit
fi
_production_brew_cask "$@";
# dispatch main
_production_brew_cask "${@}"
#
+123 -48
View File
@@ -5,77 +5,96 @@
# stats on project/release from git database
#
set -e; # exit on any uncaught error
set +o histexpand; # don't expand history expressions
shopt -s nocasematch; # case-insensitive regular expressions
###
### settings
###
set -e # exit on any uncaught error
set +o histexpand # don't expand history expressions
shopt -s nocasematch # case-insensitive regular expressions
###
### configurable global variables
###
# these paths relative to project root
declare -a cask_paths=(Casks)
declare -a code_paths=(bin developer lib test brew-cask.rb Rakefile Gemfile Gemfile.lock .travis.yml .gitignore)
declare -a doc_paths=(doc LICENSE "*.md")
end_object="HEAD"
###
### global variables
###
cask_authors=''
###
### functions
###
warn () {
local message="$@"
if ! [[ $message =~ "\n"$ ]]; then
message="${message}\n"
fi
printf "$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
printf "Could not find git project root"
exit 1;
die "ERROR: Could not find git project root"
fi
cd "$git_root"
}
warn_if_off_branch () {
local branch="$(git rev-parse --abbrev-ref HEAD)"
local wanted_branch='master'
if [[ -n "$1" ]]; then
wanted_branch="$1"
fi
if [[ "$branch" != "$wanted_branch" ]]; then
printf "\nWARNING: you are running from branch '$branch', not '$wanted_branch'\n\n"
local current_branch="$(git rev-parse --abbrev-ref HEAD)"
if ! [[ "$current_branch" = "$wanted_branch" ]]; then
warn "\nWARNING: you are running from branch '$current_branch', not '$wanted_branch'\n\n"
fi
}
verify_git_object () {
if ! git rev-parse --verify "$1" > /dev/null 2>/dev/null; then
printf "\nERROR: No such commit object: $1\n\n"
exit 1
local object="$1"
if ! git rev-parse --verify "$object" -- >/dev/null 2>&1; then
die "\nERROR: No such commit object: '$object'\n\n"
fi
}
_homebrew_cask_project_stats () {
local initial_commit="5a0d1d5556e3f963a0d34da46e16ecffa59ea2fc"
local start_object="$initial_commit"
local end_object="HEAD"
# these paths relative to project root
local cask_paths="Casks"
local code_paths="bin developer lib test brew-cask.rb Rakefile Gemfile Gemfile.lock"
local doc_paths="LICENSE *.md"
cd_to_project_root;
warn_if_off_branch 'master';
if [[ "$1" = 'release' ]]; then
start_object="$(git describe --tags --abbrev=0)"
elif [[ -n "$1" ]]; then
start_object="$1"
fi
verify_git_object "$start_object";
print_contributor_stats () {
local start_object="$1"
local initial_commit="$2"
local git_log_cmd="git log --no-merges --format='%ae' ${start_object}..${end_object}"
printf "Unique contributors"
if [[ "$start_object" != "$initial_commit" ]]; then
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf " since $start_object"
fi
printf "\n"
local git_log_cmd="git log --no-merges --format='%ae' ${start_object}..${end_object}"
local cask_authors="$($git_log_cmd -- $cask_paths | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
cask_authors="$($git_log_cmd -- "${cask_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
printf " Casks\t$cask_authors\n"
printf " code\t"
$git_log_cmd -- $code_paths | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
$git_log_cmd -- "${code_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
printf " docs\t"
$git_log_cmd -- $doc_paths | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
$git_log_cmd -- "${doc_paths[@]}" | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
printf " any\t"
$git_log_cmd -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
if [[ "$start_object" != "$initial_commit" ]]; then
$git_log_cmd -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l
if ! [[ "$start_object" = "$initial_commit" ]]; then
local alltime_contribs="$(git log --no-merges --format='%ae' ${initial_commit}..${end_object} -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local prior_contribs="$(git log --no-merges --format='%ae' ${initial_commit}..${start_object} -- . | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
# arithmetic removes whitespace
@@ -84,13 +103,42 @@ _homebrew_cask_project_stats () {
printf "\nAll-time contributors\t$alltime_contribs\n"
printf "New contributors since $start_object\t$new_contribs\n"
fi
printf "\n"
}
if [[ "$start_object" != "$initial_commit" ]]; then
local new_casks="$(git diff --name-status "$start_object" "$end_object" -- $cask_paths | /usr/bin/grep '^A.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local deleted_casks="$(git diff --name-status "$start_object" "$end_object" -- $cask_paths | /usr/bin/grep '^D.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local updated_casks="$(git diff --name-status "$start_object" "$end_object" -- $cask_paths | /usr/bin/grep '^M.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
print_commit_stats () {
local start_object="$1"
local initial_commit="$2"
local git_log_cmd="git log --no-merges --format='%ae' ${start_object}..${end_object}"
printf "Commit count"
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf " since $start_object"
fi
printf "\n"
printf " Casks\t"
$git_log_cmd -- "${cask_paths[@]}" | /usr/bin/wc -l
printf " code\t"
$git_log_cmd -- "${code_paths[@]}" | /usr/bin/wc -l
printf " docs\t"
$git_log_cmd -- "${doc_paths[@]}" | /usr/bin/wc -l
printf " any\t"
$git_log_cmd -- . | /usr/bin/wc -l
if ! [[ "$start_object" = "$initial_commit" ]]; then
printf "\nAll-time commits\t"
git log --no-merges --format='%ae' "${initial_commit}".."${end_object}" -- . | /usr/bin/wc -l
fi
printf "\n"
}
print_cask_stats () {
local start_object="$1"
local initial_commit="$2"
if ! [[ "$start_object" = "$initial_commit" ]]; then
local new_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^A.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local deleted_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^D.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
local updated_casks="$(git diff --name-status "$start_object" "$end_object" -- "${cask_paths[@]}" | /usr/bin/grep '^M.*\.rb' | cut -f2 | /usr/bin/sort | /usr/bin/uniq | /usr/bin/wc -l)"
# arithmetic removes whitespace
((cask_authors += 0))
((deleted_casks += 0))
@@ -100,10 +148,36 @@ _homebrew_cask_project_stats () {
fi
printf "Total current Casks in HEAD\t"
/usr/bin/find $cask_paths -name '*.rb' | /usr/bin/wc -l
/usr/bin/find "${cask_paths[@]}" -name '*.rb' | /usr/bin/wc -l
}
###
### main
###
_project_stats () {
local arg_object="$1"
cd_to_project_root
warn_if_off_branch 'master'
local initial_commit="$(git log --pretty=format:%H -- | /usr/bin/tail -1)"
verify_git_object "$initial_commit"
local start_object="$initial_commit"
if [[ "$arg_object" = 'release' ]]; then
start_object="$(./developer/bin/get_release_tag)"
elif [[ -n "$arg_object" ]]; then
start_object="$arg_object"
fi
verify_git_object "$start_object"
print_contributor_stats "$start_object" "$initial_commit"
print_commit_stats "$start_object" "$initial_commit"
print_cask_stats "$start_object" "$initial_commit"
}
# process args
if [[ $1 =~ ^-+h(elp)?$ ]]; then
printf "project_stats [ <commit-object> ]
@@ -119,6 +193,7 @@ Without argument, show statistics since first commit.
exit
fi
_homebrew_cask_project_stats "$@";
# dispatch main
_project_stats "${@}"
#