diff --git a/Makefile b/Makefile index 4b028a5f..c2bf2274 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ SHELL := bash +INSTALL ?= install # Make sure we have git: ifeq ($(shell which git),) @@ -17,9 +18,11 @@ SHARE = share # Install variables: PREFIX ?= /usr/local -INSTALL_LIB ?= $(DESTDIR)$(shell git --exec-path) +INSTALL_BIN ?= $(PREFIX)/bin +INSTALL_LIB ?= $(PREFIX)/share/$(NAME) INSTALL_EXT ?= $(INSTALL_LIB)/$(NAME).d -INSTALL_MAN1 ?= $(DESTDIR)$(PREFIX)/share/man/man1 +INSTALL_MAN1 ?= $(PREFIX)/share/man/man1 +LINK_REL_DIR := $(shell bash share/pnrelpath.sh $(INSTALL_BIN) $(INSTALL_LIB)) # Docker variables: DOCKER_TAG ?= 0.0.6 @@ -46,6 +49,7 @@ help: .PHONY: test test: + @echo uname: '$(shell uname)' prove $(prove) $(test) test-all: test docker-tests @@ -60,18 +64,22 @@ $(DOCKER_TESTS): # Install support: install: - install -d -m 0755 $(INSTALL_LIB)/ - install -C -m 0755 $(LIB) $(INSTALL_LIB)/ - install -d -m 0755 $(INSTALL_EXT)/ - install -C -m 0644 $(EXTS) $(INSTALL_EXT)/ - install -d -m 0755 $(INSTALL_MAN1)/ - install -C -m 0644 $(MAN1)/$(NAME).1 $(INSTALL_MAN1)/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(INSTALL_LIB)/ + $(INSTALL) -C -m 0755 $(LIB) $(DESTDIR)$(INSTALL_LIB)/ + sed -i 's!^SUBREPO_EXT_DIR=.*!SUBREPO_EXT_DIR=$(INSTALL_EXT)!' $(DESTDIR)$(INSTALL_LIB)/$(NAME) + $(INSTALL) -d -m 0755 $(DESTDIR)$(INSTALL_BIN) + ln -s $(LINK_REL_DIR)/$(NAME) $(DESTDIR)$(INSTALL_BIN)/$(NAME) + $(INSTALL) -d -m 0755 $(DESTDIR)$(INSTALL_EXT)/ + $(INSTALL) -C -m 0644 $(EXTS) $(DESTDIR)$(INSTALL_EXT)/ + $(INSTALL) -d -m 0755 $(DESTDIR)$(INSTALL_MAN1)/ + $(INSTALL) -C -m 0644 $(MAN1)/$(NAME).1 $(DESTDIR)$(INSTALL_MAN1)/ # Uninstall support: uninstall: - rm -f $(INSTALL_LIB)/$(NAME) - rm -fr $(INSTALL_EXT) - rm -f $(INSTALL_MAN1)/$(NAME).1 + rm -f $(DESTDIR)$(INSTALL_BIN)/$(NAME) + rm -fr $(DESTDIR)$(INSTALL_EXT) + rm -fr $(DESTDIR)$(INSTALL_LIB) + rm -f $(DESTDIR)$(INSTALL_MAN1)/$(NAME).1 env: @echo "export PATH=\"$$PWD/lib:\$$PATH\"" @@ -103,7 +111,7 @@ compgen: force $(SHARE)/zsh-completion/_git-subrepo clean: - rm -fr tmp test/tmp + rm -fr tmp test/tmp test/repo .gitconfig define docker-make-test docker run --rm \ diff --git a/lib/git-subrepo b/lib/git-subrepo index 546f061a..65f619f1 100755 --- a/lib/git-subrepo +++ b/lib/git-subrepo @@ -12,21 +12,8 @@ set -e export FILTER_BRANCH_SQUELCH_WARNING=1 # Import Bash+ helper functions: -SOURCE=${BASH_SOURCE[0]} -while [[ -h $SOURCE ]]; do - DIR=$( cd -P "$( dirname "$SOURCE" )" && pwd ) - SOURCE=$(readlink "$SOURCE") - [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE -done -SOURCE_DIR=$(dirname "$SOURCE") - -if [[ -z $GIT_SUBREPO_ROOT ]]; then - # If `make install` installation used: - source "${SOURCE_DIR}/git-subrepo.d/bash+.bash" -else - # If `source .rc` method used: - source "${SOURCE_DIR}/../ext/bashplus/lib/bash+.bash" -fi +SUBREPO_EXT_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/git-subrepo.d" # replaced by `make install` +source "${SUBREPO_EXT_DIR}/bash+.bash" bash+:import :std can version-check @@ -396,7 +383,7 @@ command:config() { # Launch the manpage viewer: command:help() { - source "${SOURCE_DIR}/git-subrepo.d/help-functions.bash" + source "${SUBREPO_EXT_DIR}/help-functions.bash" local cmd=${command_arguments[0]} if [[ $cmd ]]; then if can "help:$cmd"; then @@ -1992,7 +1979,7 @@ OK() { usage-error() { local msg="git-subrepo: $1" usage= if [[ $GIT_SUBREPO_TEST_ERRORS != true ]]; then - source "${SOURCE_DIR}/git-subrepo.d/help-functions.bash" + source "${SUBREPO_EXT_DIR}/help-functions.bash" if can "help:$command"; then msg=$'\n'"$msg"$'\n'"$("help:$command")"$'\n' fi diff --git a/share/pnrelpath.sh b/share/pnrelpath.sh new file mode 100644 index 00000000..800e822e --- /dev/null +++ b/share/pnrelpath.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# from: https://unix.stackexchange.com/questions/573047/how-to-get-the-relative-path-between-two-directories +# +# Expects two parameters, source-dir and target-dir, both absolute canonicalized +# non-empty pathnames, either may be /-ended, neither need exist. +# Returns result in shell variable $REPLY as a relative path from source-dir +# to target-dir without trailing /, . if void. +# +# Algorithm is from a 2005 comp.unix.shell posting which has now ascended to +# archive.org. + +pnrelpath() { + set -- "${1%/}/" "${2%/}/" '' ## '/'-end to avoid mismatch + while [ "$1" ] && [ "$2" = "${2#"$1"}" ] ## reduce $1 to shared path + do set -- "${1%/?*/}/" "$2" "../$3" ## source/.. target ../relpath + done + REPLY="${3}${2#"$1"}" ## build result + # unless root chomp trailing '/', replace '' with '.' + [ "${REPLY#/}" ] && REPLY="${REPLY%/}" || REPLY="${REPLY:-.}" +} + +pnrelpath "$1" "$2" + +echo $REPLY diff --git a/test/00-git-config.t b/test/00-git-config.t new file mode 100644 index 00000000..b121c261 --- /dev/null +++ b/test/00-git-config.t @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -e + +source test/setup + +use Test::More + +note "Define project-wide GIT setup for all tests" + +# Get git-subrepo project top directory +PROJ_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd ) + +if [ -z "${PROJ_DIR}" ] || [ "${HOME}" != "${PROJ_DIR}" ]; then + is "${HOME}" "${PROJ_DIR}" \ + "To define project-wide GIT setup for all tests: HOME '${HOME}' should equal PROJ_DIR '${PROJ_DIR}'" +else + + # Real GIT configuration for tests is set here: + rm -f "${PROJ_DIR}/.gitconfig" + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global init.defaultBranch "master" + git config --global --add safe.directory "${PROJ_DIR}" + git config --global --add safe.directory "${PROJ_DIR}/.git" + git config --list + + test-exists "${PROJ_DIR}/.gitconfig" + + # Running tests depends on the whole project being git initialized. + # So, git initialize the project, if necessary. + if [ ! -d "${PROJ_DIR}/.git" ]; then + cd "${PROJ_DIR}" + git init . + git add . + git commit -a -m"Initial commit" + cd - + fi + + test-exists "${PROJ_DIR}/.git/" + + # Running tests depends on the whole project not being in a GIT detached HEAD state. + if ! git symbolic-ref --short --quiet HEAD &> /dev/null; then + git checkout -b test + fi + + ok "$( + git symbolic-ref --short --quiet HEAD &> /dev/null + )" "Whole project is not in a GIT detached HEAD state" + +fi + +done_testing + +teardown diff --git a/test/clone.t b/test/clone.t index 14515381..de37302a 100644 --- a/test/clone.t +++ b/test/clone.t @@ -10,7 +10,7 @@ clone-foo-and-bar ( mkdir -p "$OWNER/empty" - git init "$OWNER/empty" + git init --initial-branch="${DEFAULTBRANCH}" "$OWNER/empty" ) # Test that the repos look ok: diff --git a/test/config.t b/test/config.t index ec5160c4..83fc3cb6 100644 --- a/test/config.t +++ b/test/config.t @@ -13,6 +13,9 @@ gitrepo=$OWNER/init/doc/.gitrepo ( cd "$OWNER/init" + git config user.email "ini@ini" + git config user.name "IniUser" + git config init.defaultBranch "${DEFAULTBRANCH}" git subrepo init doc ) > /dev/null diff --git a/test/genbar b/test/genbar new file mode 100755 index 00000000..9d3a2764 --- /dev/null +++ b/test/genbar @@ -0,0 +1,31 @@ +#!/bin/bash +set -xe + +if [ -z "${1}" ]; then + echo "${BASH_SOURCE[0]}: Single argument required (common test repos path)" + exit 1 +fi + +REPO="bar" +NAME="Bar" +TARGET="${1}/$REPO" +TMPREPO="${1}/tmp/$REPO" + +rm -rf "$TMPREPO" +mkdir -p "$TMPREPO" +cd "$TMPREPO" +git init --initial-branch=master . +git config user.name "${NAME}User" +git config user.email "${REPO}@${REPO}" +touch $NAME +git add $NAME +git commit -m"$NAME" +git tag A -m"$NAME" +mkdir -p bard +touch bard/Bard +git add bard +git commit -m"bard/Bard" +git config --bool core.bare true +cd - +mkdir -p "$1" +mv "$TMPREPO/.git" "$TARGET" diff --git a/test/genfoo b/test/genfoo new file mode 100755 index 00000000..a9b91671 --- /dev/null +++ b/test/genfoo @@ -0,0 +1,26 @@ +#!/bin/bash +set -xe + +if [ -z "${1}" ]; then + echo "${BASH_SOURCE[0]}: Single argument required (common test repos path)" + exit 1 +fi + +REPO="foo" +NAME="Foo" +TARGET="${1}/$REPO" +TMPREPO="${1}/tmp/$REPO" + +rm -rf "$TMPREPO" +mkdir -p "$TMPREPO" +cd "$TMPREPO" +git init --initial-branch=master . +git config user.name "${NAME}User" +git config user.email "${REPO}@${REPO}" +touch $NAME +git add $NAME +git commit -m"$NAME" +git config --bool core.bare true +cd - +mkdir -p "$1" +mv "${TMPREPO}/.git" "$TARGET" diff --git a/test/geninit b/test/geninit new file mode 100755 index 00000000..b70f9f15 --- /dev/null +++ b/test/geninit @@ -0,0 +1,60 @@ +#!/bin/bash +set -xe + +if [ -z "${1}" ]; then + echo "${BASH_SOURCE[0]}: Single argument required (common test repos path)" + exit 1 +fi + +REPO="init" +NAME="Init" +TARGET="${1}/$REPO" +TMPREPO="${1}/tmp/$REPO" + +rm -rf "$TMPREPO" +mkdir -p "$TMPREPO" +cd "$TMPREPO" +git init --initial-branch=master . +git config user.name "${NAME}User" +git config user.email "${REPO}@${REPO}" +cat < ReadMe +This is a repo to test \`git subrepo init\`. + +We will make a short history with a subdir, then we can turn that subdir into a +subrepo. +EOF +git add ReadMe +git commit -m"Initial commit" +mkdir -p doc +cat < doc/init.swim +== Subrepo Init! + +This is a file to test the \`git subrepo init\` command. +EOF +git add doc +git commit -m"Add a file in a subdir." +cat <> ReadMe + +This repo will go in the git-subrepo test suite. +EOF +git add ReadMe +git commit -m"Add a commit to the mainline." +cat <> doc/init.swim + +It lives under the doc directory which will become a subrepo. +EOF +git add doc/init.swim +git commit -m"Add a commit to the subdir." +cat <> ReadMe + +EOF +git add ReadMe +cat <> doc/init.swim + +EOF +git add doc/init.swim +git commit -m"Add a commit that affects both." +git config --bool core.bare true +cd - +mkdir -p "$1" +mv "${TMPREPO}/.git" "$TARGET" diff --git a/test/init.t b/test/init.t index 56453dc4..68ecb1c5 100644 --- a/test/init.t +++ b/test/init.t @@ -22,6 +22,9 @@ gitrepo=$OWNER/init/doc/.gitrepo output=$( cd "$OWNER/init" + git config user.email "ini@ini" + git config user.name "IniUser" + git config init.defaultBranch "${DEFAULTBRANCH}" git subrepo init doc ) @@ -48,6 +51,9 @@ rm -fr "$OWNER/init" git clone "$UPSTREAM/init" "$OWNER/init" &>/dev/null ( cd "$OWNER/init" + git config user.email "ini@ini" + git config user.name "IniUser" + git config init.defaultBranch "${DEFAULTBRANCH}" git subrepo init doc -r git@github.com:user/repo -b foo -M rebase ) >/dev/null diff --git a/test/issue29.t b/test/issue29.t index 57df236e..7c51a053 100644 --- a/test/issue29.t +++ b/test/issue29.t @@ -18,14 +18,16 @@ cd "$TMP" # Make 3 new repos: ( mkdir share main1 main2 - git init share - git init main1 - git init main2 + git init --initial-branch="${DEFAULTBRANCH}" share + git init --initial-branch="${DEFAULTBRANCH}" main1 + git init --initial-branch="${DEFAULTBRANCH}" main2 ) > /dev/null # Add an empty 'readme' to the share repo: ( cd share + git config user.name "ShrUser" + git config user.email "shr@ma1" echo '* text eol=lf' > .gitattributes touch readme git add readme .gitattributes @@ -37,19 +39,23 @@ cd "$TMP" # `subrepo clone` the share repo into main1: ( cd main1 + git config user.name "Ma1User" + git config user.email "ma1@ma1" touch main1 git add main1 git commit -m "Initial main1" - git subrepo clone ../share share -b "$DEFAULTBRANCH" + git subrepo clone ../share share -b "${DEFAULTBRANCH}" ) > /dev/null # `subrepo clone` the share repo into main2: ( cd main2 + git config user.name "Ma2User" + git config user.email "ma2@ma2" touch main2 git add main2 git commit -m "Initial main2" - git subrepo clone ../share share -b "$DEFAULTBRANCH" + git subrepo clone ../share share -b "${DEFAULTBRANCH}" ) > /dev/null diff --git a/test/issue95.t b/test/issue95.t index b268fbe8..3f2578c0 100644 --- a/test/issue95.t +++ b/test/issue95.t @@ -12,13 +12,15 @@ use Test::More # Make two new repos ( mkdir host sub - git init host - git init sub + git init --initial-branch="${DEFAULTBRANCH}" host + git init --initial-branch="${DEFAULTBRANCH}" sub ) > /dev/null # Initialize host repo ( cd host + git config user.name "HstUser" + git config user.email "hst@hst" touch host git add host git commit -m "host initial commit" @@ -27,7 +29,8 @@ use Test::More # Initialize sub repo ( cd sub - git init + git config user.name "SubUser" + git config user.email "sub@sub" touch subrepo git add subrepo git commit -m "subrepo initial commit" @@ -46,7 +49,7 @@ use Test::More touch feature git add feature git commit -m "feature added" - git checkout "$DEFAULTBRANCH" + git checkout "${DEFAULTBRANCH}" ) &> /dev/null # Commit directly to subrepo diff --git a/test/issue96.t b/test/issue96.t index 1b16567c..2334629b 100644 --- a/test/issue96.t +++ b/test/issue96.t @@ -11,13 +11,15 @@ use Test::More # Make two new repos ( mkdir host sub - git init host - git init sub + git init --initial-branch="${DEFAULTBRANCH}" host + git init --initial-branch="${DEFAULTBRANCH}" sub ) > /dev/null # Initialize host repo ( cd host + git config user.name "HstUser" + git config user.email "hst@hst" touch host git add host git commit -m "host initial commit" @@ -26,7 +28,8 @@ use Test::More # Initialize sub repo ( cd sub - git init + git config user.name "SubUser" + git config user.email "sub@sub" touch subrepo git add subrepo git commit -m "subrepo initial commit" @@ -87,7 +90,7 @@ use Test::More # expected: successful push without conflicts is "$( cd host - git subrepo push sub -b "$DEFAULTBRANCH" -u + git subrepo push sub -b "${DEFAULTBRANCH}" -u )" \ "Subrepo 'sub' pushed to '../sub' ($DEFAULTBRANCH)." diff --git a/test/push-after-init.t b/test/push-after-init.t index f0be2edd..93d8fc0f 100644 --- a/test/push-after-init.t +++ b/test/push-after-init.t @@ -12,12 +12,18 @@ use Test::More ( mkdir -p "$OWNER/init" cd "$OWNER/init" - git init + git init --initial-branch="${DEFAULTBRANCH}" + git config user.name "IniUser" + git config user.email "ini@ini" mkdir doc add-new-files doc/FooBar git subrepo init doc || die mkdir ../upstream - git init --bare ../upstream || die + git init --initial-branch="${DEFAULTBRANCH}" --bare ../upstream || die + cd ../upstream + git config user.name "UpsUser" + git config user.email "ups@ups" + cd - ) &> /dev/null output=$( diff --git a/test/setup b/test/setup index a05f7ff6..33f2e066 100644 --- a/test/setup +++ b/test/setup @@ -1,18 +1,45 @@ #!/usr/bin/env bash -# Set this locally for Windows: -git config core.autocrlf input - set -e -# Set the GIT_SUBREPO_ROOT for testing. -source "$PWD"/.rc +if [ "$(uname)" == "Linux" ]; then + export LC_ALL=C.UTF-8 +fi # Get the location of this script SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +# Running tests depends on the whole project being git initialized. +# So, git initialize the project, if necessary. +if [ ! -d "${SCRIPT_DIR}/../.git" ]; then + git init -b master . + git config user.email "you@you" + git config user.name "YouUser" + git add . + git commit -a -m"Initial commit" +fi + +# Disable any GIT configuration set outside this 'git-subrepo' project. +# Real GIT configuration for tests is set through the first test +# (00-git-config.t). +export XDG_CONFIG_HOME=$PWD +export HOME=$PWD +export GIT_CONFIG_NOSYSTEM=1 + +# Generate additional testing git repos, if not already present. +mkdir -p "${SCRIPT_DIR}/repo" +if [ ! -d "${SCRIPT_DIR}/repo/bar" ]; then + "${SCRIPT_DIR}/genbar" "${SCRIPT_DIR}/repo" +fi +if [ ! -d "${SCRIPT_DIR}/repo/foo" ]; then + "${SCRIPT_DIR}/genfoo" "${SCRIPT_DIR}/repo" +fi +if [ ! -d "${SCRIPT_DIR}/repo/init" ]; then + "${SCRIPT_DIR}/geninit" "${SCRIPT_DIR}/repo" +fi + BASHLIB=$( - find "$PWD"/ -type d -name bin -o -type d -name lib | tr '\n' ':' + find "$PWD"/ -type d -name bin -o -type d -name lib | grep -v "\/\.pc\/" | tr '\n' ':' ) export BASHLIB @@ -34,7 +61,7 @@ mkdir -p "$UPSTREAM" "$OWNER" "$COLLAB" cp -r test/repo/{foo,bar,init} "$UPSTREAM/" DEFAULTBRANCH=$( git config --global --get init.defaultbranch || true ) -[[ -z $DEFAULTBRANCH ]] && DEFAULTBRANCH="master" +[[ -z "${DEFAULTBRANCH}" ]] && DEFAULTBRANCH="master" export DEFAULTBRANCH ### @@ -46,17 +73,17 @@ clone-foo-and-bar() { git clone "$UPSTREAM/foo" "$OWNER/foo" ( cd "$OWNER/foo" - git config core.autocrlf input git config user.name "FooUser" git config user.email "foo@foo" + git config init.defaultBranch "${DEFAULTBRANCH}" ) # bar will act as the subrepo git clone "$UPSTREAM/bar" "$OWNER/bar" ( cd "$OWNER/bar" - git config core.autocrlf input git config user.name "BarUser" git config user.email "bar@bar" + git config init.defaultBranch "${DEFAULTBRANCH}" ) ) &> /dev/null || die }