Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic aliases functionality #241

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions doc/vcsh.1.ronn.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ vcsh(1) - Version Control System for $HOME - multiple Git repositories in $HOME

`@TRANSFORMED_PACKAGE_NAME@` [<options>] <command>

`@TRANSFORMED_PACKAGE_NAME@` alias [-d] [<alias>[=<command>]]

`@TRANSFORMED_PACKAGE_NAME@` clone [-b <branch>] <url> [<repo>]

`@TRANSFORMED_PACKAGE_NAME@` delete <repo>
Expand Down Expand Up @@ -82,6 +84,15 @@ an interactive user.

## COMMANDS

* alias:
List all aliases in <$XDG_CONFIG_HOME/vcsh/aliases>.

`<alias>`: Print the right side of alias definition.

`<alias>=<command>`: Add alias. Make backup in <$XDG_CONFIG_HOME/vcsh/aliases.bak>.

`-d <alias>`: Delete alias. Make backup in <$XDG_CONFIG_HOME/vcsh/aliases.bak>.

* clone:
Clone an existing repository.

Expand Down Expand Up @@ -184,6 +195,17 @@ an interactive user.
As noted earlier, `@TRANSFORMED_PACKAGE_NAME@` will set <$GIT_DIR> and <$GIT_WORK_TREE> to the
appropriate values for fake bare Git repositories.

## ALIASES

`@TRANSFORMED_PACKAGE_NAME@` allows to define aliases. The first existing file

* <$XDG_CONFIG_HOME/vcsh/aliases>
* </etc/vcsh/aliases>

will be read. An alias definition has the format `alias = command`.
Empty lines and lines starting with '#' are ignored.


## CONFIG

There are several ways to turn the various knobs on `@TRANSFORMED_PACKAGE_NAME@`. In order of
Expand Down
47 changes: 47 additions & 0 deletions t/800-aliases.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/perl
#
BEGIN { $ENV{LC_ALL} = 'C' }

use strict;
use warnings;

use Cwd 'abs_path';
use Test::Most;

chdir 't/etc/' or die $!;

$ENV{'HOME'} = abs_path ('.vcsh_home');

chdir '.vcsh_home' or die $!;

my $output = `../vcsh alias`;
ok $output eq "", 'No aliases set up yet.';

system("../vcsh alias ls=list");
$output = `../vcsh alias`;
ok $output eq "ls = list\n", 'Add alias ls';

system("../vcsh alias ci=commit -a");
$output = `../vcsh alias`;
ok $output eq "ls = list
ci = commit -a
", 'Add alias ci';

system("../vcsh alias co=upgrade");
$output = `../vcsh alias`;
ok $output eq "ls = list
ci = commit -a
co = upgrade
", 'Add alias co';

$output = `../vcsh alias ci`;
ok $output eq "commit -a\n", 'Get alias ci';

system("../vcsh alias -d ci");
$output = `../vcsh alias`;
ok $output eq "ls = list
co = upgrade
", 'Delete alias ci';

done_testing;

