Skip to content

Commit 1bcf40f

Browse files
authored
Fixes/v0.1.0 (#3)
* Minor refactor for githelpers * fix installation script
1 parent 8dbcc79 commit 1bcf40f

File tree

5 files changed

+87
-41
lines changed

5 files changed

+87
-41
lines changed

install.sh

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#!/usr/bin/env bash
22
# This file is auto-generated by scripts/build.sh
33
# DO NOT EDIT - modify scripts/*.src.sh instead and run 'make buildscripts'
4+
5+
# ── Embedded hook files ── that's a base64 of scripts/git-undo-hook.bash ────
6+
EMBEDDED_BASH_HOOK='IyBWYXJpYWJsZSB0byBzdG9yZSB0aGUgZ2l0IGNvbW1hbmQgdGVtcG9yYXJpbHkKR0lUX0NPTU1BTkRfVE9fTE9HPSIiCgojIEZ1bmN0aW9uIHRvIHN0b3JlIHRoZSBnaXQgY29tbWFuZCB0ZW1wb3JhcmlseQpzdG9yZV9naXRfY29tbWFuZCgpIHsKICBsb2NhbCByYXdfY21kPSIkMSIKICBsb2NhbCBoZWFkPSR7cmF3X2NtZCUlICp9CiAgbG9jYWwgcmVzdD0ke3Jhd19jbWQjIiRoZWFkIn0KCiAgIyBDaGVjayBpZiB0aGUgY29tbWFuZCBpcyBhbiBhbGlhcyBhbmQgZXhwYW5kIGl0CiAgaWYgYWxpYXMgIiRoZWFkIiAmPi9kZXYvbnVsbDsgdGhlbgogICAgbG9jYWwgZGVmPSQoYWxpYXMgIiRoZWFkIikKICAgICMgRXh0cmFjdCB0aGUgZXhwYW5zaW9uIGZyb20gYWxpYXMgb3V0cHV0IChmb3JtYXQ6IGFsaWFzIG5hbWU9J2V4cGFuc2lvbicpCiAgICBsb2NhbCBleHBhbnNpb249JHtkZWYjKlwnfQogICAgZXhwYW5zaW9uPSR7ZXhwYW5zaW9uJVwnfQogICAgcmF3X2NtZD0iJHtleHBhbnNpb259JHtyZXN0fSIKICBmaQoKICAjIE9ubHkgc3RvcmUgaWYgaXQncyBhIGdpdCBjb21tYW5kCiAgW1sgIiRyYXdfY21kIiA9PSBnaXRcICogXV0gfHwgcmV0dXJuCiAgR0lUX0NPTU1BTkRfVE9fTE9HPSIkcmF3X2NtZCIKfQoKIyBGdW5jdGlvbiB0byBsb2cgdGhlIGNvbW1hbmQgb25seSBpZiBpdCB3YXMgc3VjY2Vzc2Z1bApsb2dfc3VjY2Vzc2Z1bF9naXRfY29tbWFuZCgpIHsKICAjIENoZWNrIGlmIHdlIGhhdmUgYSBnaXQgY29tbWFuZCB0byBsb2cgYW5kIGlmIHRoZSBwcmV2aW91cyBjb21tYW5kIHdhcyBzdWNjZXNzZnVsCiAgaWYgW1sgLW4gIiRHSVRfQ09NTUFORF9UT19MT0ciICYmICQ/IC1lcSAwIF1dOyB0aGVuCiAgICBHSVRfVU5ET19JTlRFUk5BTF9IT09LPTEgY29tbWFuZCBnaXQtdW5kbyAtLWhvb2s9IiRHSVRfQ09NTUFORF9UT19MT0ciCiAgZmkKICAjIENsZWFyIHRoZSBzdG9yZWQgY29tbWFuZAogIEdJVF9DT01NQU5EX1RPX0xPRz0iIgp9CgojIHRyYXAgZG9lcyB0aGUgYWN0dWFsIGhvb2tpbmc6IG1ha2luZyBhbiBleHRyYSBnaXQtdW5kbyBjYWxsIGZvciBldmVyeSBnaXQgY29tbWFuZC4KdHJhcCAnc3RvcmVfZ2l0X2NvbW1hbmQgIiRCQVNIX0NPTU1BTkQiJyBERUJVRwoKIyBTZXQgdXAgUFJPTVBUX0NPTU1BTkQgdG8gbG9nIHN1Y2Nlc3NmdWwgY29tbWFuZHMgYWZ0ZXIgZXhlY3V0aW9uCmlmIFtbIC16ICIkUFJPTVBUX0NPTU1BTkQiIF1dOyB0aGVuCiAgUFJPTVBUX0NPTU1BTkQ9ImxvZ19zdWNjZXNzZnVsX2dpdF9jb21tYW5kIgplbHNlCiAgUFJPTVBUX0NPTU1BTkQ9IiRQUk9NUFRfQ09NTUFORDsgbG9nX3N1Y2Nlc3NmdWxfZ2l0X2NvbW1hbmQiCmZp'
7+
EMBEDDED_BASH_TEST_HOOK='IyBWYXJpYWJsZSB0byBzdG9yZSB0aGUgZ2l0IGNvbW1hbmQgdGVtcG9yYXJpbHkKR0lUX0NPTU1BTkRfVE9fTE9HPSIiCgojIEZ1bmN0aW9uIHRvIHN0b3JlIHRoZSBnaXQgY29tbWFuZCB0ZW1wb3JhcmlseQpzdG9yZV9naXRfY29tbWFuZCgpIHsKICBsb2NhbCByYXdfY21kPSIkMSIKICBsb2NhbCBoZWFkPSR7cmF3X2NtZCUlICp9CiAgbG9jYWwgcmVzdD0ke3Jhd19jbWQjIiRoZWFkIn0KCiAgIyBDaGVjayBpZiB0aGUgY29tbWFuZCBpcyBhbiBhbGlhcyBhbmQgZXhwYW5kIGl0CiAgaWYgYWxpYXMgIiRoZWFkIiAmPi9kZXYvbnVsbDsgdGhlbgogICAgbG9jYWwgZGVmPSQoYWxpYXMgIiRoZWFkIikKICAgICMgRXh0cmFjdCB0aGUgZXhwYW5zaW9uIGZyb20gYWxpYXMgb3V0cHV0IChmb3JtYXQ6IGFsaWFzIG5hbWU9J2V4cGFuc2lvbicpCiAgICBsb2NhbCBleHBhbnNpb249JHtkZWYjKlwnfQogICAgZXhwYW5zaW9uPSR7ZXhwYW5zaW9uJVwnfQogICAgcmF3X2NtZD0iJHtleHBhbnNpb259JHtyZXN0fSIKICBmaQoKICAjIE9ubHkgc3RvcmUgaWYgaXQncyBhIGdpdCBjb21tYW5kCiAgW1sgIiRyYXdfY21kIiA9PSBnaXRcICogXV0gfHwgcmV0dXJuCiAgR0lUX0NPTU1BTkRfVE9fTE9HPSIkcmF3X2NtZCIKfQoKIyBGdW5jdGlvbiB0byBsb2cgdGhlIGNvbW1hbmQgb25seSBpZiBpdCB3YXMgc3VjY2Vzc2Z1bApsb2dfc3VjY2Vzc2Z1bF9naXRfY29tbWFuZCgpIHsKICAjIENoZWNrIGlmIHdlIGhhdmUgYSBnaXQgY29tbWFuZCB0byBsb2cgYW5kIGlmIHRoZSBwcmV2aW91cyBjb21tYW5kIHdhcyBzdWNjZXNzZnVsCiAgaWYgW1sgLW4gIiRHSVRfQ09NTUFORF9UT19MT0ciICYmICQ/IC1lcSAwIF1dOyB0aGVuCiAgICBHSVRfVU5ET19JTlRFUk5BTF9IT09LPTEgY29tbWFuZCBnaXQtdW5kbyAtLWhvb2s9IiRHSVRfQ09NTUFORF9UT19MT0ciCiAgZmkKICAjIENsZWFyIHRoZSBzdG9yZWQgY29tbWFuZAogIEdJVF9DT01NQU5EX1RPX0xPRz0iIgp9CgoKIyBUZXN0IG1vZGU6IHByb3ZpZGUgYSBtYW51YWwgd2F5IHRvIGNhcHR1cmUgY29tbWFuZHMKIyBUaGlzIGlzIG9ubHkgdXNlZCBmb3IgaW50ZWdyYXRpb24tdGVzdC5iYXRzLiAKZ2l0KCkgewogICAgY29tbWFuZCBnaXQgIiRAIgogICAgbG9jYWwgZXhpdF9jb2RlPSQ/CiAgICBpZiBbWyAkZXhpdF9jb2RlIC1lcSAwIF1dOyB0aGVuCiAgICAgICAgR0lUX1VORE9fSU5URVJOQUxfSE9PSz0xIGNvbW1hbmQgZ2l0LXVuZG8gLS1ob29rPSJnaXQgJCoiCiAgICBmaQogICAgcmV0dXJuICRleGl0X2NvZGUKfQoKCiMgU2V0IHVwIFBST01QVF9DT01NQU5EIHRvIGxvZyBzdWNjZXNzZnVsIGNvbW1hbmRzIGFmdGVyIGV4ZWN1dGlvbgppZiBbWyAteiAiJFBST01QVF9DT01NQU5EIiBdXTsgdGhlbgogIFBST01QVF9DT01NQU5EPSJsb2dfc3VjY2Vzc2Z1bF9naXRfY29tbWFuZCIKZWxzZQogIFBST01QVF9DT01NQU5EPSIkUFJPTVBUX0NPTU1BTkQ7IGxvZ19zdWNjZXNzZnVsX2dpdF9jb21tYW5kIgpmaQo='
8+
EMBEDDED_ZSH_HOOK='IyBGdW5jdGlvbiB0byBzdG9yZSB0aGUgZ2l0IGNvbW1hbmQgdGVtcG9yYXJpbHkKc3RvcmVfZ2l0X2NvbW1hbmQoKSB7CiAgbG9jYWwgcmF3X2NtZD0iJDEiCiAgbG9jYWwgaGVhZD0ke3Jhd19jbWQlJSAqfQogIGxvY2FsIHJlc3Q9JHtyYXdfY21kIyIkaGVhZCJ9CiAgaWYgYWxpYXMgIiRoZWFkIiAmPi9kZXYvbnVsbDsgdGhlbgogICAgbG9jYWwgZGVmPSQoYWxpYXMgIiRoZWFkIikKICAgIGxvY2FsIGV4cGFuc2lvbj0ke2RlZiMqXCd9CiAgICBleHBhbnNpb249JHtleHBhbnNpb24lXCd9CiAgICByYXdfY21kPSIke2V4cGFuc2lvbn0ke3Jlc3R9IgogIGZpCiAgW1sgIiRyYXdfY21kIiA9PSBnaXRcICogXV0gfHwgcmV0dXJuCiAgR0lUX0NPTU1BTkRfVE9fTE9HPSIkcmF3X2NtZCIKfQoKIyBGdW5jdGlvbiB0byBsb2cgdGhlIGNvbW1hbmQgb25seSBpZiBpdCB3YXMgc3VjY2Vzc2Z1bApsb2dfc3VjY2Vzc2Z1bF9naXRfY29tbWFuZCgpIHsKICAjIENoZWNrIGlmIHdlIGhhdmUgYSBnaXQgY29tbWFuZCB0byBsb2cgYW5kIGlmIHRoZSBwcmV2aW91cyBjb21tYW5kIHdhcyBzdWNjZXNzZnVsCiAgaWYgW1sgLW4gIiRHSVRfQ09NTUFORF9UT19MT0ciICYmICQ/IC1lcSAwIF1dOyB0aGVuCiAgICBHSVRfVU5ET19JTlRFUk5BTF9IT09LPTEgY29tbWFuZCBnaXQtdW5kbyAtLWhvb2s9IiRHSVRfQ09NTUFORF9UT19MT0ciCiAgZmkKICAjIENsZWFyIHRoZSBzdG9yZWQgY29tbWFuZAogIEdJVF9DT01NQU5EX1RPX0xPRz0iIgp9CgphdXRvbG9hZCAtVSBhZGQtenNoLWhvb2sKYWRkLXpzaC1ob29rIHByZWV4ZWMgc3RvcmVfZ2l0X2NvbW1hbmQKYWRkLXpzaC1ob29rIHByZWNtZCBsb2dfc3VjY2Vzc2Z1bF9naXRfY29tbWFuZAo='
9+
# ── End of embedded hook files ──────────────────────────────────────────────
10+
411
set -e
512

613
# ── Inlined content from common.sh ──────────────────────────────────────────
@@ -140,6 +147,17 @@ version_compare() {
140147
}
141148
# ── End of inlined content ──────────────────────────────────────────────────
142149

150+
# Function to write an embedded hook file
151+
write_embedded_hook() {
152+
local target_file="$1"
153+
local embedded_var="$2"
154+
155+
# Decode the base64 embedded content and write it to the target file
156+
echo "${!embedded_var}" | base64 -d > "$target_file" 2>/dev/null || return 1
157+
chmod 644 "$target_file" 2>/dev/null || return 1
158+
return 0
159+
}
160+
143161
install_shell_hook() {
144162
local shell_type="$1"
145163
local is_noop=true
@@ -153,14 +171,12 @@ install_shell_hook() {
153171

154172
case "$shell_type" in
155173
"zsh")
156-
local hook_file="git-undo-hook.zsh"
157174
local rc_file="$HOME/.zshrc"
158-
local source_line="source ~/.config/git-undo/$hook_file"
175+
local source_line="source ~/.config/git-undo/git-undo-hook.zsh"
159176

160-
# Copy the hook file and set permissions
177+
# Write the embedded hook file
161178
if [ ! -f "$ZSH_HOOK" ]; then
162-
cp "scripts/$hook_file" "$ZSH_HOOK" 2>/dev/null || return 1
163-
chmod 644 "$ZSH_HOOK" 2>/dev/null || return 1
179+
write_embedded_hook "$ZSH_HOOK" "EMBEDDED_ZSH_HOOK" || return 1
164180
is_noop=false
165181
fi
166182

@@ -172,18 +188,17 @@ install_shell_hook() {
172188
;;
173189

174190
"bash")
175-
local hook_file="git-undo-hook.bash"
176-
local source_line="source ~/.config/git-undo/$hook_file"
191+
local source_line="source ~/.config/git-undo/git-undo-hook.bash"
177192

178-
# Use test hook in test environments (e.g., integration tests)
193+
# Determine which embedded hook to use
194+
local embedded_var="EMBEDDED_BASH_HOOK"
179195
if [[ "${GIT_UNDO_TEST_MODE:-}" == "true" ]]; then
180-
hook_file="git-undo-hook.test.bash"
196+
embedded_var="EMBEDDED_BASH_TEST_HOOK"
181197
fi
182198

183-
# Copy the hook file and set permissions
199+
# Write the embedded hook file
184200
if [ ! -f "$BASH_HOOK" ]; then
185-
cp "scripts/$hook_file" "$BASH_HOOK" 2>/dev/null || return 1
186-
chmod 644 "$BASH_HOOK" 2>/dev/null || return 1
201+
write_embedded_hook "$BASH_HOOK" "$embedded_var" || return 1
187202
is_noop=false
188203
fi
189204

internal/app/app.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
type GitHelper interface {
1717
GetCurrentGitRef() (string, error)
1818
GetRepoGitDir() (string, error)
19-
ValidateGitRepo() error
2019

2120
GitRun(subCmd string, args ...string) error
2221
GitOutput(subCmd string, args ...string) (string, error)
@@ -138,7 +137,7 @@ func (a *App) Run(args []string) error {
138137
}
139138

140139
// Ensure we're inside a Git repository for other commands
141-
if err := a.git.ValidateGitRepo(); err != nil {
140+
if _, err := a.git.GetRepoGitDir(); err != nil {
142141
return err
143142
}
144143

internal/githelpers/githelper.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ func NewGitHelper(repoDirArg ...string) *H {
3434

3535
// execGitOutput executes a git command and returns its output as string.
3636
func (h *H) execGitOutput(subCmd string, args ...string) (string, error) {
37-
gitArgs := append([]string{subCmd}, args...)
38-
cmd := exec.Command("git", gitArgs...)
3937
if h.repoDir == invalidRepoDir {
4038
return "", errors.New("not a valid git repository")
4139
}
4240

41+
gitArgs := append([]string{subCmd}, args...)
42+
cmd := exec.Command("git", gitArgs...)
4343
cmd.Dir = h.repoDir
4444

4545
output, err := cmd.Output()
@@ -52,17 +52,27 @@ func (h *H) execGitOutput(subCmd string, args ...string) (string, error) {
5252

5353
// execGitRun executes a git command without output (via Run).
5454
func (h *H) execGitRun(subCmd string, args ...string) error {
55-
gitArgs := append([]string{subCmd}, args...)
56-
cmd := exec.Command("git", gitArgs...)
5755
if h.repoDir == invalidRepoDir {
5856
return errors.New("not a valid git repository")
5957
}
6058

59+
gitArgs := append([]string{subCmd}, args...)
60+
cmd := exec.Command("git", gitArgs...)
6161
cmd.Dir = h.repoDir
6262

6363
return cmd.Run()
6464
}
6565

66+
// validateGitRepo checks if the current directory is inside a git repository.
67+
func (h *H) validateGitRepo() (string, error) {
68+
gitDir, err := h.execGitOutput("rev-parse", "--git-dir")
69+
if err != nil {
70+
return "", errors.New("not in a git repository")
71+
}
72+
73+
return gitDir, nil
74+
}
75+
6676
// GetCurrentGitRef returns the current ref (branch, tag, commit hash) in the repository.
6777
func (h *H) GetCurrentGitRef() (string, error) {
6878
// Try to get branch name first
@@ -86,9 +96,9 @@ func (h *H) GetCurrentGitRef() (string, error) {
8696
// GetRepoGitDir returns the path to the .git directory of current repository.
8797
func (h *H) GetRepoGitDir() (string, error) {
8898
// Get the git directory (usually .git, but could be elsewhere in worktrees)
89-
gitDir, err := h.execGitOutput("rev-parse", "--git-dir")
99+
gitDir, err := h.validateGitRepo()
90100
if err != nil {
91-
return "", fmt.Errorf("failed to get git directory: %w", err)
101+
return "", err
92102
}
93103

94104
// If gitDir is not an absolute path, make it absolute relative to the repo root
@@ -104,19 +114,12 @@ func (h *H) GetRepoGitDir() (string, error) {
104114
return gitDir, nil
105115
}
106116

107-
// ValidateGitRepo checks if the current directory is inside a git repository.
108-
func (h *H) ValidateGitRepo() error {
109-
if err := h.execGitRun("rev-parse", "--git-dir"); err != nil {
110-
return errors.New("not in a git repository")
111-
}
112-
113-
return nil
114-
}
115-
117+
// GitRun executes a git command without output (via Run).
116118
func (h *H) GitRun(subCmd string, args ...string) error {
117119
return h.execGitRun(subCmd, args...)
118120
}
119121

122+
// GitOutput executes a git command and returns its output as string.
120123
func (h *H) GitOutput(subCmd string, args ...string) (string, error) {
121124
return h.execGitOutput(subCmd, args...)
122125
}

scripts/build.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ set -e
55
SCRIPT_DIR="$(dirname "$0")"
66
COLORS_FILE="$SCRIPT_DIR/colors.sh"
77
COMMON_FILE="$SCRIPT_DIR/common.sh"
8+
BASH_HOOK_FILE="$SCRIPT_DIR/git-undo-hook.bash"
9+
BASH_TEST_HOOK_FILE="$SCRIPT_DIR/git-undo-hook.test.bash"
10+
ZSH_HOOK_FILE="$SCRIPT_DIR/git-undo-hook.zsh"
811
SRC_INSTALL="$SCRIPT_DIR/install.src.sh"
912
SRC_UNINSTALL="$SCRIPT_DIR/uninstall.src.sh"
1013
SRC_UPDATE="$SCRIPT_DIR/update.src.sh"
@@ -14,6 +17,13 @@ OUT_UPDATE="$SCRIPT_DIR/../update.sh"
1417

1518
echo "Building standalone scripts..."
1619

20+
# Function to encode a file as a base64 string for embedding
21+
encode_hook_file() {
22+
local file="$1"
23+
local var_name="$2"
24+
echo "${var_name}='$(base64 < "$file" | tr -d '\n')'"
25+
}
26+
1727
# Function to build a standalone script
1828
build_script() {
1929
local src_file="$1"
@@ -29,6 +39,17 @@ build_script() {
2939
# DO NOT EDIT - modify scripts/*.src.sh instead and run 'make buildscripts'
3040
EOF
3141

42+
# If building install.sh, add embedded hook files
43+
if [[ "$script_name" == "install.sh" ]]; then
44+
echo "" >> "$out_file"
45+
echo "# ── Embedded hook files ── that's a base64 of scripts/git-undo-hook.bash ────" >> "$out_file"
46+
encode_hook_file "$BASH_HOOK_FILE" "EMBEDDED_BASH_HOOK" >> "$out_file"
47+
encode_hook_file "$BASH_TEST_HOOK_FILE" "EMBEDDED_BASH_TEST_HOOK" >> "$out_file"
48+
encode_hook_file "$ZSH_HOOK_FILE" "EMBEDDED_ZSH_HOOK" >> "$out_file"
49+
echo "# ── End of embedded hook files ──────────────────────────────────────────────" >> "$out_file"
50+
echo "" >> "$out_file"
51+
fi
52+
3253
# Process the source file line by line
3354
while IFS= read -r line; do
3455
# Skip the shebang in source file

scripts/install.src.sh

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ set -e
33

44
source "$(dirname "$0")/common.sh"
55

6+
# Function to write an embedded hook file
7+
write_embedded_hook() {
8+
local target_file="$1"
9+
local embedded_var="$2"
10+
11+
# Decode the base64 embedded content and write it to the target file
12+
echo "${!embedded_var}" | base64 -d > "$target_file" 2>/dev/null || return 1
13+
chmod 644 "$target_file" 2>/dev/null || return 1
14+
return 0
15+
}
16+
617
install_shell_hook() {
718
local shell_type="$1"
819
local is_noop=true
@@ -16,14 +27,12 @@ install_shell_hook() {
1627

1728
case "$shell_type" in
1829
"zsh")
19-
local hook_file="git-undo-hook.zsh"
2030
local rc_file="$HOME/.zshrc"
21-
local source_line="source ~/.config/git-undo/$hook_file"
31+
local source_line="source ~/.config/git-undo/git-undo-hook.zsh"
2232

23-
# Copy the hook file and set permissions
33+
# Write the embedded hook file
2434
if [ ! -f "$ZSH_HOOK" ]; then
25-
cp "scripts/$hook_file" "$ZSH_HOOK" 2>/dev/null || return 1
26-
chmod 644 "$ZSH_HOOK" 2>/dev/null || return 1
35+
write_embedded_hook "$ZSH_HOOK" "EMBEDDED_ZSH_HOOK" || return 1
2736
is_noop=false
2837
fi
2938

@@ -35,18 +44,17 @@ install_shell_hook() {
3544
;;
3645

3746
"bash")
38-
local hook_file="git-undo-hook.bash"
39-
local source_line="source ~/.config/git-undo/$hook_file"
47+
local source_line="source ~/.config/git-undo/git-undo-hook.bash"
4048

41-
# Use test hook in test environments (e.g., integration tests)
49+
# Determine which embedded hook to use
50+
local embedded_var="EMBEDDED_BASH_HOOK"
4251
if [[ "${GIT_UNDO_TEST_MODE:-}" == "true" ]]; then
43-
hook_file="git-undo-hook.test.bash"
52+
embedded_var="EMBEDDED_BASH_TEST_HOOK"
4453
fi
4554

46-
# Copy the hook file and set permissions
55+
# Write the embedded hook file
4756
if [ ! -f "$BASH_HOOK" ]; then
48-
cp "scripts/$hook_file" "$BASH_HOOK" 2>/dev/null || return 1
49-
chmod 644 "$BASH_HOOK" 2>/dev/null || return 1
57+
write_embedded_hook "$BASH_HOOK" "$embedded_var" || return 1
5058
is_noop=false
5159
fi
5260

0 commit comments

Comments
 (0)