Skip to content

Commit

Permalink
Add helper commands for repository processing
Browse files Browse the repository at this point in the history
  • Loading branch information
asherikov committed Aug 9, 2024
1 parent ef2070e commit 44e46ec
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 28 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ Introduction
============

`wshandler` is a workspace management utility similar to
https://github.com/dirk-thomas/vcstool and discontinued
https://github.com/vcstools/wstool. A workspace is a directory containing a set
<https://github.com/dirk-thomas/vcstool> and discontinued
<https://github.com/vcstools/wstool>. A workspace is a directory containing a set
of packages (typically git repositories) under development, see
https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html
or http://wiki.ros.org/catkin/workspaces for more information.
<https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html>
or <http://wiki.ros.org/catkin/workspaces for more information>.

Key features:
- `wshandler` mimics `wstool`'s 'stateful' workflow dropped in `vcstool`, e.g.,
it is easy to keep track of your local changes with respect to the upstream;
- `wshandler` is implemented using `bash` and `yq` (https://github.com/mikefarah/yq);
- `wshandler` is implemented using `bash` and `yq` (<https://github.com/mikefarah/yq>);
- currently supported package sources: `git`;
- supported repository list formats: `repos` (default) and `rosinstall`
(https://docs.ros.org/en/independent/api/rosinstall/html/rosinstall_file_format.html)
(<https://docs.ros.org/en/independent/api/rosinstall/html/rosinstall_file_format.html>)


Installation
Expand Down Expand Up @@ -62,11 +62,13 @@ Examples

- `wshandler status`
```
>>> wshandler status .../wshandler/tests/scrape/: git sources ---
name version (hash) actual version repository
---- -------------- -------------- ----------
qpmad master (53edb8a) heads/master-0-g53edb8a https://github.com/asherikov/qpmad.git
staticoma master (06e8628) heads/master-0-g06e8628 https://github.com/asherikov/staticoma.git
>>> wshandler status .../ccws/src/: git sources ---
Flags: H - version hash mismatch, M - uncommited changes
name version actual version flags repository
---- ------- -------------- ----- ----------
ariles pkg_ws_2 tags/ws-2.3.1-0-ge2748ad4 https://github.com/asherikov/ariles.git
intrometry main tags/0.1.0-0-ga033cd5-dirty M https://github.com/asherikov/intrometry.git
thread_supervisor master tags/1.0.0-2-g00e3d88-dirty HM https://github.com/asherikov/thread_supervisor.git
<<< wshandler status .../wshandler/tests/scrape/: git sources ---
<<< wshandler status .../ccws/src/: git sources ---
```
159 changes: 143 additions & 16 deletions wshandler
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ help()
echo " -i|--indent 1|2|3... {4}"
echo " -k|--keep-going {false}"

echo "Commands:"
echo "List commands:"
echo " status"
echo " [-j|--jobs <NUM_THREADS> {1}] [-p|--policy {default}|shallow|rebase] update"
echo " [-j|--jobs <NUM_THREADS> {1}] clean"
Expand All @@ -30,6 +30,17 @@ help()
echo " remove_by_url <URL>"
echo " [-p|--policy {keep}|replace] merge <FILENAME>"

echo "Repository commands:"
echo " [-j|--jobs <NUM_THREADS> {1}] [-s|-source {git}] foreach '<COMMAND>'"
echo " show_branches ['<GREP_PATTERN>']"
echo " prune"
echo " push"
echo " branch new <BRANCH_NAME>"
echo " branch delete <BRANCH_NAME>"
echo " branch switch <BRANCH_NAME>"
echo " branch merge <BRANCH_NAME> <TARGET_BRANCH {main}>"
echo " commit '<MESSAGE>'"

echo "Installation commands:"
echo " install_test_deps"
echo " [-p|--policy {skip_yq}|snap|download] install <BIN_PATH {~/bin}>"
Expand Down Expand Up @@ -68,22 +79,30 @@ repos_git_repo_names()
git_status()
{
DATA=$(
echo "name|version (hash)|actual version|repository";
echo "----|--------------|--------------|----------";
echo "name|version|actual version|flags|repository";
echo "----|-------|--------------|-----|----------";
"${WSH_WORKSPACE_TYPE}_git_repo_triplets" | while read -r -a TRIPLET; do dir_git_status "${TRIPLET[@]}"; done
)

MAX_LEN_1=$(cut -f 1 -d '|' <<< "${DATA}" | wc -L | grep -o "[0-9]*")
MAX_LEN_2=$(cut -f 2 -d '|' <<< "${DATA}" | wc -L | grep -o "[0-9]*")
MAX_LEN_3=$(cut -f 3 -d '|' <<< "${DATA}" | wc -L | grep -o "[0-9]*")
MAX_LEN_4=$(cut -f 4 -d '|' <<< "${DATA}" | wc -L | grep -o "[0-9]*")
FORMAT_STRING=""
for i in {1..5};
do
MAX_LEN=$(cut -f "$i" -d '|' <<< "${DATA}" | wc -L | grep -o "[0-9]*")
if [ "$i" != "1" ]
then
FORMAT_STRING+=" "
fi
FORMAT_STRING+="%-${MAX_LEN}.${MAX_LEN}s"
done

echo "Flags: H - version hash mismatch, M - uncommited changes"
IFS=$'\n' readarray -t ROWS <<< "${DATA}"
for ROW in "${ROWS[@]}"
do
IFS='|' read -ra COLS <<< "${ROW}"
# use ${COLUMNS} to crop?
printf "%-${MAX_LEN_1}.${MAX_LEN_1}s %-${MAX_LEN_2}.${MAX_LEN_2}s %-${MAX_LEN_3}.${MAX_LEN_3}s %-${MAX_LEN_4}.${MAX_LEN_4}s\n" "${COLS[@]}"
# shellcheck disable=SC2059
printf "${FORMAT_STRING}\n" "${COLS[@]}"
done

echo
Expand All @@ -94,6 +113,30 @@ git_status()

git_update()
{
IFS=',' read -ra POLICIES <<< "${WSH_COMMAND_POLICY}"

if [ -d "${WSH_WORKSPACE_ROOT}/.git" ]
then
echo "Processing workspace root"
git fetch
if git diff --exit-code > /dev/null && git diff --cached --exit-code > /dev/null
then
# if we are on a branch make sure that it is updated
if (git branch --show-current | grep "${GIT_VERSION}")
then
PULL_ARGS=()
for POLICY in "${POLICIES[@]}";
do
if [ "${POLICY}" == "rebase" ]
then
PULL_ARGS+=(--rebase)
fi
done
git pull "${PULL_ARGS[@]}"
fi
fi
fi

"${WSH_WORKSPACE_TYPE}_git_repo_triplets" | "${WSH_XARGS[@]}" "${WSHANDLER[@]}" dir_git_update
}

Expand Down Expand Up @@ -150,6 +193,17 @@ git_scrape()
done
}

dir_run()
{
echo ">>> Processing '$1'"
if [ -d "${WSH_WORKSPACE_ROOT}/$1/" ]
then
cd "${WSH_WORKSPACE_ROOT}/$1/" && sh -c "$2"
else
echo "Missing directory: ${WSH_WORKSPACE_ROOT}/$1/"
fi
}

dir_git_status()
{
NAME="$1"
Expand All @@ -161,11 +215,27 @@ dir_git_status()
if [ -d "${GIT_DIR}/.git" ]
then
cd "${GIT_DIR}"
GIT_VERSION_HASH=$(git rev-parse --short "${GIT_VERSION}" || echo -n "unknown")
GIT_VERSION_HASH=$(git rev-parse --short "${GIT_VERSION}" || echo -n "-")
GIT_ACTUAL_VERSION=$(git describe --dirty --broken --all --long --always | tr -d '\n')
GIT_ACTUAL_HASH=$(git rev-parse --short HEAD || echo -n "-")
fi

FLAGS=""
if [ "${GIT_VERSION_HASH}" = "${GIT_ACTUAL_HASH}" ] && [ "${GIT_ACTUAL_HASH}" != "-" ]
then
FLAGS+=" "
else
FLAGS+="H"
fi

echo "${NAME}|${GIT_VERSION} (${GIT_VERSION_HASH})|${GIT_ACTUAL_VERSION}|${GIT_REPO}"
if git status --porcelain | grep . > /dev/null;
then
FLAGS+="M"
else
FLAGS+=" "
fi

echo "${NAME}|${GIT_VERSION}|${GIT_ACTUAL_VERSION}|${FLAGS}|${GIT_REPO}"
}

dir_git_update()
Expand Down Expand Up @@ -260,7 +330,7 @@ check_workspace()
esac
fi

WSHANDLER=("$(realpath "${BASH_SOURCE[0]}")" -r "${WSH_WORKSPACE_ROOT}" -c "${WSH_CACHE_DIR}" -t "${WSH_WORKSPACE_TYPE} -p ${WSH_COMMAND_POLICY}")
WSHANDLER=("$(realpath "${BASH_SOURCE[0]}")" -r "${WSH_WORKSPACE_ROOT}" -c "${WSH_CACHE_DIR}" -t "${WSH_WORKSPACE_TYPE}" -p "${WSH_COMMAND_POLICY}")
if [ -n "${WSH_KEEP_GOING}" ]
then
WSHANDLER+=("${WSH_KEEP_GOING}")
Expand Down Expand Up @@ -377,6 +447,52 @@ execute_add()
"${WSH_WORKSPACE_TYPE}_$1_add" "$@"
}


git_foreach()
{
"${WSH_WORKSPACE_TYPE}_${WSH_SOURCE_TYPE}_repo_names" | "${WSH_XARGS[@]}" -I {} "${WSHANDLER[@]}" dir_run "{}" "$1"
}

execute_foreach()
{
"${WSH_SOURCE_TYPE}_foreach" "$@"
}

execute_prune()
{
git_foreach "git remote | xargs --no-run-if-empty -L 1 -I {} git remote prune {}"
}

execute_push()
{
git_foreach "git push"
}

execute_show_branches()
{
git_foreach "git branch -a | grep '$1'"
}

execute_branch()
{
ACTION=$1
BRANCH=$2

case ${ACTION} in
new)
git_foreach "((git status --porcelain | grep . > /dev/null) && git checkout -b ${BRANCH}) || true";;
delete)
git_foreach "(git ls-remote --exit-code --heads origin ${BRANCH} > /dev/null && git push origin --delete ${BRANCH}) || true";;
*) help 1;;
esac
}

