geet-geet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/bin/geet.sh +150 -0
- package/docs/AUTO_PROMOTE.md +173 -0
- package/docs/CONTRIBUTING.md +142 -0
- package/docs/DEMO.md +131 -0
- package/docs/DEV_GUIDE.md +519 -0
- package/docs/FAQ.md +128 -0
- package/docs/MERGE_KEEP_OURS.md +243 -0
- package/docs/MULTI_LAYERED_TEMPLATES.md +92 -0
- package/docs/PREVENT_COMMIT_PATTERNS.md +250 -0
- package/docs/PUBLISHING_A_TEMPLATE.md +150 -0
- package/docs/UNDERSTANDING_GEET.md +68 -0
- package/docs/USING_A_TEMPLATE.md +131 -0
- package/lib/detach.sh +225 -0
- package/lib/digest-and-locate.sh +476 -0
- package/lib/doctor.sh +252 -0
- package/lib/flags.sh +52 -0
- package/lib/ghcli.sh +386 -0
- package/lib/git.sh +55 -0
- package/lib/help.sh +53 -0
- package/lib/ignored.sh +4 -0
- package/lib/include.sh +54 -0
- package/lib/init.sh +234 -0
- package/lib/install.sh +166 -0
- package/lib/logger.sh +278 -0
- package/lib/pre-commit/auto-promote-pgi.sh +20 -0
- package/lib/pre-commit/auto-promote-readme.sh +20 -0
- package/lib/pre-commit/hook.sh +66 -0
- package/lib/pre-commit/protect-patterns.sh +76 -0
- package/lib/pre-commit/unstage-soft-detached-files.sh +48 -0
- package/lib/prework.sh +181 -0
- package/lib/session.sh +111 -0
- package/lib/split.sh +120 -0
- package/lib/sync.sh +98 -0
- package/lib/template.sh +635 -0
- package/lib/tree.sh +252 -0
- package/lib/whoops.sh +37 -0
- package/package.json +15 -0
package/lib/session.sh
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# session.sh — run commands in isolated template snapshot
|
|
2
|
+
# Usage:
|
|
3
|
+
# source session.sh
|
|
4
|
+
# session run [options] -- <command...>
|
|
5
|
+
|
|
6
|
+
session() {
|
|
7
|
+
|
|
8
|
+
# digest-and-locate.sh provides: APP_DIR, TEMPLATE_DIR, TEMPLATE_NAME, GEET_LIB, GEET_ALIAS, die, log
|
|
9
|
+
|
|
10
|
+
usage() {
|
|
11
|
+
cat <<EOF
|
|
12
|
+
$GEET_ALIAS session — run commands in isolated template snapshot
|
|
13
|
+
|
|
14
|
+
This creates a temporary isolated copy of just the template files,
|
|
15
|
+
runs your command there, and optionally copies results back.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
$GEET_ALIAS session run [options] -- <command...>
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--mode tracked|all split mode (default: tracked)
|
|
22
|
+
--tmp <dir> use a specific temp dir (default: mktemp)
|
|
23
|
+
--keep do not delete temp dir after command
|
|
24
|
+
--copy-back A:B copy tmp/A back to repo/B after command
|
|
25
|
+
(repeatable)
|
|
26
|
+
|
|
27
|
+
Use cases:
|
|
28
|
+
- Build template in isolation (avoid polluting app with artifacts)
|
|
29
|
+
- Test template without app-specific code interfering
|
|
30
|
+
- Generate files that should live only in the template
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
$GEET_ALIAS session run -- npm run build
|
|
34
|
+
$GEET_ALIAS session run --mode all -- npm test
|
|
35
|
+
$GEET_ALIAS session run --copy-back dist:dist -- npm run build
|
|
36
|
+
$GEET_ALIAS session run --keep -- npm run build
|
|
37
|
+
EOF
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
sub="${1:-help}"; shift || true
|
|
41
|
+
if [[ "$sub" == "help" || "$sub" == "-h" || "$sub" == "--help" ]]; then
|
|
42
|
+
usage
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
[[ "$sub" == "run" ]] || { usage; return 1; }
|
|
46
|
+
|
|
47
|
+
mode="tracked"
|
|
48
|
+
tmp=""
|
|
49
|
+
keep=0
|
|
50
|
+
declare -a copy_back=()
|
|
51
|
+
|
|
52
|
+
# Parse args until "--"
|
|
53
|
+
while [[ $# -gt 0 ]]; do
|
|
54
|
+
case "$1" in
|
|
55
|
+
--mode) mode="${2:-}"; shift 2 ;;
|
|
56
|
+
--tmp) tmp="${2:-}"; shift 2 ;;
|
|
57
|
+
--keep) keep=1; shift ;;
|
|
58
|
+
--copy-back) copy_back+=("${2:-}"); shift 2 ;;
|
|
59
|
+
--) shift; break ;;
|
|
60
|
+
-h|--help) usage; return 0 ;;
|
|
61
|
+
*) die "unknown option: $1 (use --help)" ;;
|
|
62
|
+
esac
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
[[ $# -gt 0 ]] || die "missing command (use -- <command...>)"
|
|
66
|
+
|
|
67
|
+
# Decide temp dir
|
|
68
|
+
if [[ -z "$tmp" ]]; then
|
|
69
|
+
tmp="$(mktemp -d -t "${TEMPLATE_NAME}-session-XXXXXX")"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
cleanup() {
|
|
73
|
+
if [[ "$keep" -eq 1 ]]; then
|
|
74
|
+
log "keeping temp dir: $tmp"
|
|
75
|
+
return 0
|
|
76
|
+
fi
|
|
77
|
+
rm -rf "$tmp"
|
|
78
|
+
}
|
|
79
|
+
trap cleanup EXIT
|
|
80
|
+
|
|
81
|
+
log "splitting ($mode) to: $tmp"
|
|
82
|
+
# Call split function from split.sh
|
|
83
|
+
source "$GEET_LIB/split.sh"
|
|
84
|
+
split "$tmp" "$mode"
|
|
85
|
+
|
|
86
|
+
log "running in temp dir: $*"
|
|
87
|
+
(
|
|
88
|
+
cd "$tmp"
|
|
89
|
+
"$@"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Copy-back steps (optional)
|
|
93
|
+
for spec in "${copy_back[@]}"; do
|
|
94
|
+
src="${spec%%:*}"
|
|
95
|
+
dst="${spec#*:}"
|
|
96
|
+
[[ -n "$src" && -n "$dst" ]] || die "--copy-back expects A:B, got: $spec"
|
|
97
|
+
|
|
98
|
+
if [[ ! -e "$tmp/$src" ]]; then
|
|
99
|
+
log "copy-back skipped (missing in temp): $src"
|
|
100
|
+
continue
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
log "copying back: $src -> $dst"
|
|
104
|
+
rm -rf "$APP_DIR/$dst"
|
|
105
|
+
mkdir -p "$(dirname "$APP_DIR/$dst")"
|
|
106
|
+
cp -a "$tmp/$src" "$APP_DIR/$dst"
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
log "done"
|
|
110
|
+
|
|
111
|
+
} # end of session()
|
package/lib/split.sh
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# split.sh — export template files to external folder
|
|
2
|
+
# Usage:
|
|
3
|
+
# source split.sh
|
|
4
|
+
# split <dest_dir> [tracked|all]
|
|
5
|
+
|
|
6
|
+
split() {
|
|
7
|
+
|
|
8
|
+
# digest-and-locate.sh provides: APP_DIR, TEMPLATE_DIR, DOTGIT, TEMPLATE_NAME,
|
|
9
|
+
# TEMPLATE_GEETEXCLUDE, GEET_LIB, GEET_ALIAS, die, log
|
|
10
|
+
|
|
11
|
+
usage() {
|
|
12
|
+
cat <<EOF
|
|
13
|
+
$GEET_ALIAS split — export template files to external folder
|
|
14
|
+
|
|
15
|
+
This creates a clean snapshot of your template files in a separate directory.
|
|
16
|
+
Useful for inspecting, zipping, publishing, or comparing what's included.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
$GEET_ALIAS split <dest_dir> [tracked|all]
|
|
20
|
+
|
|
21
|
+
Modes:
|
|
22
|
+
tracked Export only files tracked by template repo (default)
|
|
23
|
+
all Export all files included by whitelist (may include untracked)
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
$GEET_ALIAS split /tmp/${TEMPLATE_NAME}-export
|
|
27
|
+
$GEET_ALIAS split ../exports/${TEMPLATE_NAME} all
|
|
28
|
+
$GEET_ALIAS split --help
|
|
29
|
+
|
|
30
|
+
Safety:
|
|
31
|
+
- Destination directory must NOT exist (prevents accidental overwrites)
|
|
32
|
+
- This does NOT change git history, only copies files
|
|
33
|
+
- Creates .layer-export-manifest.txt for auditing
|
|
34
|
+
|
|
35
|
+
Requirements:
|
|
36
|
+
- Layer must be initialized (dot-git exists)
|
|
37
|
+
- Whitelist must be compiled (.geetexclude exists)
|
|
38
|
+
EOF
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Handle help
|
|
42
|
+
if [[ "${1:-}" == "help" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
43
|
+
usage
|
|
44
|
+
return 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
dest="${1:-}"
|
|
48
|
+
mode="${2:-tracked}"
|
|
49
|
+
|
|
50
|
+
[[ -n "$dest" ]] || { usage; return 1; }
|
|
51
|
+
|
|
52
|
+
# Precondition checks
|
|
53
|
+
[[ -d "$DOTGIT" && -f "$DOTGIT/HEAD" ]] || die "layer not initialized (run: $GEET_ALIAS init)"
|
|
54
|
+
[[ -f "$TEMPLATE_DIR/.geetexclude" ]] || die "missing compiled exclude. Run: $GEET_ALIAS sync"
|
|
55
|
+
|
|
56
|
+
# Safety: refuse to export into an existing directory to avoid accidental overwrites.
|
|
57
|
+
if [[ -e "$dest" ]]; then
|
|
58
|
+
die "destination already exists: $dest"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Build file list
|
|
62
|
+
tmp_list="$(mktemp)"
|
|
63
|
+
cleanup() { rm -f "$tmp_list"; }
|
|
64
|
+
trap cleanup EXIT
|
|
65
|
+
|
|
66
|
+
case "$mode" in
|
|
67
|
+
tracked)
|
|
68
|
+
# Export what the template repo actually tracks
|
|
69
|
+
git --git-dir="$DOTGIT" --work-tree="$APP_DIR" ls-files > "$tmp_list"
|
|
70
|
+
;;
|
|
71
|
+
all)
|
|
72
|
+
# Export anything the whitelist includes (even if untracked)
|
|
73
|
+
source "$GEET_LIB/tree.sh"
|
|
74
|
+
tree list all > "$tmp_list"
|
|
75
|
+
;;
|
|
76
|
+
*)
|
|
77
|
+
die "unknown mode: $mode (use tracked|all)"
|
|
78
|
+
;;
|
|
79
|
+
esac
|
|
80
|
+
|
|
81
|
+
# Ensure there is something to export
|
|
82
|
+
if ! grep -q . "$tmp_list"; then
|
|
83
|
+
die "nothing to export in mode '$mode' (is your whitelist empty?)"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
log "exporting layer '$TEMPLATE_NAME' ($mode) to: $dest"
|
|
87
|
+
mkdir -p "$dest"
|
|
88
|
+
|
|
89
|
+
# Copy files preserving paths.
|
|
90
|
+
# We use tar because it is:
|
|
91
|
+
# - fast
|
|
92
|
+
# - preserves directories
|
|
93
|
+
# - handles lots of files well
|
|
94
|
+
#
|
|
95
|
+
# This avoids rsync dependency and avoids writing a bunch of mkdir/cp loops.
|
|
96
|
+
(
|
|
97
|
+
cd "$APP_DIR"
|
|
98
|
+
# Use null delimiters to safely handle weird filenames
|
|
99
|
+
# Convert line-delimited list to null-delimited for tar
|
|
100
|
+
while IFS= read -r line; do
|
|
101
|
+
# Skip empty lines
|
|
102
|
+
[[ -n "$line" ]] && printf '%s\0' "$line"
|
|
103
|
+
done < "$tmp_list" | tar -cpf - --null -T - | (cd "$dest" && tar -xpf -)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Write a small manifest for auditing
|
|
107
|
+
{
|
|
108
|
+
echo "layer: $TEMPLATE_NAME"
|
|
109
|
+
echo "mode: $mode"
|
|
110
|
+
echo "source_root: $APP_DIR"
|
|
111
|
+
echo "exported_at: $(date -Is 2>/dev/null || date)"
|
|
112
|
+
echo
|
|
113
|
+
echo "files:"
|
|
114
|
+
cat "$tmp_list"
|
|
115
|
+
} > "$dest/.layer-export-manifest.txt"
|
|
116
|
+
|
|
117
|
+
log "done"
|
|
118
|
+
log "wrote manifest: $dest/.layer-export-manifest.txt"
|
|
119
|
+
|
|
120
|
+
} # end of split()
|
package/lib/sync.sh
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
sync() {
|
|
2
|
+
debug "running sync"
|
|
3
|
+
# Show help if requested
|
|
4
|
+
if [[ "${1:-}" == "help" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
5
|
+
cat <<EOF
|
|
6
|
+
$GEET_ALIAS sync — compile .geetinclude whitelist into .geetexclude
|
|
7
|
+
|
|
8
|
+
This command processes your .geetinclude file (whitelist) and compiles it
|
|
9
|
+
into .geetexclude (gitignore-style format) between special markers.
|
|
10
|
+
|
|
11
|
+
What it does:
|
|
12
|
+
1. Reads each line from .geetinclude
|
|
13
|
+
2. Converts whitelist patterns to gitignore format:
|
|
14
|
+
- 'foo' → '!foo' (include this)
|
|
15
|
+
- '!foo' → 'foo' (exclude this - removes the !)
|
|
16
|
+
- '!!foo' → '!foo' (literal ! prefix)
|
|
17
|
+
3. Inserts compiled rules between GEETINCLUDESTART and GEETINCLUDEEND markers
|
|
18
|
+
4. Preserves manual rules before/after the markers
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
$GEET_ALIAS sync
|
|
22
|
+
|
|
23
|
+
When to run:
|
|
24
|
+
- After editing .geetinclude
|
|
25
|
+
- Before running git commands on the template
|
|
26
|
+
- Note: Most geet commands auto-sync, so manual sync is rarely needed
|
|
27
|
+
|
|
28
|
+
File locations:
|
|
29
|
+
Source: $TEMPLATE_DIR/.geetinclude
|
|
30
|
+
Output: $TEMPLATE_DIR/.geetexclude
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
$GEET_ALIAS sync # Compile whitelist rules
|
|
34
|
+
EOF
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
[[ -f "$TEMPLATE_DIR/.geetinclude" ]] || return 0
|
|
39
|
+
|
|
40
|
+
# Markers for the auto-populated section
|
|
41
|
+
local START_MARKER="# GEETINCLUDESTART"
|
|
42
|
+
local END_MARKER="# GEETINCLUDEEND"
|
|
43
|
+
|
|
44
|
+
# Generate compiled rules
|
|
45
|
+
local compiled_rules=""
|
|
46
|
+
# WHITELIST MODE: Process .geetinclude
|
|
47
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
48
|
+
line="${line#"${line%%[![:space:]]*}"}"
|
|
49
|
+
line="${line%"${line##*[![:space:]]}"}"
|
|
50
|
+
|
|
51
|
+
[[ -z "$line" ]] && continue
|
|
52
|
+
[[ "$line" == \#* ]] && continue
|
|
53
|
+
|
|
54
|
+
if [[ "$line" == "!!"* ]]; then
|
|
55
|
+
compiled_rules+="!${line#!!}"$'\n'
|
|
56
|
+
elif [[ "$line" == "!"* ]]; then
|
|
57
|
+
compiled_rules+="${line#!}"$'\n'
|
|
58
|
+
else
|
|
59
|
+
compiled_rules+="!$line"$'\n'
|
|
60
|
+
fi
|
|
61
|
+
done < "$TEMPLATE_DIR/.geetinclude"
|
|
62
|
+
|
|
63
|
+
# Read existing .geetexclude or create default structure
|
|
64
|
+
local before_marker=""
|
|
65
|
+
local after_marker=""
|
|
66
|
+
|
|
67
|
+
if [[ -f "$TEMPLATE_DIR/.geetexclude" ]]; then
|
|
68
|
+
# File exists - extract parts before and after markers
|
|
69
|
+
local in_marker=0
|
|
70
|
+
while IFS= read -r line; do
|
|
71
|
+
if [[ "$line" == "$START_MARKER" ]]; then
|
|
72
|
+
in_marker=1
|
|
73
|
+
continue
|
|
74
|
+
elif [[ "$line" == "$END_MARKER" ]]; then
|
|
75
|
+
in_marker=2
|
|
76
|
+
continue
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [[ $in_marker -eq 0 ]]; then
|
|
80
|
+
before_marker+="$line"$'\n'
|
|
81
|
+
elif [[ $in_marker -eq 2 ]]; then
|
|
82
|
+
after_marker+="$line"$'\n'
|
|
83
|
+
fi
|
|
84
|
+
done < "$TEMPLATE_DIR/.geetexclude"
|
|
85
|
+
else
|
|
86
|
+
die "$TEMPLATE_DIR/.geetexclude not found"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Write new .geetexclude with compiled rules between markers
|
|
90
|
+
{
|
|
91
|
+
printf "%s" "$before_marker"
|
|
92
|
+
echo "$START_MARKER"
|
|
93
|
+
echo "# Autopopulated from .geetinclude, do not modify"
|
|
94
|
+
printf "%s" "$compiled_rules"
|
|
95
|
+
echo "$END_MARKER"
|
|
96
|
+
printf "%s" "$after_marker"
|
|
97
|
+
} > "$TEMPLATE_DIR/.geetexclude"
|
|
98
|
+
}
|