-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhooks.ts
More file actions
130 lines (112 loc) · 3.48 KB
/
Copy pathhooks.ts
File metadata and controls
130 lines (112 loc) · 3.48 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
124
125
126
127
128
129
130
// 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;
};