diff --git a/.editorconfig b/.editorconfig index f273d302..abd7452a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,6 +4,6 @@ root = true end_of_line = lf insert_final_newline = true -[{vcsh,_vcsh_bash}] +[{vcsh.in,completions/vcsh.*}] indent_style = tab trim_trailing_whitespace = true diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 74546148..749157df 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,6 +13,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + - name: Configure + run: | + ./bootstrap.sh + ./configure --without-man-page --disable-tests - name: Run shellcheck uses: reviewdog/action-shellcheck@v1.0.0 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..c3bdfa1b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,39 @@ +name: Release + +on: + push: + tags: + - v*.*.* + +jobs: + + ghrelase: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Configure + run: | + echo "VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV + echo "${GITHUB_REF#refs/*/v}" > .tarball-version + ./bootstrap.sh + ./configure --disable-dependency-checks + - name: Build source package + run: | + make dist + - name: Check source package behaviour + run: | + make distcheck + - name: Make sure changelog was updated + run: | + make changelog-HEAD + grep -F "* Release ${{ env.VERSION }}" changelog-HEAD + - name: Publish Release + uses: softprops/action-gh-release@v1 + with: + body_path: changelog-HEAD + files: | + vcsh-${{ env.VERSION }}.zip + vcsh-${{ env.VERSION }}.tar.xz + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3a674d1..c1808e01 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,15 +6,33 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Install build dependencies + with: + fetch-depth: 0 + - name: Fetch tags + run: | + git fetch --prune --tags ||: + - name: Install dependencies run: | - sudo apt-get install ruby-ronn + sudo apt install ronn - name: Install perl test dependencies uses: perl-actions/install-with-cpanm@v1.1 with: install: | Shell::Command Test::Most + - name: Configure + run: | + ./bootstrap.sh + ./configure - name: Run tests run: | - make test + make check + - name: Build source package + run: | + make dist + echo VERSION=$(cat .version) >> $GITHUB_ENV + - name: Post build artifacts + uses: actions/upload-artifact@v2 + with: + name: vcsh-${{ env.VERSION }} + path: vcsh-${{ env.VERSION }}.zip diff --git a/.gitignore b/.gitignore index 4dec9bf3..2562f6ab 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,18 @@ vcsh.1 *.swp .swp *.bak +.version +.version-prev +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +build-aux/install-sh +build-aux/missing +completions/_vcsh +completions/vcsh +config.log +config.status +configure +/vcsh +vcsh-* diff --git a/CONTRIBUTORS b/CONTRIBUTORS index cf286198..8cd4d5f3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,41 +1,66 @@ -Alphabetical list of surnames of everyone who ever committed to this repository. -Auto-generated from tools/list_CONTRIBUTORS. +Alphabetical list of names of everyone who ever committed to this repository. +Auto-generated using `make -B CONTRIBUTORS` -Skurikhin Alexander -Eric Bouchut -Dridi Boukelmoune -Rob Cornish -Vincent Demeester -Mert Dirik -Jeff Fein-Worton -Thomas Ferris Nicolaisen -martin f. krafft +Aaron Schumacher +Aaron VonderHaar Alessandro Ghedini -Dennis Gilmore -Thorsten Glaser -G.raud -Mikhail Gusarov -Valentin Haenel -Richard Hartmann -Gregor Jasny -Errietta Kostala -Yuval Langer +Alexander Skurikhin +Andrew Schwartzmeyer +arndtc +Aryel Mota Góis Caleb Maclennan -Markus Martin -mek-apelsin -Evan Pitstick -Dieter Plaetinck Corey Quinn -Pavlos Ratis +Daniel Shahaf +Dato Simó +Debian Janitor +Dennis Gilmore +Devin J. Pohly Dewey Sasser +Dieter Plaetinck +Don +Don March +Dridi Boukelmoune +Edward Betts +Eli Young +Eric Bouchut +Errietta Kostala +Evan Pitstick +Fedora Release Engineering +Felix Eckhofer +Florian Engel +Frank Terbeck Gernot Schulz -Aaron Schumacher -Andrew Schwartzmeyer -Dato Simó -Alexander Skurikhin +G.raud +Gregor Jasny +guy hughes +Harendra Kumar +James Davidson +Jeff Fein-Worton +Jochen Keil Jonathan Sternberg +Julien Lecomte +Kevin Lyda +leycec +Markus Martin +martin f. krafft Mathias Svensson -Frank Terbeck +mek-apelsin +Mert Dirik +Mikhail Gusarov mirabilos -Aaron VonderHaar +miramir +Noah Birnel +Pavlos Ratis +Richard Hartmann +Rob Cornish +Roland Hopferwieser +Skurikhin Alexander +soulofmischief <30357883+soulofmischief@users.noreply.github.com> +Thomas Ferris Nicolaisen +Thomas Tuegel +Thorsten Glaser +tikki Tony +Valentin Haenel +Vincent Demeester +Yuval Langer diff --git a/Makefile b/Makefile deleted file mode 100644 index 43fb92db..00000000 --- a/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -PREFIX?=/usr -DOCDIR_PREFIX=$(PREFIX)/share/doc -DOCDIR=$(DOCDIR_PREFIX)/$(self) -ZSHDIR=$(PREFIX)/share/zsh/vendor-completions -RONN ?= ronn - -self=vcsh -manpages=$(self).1 -all=manpages - -all: $(all) - -install: all - install -d $(DESTDIR)$(PREFIX)/bin - install -m 0755 $(self) $(DESTDIR)$(PREFIX)/bin - install -d $(DESTDIR)$(PREFIX)/share/man/man1 - install -m 0644 $(manpages) $(DESTDIR)$(PREFIX)/share/man/man1 - install -d $(DESTDIR)$(DOCDIR) - install -m 0644 README.md $(DESTDIR)$(DOCDIR) - install -m 0644 doc/hooks $(DESTDIR)$(DOCDIR) - install -d $(DESTDIR)$(ZSHDIR) - install -m 0644 _$(self) $(DESTDIR)$(ZSHDIR) - -manpages: $(manpages) - -$(self).1: doc/$(self).1.ronn - $(RONN) < doc/$(self).1.ronn > $(self).1 || rm $(self).1 - -clean: - rm -rf $(self).1 - -uninstall: - rm -rf $(DESTDIR)$(PREFIX)/bin/$(self) - rm -rf $(DESTDIR)$(PREFIX)/share/man/man1/$(self).1 - rm -rf $(DESTDIR)$(DOCDIR) - rm -rf $(DESTDIR)$(ZSHDIR)/_$(self) - -# Potentially harmful, used a non-standard option on purpose. -# If PREFIX=/usr/local and that's empty... -purge: uninstall - rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(PREFIX)/bin/ - rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(PREFIX)/share/man/man1/ - rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(DOCDIR) - rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(ZSHDIR) - -test: - @if which git > /dev/null; then : ; else echo "'git' not found, exiting..." ; exit 1; fi - @if which prove > /dev/null; then prove; else echo "'prove' not found; not running tests"; fi diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..ca452654 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,99 @@ +ACLOCAL_AMFLAGS = -I build-aux + +.ONESHELL: +.SECONDARY: +.SECONDEXPANSION: +.DELETE_ON_ERROR: + +docdir = $(datarootdir)/doc/$(TRANSFORMED_PACKAGE_NAME) +licensedir = $(datarootdir)/licenses/$(TRANSFORMED_PACKAGE_NAME) + +dist_doc_DATA = changelog doc/INSTALL.md doc/README.md doc/error_codes.md +samplehooksdir = $(docdir)/sample_hooks +dist_samplehooks_DATA = doc/sample_hooks/post-init-add-origin doc/sample_hooks/post-init-setup-mr doc/sample_hooks/post-merge-unclobber doc/sample_hooks/pre-merge-unclobber +dist_license_DATA = LICENSE CONTRIBUTORS +if ENABLE_MAN_PAGE +dist_man_MANS = vcsh.1 +endif +bin_SCRIPTS = vcsh + +EXTRA_DIST = completions/vcsh.bash completions/vcsh.zsh build-aux/git-version-gen build-aux/ax_prog_perl_modules.m4 + +BUILT_SOURCES = .version +CLEANFILES = $(BUILT_SOURCES) .version-prev $(dist_man_MANS) $(bin_SCRIPTS) + +if ENABLE_BASH_COMPLETION +bashcompletiondir = $(BASH_COMPLETION_DIR) +nodist_bashcompletion_DATA = completions/$(TRANSFORMED_PACKAGE_NAME) +CLEANFILES += $(nodist_bashcompletion_DATA) +endif + +if ENABLE_ZSH_COMPLETION +zshcompletiondir = $(ZSH_COMPLETION_DIR) +nodist_zshcompletion_DATA = completions/_$(TRANSFORMED_PACKAGE_NAME) +CLEANFILES += $(nodist_zshcompletion_DATA) +endif + +vcsh.1: doc/vcsh.1.ronn + $(RONN) < $< > $@ + +completions/$(TRANSFORMED_PACKAGE_NAME): completions/vcsh.bash + mkdir -p $(dir $@) + cp -bf $< $@ + +completions/_$(TRANSFORMED_PACKAGE_NAME): completions/vcsh.zsh + mkdir -p $(dir $@) + cp -bf $< $@ + +.version: $(shell $(AWK) '{print ".git/" $$2}' .git/HEAD 2>/dev/null ||:) + [ -e "$@" ] && mv "$@" "$@-prev" || $(if $<,touch,cp "$(srcdir)/.tarball-version") "$@-prev" + $(if $<,./build-aux/git-version-gen "$(srcdir)/.tarball-version",printf "$(VERSION)") > "$@" + $(CMP) -s "$@" "$@-prev" || autoreconf configure.ac --force + +_CHECKDEPS = check-version + +if ENABLE_TESTS +_CHECKDEPS += prove +endif + +check-local: $(_CHECKDEPS) + +installcheck-local: + ./$(TRANSFORMED_PACKAGE_NAME) version + +.PHONY: check-version +check-version: vcsh | .version + $(GREP) -Fx '$(VERSION)' $| + ./$< version | $(GREP) -Ff $| + ./$< version | $(GREP) -Ff <($(GIT) version) + +.PHONY: prove +prove: + prove + +.PHONY: test +test: prove + +.PHONY: lint +lint: lint-editor-config lint-shellcheck + +.PHONY: lint-editor-config +lint-editor-config: + ec + +.PHONY: lint-shellheck +lint-shellcheck: vcsh + shellcheck $< + +CONTRIBUTORS: + exec > $@ + echo 'Alphabetical list of names of everyone who ever committed to this repository.' + echo 'Auto-generated using `make -B CONTRIBUTORS`' + echo + $(GIT) shortlog -se --all | cut -f1 --complement | sort -u + +changelog-HEAD: changelog + sed -nEe '2d;s/^\t//p;/^$$/q;' $< > $@ + +dist-hook: + printf "$(VERSION)" > "$(distdir)/.tarball-version" diff --git a/README.md b/README.md index e1df357f..77ce7cd5 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,9 @@ All slides, videos, and further information can be found # Installation A lot of modern UNIX-based systems offer packages for `vcsh`. In case yours -does not, read [INSTALL.md](doc/INSTALL.md) for install instructions or -[PACKAGING.md](doc/PACKAGING.md) to create a package yourself. If you do end -up packaging `vcsh` please let us know so we can give you your own packaging -branch in the upstream repository. +does not, read [INSTALL.md](doc/INSTALL.md) for instructions on installing from +sources or even create a package for your system. If you do end up packaging +`vcsh` please let us know so we can document package availability. # Contact diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 00000000..0d8d2841 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +set -e + +incomplete_source () { + printf '%s\n' \ + "$1. Please either:" \ + "* $2," \ + "* or use the source packages instead of a repo archive" \ + "* or use a full Git clone." >&2 + exit 1 +} + +# This enables easy building from Github's snapshot archives +if [ ! -e ".git" ]; then + if [ ! -f ".tarball-version" ]; then + incomplete_source "No version information found" \ + "identify the correct version with \`echo \$version > .tarball-version\`" + fi +else + # Just a head start to save a ./configure cycle + ./build-aux/git-version-gen .tarball-version > .version +fi + +autoreconf --install diff --git a/build-aux/ax_prog_perl_modules.m4 b/build-aux/ax_prog_perl_modules.m4 new file mode 100644 index 00000000..70b3230e --- /dev/null +++ b/build-aux/ax_prog_perl_modules.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_prog_perl_modules.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_PERL_MODULES([MODULES], [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# Checks to see if the given perl modules are available. If true the shell +# commands in ACTION-IF-TRUE are executed. If not the shell commands in +# ACTION-IF-FALSE are run. Note if $PERL is not set (for example by +# calling AC_CHECK_PROG, or AC_PATH_PROG), AC_CHECK_PROG(PERL, perl, perl) +# will be run. +# +# MODULES is a space separated list of module names. To check for a +# minimum version of a module, append the version number to the module +# name, separated by an equals sign. +# +# Example: +# +# AX_PROG_PERL_MODULES( Text::Wrap Net::LDAP=1.0.3, , +# AC_MSG_WARN(Need some Perl modules) +# +# LICENSE +# +# Copyright (c) 2009 Dean Povey +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_PERL_MODULES], [AX_PROG_PERL_MODULES]) +AC_DEFUN([AX_PROG_PERL_MODULES],[dnl + +m4_define([ax_perl_modules]) +m4_foreach([ax_perl_module], m4_split(m4_normalize([$1])), + [ + m4_append([ax_perl_modules], + [']m4_bpatsubst(ax_perl_module,=,[ ])[' ]) + ]) + +# Make sure we have perl +if test -z "$PERL"; then +AC_CHECK_PROG(PERL,perl,perl) +fi + +if test "x$PERL" != x; then + ax_perl_modules_failed=0 + for ax_perl_module in ax_perl_modules; do + AC_MSG_CHECKING(for perl module $ax_perl_module) + + # Would be nice to log result here, but can't rely on autoconf internals + $PERL -e "use $ax_perl_module; exit" > /dev/null 2>&1 + if test $? -ne 0; then + AC_MSG_RESULT(no); + ax_perl_modules_failed=1 + else + AC_MSG_RESULT(ok); + fi + done + + # Run optional shell commands + if test "$ax_perl_modules_failed" = 0; then + : + $2 + else + : + $3 + fi +else + AC_MSG_WARN(could not find perl) +fi])dnl diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen new file mode 100755 index 00000000..e80e810e --- /dev/null +++ b/build-aux/git-version-gen @@ -0,0 +1,220 @@ +#!/usr/bin/env sh + +# Print a version string. +scriptversion=2012-03-18.17; # UTC + +# Copyright (C) 2007-2012 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. +# It may be run two ways: +# - from a git repository in which the "git describe" command below +# produces useful output (thus requiring at least one signed tag) +# - from a non-git-repo directory containing a .tarball-version file, which +# presumes this script is invoked like "./git-version-gen .tarball-version". + +# In order to use intra-version strings in your project, you will need two +# separate generated version string files: +# +# .tarball-version - present only in a distribution tarball, and not in +# a checked-out repository. Created with contents that were learned at +# the last time autoconf was run, and used by git-version-gen. Must not +# be present in either $(srcdir) or $(builddir) for git-version-gen to +# give accurate answers during normal development with a checked out tree, +# but must be present in a tarball when there is no version control system. +# Therefore, it cannot be used in any dependencies. GNUmakefile has +# hooks to force a reconfigure at distribution time to get the value +# correct, without penalizing normal development with extra reconfigures. +# +# .version - present in a checked-out repository and in a distribution +# tarball. Usable in dependencies, particularly for files that don't +# want to depend on config.h but do want to track version changes. +# Delete this file prior to any autoconf run where you want to rebuild +# files to pick up a version string change; and leave it stale to +# minimize rebuild time after unrelated changes to configure sources. +# +# As with any generated file in a VC'd directory, you should add +# /.version to .gitignore, so that you don't accidentally commit it. +# .tarball-version is never generated in a VC'd directory, so needn't +# be listed there. +# +# Use the following line in your configure.ac, so that $(VERSION) will +# automatically be up-to-date each time configure is run (and note that +# since configure.ac no longer includes a version string, Makefile rules +# should not depend on configure.ac for version updates). +# +# AC_INIT([GNU project], +# m4_esyscmd([build-aux/git-version-gen .tarball-version]), +# [bug-project@example]) +# +# Then use the following lines in your Makefile.am, so that .version +# will be present for dependencies, and so that .version and +# .tarball-version will exist in distribution tarballs. +# +# EXTRA_DIST = $(top_srcdir)/.version +# BUILT_SOURCES = $(top_srcdir)/.version +# $(top_srcdir)/.version: +# echo $(VERSION) > $@-t && mv $@-t $@ +# dist-hook: +# echo $(VERSION) > $(distdir)/.tarball-version + + +me=$0 + +version="git-version-gen $scriptversion + +Copyright 2011 Free Software Foundation, Inc. +There is NO warranty. You may redistribute this software +under the terms of the GNU General Public License. +For more information about these matters, see the files named COPYING." + +usage="\ +Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT] +Print a version string. + +Options: + + --prefix prefix of git tags (default 'v') + + --help display this help and exit + --version output version information and exit + +Running without arguments will suffice in most cases." + +prefix=v + +while test $# -gt 0; do + case $1 in + --help) echo "$usage"; exit 0;; + --version) echo "$version"; exit 0;; + --prefix) shift; prefix="$1";; + -*) + echo "$0: Unknown option '$1'." >&2 + echo "$0: Try '--help' for more information." >&2 + exit 1;; + *) + if test -z "$tarball_version_file"; then + tarball_version_file="$1" + elif test -z "$tag_sed_script"; then + tag_sed_script="$1" + else + echo "$0: extra non-option argument '$1'." >&2 + exit 1 + fi;; + esac + shift +done + +if test -z "$tarball_version_file"; then + echo "$usage" + exit 1 +fi + +tag_sed_script="${tag_sed_script:-s/x/x/}" + +nl=' +' + +# Avoid meddling by environment variable of the same name. +v= +v_from_git= + +# First see if there is a tarball-only version file. +# then try "git describe", then default. +if test -f $tarball_version_file +then + v=`cat $tarball_version_file` || v= + case $v in + *$nl*) v= ;; # reject multi-line output + [0-9]*) ;; + *) v= ;; + esac + test -z "$v" \ + && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2 +fi + +if test -n "$v" +then + : # use $v +# Otherwise, if there is at least one git commit involving the working +# directory, and "git describe" output looks sensible, use that to +# derive a version string. +elif test "`git log -1 --pretty=format:x . 2>/dev/null`" = x \ + && v=`git describe --tags --abbrev=7 --match="$prefix*" HEAD 2>/dev/null \ + || git describe --tags --abbrev=7 HEAD 2>/dev/null \ + || git log -1 --pretty=format:'v0-HEAD-%h' 2>/dev/null` \ + && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ + && case $v in + $prefix[0-9]*) ;; + *) (exit 1) ;; + esac +then + # Is this a new git that lists number of commits since the last + # tag or the previous older version that did not? + # Newer: v6.10-77-g0f8faeb + # Older: v6.10-g0f8faeb + case $v in + *-*-*) : git describe is okay three part flavor ;; + *-*) + : git describe is older two part flavor + # Recreate the number of commits and rewrite such that the + # result is the same as if we were using the newer version + # of git describe. + vtag=`echo "$v" | sed 's/-.*//'` + commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \ + || { commit_list=failed; + echo "$0: WARNING: git rev-list failed" 1>&2; } + numcommits=`echo "$commit_list" | wc -l` + v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; + test "$commit_list" = failed && v=UNKNOWN + ;; + esac + + v=`echo "$v" | sed 's/-/.r/'`; + v_from_git=1 +else + v=UNKNOWN +fi + +v=`echo "$v" |sed "s/^$prefix//"` + +# Test whether to append the "-dirty" suffix only if the version +# string we're using came from git. I.e., skip the test if it's "UNKNOWN" +# or if it came from .tarball-version. +if test -n "$v_from_git"; then + # Don't declare a version "dirty" merely because a time stamp has changed. + git update-index --refresh > /dev/null 2>&1 + + dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty= + case "$dirty" in + '') ;; + *) # Append the suffix only if there isn't one already. + case $v in + *-dirty) ;; + *) v="$v-dirty" ;; + esac ;; + esac +fi + +# Omit the trailing newline, so that m4_esyscmd can use the result directly. +echo "$v" | tr -d "$nl" + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/changelog b/changelog index 9afbcd59..a63821b0 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,25 @@ +unreleased + + * Replace homegrown Makefile with Autotools for configure and build + * Post source builds as part of automated release process + * Switch to versioning scheme to semver + * Replace Travis test runner with GitHub Actions + * Make VCSH_* variables available to hooks + * More carefully handle shell quoting + * Improve handling of non-default remote names and branches + * Fix per-repo pre/post hook handling + * Output path relative to $HOME in ‘vcsh status’ + * Add flag to prefix output of ‘vcsh foreach -p’ with repo name + * Fix debugging on Windows 10 / Cygwin + * Improve option flag handling to allow multiple flags, squash bugs + * Don't require Ruby or Perl tooling to build and install + * Avoid false-positive conflicts on checkout + * Make arg optional for write-ignore subcommand + * Fix ZSH completions, improve Bash completions + * Allow use of specific path when running Git or any dependency + * Fail if hook scripts return failure codes + * Check GIT_REMOTE early on clone() + 2021-04-05 Richard Hartmann * Release 1.20190621 diff --git a/_vcsh_bash b/completions/vcsh.bash similarity index 94% rename from _vcsh_bash rename to completions/vcsh.bash index 2ee12064..47367a54 100644 --- a/_vcsh_bash +++ b/completions/vcsh.bash @@ -1,5 +1,3 @@ -# bash completion for vcsh. - # run git command # based on bash_completion:_command_offset() _vcsh_git_command () { @@ -68,8 +66,7 @@ _vcsh () { for r in "${reponames[@]}"; do repos["$r"]="$r"; done unset r reponames local cmds - cmds="clone delete enter foreach help init list list-tracked list-untracked - pull push rename run status upgrade version which write-gitignore" + cmds="clone delete enter foreach help init list list-tracked list-untracked pull push rename run status upgrade version which write-gitignore" local subcword cmd subcmd for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do @@ -146,9 +143,3 @@ _vcsh () { } complete -F _vcsh vcsh - -# Local Variables: -# mode:shell-script -# sh-shell:bash -# End: -# vim: ft=sh: diff --git a/_vcsh b/completions/vcsh.zsh similarity index 97% rename from _vcsh rename to completions/vcsh.zsh index 72924ce2..a3c964db 100644 --- a/_vcsh +++ b/completions/vcsh.zsh @@ -99,7 +99,7 @@ function _vcsh () { local -a args subcommands local VCSH_REPO_D - : ${VCSH_REPO_D:="${XDG_CONFIG_HOME:-"$HOME/.config"}/vcsh/repo.d"} + : ${VCSH_REPO_D:="${XDG_CONFIG_HOME:-"$HOME/.config"}/vcsh/repo.d"} subcommands=( "clone:clone an existing repository" diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..19b0747d --- /dev/null +++ b/configure.ac @@ -0,0 +1,87 @@ +AC_PREREQ([2.69]) +AC_INIT([vcsh], [m4_esyscmd(build-aux/git-version-gen .tarball-version)]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([foreign tar-pax dist-xz dist-zip no-dist-gzip color-tests]) +AM_SILENT_RULES([yes]) +AC_CONFIG_MACRO_DIR([build-aux]) + +AC_DEFUN([AX_PROGVAR], [ + test -n "$m4_toupper($1)" || AC_PATH_PROG(m4_toupper($1), m4_default($2,$1)) + test -n "$m4_toupper($1)" || AC_MSG_ERROR([m4_default($2,$1) is required]) + ]) + +AC_PROG_AWK +AC_PROG_GREP +AC_PROG_SED + +AX_PROGVAR([comm]) +AX_PROGVAR([cmp]) +AX_PROGVAR([git]) + +AC_ARG_WITH([man-page], + AS_HELP_STRING([--with-man-page], + [Generate man page @<:@default=yes@:>@]), + [], + [with_man_page=yes]) +if test x"$with_man_page" = x"yes"; then + AX_PROGVAR([ronn]) +fi +AM_CONDITIONAL([ENABLE_MAN_PAGE], + [test x"$with_man_page" != x"no"]) + +AS_IF([test -e .tarball-version], + m4_define([TESTDEF], [yes]), + m4_define([TESTDEF], [no])) +AC_ARG_ENABLE([tests], + AS_HELP_STRING([--disable-tests], + [Configure tooling to run tests @<:@default=TESTDEF@:>@]), + [], + [enable_tests=TESTDEF]) +AM_CONDITIONAL([ENABLE_TESTS],[test x"$enable_tests" != x"no"]) + +AS_IF([test x"$enable_tests" != x"no"], [ + AX_PROGVAR([prove]) + AX_PROG_PERL_MODULES(Shell::Command, [], + AC_MSG_ERROR(Perl module required for testing not found)) + AX_PROG_PERL_MODULES(Test::Most, [], + AC_MSG_ERROR(Perl module required for testing not found)) +]) + +AC_ARG_WITH([bash-completion-dir], + AS_HELP_STRING([--with-bash-completion-dir[=PATH]], + [Install bash auto-completion definitions to a directory. @<:@default=yes@:>@]), + [], + [with_bash_completion_dir=yes]) +AS_IF([test x"$with_bash_completion_dir" = x"yes"], + [PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], + [BASH_COMPLETION_DIR="$(pkg-config --define-variable=datadir=$datadir --variable=completionsdir bash-completion)"], + [BASH_COMPLETION_DIR="$datadir/bash-completion/completions"])], + [BASH_COMPLETION_DIR="$with_bash_completion_dir"]) +AC_SUBST([BASH_COMPLETION_DIR]) +AM_CONDITIONAL([ENABLE_BASH_COMPLETION], + [test x"$with_bash_completion_dir" != x"no"]) + +AC_ARG_WITH([zsh-completion-dir], + AS_HELP_STRING([--with-zsh-completion-dir[=PATH]], + [Install zsh auto-completion definitions to a directory. @<:@default=yes@:>@]), + [], + [with_zsh_completion_dir=yes]) +if test x"$with_zsh_completion_dir" = x"yes"; then + ZSH_COMPLETION_DIR="$datadir/zsh/site-functions" +else + ZSH_COMPLETION_DIR="$with_zsh_completion_dir" +fi +AC_SUBST([ZSH_COMPLETION_DIR]) +AM_CONDITIONAL([ENABLE_ZSH_COMPLETION], + [test x"$with_zsh_completion_dir" != x"no"]) + +TRANSFORMED_PACKAGE_NAME="$(printf "$PACKAGE_NAME" | $SED -e "${program_transform_name//\$\$/\$}")" +AC_SUBST([TRANSFORMED_PACKAGE_NAME]) + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([vcsh], [chmod +x vcsh]) +AC_CONFIG_FILES([doc/vcsh.1.ronn]) + +AC_ARG_PROGRAM + +AC_OUTPUT diff --git a/doc/INSTALL.md b/doc/INSTALL.md index 3fbf129f..c2965e63 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -1,59 +1,127 @@ -# Pre-requisites # +# Distro Packages -If you want to build the manpage, you will need [ronn] [1]. -Debian 7.0 and above come with a package, so do most Debian clones. +Many distributions have packages ready to go. +If yours doesn't, you can install [from source](#installing-from-source). +If you package VCSH for a distro please let us know. -To install ronn on your Debian-based system, simply run +## Arch Linux - apt-get install ruby-ronn +Use your favorite AUR helper to build and install the [vcsh](https://aur.archlinux.org/packages/vcsh) package: -There are no other dependencies other than `git`, `ronn` and a POSIX shell. +```console +$ paru -S aur +``` +## CentOS / Fedora / RedHat -# Installing # +```console +$ yum install vcsh +``` - sudo make install +## Debian / Deepin / Kali Linux / Parrot / PureOS / Raspbian / Trisquel / Ubuntu -## Installing without root privileges ## +```console +$ apt install vcsh +``` - make install DESTDIR=/home/myuser/local +## Gentoo / Funtoo / LiGurOS -or simply copy the shell script into any place you like, e.g. `~/bin` +```console +$ emerge --ask dev-vcs/vcsh +``` +## GNU Guix -# Uninstalling # +```console +$ guix install vcsh +``` - sudo make uninstall +## Homebrew (macOS) / Linuxbrew -There is another, more thorough, version. Just make sure you are not running -this when you have installed to an important directory which is empty, -otherwise. +```console +$ brew install vcsh +``` -**THIS WILL DELETE /usr/local IF YOU INSTALLED THERE AND IT BECOMES EMPTY** +## KISS Linux - sudo make purge +```console +$ kiss install vcsh +``` -**THIS WILL DELETE /usr/local IF YOU INSTALLED THERE AND IT BECOMES EMPTY** +## MacPorts (macOS) -This is not in the default behaviour of `make uninstall` for obvious reasons. +```console +$ port install vcsh +``` +## NIX -# Other stuff # +```console +$ nix-env -i vcsh +``` -To clean up the generated manpage, run +## openSUSE - make clean +```console +$ zypper install vcsh +``` -To run the test suite, run +## Pardus - make test +```console +$ pisi install vcsh +``` -To run the test suite, you will need `perl`, -and the modules `Test::Most` and `Shell::Command`. +## Termux -To install the perl modules, run +```console +$ pkg install vcsh +``` - cpan install 'Test::Most' 'Shell::Command'. +# Installing from Source +First you'll want a copy of the source code. +The easiest to use place to get this is the [latest release](https://github.com/RichiH/vcsh/releases/latest) posted on GitHub. +The souree distribution will have a name such as `vcsh-2.0.0.tar.xz`. +Note under each release GitHub also shows a "Source code" link that will download a snapshot of the repository; this is **not** the file you want (unless you want to jump through extra hoops). +The official source release packages are the ones you want. + +Alternatively you may `git clone` the source repository. +Note than some extra tooling will be required over using the regular source releases. +Building from a clone will require a system with GNU Autotools installed; something not needed if using a source package. +Also source releases have prebuilt man pages; to (optionally) build them from a Git clone you will need `ronn`. +Finally building from Git clones will check for extra dependencies needed for testing, although tests can be disabled. +If starting from a clone, run `./bootstrap.sh` once before doing anything below. + +Once you have the source, it's time to let it get aquainted with your system: + +```console +$ ./configure +``` + +This command has *lots* of possible options, but the defaults should suite most use cases. +See `./configure --help` for details if you have special needs. + +Once configured, you can build: + +```console +$ make +``` + +Lastly you'll want to install it somewhere. + +```console +$ make install +``` + +If you need elevated system permissions you may need to use `sudo make install` for this step. +If you don't have such permissions and wish to install to your home directory, something like this might work: + +```console +$ ./configure --prefix=/ +$ make DESTDIR="$HOME" install-exec +``` + +This will install to `~/bin/vcsh`; add `~/bin` to your path to use. [1]: http://rtomayko.github.io/ronn/ diff --git a/doc/PACKAGING.md b/doc/PACKAGING.md deleted file mode 100644 index ecbfa551..00000000 --- a/doc/PACKAGING.md +++ /dev/null @@ -1,44 +0,0 @@ -# Distributions with readily available packages - -## Archlinux - -AUR does not require any packaging information within this repository. - -## Debian - -Debian packages are provided by the author in separate branches, maintained in -the upstream repository - -### Ubuntu - -Ubuntu imports Debian's package automagically. - - -## Mac OS X / Homebrew - -Homebrew does not require any packaging information within this repository. -A separate branch with a statically compiled manpage and release tags is -provided to ease the work of Homebrew packagers: - -* The static manpage because Homebrew lacks ronn -* The tag so GitHub generates tarballs Homebrew can be pointed at - - -# Supporting new distributions - -## Your own work - -If you are maintaining a package for a different distribution, please get -in touch so your work can be included in a packaging branch in the upstream -repository. -This allows others to adapt your work for their own distributions or -packaging needs. - -## Static manpage - -The "debian-squeeze" branch carries a quilt patchset with a pre-compiled -manpage and the "homebrew" one carries a static manpage. - -In case you can not build the manpage because you are missing ronn or you -prefer a precompiled manpage for another reason, please contact us; we will -gladly provide up-to-date packages with every release. diff --git a/doc/vcsh.1.ronn b/doc/vcsh.1.ronn.in similarity index 76% rename from doc/vcsh.1.ronn rename to doc/vcsh.1.ronn.in index c1021ae6..2300989e 100644 --- a/doc/vcsh.1.ronn +++ b/doc/vcsh.1.ronn.in @@ -3,66 +3,66 @@ vcsh(1) - Version Control System for $HOME - multiple Git repositories in $HOME ## SYNOPSIS -`vcsh` [] +`@TRANSFORMED_PACKAGE_NAME@` [] -`vcsh` clone [-b ] [] +`@TRANSFORMED_PACKAGE_NAME@` clone [-b ] [] -`vcsh` delete +`@TRANSFORMED_PACKAGE_NAME@` delete -`vcsh` enter +`@TRANSFORMED_PACKAGE_NAME@` enter -`vcsh` foreach [-g] +`@TRANSFORMED_PACKAGE_NAME@` foreach [-g] -`vcsh` help +`@TRANSFORMED_PACKAGE_NAME@` help -`vcsh` init +`@TRANSFORMED_PACKAGE_NAME@` init -`vcsh` list +`@TRANSFORMED_PACKAGE_NAME@` list -`vcsh` list-tracked [] +`@TRANSFORMED_PACKAGE_NAME@` list-tracked [] -`vcsh` list-untracked [<-a>] [<-r>] [] +`@TRANSFORMED_PACKAGE_NAME@` list-untracked [<-a>] [<-r>] [] -`vcsh` pull +`@TRANSFORMED_PACKAGE_NAME@` pull -`vcsh` push +`@TRANSFORMED_PACKAGE_NAME@` push -`vcsh` rename +`@TRANSFORMED_PACKAGE_NAME@` rename -`vcsh` run +`@TRANSFORMED_PACKAGE_NAME@` run -`vcsh` status [] +`@TRANSFORMED_PACKAGE_NAME@` status [] -`vcsh` upgrade +`@TRANSFORMED_PACKAGE_NAME@` upgrade -`vcsh` version +`@TRANSFORMED_PACKAGE_NAME@` version -`vcsh` which +`@TRANSFORMED_PACKAGE_NAME@` which -`vcsh` write-gitignore [] +`@TRANSFORMED_PACKAGE_NAME@` write-gitignore [] -`vcsh` +`@TRANSFORMED_PACKAGE_NAME@` -`vcsh` +`@TRANSFORMED_PACKAGE_NAME@` ## DESCRIPTION -`vcsh` allows you to have several `git`(1) repositories, all maintaining their +`@TRANSFORMED_PACKAGE_NAME@` allows you to have several `git`(1) repositories, all maintaining their working trees in $HOME without clobbering each other. That, in turn, means you can have one repository per config set (zsh, vim, ssh, etc), picking and choosing which configs you want to use on which machine. -`vcsh` is using a technique called fake bare Git repositories, keeping <$GIT_DIR> +`@TRANSFORMED_PACKAGE_NAME@` is using a technique called fake bare Git repositories, keeping <$GIT_DIR> in a different directory from <$GIT_WORK_TREE> which is pointed to <$HOME>. The use of symlinks is not needed in this setup, making for a cleaner setup. -`vcsh` was designed with `mr`(1) in mind so you might want to install it alongside -vcsh. That being said, you can easily use `vcsh` without `mr` if you prefer. +`@TRANSFORMED_PACKAGE_NAME@` was designed with `mr`(1) in mind so you might want to install it alongside +vcsh. That being said, you can easily use `@TRANSFORMED_PACKAGE_NAME@` without `mr` if you prefer. -A sample configuration for `vcsh` and `mr` can be found at -*https://github.com/RichiH/vcsh_mr_template* and used with `vcsh clone +A sample configuration for `@TRANSFORMED_PACKAGE_NAME@` and `mr` can be found at +*https://github.com/RichiH/vcsh_mr_template* and used with `@TRANSFORMED_PACKAGE_NAME@ clone https://github.com/RichiH/vcsh_mr_template mr`. Please note that you can always use a path instead of a name for . @@ -152,7 +152,7 @@ an interactive user. Please note that there is a somewhat magic feature for run. Instead of it accepts , as well. Anything that has a slash in it will be assumed to - be a path. `vcsh run` will then operate on this directory instead of the one + be a path. `@TRANSFORMED_PACKAGE_NAME@ run` will then operate on this directory instead of the one normally generated from the repository's name. This is needed to support mr and other scripts properly and of no concern to an interactive user. @@ -177,22 +177,22 @@ an interactive user. Shortcut to run `git` commands on a repo. Will prepend `git` to . * : - Shortcut to run `vcsh enter `. + Shortcut to run `@TRANSFORMED_PACKAGE_NAME@ enter `. ## ENVIRONMENT -As noted earlier, `vcsh` will set <$GIT_DIR> and <$GIT_WORK_TREE> to the +As noted earlier, `@TRANSFORMED_PACKAGE_NAME@` will set <$GIT_DIR> and <$GIT_WORK_TREE> to the appropriate values for fake bare Git repositories. ## CONFIG -There are several ways to turn the various knobs on `vcsh`. In order of +There are several ways to turn the various knobs on `@TRANSFORMED_PACKAGE_NAME@`. In order of ascending precedence, they are: -* `VARIABLE=foo vcsh` +* `VARIABLE=foo @TRANSFORMED_PACKAGE_NAME@` * * <$XDG_CONFIG_HOME/vcsh/config> -* `vcsh -c ` +* `@TRANSFORMED_PACKAGE_NAME@ -c ` Please note that those files are sourced. Any and all commands will be executed in the context of your shell. @@ -259,9 +259,9 @@ Less interesting knobs you could turn: ## HOOK SYSTEM -`vcsh` provides a hook system. Hook scripts must be executable and should be +`@TRANSFORMED_PACKAGE_NAME@` provides a hook system. Hook scripts must be executable and should be placed in <$XDG_CONFIG_HOME/vcsh/hooks-available>. From there, they can be -soft-linked into <$XDG_CONFIG_HOME/vcsh/hooks-enabled>; `vcsh` will only +soft-linked into <$XDG_CONFIG_HOME/vcsh/hooks-enabled>; `@TRANSFORMED_PACKAGE_NAME@` will only execute hooks that are in this directory. Hooks follow a simple format. will be run before anything is run. @@ -284,7 +284,7 @@ we can ship them by default. ## OVERLAY SYSTEM -`vcsh` also provides an overlay system. Similar to hooks, the recommended +`@TRANSFORMED_PACKAGE_NAME@` also provides an overlay system. Similar to hooks, the recommended locations are <$XDG_CONFIG_HOME/vcsh/overlays-available> and <$XDG_CONFIG_HOME/vcsh/overlays-enabled>. @@ -314,8 +314,8 @@ On Debian-based systems, this file can be found in . ## SECURITY CONSIDERATIONS -`vcsh` allows you to execute arbitrary commands via `vcsh run`. For example, -adding a `sudo`(8) rule for `vcsh` would be pretty stupid. +`@TRANSFORMED_PACKAGE_NAME@` allows you to execute arbitrary commands via `@TRANSFORMED_PACKAGE_NAME@ run`. For example, +adding a `sudo`(8) rule for `@TRANSFORMED_PACKAGE_NAME@` would be pretty stupid. Additionally, vcsh will source, i.e. execute, all files listed in . You can put any and all commands into these config files and they will be @@ -345,7 +345,7 @@ take over the name. ## AUTHOR -This manpage and `vcsh` itself were written by Richard "RichiH" Hartmann. +This manpage and `@TRANSFORMED_PACKAGE_NAME@` itself were written by Richard "RichiH" Hartmann. ## COPYRIGHT diff --git a/tools/hooks/pre-commit b/tools/hooks/pre-commit deleted file mode 100755 index ddb0550d..00000000 --- a/tools/hooks/pre-commit +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -# Unfortunately, Git decided to set those two during pre-commit -unset GIT_DIR -unset GIT_INDEX_FILE - -prove diff --git a/tools/list_CONTRIBUTORS b/tools/list_CONTRIBUTORS deleted file mode 100755 index 1b88451d..00000000 --- a/tools/list_CONTRIBUTORS +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# This program is licensed under the GNU GPL version 2 or later. -# (c) Richard "RichiH" Hartmann , 2012-2014 -# For details, see LICENSE. To submit patches, you have to agree to -# license your code under the GNU GPL version 2 or later. - - -echo 'Alphabetical list of surnames of everyone who ever committed to this repository. -Auto-generated from tools/list_CONTRIBUTORS. -' -git shortlog -se --all | cut -f1 --complement | sort -u -k2 diff --git a/vcsh b/vcsh.in similarity index 86% rename from vcsh rename to vcsh.in index 748759aa..4b2c70a2 100755 --- a/vcsh +++ b/vcsh.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!@SHELL@ # This program is licensed under the GNU GPL version 2 or later. # (c) Richard "RichiH" Hartmann , 2011-2015 @@ -16,11 +16,11 @@ [ -n "$VCSH_DEBUG" ] && set -vx -# If '.git-HEAD' is appended to the version, you are seeing an unreleased -# version of vcsh; the master branch is supposed to be clean at all times +# If '.r-g' is appended to the version, you are seeing an unreleased +# version of vcsh; the main branch is supposed to be clean at all times # so you can most likely just use it nonetheless -VCSH_VERSION='0.2021-GIT'; export VCSH_VERSION -VCSH_SELF="$(basename "$0")"; export VCSH_SELF +VCSH_VERSION='@VERSION@'; export VCSH_VERSION +VCSH_SELF="@TRANSFORMED_PACKAGE_NAME@"; export VCSH_SELF # Ensure all files created are accessible only to the current user. umask 0077 @@ -173,28 +173,28 @@ info() { clone() { hook pre-clone # Check if remote is reachable. Abort early if there's a typo, TLS certificate problem, etc - git ls-remote "$GIT_REMOTE" 2> /dev/null || fatal "Can not reach '$GIT_REMOTE'" + @GIT@ ls-remote "$GIT_REMOTE" 2> /dev/null || fatal "Can not reach '$GIT_REMOTE'" init - git remote add origin "$GIT_REMOTE" - git checkout -b "$VCSH_BRANCH" || return $? - git config branch."$VCSH_BRANCH".remote origin - git config branch."$VCSH_BRANCH".merge refs/heads/"$VCSH_BRANCH" - if [ "$(git ls-remote origin "$VCSH_BRANCH" 2> /dev/null | wc -l )" -lt 1 ]; then + @GIT@ remote add origin "$GIT_REMOTE" + @GIT@ checkout -b "$VCSH_BRANCH" || return $? + @GIT@ config branch."$VCSH_BRANCH".remote origin + @GIT@ config branch."$VCSH_BRANCH".merge refs/heads/"$VCSH_BRANCH" + if [ "$(@GIT@ ls-remote origin "$VCSH_BRANCH" 2> /dev/null | wc -l )" -lt 1 ]; then info "remote is empty, not merging anything. You should add files to your new repository." # editorconfig-checker-disable-line exit fi - GIT_VERSION_MAJOR=$(git --version | sed -E -n 's/.* ([0-9]+)\..*/\1/p' ) + GIT_VERSION_MAJOR=$(@GIT@ --version | @SED@ -E -n 's/.* ([0-9]+)\..*/\1/p' ) if [ 1 -lt "$GIT_VERSION_MAJOR" ];then - git fetch origin "$VCSH_BRANCH" + @GIT@ fetch origin "$VCSH_BRANCH" else - git fetch origin + @GIT@ fetch origin fi hook pre-merge - git read-tree -n -mu origin/"$VCSH_BRANCH" \ + @GIT@ read-tree -n -mu origin/"$VCSH_BRANCH" \ || fatal "will stop after fetching and not try to merge! Once this situation has been resolved, run 'vcsh $VCSH_REPO_NAME pull' to finish cloning." 17 # editorconfig-checker-disable-line - git -c merge.ff=true merge origin/"$VCSH_BRANCH" + @GIT@ -c merge.ff=true merge origin/"$VCSH_BRANCH" hook post-merge hook post-clone retire @@ -210,7 +210,7 @@ commit() { GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR use hook_repo pre-commit - git commit --untracked-files=no --quiet "$@" + @GIT@ commit --untracked-files=no --quiet "$@" hook_repo post-commit VCSH_COMMAND_RETURN_CODE=$? echo @@ -222,7 +222,7 @@ delete() { cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11 use info "This operation WILL DESTROY DATA!" - files=$(git ls-files) + files=$(@GIT@ ls-files) echo "These files will be deleted: $files @@ -249,7 +249,7 @@ foreach() { # We default to prefixing `git` to all commands passed to foreach, but # allow running in general context with -g - command_prefix=git + command_prefix=@GIT@ # shellcheck disable=SC2220 while getopts gp flag; do case "$flag" in @@ -265,7 +265,7 @@ foreach() { use hook_repo pre-foreach if [ -n "${VCSH_PRINT_REPO_PREFIX+x}" ]; then - $command_prefix "$@" | sed "s/^/$VCSH_REPO_NAME: /" + $command_prefix "$@" | @SED@ "s/^/$VCSH_REPO_NAME: /" else echo "$VCSH_REPO_NAME:" $command_prefix "$@" @@ -305,7 +305,7 @@ init() { [ ! -e "$GIT_DIR" ] || fatal "'$GIT_DIR' exists" 10 mkdir -p "$VCSH_BASE" || fatal "could not create '$VCSH_BASE'" 50 cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11 - git init --shared=false + @GIT@ init --shared=false upgrade hook post-init } @@ -319,13 +319,13 @@ list() { list_has_remote() { for VCSH_REPO_NAME in $(list); do GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR - git config branch."$VCSH_BRANCH".remote > /dev/null && echo "$VCSH_REPO_NAME" + @GIT@ config branch."$VCSH_BRANCH".remote > /dev/null && echo "$VCSH_REPO_NAME" done } get_files() { GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR - git ls-files --full-name + @GIT@ ls-files --full-name } list_tracked() { @@ -340,7 +340,7 @@ list_tracked() { } list_tracked_helper() { - sed "s,^,$(printf '%s\n' "$VCSH_BASE/" | sed 's/[,\&]/\\&/g')," | sort -u + @SED@ "s,^,$(printf '%s\n' "$VCSH_BASE/" | @SED@ 's/[,\&]/\\&/g')," | sort -u } list_tracked_by() { @@ -348,8 +348,6 @@ list_tracked_by() { } list_untracked() { - command -v 'comm' >/dev/null 2>&1 || fatal "Could not find 'comm'" - temp_file_others=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file' temp_file_untracked=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file' temp_file_untracked_copy=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file' @@ -384,7 +382,7 @@ list_untracked() { list_untracked_helper() { export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git" - git ls-files --others $exclude_standard_opt "$directory_opt" | ( + @GIT@ ls-files --others $exclude_standard_opt "$directory_opt" | ( while read -r line; do echo "$line" directory_component=${line%%/*} @@ -396,7 +394,7 @@ list_untracked_helper() { cp "$temp_file_others" "$temp_file_untracked" || fatal 'Could not copy temp file' fi cp "$temp_file_untracked" "$temp_file_untracked_copy" || fatal 'Could not copy temp file' - comm -12 "$temp_file_others" "$temp_file_untracked_copy" > "$temp_file_untracked" + @COMM@ -12 "$temp_file_others" "$temp_file_untracked_copy" > "$temp_file_untracked" } pull() { @@ -407,7 +405,7 @@ pull() { GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR use hook_repo pre-pull - git pull + @GIT@ pull hook_repo post-pull VCSH_COMMAND_RETURN_CODE=$? echo @@ -423,7 +421,7 @@ push() { GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR use hook_repo pre-push - git push + @GIT@ push hook_repo post-push VCSH_COMMAND_RETURN_CODE=$? echo @@ -481,13 +479,13 @@ status_helper() { use # Shellcheck isn't understanding a complex block. # shellcheck disable=SC1083 - remote_tracking_branch=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2> /dev/null) && { - commits_behind=$(git log ..${remote_tracking_branch} --oneline | wc -l) - commits_ahead=$(git log ${remote_tracking_branch}.. --oneline | wc -l) + remote_tracking_branch=$(@GIT@ rev-parse --abbrev-ref --symbolic-full-name @{u} 2> /dev/null) && { + commits_behind=$(@GIT@ log ..${remote_tracking_branch} --oneline | wc -l) + commits_ahead=$(@GIT@ log ${remote_tracking_branch}.. --oneline | wc -l) [ ${commits_behind} -ne 0 ] && echo "Behind $remote_tracking_branch by $commits_behind commits" [ ${commits_ahead} -ne 0 ] && echo "Ahead of $remote_tracking_branch by $commits_ahead commits" } - git ${VCSH_GIT_OPTIONS} status --short --untracked-files='no' | sed -E 's@([^ ] +)@\1~/@' + @GIT@ ${VCSH_GIT_OPTIONS} status --short --untracked-files='no' | @SED@ -E 's@([^ ] +)@\1~/@' VCSH_COMMAND_RETURN_CODE=$? } @@ -496,20 +494,20 @@ upgrade() { # fake-bare repositories are not bare, actually. Set this to false # because otherwise Git complains "fatal: core.bare and core.worktree # do not make sense" - git config core.bare false + @GIT@ config core.bare false # core.worktree may be absolute or relative to $GIT_DIR, depending on # user preference if [ ! "x$VCSH_WORKTREE" = 'xabsolute' ]; then - git config core.worktree "$(cd "$GIT_DIR" && GIT_WORK_TREE=$VCSH_BASE git rev-parse --show-cdup)" + @GIT@ config core.worktree "$(cd "$GIT_DIR" && GIT_WORK_TREE=$VCSH_BASE @GIT@ rev-parse --show-cdup)" elif [ ! "x$VCSH_WORKTREE" = 'xrelative' ]; then - git config core.worktree "$VCSH_BASE" + @GIT@ config core.worktree "$VCSH_BASE" fi - [ ! "x$VCSH_GITIGNORE" = 'xnone' ] && git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME" - [ ! "x$VCSH_GITATTRIBUTES" = 'xnone' ] && git config core.attributesfile ".gitattributes.d/$VCSH_REPO_NAME" - git config vcsh.vcsh 'true' + [ ! "x$VCSH_GITIGNORE" = 'xnone' ] && @GIT@ config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME" + [ ! "x$VCSH_GITATTRIBUTES" = 'xnone' ] && @GIT@ config core.attributesfile ".gitattributes.d/$VCSH_REPO_NAME" + @GIT@ config vcsh.vcsh 'true' use - [ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ] && git add -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" - [ -e "$VCSH_BASE/.gitattributes.d/$VCSH_REPO_NAME" ] && git add -f "$VCSH_BASE/.gitattributes.d/$VCSH_REPO_NAME" + [ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ] && @GIT@ add -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" + [ -e "$VCSH_BASE/.gitattributes.d/$VCSH_REPO_NAME" ] && @GIT@ add -f "$VCSH_BASE/.gitattributes.d/$VCSH_REPO_NAME" hook post-upgrade } @@ -522,7 +520,7 @@ which() { # It's ok to modify VCSH_REPO_NAME in a subshell. # shellcheck disable=SC2030 output=$(for VCSH_REPO_NAME in $(list); do - get_files | grep -- "$VCSH_COMMAND_PARAMETER" | sed "s/^/$VCSH_REPO_NAME: /" + get_files | @GREP@ -- "$VCSH_COMMAND_PARAMETER" | @SED@ "s/^/$VCSH_REPO_NAME: /" done | sort -u) if [ -z "$output" ]; then fatal "'$VCSH_COMMAND_PARAMETER' does not exist" 1 @@ -545,12 +543,12 @@ write_gitignore() { # Works in all shells we care about. # shellcheck disable=SC2039,SC3043 local GIT_VERSION GIT_VERSION_MAJOR GIT_VERSION_MINOR - GIT_VERSION="$(git --version)" - GIT_VERSION_MAJOR="$(echo "$GIT_VERSION" | sed -E -n 's/.* ([0-9]+)\..*/\1/p')" - GIT_VERSION_MINOR="$(echo "$GIT_VERSION" | sed -E -n 's/.* ([0-9]+)\.([0-9]+)\..*/\2/p')" + GIT_VERSION="$(@GIT@ --version)" + GIT_VERSION_MAJOR="$(echo "$GIT_VERSION" | @SED@ -E -n 's/.* ([0-9]+)\..*/\1/p')" + GIT_VERSION_MINOR="$(echo "$GIT_VERSION" | @SED@ -E -n 's/.* ([0-9]+)\.([0-9]+)\..*/\2/p')" OLDIFS=$IFS IFS=$(printf '\n\t') - gitignores=$(for file in $(git ls-files); do + gitignores=$(for file in $(@GIT@ ls-files); do if [ "$GIT_VERSION_MAJOR" -ge 2 ] \ && [ "$GIT_VERSION_MINOR" -ge 7 ]; then echo "$file"; @@ -570,9 +568,9 @@ write_gitignore() { echo '*' > "$tempfile" || fatal "could not write to '$tempfile'" 57 for gitignore in $gitignores; do - echo "$gitignore" | sed 's@^@!/@' >> "$tempfile" || fatal "could not write to '$tempfile'" 57 + echo "$gitignore" | @SED@ 's@^@!/@' >> "$tempfile" || fatal "could not write to '$tempfile'" 57 if [ "x$VCSH_GITIGNORE" = 'xrecursive' ] && [ -d "$gitignore" ]; then - { echo "$gitignore/*" | sed 's@^@!/@' >> "$tempfile" || fatal "could not write to '$tempfile'" 57; } + { echo "$gitignore/*" | @SED@ 's@^@!/@' >> "$tempfile" || fatal "could not write to '$tempfile'" 57; } fi done IFS=$OLDIFS @@ -589,7 +587,7 @@ write_gitignore() { fatal "could not move '$tempfile' to '$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME'" 53 } -debug "$(git version)" +debug "$(@GIT@ version)" if [ ! "x$VCSH_GITIGNORE" = 'xexact' ] && [ ! "x$VCSH_GITIGNORE" = 'xnone' ] && [ ! "x$VCSH_GITIGNORE" = 'xrecursive' ]; then fatal "'\$VCSH_GITIGNORE' must equal 'exact', 'none', or 'recursive'" 1 @@ -643,7 +641,7 @@ elif [ "$VCSH_COMMAND" = 'help' ]; then help && exit elif [ "$VCSH_COMMAND" = 'version' ]; then echo "$VCSH_SELF $VCSH_VERSION" - git version + @GIT@ version exit elif [ x"$VCSH_COMMAND" = x'which' ]; then [ -z "$2" ] && fatal "$VCSH_COMMAND: please specify a filename" 1 @@ -690,7 +688,7 @@ elif [ -n "$2" ]; then GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR [ -d "$GIT_DIR" ] || { help; exit 1; } shift 1 - set -- "git" "$@" + set -- "@GIT@" "$@" elif [ -n "$VCSH_COMMAND" ]; then VCSH_COMMAND='enter'; export VCSH_COMMAND VCSH_REPO_NAME=$1; export VCSH_REPO_NAME @@ -703,7 +701,7 @@ fi # Did we receive a directory instead of a name? # Mangle the input to fit normal operation. -if echo "$VCSH_REPO_NAME" | grep -q '/'; then +if echo "$VCSH_REPO_NAME" | @GREP@ -q '/'; then GIT_DIR=$VCSH_REPO_NAME; export GIT_DIR VCSH_REPO_NAME=$(basename "$VCSH_REPO_NAME" .git); export VCSH_REPO_NAME fi @@ -725,7 +723,7 @@ check_dir "$VCSH_REPO_D" [ ! "x$VCSH_GITATTRIBUTES" = 'xnone' ] && check_dir "$VCSH_BASE/.gitattributes.d" verbose "$VCSH_COMMAND begin" -VCSH_COMMAND=$(echo "$VCSH_COMMAND" | sed 's/-/_/g'); export VCSH_COMMAND +VCSH_COMMAND=$(echo "$VCSH_COMMAND" | @SED@ 's/-/_/g'); export VCSH_COMMAND # Source repo-specific configuration file # shellcheck source=/dev/null @@ -745,3 +743,9 @@ $VCSH_COMMAND "$@" hook post-command verbose "$VCSH_COMMAND end, exiting" exit $VCSH_COMMAND_RETURN_CODE + +# Local Variables: +# mode:shell-script +# sh-shell:sh +# End: +# vim: ft=sh: