-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproject-root
More file actions
executable file
·88 lines (71 loc) · 1.74 KB
/
project-root
File metadata and controls
executable file
·88 lines (71 loc) · 1.74 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
#!/bin/sh
# Print project root relative to current working directory
# Favors correctness over speed; stops at first match.
set -eu
cwd="$(pwd -P)"
# Normalize path
abspath() {
cd "$1" 2>/dev/null && pwd -P
}
# Convert absolute path to relative (portable)
relpath() {
target="$1"
base="$2"
# If realpath is available, use it
if command -v realpath >/dev/null 2>&1; then
realpath --relative-to="$base" "$target"
return
fi
# Fallback: manual method
common="$base"
up=""
while [ "${target#"$common"/}" = "$target" ]; do
common=$(dirname "$common")
up="../$up"
[ "$common" = "/" ] && break
done
down="${target#"$common"/}"
printf '%s%s\n' "$up" "$down"
}
# Try VCS-based detection
find_vcs_root() {
if command -v git >/dev/null 2>&1; then
git_root=$(git rev-parse --show-toplevel 2>/dev/null || true)
[ -n "$git_root" ] && echo "$git_root" && return
fi
dir="$cwd"
while [ "$dir" != "/" ]; do
for m in .hg .svn; do
[ -e "$dir/$m" ] && echo "$dir" && return
done
dir=$(dirname "$dir")
done
}
# Try project marker files
find_marker_root() {
markers="
.project-root
.root
pyproject.toml
setup.py
package.json
go.mod
Cargo.toml
Makefile
"
dir="$cwd"
while [ "$dir" != "/" ]; do
for m in $markers; do
[ -e "$dir/$m" ] && echo "$dir" && return
done
dir=$(dirname "$dir")
done
}
# Main detection logic
root=""
root="$(find_vcs_root || true)"
[ -z "$root" ] && root="$(find_marker_root || true)"
[ -z "$root" ] && root="$cwd"
root="$(abspath "$root")"
# Print relative path
relpath "$root" "$cwd"