forked from rstackjs/rstack-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhooks.ts
More file actions
123 lines (105 loc) · 3.42 KB
/
Copy pathhooks.ts
File metadata and controls
123 lines (105 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Keep this list aligned with the client-side hooks generated by Husky v9.
// `pre-auto-gc` is included even though it is not listed in Husky's documentation.
export const hookNames: string[] = [
'pre-commit',
'pre-merge-commit',
'prepare-commit-msg',
'commit-msg',
'post-commit',
'applypatch-msg',
'pre-applypatch',
'post-applypatch',
'pre-rebase',
'post-rewrite',
'post-checkout',
'post-merge',
'pre-push',
'pre-auto-gc',
];
// Git for Windows runs hooks in a POSIX shell, where drive-letter paths need
// their Git Bash form to avoid treating the drive colon as a PATH separator.
const quoteShellPath = (value: string): string => {
const shellPath =
process.platform === 'win32'
? value
.replaceAll('\\', '/')
.replace(/^([A-Za-z]):\//u, (_, drive: string) => `/${drive.toLowerCase()}/`)
: value;
return `'${shellPath.replaceAll("'", `'"'"'`)}'`;
};
const createRunner = (nodeExecutable: string): string => `#!/usr/bin/env sh
# Generated by Rstack. Do not edit.
rs_name=\${0##*/}
rs_root=$PWD
rs_hook="\${rs_dir%/*}/$rs_name"
[ -f "$rs_hook" ] || exit 0
rs_init="\${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh"
[ -f "$rs_init" ] && . "$rs_init"
[ "\${RSTACK_HOOKS-}" = "0" ] && exit 0
[ "\${RSTACK_HOOKS-}" = "2" ] && set -x
IFS= read -r rs_project_path < "$rs_dir/.owner" || exit 1
[ -n "$rs_project_path" ] || exit 1
# Fall back to the Node.js executable that ran rs setup when GUI clients omit
# it from PATH. Keep an existing Node.js environment ahead of this fallback.
rs_node_fallback=${quoteShellPath(nodeExecutable)}
if ! command -v node >/dev/null 2>&1 && [ -x "$rs_node_fallback" ]; then
PATH="\${PATH:+$PATH:}\${rs_node_fallback%/*}"
fi
rs_run() {
cd "$rs_root/$rs_project_path" || return 1
export PATH="node_modules/.bin\${PATH:+:$PATH}"
rs_code=0
sh -e "$rs_hook" "$@" || rs_code=$?
[ "$rs_code" = "0" ] || echo "Rstack - $rs_name hook failed (code $rs_code)"
[ "$rs_code" = "127" ] && echo "Rstack - command not found in PATH=$PATH"
return "$rs_code"
}
`;
const createShim = (prepareArguments = ''): string => `#!/usr/bin/env sh
rs_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) || exit 1
. "$rs_dir/runner"
${prepareArguments}
rs_run "$@"
`;
export const createHookFiles = (
nodeExecutable: string = process.execPath,
): Record<string, string> => {
const messageShim = createShim(`# Keep the message file valid after changing directories.
[ -n "\${1-}" ] || exit 1
case "$1" in
/*|[A-Za-z]:/*) ;;
*)
rs_file=$1
shift
set -- "$rs_root/$rs_file" "$@"
;;
esac
`);
const prePushShim = createShim(`# Keep a local remote path valid after changing directories.
rs_remote_name=\${1-}
rs_remote_location=\${2-}
[ -n "$rs_remote_name" ] && [ -n "$rs_remote_location" ] || exit 1
case "$rs_remote_location" in
/*|[A-Za-z]:/*) ;;
*:*)
# Git treats a colon before any slash as a URL or SCP-style remote.
case "\${rs_remote_location%%:*}" in
*/*) rs_remote_location="$rs_root/$rs_remote_location" ;;
esac
;;
*) rs_remote_location="$rs_root/$rs_remote_location" ;;
esac
shift 2
set -- "$rs_remote_name" "$rs_remote_location" "$@"
`);
const defaultShim = createShim();
const files: Record<string, string> = { runner: createRunner(nodeExecutable) };
for (const name of hookNames) {
files[name] = name.endsWith('-msg')
? messageShim
: name === 'pre-push'
? prePushShim
: defaultShim;
}
return files;
};