execute_commit()
{
git_foreach "((git status --porcelain | grep . > /dev/null) && git commit -a -m '${1}') || true"
}


set_version()
{
TARGET_MATCH="$2"
Expand Down Expand Up @@ -422,6 +538,7 @@ WSH_INDENT=4
WSH_XARGS=(xargs --no-run-if-empty -L 1 -P "${WSH_JOBS}")
WSH_KEEP_GOING=""
WSH_YQ_BINARY="yq"
WSH_SOURCE_TYPE="git"

while [[ $# -gt 0 ]]
do
Expand Down Expand Up @@ -458,22 +575,26 @@ do
WSH_KEEP_GOING="-k"
shift;;

-s|--source)
WSH_SOURCE_TYPE=$2
shift; shift;;

status|update|clean|scrape)
check_workspace "$1"
execute_command "$1"
exit;;

add|remove|merge|remove_by_url)
add|remove|merge|remove_by_url|foreach|prune|show_branches|push|branch|commit|set_version_branch)
check_workspace "$1"
"execute_$1" "${@:2}"
exit;;

set_version_by_url|set_version_by_name)
check_workspace "$1"
set_version "$1" "${@:2}"
set_version "${@}"
exit;;

dir_*_update)
dir_*_update|dir_run)
if [ -n "${WSH_KEEP_GOING}" ]
then
"$1" "${@:2}" || true
Expand Down Expand Up @@ -505,11 +626,17 @@ do
skip_yq|default)
;;
snap)
apt_install snap
if ! command -v "snap" > /dev/null
then
apt_install snap
fi
snap_install yq
;;
download)
apt_install wget
if ! command -v "wget" > /dev/null
then
apt_install wget
fi
wget -O - "https://github.com/mikefarah/yq/releases/download/v4.44.2/yq_linux_$(dpkg --print-architecture).tar.gz" \
| tar -zxO > "${BIN_PATH}/yq"
chmod +x "${BIN_PATH}/yq"
Expand Down

0 comments on commit 44e46ec

Please sign in to comment.