121 changes: 104 additions & 17 deletions vcsh.in
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ help() {
-v Enable verbose mode

commands:
alias [<name>] List defined aliases
clone [-b <branch>] \\
<remote> \\
[<repo>] Clone from an existing repository
Expand Down Expand Up @@ -170,6 +171,78 @@ info() {
echo "$VCSH_SELF: info: $1"
}

alias_read() {
local aliases
if [ -r "$XDG_CONFIG_HOME/vcsh/aliases" ]; then
aliases="$XDG_CONFIG_HOME/vcsh/aliases"
elif [ -r /etc/vcsh/aliases ]; then
aliases=/etc/vcsh/aliases
else
return
fi
sed -r -e 's/#.*//' -ne 's/(\w+)\s*=\s*(.+)/\1 \2/p' "$aliases"
}

alias_get() {
local a cmd
if [ -n "$1" ]; then
alias_read | while read a cmd; do
if [ x"$1" = x"$a" ]; then
echo $cmd
return
fi
done
fi
}

alias_write() {
[ -w "$XDG_CONFIG_HOME/vcsh/aliases" ] ||
[ ! -e "$XDG_CONFIG_HOME/vcsh/aliases" -a -w "$XDG_CONFIG_HOME/vcsh/" ] ||
fatal "File '$XDG_CONFIG_HOME/vcsh/aliases' not writeable"
[ "$2" = '=' ] || fatal 'Invalid alias format'
if [ -n "$(alias_get $1)" ]; then
local regex="s/^$1\s*=.*/$@/"
sed -i.bak -re "$regex" "$XDG_CONFIG_HOME/vcsh/aliases"
else
echo "$@" >> "$XDG_CONFIG_HOME/vcsh/aliases"
fi
}

alias_remove() {
[ -w "$XDG_CONFIG_HOME/vcsh/aliases" ] ||
[ ! -e "$XDG_CONFIG_HOME/vcsh/aliases" -a -w "$XDG_CONFIG_HOME/vcsh/" ] ||
fatal "File '$XDG_CONFIG_HOME/vcsh/aliases' not writeable"
[ -n "$1" ] || fatal 'Empty alias'
local regex="/^$1\s*=/d"
sed -i.bak -re "$regex" "$XDG_CONFIG_HOME/vcsh/aliases"
}

aliases() {
if [ -n "$1" ]; then
local opts subcmd
while getopts d: opts; do
if [ $opts = d ]; then
alias_remove "$OPTARG"
fi
done
shift $(($OPTIND - 1))
local alias="$(echo "$@" | sed -nre 's/(\w+)\s*=\s*(\w.*)/\1 = \2/p')"
if [ -n "$alias" ]; then
alias_write $alias
else
alias_get "$1"
fi
else
# print all aliases
local a cmd
alias_read | while read a cmd; do
if [ -n "$a" ]; then
echo $a = $cmd
fi
done
fi
}

clone() {
hook pre-clone
# Check if remote is reachable. Abort early if there's a typo, TLS certificate problem, etc
Expand Down Expand Up @@ -429,6 +502,7 @@ push() {
hook_global post-push
}


retire() {
unset VCSH_DIRECTORY
}
Expand Down Expand Up @@ -595,23 +669,32 @@ fi

VCSH_COMMAND=$1; export VCSH_COMMAND

case $VCSH_COMMAND in
clon|clo|cl) VCSH_COMMAND=clone;;
commi|comm|com|co|ci) VCSH_COMMAND=commit;;
delet|dele|del|de) VCSH_COMMAND=delete;;
ente|ent|en) VCSH_COMMAND=enter;;
hel|he) VCSH_COMMAND=help;;
ini|in) VCSH_COMMAND=init;;
pul) VCSH_COMMAND=pull;;
pus) VCSH_COMMAND=push;;
renam|rena|ren|re) VCSH_COMMAND=rename;;
ru) VCSH_COMMAND=run;;
statu|stat|sta|st) VCSH_COMMAND=status;;
upgrad|upgra|upgr|up) VCSH_COMMAND=upgrade;;
versio|versi|vers|ver|ve) VCSH_COMMAND=version;;
which|whi|wh) VCSH_COMMAND=which;;
write|writ|wri|wr) VCSH_COMMAND=write-gitignore;;
esac
alias="$(alias_get $VCSH_COMMAND)"
if [ -n "$alias" ]; then
VCSH_COMMAND="$alias"
else
case $VCSH_COMMAND in
clon|clo|cl) old_alias=1;;
commi|comm|com|co|ci) old_alias=1;;
delet|dele|del|de) old_alias=1;;
ente|ent|en) old_alias=1;;
hel|he) old_alias=1;;
ini|in) old_alias=1;;
pul) old_alias=1;;
pus) old_alias=1;;
renam|rena|ren|re) old_alias=1;;
ru) old_alias=1;;
statu|stat|sta|st) old_alias=1;;
upgrad|upgra|upgr|up) old_alias=1;;
versio|versi|vers|ver|ve) old_alias=1;;
which|whi|wh) old_alias=1;;
write|writ|wri|wr) old_alias=1;;
esac
if [ -n "$old_alias" ]; then
echo "Aliases now dynamically defined. See vcsh(1) for details."
exit 1
fi
fi

if [ x"$VCSH_COMMAND" = x'clone' ]; then
VCSH_BRANCH=
Expand Down Expand Up @@ -682,6 +765,10 @@ elif [ x"$VCSH_COMMAND" = x'status' ]; then
shift
fi
VCSH_REPO_NAME=$2; export VCSH_REPO_NAME
elif [ x"$VCSH_COMMAND" = x'alias' ]; then
shift
aliases $@
exit
elif [ -n "$2" ]; then
VCSH_COMMAND='run'; export VCSH_COMMAND
VCSH_REPO_NAME=$1; export VCSH_REPO_NAME
Expand Down