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/git.sh
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# git.sh — template git operations
|
|
2
|
+
# Usage:
|
|
3
|
+
# source git.sh
|
|
4
|
+
# (exposed functions are used via geet.sh command dispatcher)
|
|
5
|
+
#
|
|
6
|
+
# Provides git wrapper functions for template repo operations
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Helper: sync .geetinclude to .geetexclude
|
|
11
|
+
sync_exclude() {
|
|
12
|
+
source "$GEET_LIB/sync.sh"
|
|
13
|
+
sync
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Helper: check if template git repo exists
|
|
17
|
+
need_dotgit() {
|
|
18
|
+
[[ -d "$DOTGIT" && -f "$DOTGIT/HEAD" ]] || die "missing $DOTGIT (run: $GEET_ALIAS init)"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Helper: block dangerous git commands
|
|
22
|
+
block_footguns() {
|
|
23
|
+
case "${1-}" in
|
|
24
|
+
clean|reset|checkout|restore|rm)
|
|
25
|
+
brave_guard "git $1" "git $1 can be destructive and mess with your app's working directory"
|
|
26
|
+
;;
|
|
27
|
+
esac
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
###############################################################################
|
|
31
|
+
# CLONE - Simple git clone without init
|
|
32
|
+
###############################################################################
|
|
33
|
+
# Just clones a repository without running any post-install logic
|
|
34
|
+
call_cmd() {
|
|
35
|
+
if [[ -z "$TEMPLATE_DIR" ]]; then
|
|
36
|
+
critical "We could not find your template repo anywhere in this project!"
|
|
37
|
+
warn "Are you sure you are somewhere inside a project which has a template repo?"
|
|
38
|
+
warn "The template repo is a hidden folder at the root of your working directory which contains a .geethier file inside it"
|
|
39
|
+
warn "To debug our search, run \`$GEET_ALIAS status --verbose --filter LOCATE\`"
|
|
40
|
+
warn "If you think we made a mistake, review the code at $GEET_LIB/digest-and-locate.sh detect_template_dir_from_cwd"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
need_dotgit
|
|
44
|
+
sync_exclude
|
|
45
|
+
block_footguns "$@"
|
|
46
|
+
if [[ "$1" == "push" ]] && ! [[ "$(geet_git remote -v)" ]]; then
|
|
47
|
+
log "It looks like you have no remote setup yet. Would you like to publish on github?"
|
|
48
|
+
log "Just run \`$GEET_ALIAS pub\` to publish as a public repo or \`$GEET_ALIAS publish --private\`"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
geet_git "$@"
|
|
52
|
+
# if [[ "$1" == "status" ]]; then
|
|
53
|
+
# log "Don't Panic! it is expected to see README.md and .gitignore show up as deleted, don't worry. read docs/AUTO_PROMOTE.md to understand why"
|
|
54
|
+
# fi
|
|
55
|
+
}
|
package/lib/help.sh
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# help.sh — display overview of all geet commands
|
|
2
|
+
# Usage:
|
|
3
|
+
# source help.sh
|
|
4
|
+
# help
|
|
5
|
+
|
|
6
|
+
help() {
|
|
7
|
+
|
|
8
|
+
# digest-and-locate.sh provides: GEET_ALIAS, TEMPLATE_NAME, die, log
|
|
9
|
+
|
|
10
|
+
cat <<EOF
|
|
11
|
+
$GEET_ALIAS — Git-based template layering system
|
|
12
|
+
|
|
13
|
+
Usage: $GEET_ALIAS <command> [args...]
|
|
14
|
+
|
|
15
|
+
TEMPLATE MANAGEMENT:
|
|
16
|
+
template <name> [desc] Create a new template layer from current app
|
|
17
|
+
init Initialize a freshly-cloned template repo as your app
|
|
18
|
+
install <repo> Clone a template repo and initialize it (clone + init)
|
|
19
|
+
clone <repo> Clone a git repository (standard git clone)
|
|
20
|
+
|
|
21
|
+
FILE MANAGEMENT:
|
|
22
|
+
tree [list|tracked|all] Show what files the template includes
|
|
23
|
+
split <dest> [mode] Export template files to external folder
|
|
24
|
+
sync Compile .geetinclude whitelist into .geetexclude
|
|
25
|
+
detach "Detach" a file, folder, or glob to always use "keep-ours" to resolve merge conflicts, essentially allowing you to overwrite a file's template
|
|
26
|
+
retach undo a detach command
|
|
27
|
+
detached list files that have been detached
|
|
28
|
+
|
|
29
|
+
OPERATIONS:
|
|
30
|
+
session run [opts] -- cmd Run command in isolated template snapshot
|
|
31
|
+
publish [opts] Publish template to GitHub (auto-detects repo name)
|
|
32
|
+
gh <subcommand> [...] GitHub CLI integration (pr, issue, etc.)
|
|
33
|
+
doctor Run health checks on your geet setup
|
|
34
|
+
|
|
35
|
+
GIT ACCESS:
|
|
36
|
+
git <command> [...] Direct git access to template repo
|
|
37
|
+
<git-command> [...] Any git command (auto-forwarded to template repo)
|
|
38
|
+
|
|
39
|
+
Get help on any command:
|
|
40
|
+
$GEET_ALIAS <command> --help
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
$GEET_ALIAS template my-stack "A modern web stack"
|
|
44
|
+
$GEET_ALIAS install https://github.com/user/template-repo
|
|
45
|
+
$GEET_ALIAS tree list
|
|
46
|
+
$GEET_ALIAS publish --public
|
|
47
|
+
$GEET_ALIAS status
|
|
48
|
+
$GEET_ALIAS commit -m "Update template"
|
|
49
|
+
|
|
50
|
+
Current layer: ${TEMPLATE_NAME:-none}
|
|
51
|
+
EOF
|
|
52
|
+
|
|
53
|
+
} # end of help()
|
package/lib/ignored.sh
ADDED
package/lib/include.sh
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# git.sh — template git operations
|
|
2
|
+
# Usage:
|
|
3
|
+
# source git.sh
|
|
4
|
+
# (exposed functions are used via geet.sh command dispatcher)
|
|
5
|
+
#
|
|
6
|
+
# Provides git wrapper functions for template repo operations
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Helper: sync .geetinclude to .geetexclude
|
|
11
|
+
sync_exclude() {
|
|
12
|
+
source "$GEET_LIB/sync.sh"
|
|
13
|
+
sync
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Helper: check if template git repo exists
|
|
17
|
+
need_dotgit() {
|
|
18
|
+
[[ -d "$DOTGIT" && -f "$DOTGIT/HEAD" ]] || die "missing $DOTGIT (run: $GEET_ALIAS init)"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
###############################################################################
|
|
23
|
+
# CLONE - Simple git clone without init
|
|
24
|
+
###############################################################################
|
|
25
|
+
# Just clones a repository without running any post-install logic
|
|
26
|
+
include() {
|
|
27
|
+
if [[ -z "$TEMPLATE_DIR" ]]; then
|
|
28
|
+
critical "We could not find your template repo anywhere in this project!"
|
|
29
|
+
warn "Are you sure you are somewhere inside a project which has a template repo?"
|
|
30
|
+
warn "The template repo is a hidden folder at the root of your working directory which contains a .geethier file inside it"
|
|
31
|
+
warn "To debug our search, run \`$GEET_ALIAS status --verbose --filter LOCATE\`"
|
|
32
|
+
warn "If you think we made a mistake, review the code at $GEET_LIB/digest-and-locate.sh detect_template_dir_from_cwd"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
need_dotgit
|
|
36
|
+
sync_exclude
|
|
37
|
+
# first, modify .geetinclude
|
|
38
|
+
source "$GEET_LIB/ignored.sh"
|
|
39
|
+
for arg in "$@"; do
|
|
40
|
+
status="$(is_ignored $arg)"
|
|
41
|
+
debug "status of $arg is \"$status\""
|
|
42
|
+
if [[ "$status" == "ignored" ]]; then
|
|
43
|
+
echo "$arg" >> "$TEMPLATE_DIR/.geetinclude"
|
|
44
|
+
sync_exclude
|
|
45
|
+
status="$(is_ignored $arg)"
|
|
46
|
+
if [[ "$status" == "ignored" ]]; then
|
|
47
|
+
die "failed to unignore $arg"
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
geet_git add "$arg"
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
}
|
package/lib/init.sh
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# init.sh — layer initializer / bootstrapper (IDEMPOTENT)
|
|
2
|
+
# Usage:
|
|
3
|
+
# source init.sh
|
|
4
|
+
# init [args...]
|
|
5
|
+
#
|
|
6
|
+
# Turns a freshly-cloned TEMPLATE REPO into a normal APP REPO,
|
|
7
|
+
# while preserving the template repo as a "layer view" in dot-git/
|
|
8
|
+
|
|
9
|
+
init() {
|
|
10
|
+
|
|
11
|
+
###############################################################################
|
|
12
|
+
# HELP
|
|
13
|
+
###############################################################################
|
|
14
|
+
if [[ "${1:-}" == "help" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
15
|
+
cat <<EOF
|
|
16
|
+
$GEET_ALIAS init — initialize a freshly-cloned template repo as your app
|
|
17
|
+
|
|
18
|
+
This command turns a freshly-cloned TEMPLATE REPO into a normal APP REPO,
|
|
19
|
+
while preserving the template repo as a "layer view" in dot-git/
|
|
20
|
+
|
|
21
|
+
What it does:
|
|
22
|
+
1. Moves .git → .$APP_NAME/dot-git (or whatever the layer is called)
|
|
23
|
+
This "captures" the cloned template repo's git database
|
|
24
|
+
2. Creates a brand new app repo at .git
|
|
25
|
+
Your new app starts with a clean slate
|
|
26
|
+
3. Syncs whitelist rules (.geetinclude → .geetexclude)
|
|
27
|
+
4. Ensures .gitignore excludes **/dot-git/
|
|
28
|
+
5. Optionally runs post-init hook if present
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
$GEET_ALIAS init [post-init-args...]
|
|
32
|
+
|
|
33
|
+
Note: Usually called automatically by '$GEET_ALIAS install'
|
|
34
|
+
|
|
35
|
+
Arguments:
|
|
36
|
+
post-init-args Optional arguments passed to the post-init hook
|
|
37
|
+
(if .geet/post-init.sh exists and is executable)
|
|
38
|
+
|
|
39
|
+
Key Idea (two repos, one working tree):
|
|
40
|
+
- App repo: $DD_APP_NAME/.git (your normal development)
|
|
41
|
+
- Template layer: $DD_APP_NAME/.geet/dot-git (tracks whitelisted files only)
|
|
42
|
+
|
|
43
|
+
Both repos share the same working tree ($DD_APP_NAME/), but have separate gitdirs.
|
|
44
|
+
|
|
45
|
+
Idempotency:
|
|
46
|
+
- If already initialized, prints status and exits successfully
|
|
47
|
+
- Safe to run multiple times
|
|
48
|
+
|
|
49
|
+
Environment Variables:
|
|
50
|
+
GEET_RUN_POST_INIT Set to 0 to skip post-init hook (default: 1)
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
cd MyNewApp && $GEET_ALIAS init
|
|
54
|
+
cd MyNewApp && $GEET_ALIAS init --app-name "My Cool App"
|
|
55
|
+
GEET_RUN_POST_INIT=0 $GEET_ALIAS init # Skip post-init hook
|
|
56
|
+
EOF
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
has_flag --skip-post SKIP_POST_INIT
|
|
62
|
+
|
|
63
|
+
###############################################################################
|
|
64
|
+
# SETUP
|
|
65
|
+
###############################################################################
|
|
66
|
+
# digest-and-locate.sh provides: GEET_LIB, APP_DIR, TEMPLATE_DIR, DOTGIT,
|
|
67
|
+
# TEMPLATE_GEET_CMD, die, log, debug
|
|
68
|
+
|
|
69
|
+
# App repo git directory (normal repo)
|
|
70
|
+
APP_GIT="$APP_DIR/.git"
|
|
71
|
+
|
|
72
|
+
###############################################################################
|
|
73
|
+
# PRECONDITIONS
|
|
74
|
+
###############################################################################
|
|
75
|
+
|
|
76
|
+
# Sanity check: git.sh should exist
|
|
77
|
+
if [[ ! -f "$GEET_LIB/git.sh" ]]; then
|
|
78
|
+
log "warning: missing $GEET_LIB/git.sh (will skip post-init exclude sync)"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
###############################################################################
|
|
82
|
+
# IDEMPOTENCY CHECK
|
|
83
|
+
###############################################################################
|
|
84
|
+
|
|
85
|
+
# If the layer dot-git already exists, we've already initialized this layer
|
|
86
|
+
# for this working tree. Do not attempt to re-run conversion.
|
|
87
|
+
if [[ -d "$DOTGIT" && -f "$DOTGIT/HEAD" ]]; then
|
|
88
|
+
log "already initialized"
|
|
89
|
+
log "layer gitdir: $DOTGIT"
|
|
90
|
+
log "app gitdir: $APP_GIT"
|
|
91
|
+
return 0
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
###############################################################################
|
|
95
|
+
# MAIN CONVERSION LOGIC
|
|
96
|
+
###############################################################################
|
|
97
|
+
|
|
98
|
+
# The expected "fresh clone" state for THIS layer is:
|
|
99
|
+
# - APP_GIT exists (because you just cloned a template repo)
|
|
100
|
+
# - DOTGIT does not exist yet
|
|
101
|
+
#
|
|
102
|
+
# Example:
|
|
103
|
+
# - user clones $GEET_ALIAS template to MyApp2
|
|
104
|
+
# - MyApp2/.git exists
|
|
105
|
+
# - MyApp2/.geet/dot-git does not
|
|
106
|
+
#
|
|
107
|
+
# Another example:
|
|
108
|
+
# - user clones sk2 template to MyApp3
|
|
109
|
+
# - MyApp3/.git exists
|
|
110
|
+
# - MyApp3/.sk2/dot-git does not
|
|
111
|
+
#
|
|
112
|
+
# If APP_GIT doesn't exist, we do NOT know what to do (maybe user didn't clone).
|
|
113
|
+
if [[ ! -d "$APP_GIT" ]]; then
|
|
114
|
+
die "expected $APP_GIT to exist (did you run this in a freshly cloned template repo?)"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# Create layer directory if missing (should exist because this script is inside it)
|
|
118
|
+
log "making $TEMPLATE_DIR"
|
|
119
|
+
mkdir -p "$TEMPLATE_DIR"
|
|
120
|
+
|
|
121
|
+
log "moving $APP_GIT to $DOTGIT"
|
|
122
|
+
mv "$APP_GIT" "$DOTGIT"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
###############################################################################
|
|
126
|
+
# CREATE NEW APP REPO
|
|
127
|
+
###############################################################################
|
|
128
|
+
|
|
129
|
+
# After the move:
|
|
130
|
+
# - APP_DIR/.git no longer exists
|
|
131
|
+
# - DOTGIT contains the template git database
|
|
132
|
+
#
|
|
133
|
+
# Now we create a fresh app repo at APP_DIR/.git
|
|
134
|
+
log "initializing new app repo at $APP_GIT"
|
|
135
|
+
git -C "$APP_DIR" init >/dev/null
|
|
136
|
+
|
|
137
|
+
###############################################################################
|
|
138
|
+
# ENSURE APP .geetexclude IGNORES dot-git/
|
|
139
|
+
###############################################################################
|
|
140
|
+
|
|
141
|
+
# Critical safety: dot-git/ contains git internals and must NEVER be committed
|
|
142
|
+
# to the app repo. Ensure it's in .gitignore.
|
|
143
|
+
APP_GITIGNORE="$APP_DIR/.gitignore"
|
|
144
|
+
DOTGIT_PATTERN="**/dot-git/"
|
|
145
|
+
UNTRACKED_PATTERN="**/untracked-template-config.env"
|
|
146
|
+
if [[ -f "$APP_GITIGNORE" ]]; then
|
|
147
|
+
# Check if any form of dot-git ignore already exists
|
|
148
|
+
if ! grep -Eq '(^|[[:space:]])((\*\*/)?dot-git/|\.geet/dot-git/)([[:space:]]|$)' "$APP_GITIGNORE"; then
|
|
149
|
+
log "adding $DOTGIT_PATTERN to app .gitignore"
|
|
150
|
+
echo "$DOTGIT_PATTERN" >> "$APP_GITIGNORE"
|
|
151
|
+
else
|
|
152
|
+
log "app .gitignore already ignores dot-git/"
|
|
153
|
+
fi
|
|
154
|
+
if ! grep -Eq 'untracked-template-config.env' "$APP_GITIGNORE"; then
|
|
155
|
+
log "adding $UNTRACKED_PATTERN to app .gitignore"
|
|
156
|
+
echo "$UNTRACKED_PATTERN" >> "$APP_GITIGNORE"
|
|
157
|
+
else
|
|
158
|
+
log "app .gitignore already ignores untracked/"
|
|
159
|
+
fi
|
|
160
|
+
else
|
|
161
|
+
log "creating app .gitignore with $DOTGIT_PATTERN"
|
|
162
|
+
echo "$DOTGIT_PATTERN" > "$APP_GITIGNORE"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
git add .
|
|
167
|
+
git commit -m "initial commit"
|
|
168
|
+
###############################################################################
|
|
169
|
+
# FINAL OUTPUT
|
|
170
|
+
###############################################################################
|
|
171
|
+
log "done"
|
|
172
|
+
log "layer initialized:"
|
|
173
|
+
log " layer: $TEMPLATE_NAME"
|
|
174
|
+
log " worktree: $APP_DIR"
|
|
175
|
+
log " layer gitdir: $DOTGIT"
|
|
176
|
+
log " app gitdir: $APP_GIT"
|
|
177
|
+
log
|
|
178
|
+
log "next steps:"
|
|
179
|
+
log " - develop normally with: git ..."
|
|
180
|
+
log " - update this layer with: $GEET_ALIAS pull"
|
|
181
|
+
log " - see included files with: $GEET_ALIAS tree"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if ! [[ "$SKIP_POST_INIT" ]]; then
|
|
185
|
+
###############################################################################
|
|
186
|
+
# OPTIONAL POST-INIT HOOK
|
|
187
|
+
###############################################################################
|
|
188
|
+
# Some templates want to do a one-time setup step after init, e.g.:
|
|
189
|
+
# - create .env from .env.sample
|
|
190
|
+
# - rename package name / bundle id
|
|
191
|
+
# - install dependencies
|
|
192
|
+
# - print “next steps” instructions
|
|
193
|
+
#
|
|
194
|
+
# geet itself should not become a framework-specific scaffold tool, so we keep
|
|
195
|
+
# this mechanism very small and template-owned:
|
|
196
|
+
#
|
|
197
|
+
# - If <layer>/post-init.sh exists AND is executable, we run it.
|
|
198
|
+
# - Otherwise, we do nothing.
|
|
199
|
+
#
|
|
200
|
+
# Security note:
|
|
201
|
+
# - This is code from the template you just cloned.
|
|
202
|
+
# - Running it is equivalent to "running a script from the internet".
|
|
203
|
+
# - Keep it simple and obvious, and consider requiring an env var gate later.
|
|
204
|
+
POST_INIT_SH="$TEMPLATE_DIR/post-init.sh"
|
|
205
|
+
|
|
206
|
+
if [[ -f "$POST_INIT_SH" ]]; then
|
|
207
|
+
if [[ ! -x "$POST_INIT_SH" ]]; then
|
|
208
|
+
die "found post-init hook but it is not executable: $POST_INIT_SH (run: chmod +x $POST_INIT_SH)"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
log "running post-init hook:"
|
|
212
|
+
log " $POST_INIT_SH"
|
|
213
|
+
|
|
214
|
+
# Provide some context to the hook.
|
|
215
|
+
# The hook can use these to make decisions without re-discovering paths.
|
|
216
|
+
export GEET_LAYER_DIR="$TEMPLATE_DIR"
|
|
217
|
+
export GEET_LAYER_NAME="$TEMPLATE_NAME"
|
|
218
|
+
export GEET_ROOT="$APP_DIR"
|
|
219
|
+
export GEET_DOTGIT="$DOTGIT"
|
|
220
|
+
|
|
221
|
+
# Run from the project root so relative paths behave naturally.
|
|
222
|
+
# Pass through any arguments that were provided to init.sh (from install command).
|
|
223
|
+
(
|
|
224
|
+
cd "$APP_DIR"
|
|
225
|
+
"$POST_INIT_SH" "$@"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
log "post-init hook complete"
|
|
229
|
+
log "enjoy developing!"
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
} # end of init()
|
package/lib/install.sh
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# install.sh — clone and init
|
|
2
|
+
# Usage:
|
|
3
|
+
# source install.sh
|
|
4
|
+
# (exposed functions are used via geet.sh command dispatcher)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
###############################################################################
|
|
8
|
+
# INSTALL - Clone a template repo and run init
|
|
9
|
+
###############################################################################
|
|
10
|
+
# This is a convenience command for first-time users:
|
|
11
|
+
#
|
|
12
|
+
# $GEET_ALIAS install <repo> [dir] [--recurse-submodules]
|
|
13
|
+
#
|
|
14
|
+
# It:
|
|
15
|
+
# 1) runs `git clone`
|
|
16
|
+
# 2) cd's into the directory
|
|
17
|
+
# 3) runs this layer's init.sh to convert the clone into an app + layer
|
|
18
|
+
#
|
|
19
|
+
install() {
|
|
20
|
+
local INIT_SH="$GEET_LIB/init.sh"
|
|
21
|
+
[[ -f "$INIT_SH" ]] || die "missing init script: $INIT_SH"
|
|
22
|
+
|
|
23
|
+
# Check for help first
|
|
24
|
+
if [[ "${1:-}" == "help" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
25
|
+
cat <<EOF
|
|
26
|
+
Usage:
|
|
27
|
+
$GEET_ALIAS install <repo> <dir> [options] [-- post-init-args...]
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--recurse-submodules, -r Clone with submodules
|
|
31
|
+
--pub, --public Publish app as public GitHub repo after install
|
|
32
|
+
--pri, --private Publish app as private GitHub repo after install
|
|
33
|
+
--int, --internal Publish app as internal GitHub repo after install
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
$GEET_ALIAS install git@github.com:$GH_USER/template.git MyApp
|
|
37
|
+
$GEET_ALIAS install mytemplate MyApp --pub
|
|
38
|
+
$GEET_ALIAS install modularizer/geet MyGeetApp --private
|
|
39
|
+
$GEET_ALIAS install --recurse-submodules git@github.com:$GH_USER/template.git MyApp -- --app-name "My Cool App"
|
|
40
|
+
|
|
41
|
+
Notes:
|
|
42
|
+
- <dir> is required and must be different from the template repo name
|
|
43
|
+
- After cloning, this runs init automatically
|
|
44
|
+
- Arguments after '--' are passed to the post-init hook (if present)
|
|
45
|
+
- Publish flags create a NEW GitHub repo for the app (not the template)
|
|
46
|
+
EOF
|
|
47
|
+
return 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Extract flags using has_flag
|
|
51
|
+
local RECURSE=""
|
|
52
|
+
local PUB_APP=""
|
|
53
|
+
local PRI_APP=""
|
|
54
|
+
local INT_APP=""
|
|
55
|
+
|
|
56
|
+
has_flag --recurse-submodules RECURSE
|
|
57
|
+
has_flag --public PUB_APP
|
|
58
|
+
has_flag --private PRI_APP
|
|
59
|
+
has_flag --internal INT_APP
|
|
60
|
+
|
|
61
|
+
# Determine publish visibility
|
|
62
|
+
local publish_visibility=""
|
|
63
|
+
if [[ -n "$PUB_APP" ]]; then
|
|
64
|
+
publish_visibility="public"
|
|
65
|
+
elif [[ -n "$PRI_APP" ]]; then
|
|
66
|
+
publish_visibility="private"
|
|
67
|
+
elif [[ -n "$INT_APP" ]]; then
|
|
68
|
+
publish_visibility="internal"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Separate positional args from post-init args
|
|
72
|
+
local -a args=()
|
|
73
|
+
local -a post_init_args=()
|
|
74
|
+
local parsing_post_init=0
|
|
75
|
+
|
|
76
|
+
for arg in "${GEET_ARGS[@]}"; do
|
|
77
|
+
if [[ "$arg" == "--" ]]; then
|
|
78
|
+
parsing_post_init=1
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [[ "$parsing_post_init" -eq 1 ]]; then
|
|
83
|
+
post_init_args+=("$arg")
|
|
84
|
+
else
|
|
85
|
+
args+=("$arg")
|
|
86
|
+
fi
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
[[ ${#args[@]} -ge 2 ]] || die "install requires both <repo> and <dir> arguments"
|
|
90
|
+
|
|
91
|
+
local repo="${args[0]}"
|
|
92
|
+
local dir="${args[1]}"
|
|
93
|
+
|
|
94
|
+
# repo supports 5 possibilities
|
|
95
|
+
# OPTION 1: resolves to a path on your own computer which already exists
|
|
96
|
+
# OPTION 2: startswith http, treat as a git remote. add ".git" to the end if it isn't there already
|
|
97
|
+
# OPTION 3: startswith git@, treat as a git ssh remote. add ".git" to the end if it isn't there already
|
|
98
|
+
# OPTION 4: in format or username/name, e.g. "modularizer/geet" or "modularizer/geet/", convert to "https://github.com/modularizer/geet.git"
|
|
99
|
+
# OPTION 5: just a repo name, e.g. "mytemplate", use get_gh_user then convert to "$GH_USER/mytemplate"
|
|
100
|
+
|
|
101
|
+
if [[ -e "$repo" ]]; then
|
|
102
|
+
# OPTION 1: local path exists, use as-is
|
|
103
|
+
:
|
|
104
|
+
elif [[ "$repo" == http* ]]; then
|
|
105
|
+
# OPTION 2: HTTP URL
|
|
106
|
+
if [[ "$repo" != *.git ]]; then
|
|
107
|
+
repo="${repo}.git"
|
|
108
|
+
fi
|
|
109
|
+
elif [[ "$repo" == git@* ]]; then
|
|
110
|
+
# OPTION 3: SSH URL
|
|
111
|
+
if [[ "$repo" != *.git ]]; then
|
|
112
|
+
repo="${repo}.git"
|
|
113
|
+
fi
|
|
114
|
+
elif [[ "$repo" =~ ^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+/?$ ]]; then
|
|
115
|
+
# OPTION 4: username/repo format
|
|
116
|
+
repo="${repo%/}" # remove trailing slash if present
|
|
117
|
+
repo="git@github.com:${repo}.git"
|
|
118
|
+
elif [[ "$repo" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
|
|
119
|
+
# OPTION 5: just a repo name
|
|
120
|
+
get_gh_user
|
|
121
|
+
repo="git@github.com:${GH_USER}/${repo}.git"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# Extract repo name for validation
|
|
125
|
+
local repo_name="$(basename "$repo")"
|
|
126
|
+
repo_name="${repo_name%.git}"
|
|
127
|
+
|
|
128
|
+
# Ensure dir is different from repo name to avoid confusion
|
|
129
|
+
# (template repo vs new app directory)
|
|
130
|
+
if [[ "$dir" == "$repo_name" ]]; then
|
|
131
|
+
die "dir must be different from repo name ('$repo_name'). The dir is your NEW app, not the template."
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
local -a clone_args=()
|
|
135
|
+
if [[ -n "$RECURSE" ]]; then
|
|
136
|
+
clone_args+=(--recurse-submodules)
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
log "cloning template repo:"
|
|
140
|
+
log " repo: $repo"
|
|
141
|
+
log " dir: $dir"
|
|
142
|
+
git clone "${clone_args[@]}" "$repo" "$dir"
|
|
143
|
+
log "calling \`cd \"$dir\"\`"
|
|
144
|
+
cd "$dir" || exit
|
|
145
|
+
log "pwd: $(pwd)"
|
|
146
|
+
|
|
147
|
+
GEET_CMD="${BASH_SOURCE[-1]}"
|
|
148
|
+
log "geet_cmd=$GEET_CMD"
|
|
149
|
+
|
|
150
|
+
log "running init in cloned directory"
|
|
151
|
+
(
|
|
152
|
+
"$GEET_CMD" init "${post_init_args[@]}"
|
|
153
|
+
)
|
|
154
|
+
log "pwd: $(pwd)"
|
|
155
|
+
log "publish_visibility=$publish_visibility"
|
|
156
|
+
|
|
157
|
+
# Publish the app as a GitHub repo if requested
|
|
158
|
+
if [[ -n "$publish_visibility" ]]; then
|
|
159
|
+
log "Calling \`$GEET_CMD publish app\`"
|
|
160
|
+
(
|
|
161
|
+
"$GEET_CMD" publish app "--${publish_visibility}"
|
|
162
|
+
)
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
log "install complete"
|
|
166
|
+
}
|