Skip to content

Commit a35ab98

Browse files
committed
Simplify apply-md script with focused features and clearer documentation
1 parent e9e8446 commit a35ab98

File tree

2 files changed

+40
-206
lines changed

2 files changed

+40
-206
lines changed

apply-md

Lines changed: 30 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -6,75 +6,33 @@
66
# Default values
77
DRY_RUN=false
88
CREATE_MISSING=false
9-
BACKUP=false
10-
BACKUP_DIR="./.backups"
11-
FILE_MARKER='^```[a-z]+ (.+)$'
12-
SKIP_UNCHANGED=false
139
VERBOSE=false
14-
CONFIRM=false
15-
ONLY_FILES=""
16-
IGNORE_FILES=""
17-
18-
# Function to get git repository root
19-
get_git_root() {
20-
git rev-parse --show-toplevel 2>/dev/null
21-
}
2210

2311
# Parse arguments
2412
while [[ "$#" -gt 0 ]]; do
2513
case $1 in
2614
--dry-run) DRY_RUN=true; shift ;;
2715
--create-missing) CREATE_MISSING=true; shift ;;
28-
--backup) BACKUP=true; shift ;;
29-
--backup-dir=*) BACKUP_DIR="${1#*=}"; shift ;;
30-
--file-marker=*) FILE_MARKER="${1#*=}"; shift ;;
31-
--skip-unchanged) SKIP_UNCHANGED=true; shift ;;
3216
--verbose) VERBOSE=true; shift ;;
33-
--confirm) CONFIRM=true; shift ;;
34-
--only-files=*) ONLY_FILES="${1#*=}"; shift ;;
35-
--ignore-files=*) IGNORE_FILES="${1#*=}"; shift ;;
3617
--help|-h)
3718
echo "Usage: ./apply-md [options]"
3819
echo ""
3920
echo "Options:"
40-
echo " --dry-run Preview changes without applying them"
41-
echo " --create-missing Create files that don't exist"
42-
echo " --backup Create backup files before applying changes"
43-
echo " --backup-dir=<dir> Directory for backups (default: ./.backups)"
44-
echo " --file-marker=<regex> Regex to identify target files from markdown"
45-
echo " --skip-unchanged Skip files with no changes"
46-
echo " --verbose Show detailed output about changes"
47-
echo " --confirm Prompt for confirmation before applying each change"
48-
echo " --only-files=<pattern> Only apply changes to files matching pattern"
49-
echo " --ignore-files=<pattern> Ignore changes for files matching pattern"
50-
echo " --help, -h Show this help message"
21+
echo " --dry-run Preview changes without applying them"
22+
echo " --create-missing Create files that don't exist"
23+
echo " --verbose Show detailed output about changes"
24+
echo " --help, -h Show this help message"
5125
exit 0
5226
;;
5327
*) echo "Unknown parameter: $1"; exit 1 ;;
5428
esac
5529
done
5630

57-
# Get git root if available
58-
GIT_ROOT=$(get_git_root)
59-
if [ -z "$GIT_ROOT" ] && [ "$VERBOSE" = true ]; then
60-
echo "Warning: Not in a git repository, absolute paths will be treated as system paths"
61-
fi
62-
63-
# Create backup directory if needed
64-
if [ "$BACKUP" = true ] && [ ! -d "$BACKUP_DIR" ]; then
65-
if [ "$DRY_RUN" = false ]; then
66-
mkdir -p "$BACKUP_DIR"
67-
elif [ "$VERBOSE" = true ]; then
68-
echo "[DRY RUN] Would create backup directory: $BACKUP_DIR"
69-
fi
70-
fi
71-
7231
# Read markdown content from stdin
7332
MARKDOWN=$(cat)
7433

7534
# Create temporary directory
7635
TEMP_DIR=$(mktemp -d)
77-
BLOCKS_FILE="$TEMP_DIR/blocks.txt"
7836
FILES_FILE="$TEMP_DIR/files.txt"
7937

8038
# Function to cleanup temporary files
@@ -83,18 +41,6 @@ cleanup() {
8341
}
8442
trap cleanup EXIT
8543

86-
# Function to normalize path relative to git root
87-
normalize_path() {
88-
local path="$1"
89-
if [ -n "$GIT_ROOT" ] && [[ "$path" == /* ]]; then
90-
# Remove leading slash and resolve relative to git root
91-
local rel_path="${path#/}"
92-
echo "$GIT_ROOT/$rel_path"
93-
else
94-
echo "$path"
95-
fi
96-
}
97-
9844
# Extract code blocks and their file names
9945
extract_blocks() {
10046
local current_file=""
@@ -104,23 +50,21 @@ extract_blocks() {
10450
echo "$MARKDOWN" | while IFS= read -r line; do
10551
if [[ "$line" =~ ^[[:space:]]*\`\`\`([a-zA-Z0-9\+\-]+)[[:space:]]+(.+) ]]; then
10652
current_file="${BASH_REMATCH[2]}"
107-
normalized_file=$(normalize_path "$current_file")
10853
in_block=true
10954
temp_file="$TEMP_DIR/$current_file"
11055
mkdir -p "$(dirname "$temp_file")"
11156
: > "$temp_file" # Create empty file
11257
if [ "$VERBOSE" = true ]; then
113-
echo "Starting code block for file: $current_file (normalized: $normalized_file)"
58+
echo "Starting code block for file: $current_file"
11459
fi
11560
continue
11661
fi
11762

11863
if [[ "$line" =~ ^[[:space:]]*\`\`\`[[:space:]]*$ ]]; then
11964
if [ -n "$current_file" ] && [ "$in_block" = true ]; then
12065
echo "$current_file" >> "$FILES_FILE"
121-
current_file_formatted=$(echo "$current_file" | sed 's/^\.\///')
12266
if [ "$VERBOSE" = true ]; then
123-
echo "Completed code block for file: $current_file_formatted"
67+
echo "Completed code block for file: $current_file"
12468
fi
12569
fi
12670
in_block=false
@@ -139,106 +83,54 @@ extract_blocks() {
13983
apply_block() {
14084
local file="$1"
14185
local content_file="$TEMP_DIR/$file"
142-
local skipped=false
143-
144-
if [ -n "$IGNORE_FILES" ] && [[ "$file" == $IGNORE_FILES ]]; then
145-
if [ "$VERBOSE" = true ]; then
146-
echo "Skipping ignored file: $file"
147-
fi
148-
return
149-
fi
150-
151-
if [ -n "$ONLY_FILES" ] && [[ "$file" != $ONLY_FILES ]]; then
152-
if [ "$VERBOSE" = true ]; then
153-
echo "Skipping file not matching include pattern: $file"
154-
fi
155-
return
156-
fi
15786

15887
if [ ! -f "$content_file" ]; then
15988
echo "Error: Content file not found for $file"
16089
return
16190
fi
16291

163-
# Normalize file path
164-
local normalized_file=$(normalize_path "$file")
165-
file="$normalized_file"
166-
16792
if [ ! -f "$file" ]; then
16893
if [ "$CREATE_MISSING" = true ]; then
16994
if [ "$DRY_RUN" = false ]; then
17095
mkdir -p "$(dirname "$file")"
17196
cat "$content_file" > "$file"
17297
echo "Created file: $file"
173-
elif [ "$VERBOSE" = true ]; then
174-
echo "[DRY RUN] Would create file: $file"
175-
echo "---"
176-
cat "$content_file"
177-
echo "---"
17898
else
17999
echo "[DRY RUN] Would create file: $file"
100+
if [ "$VERBOSE" = true ]; then
101+
echo "---"
102+
cat "$content_file"
103+
echo "---"
104+
fi
180105
fi
181106
else
182107
echo "Warning: File does not exist and --create-missing not specified: $file"
183108
fi
184109
return
185110
fi
186111

187-
if [ "$SKIP_UNCHANGED" = true ]; then
188-
diff -q "$file" "$content_file" > /dev/null
189-
if [ $? -eq 0 ]; then
190-
if [ "$VERBOSE" = true ]; then
191-
echo "Skipping unchanged file: $file"
192-
fi
193-
skipped=true
112+
# Check for changes
113+
diff -q "$file" "$content_file" > /dev/null
114+
if [ $? -eq 0 ]; then
115+
if [ "$VERBOSE" = true ]; then
116+
echo "No changes needed for: $file"
194117
fi
118+
return
195119
fi
196120

197-
if [ "$skipped" = false ]; then
198-
local changes=$(diff -u "$file" "$content_file")
199-
if [ -z "$changes" ]; then
200-
if [ "$VERBOSE" = true ]; then
201-
echo "No changes needed for: $file"
202-
fi
203-
return
204-
fi
205-
206-
if [ "$VERBOSE" = true ]; then
207-
echo "Changes for $file:"
208-
echo "$changes"
209-
echo ""
210-
else
211-
echo "Modifying: $file"
212-
fi
213-
214-
if [ "$CONFIRM" = true ]; then
215-
read -p "Apply changes to $file? (y/n) " -n 1 -r
216-
echo
217-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
218-
echo "Skipping file: $file"
219-
return
220-
fi
221-
fi
222-
223-
if [ "$BACKUP" = true ]; then
224-
local backup_file="$BACKUP_DIR/$(basename "$file").$(date +%Y%m%d%H%M%S).bak"
225-
if [ "$DRY_RUN" = false ]; then
226-
mkdir -p "$(dirname "$backup_file")"
227-
cp "$file" "$backup_file"
228-
if [ "$VERBOSE" = true ]; then
229-
echo "Created backup: $backup_file"
230-
fi
231-
elif [ "$VERBOSE" = true ]; then
232-
echo "[DRY RUN] Would create backup: $backup_file"
233-
fi
234-
fi
235-
236-
if [ "$DRY_RUN" = false ]; then
237-
cat "$content_file" > "$file"
238-
echo "Updated file: $file"
239-
else
240-
echo "[DRY RUN] Would update file: $file"
241-
fi
121+
if [ "$VERBOSE" = true ]; then
122+
echo "Changes for $file:"
123+
diff -u "$file" "$content_file"
124+
echo ""
125+
else
126+
echo "Modifying: $file"
127+
fi
128+
129+
if [ "$DRY_RUN" = false ]; then
130+
cat "$content_file" > "$file"
131+
echo "Updated file: $file"
132+
else
133+
echo "[DRY RUN] Would update file: $file"
242134
fi
243135
}
244136

@@ -248,9 +140,6 @@ if [ "$VERBOSE" = true ]; then
248140
if [ "$DRY_RUN" = true ]; then
249141
echo "Running in DRY RUN mode (no changes will be applied)"
250142
fi
251-
if [ -n "$GIT_ROOT" ]; then
252-
echo "Git repository root detected at: $GIT_ROOT"
253-
fi
254143
fi
255144

256145
extract_blocks

docs/apply-md.md

Lines changed: 10 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Overview
44

5-
The `apply-md` tool extracts code blocks from markdown (typically LLM responses) and applies them to your filesystem. It supports both relative and absolute paths, with absolute paths resolved relative to the git repository root when run within a git repository.
5+
The `apply-md` tool extracts code blocks from markdown (typically LLM responses) and applies them to your filesystem. This simplified version focuses on core functionality without the complexity of advanced features.
66

77
## Usage
88

@@ -16,23 +16,15 @@ cat llm_response.md | ./apply-md --dry-run --verbose
1616
|----------|-------------|---------|
1717
| `--dry-run` | Preview changes without applying them | False |
1818
| `--create-missing` | Create files that don't exist | False |
19-
| `--backup` | Create backup files before applying changes | False |
20-
| `--backup-dir=<dir>` | Directory for backups | "./.backups" |
21-
| `--file-marker=<regex>` | Regex to identify target files from markdown | "```[a-z]+ (.+)" |
22-
| `--skip-unchanged` | Skip files with no changes | False |
23-
| `--verbose` | Show detailed output about changes, including git root detection | False |
24-
| `--confirm` | Prompt for confirmation before applying each change | False |
25-
| `--only-files=<pattern>` | Only apply changes to files matching pattern | None |
26-
| `--ignore-files=<pattern>` | Ignore changes for files matching pattern | None |
19+
| `--verbose` | Show detailed output about changes | False |
20+
| `--help`, `-h` | Show help message | - |
2721

2822
## How It Works
2923

3024
1. The tool reads markdown content from stdin
31-
2. If run within a git repository, it detects the repository root
32-
3. It looks for code blocks that specify a filename (e.g., ```javascript src/utils.js or ```bash /apply-md)
33-
4. Absolute paths (starting with /) are resolved relative to the git root when applicable
34-
5. It extracts the code from these blocks
35-
6. It applies the code to the corresponding files in your filesystem
25+
2. It looks for code blocks that specify a filename (e.g., ```javascript src/utils.js)
26+
3. It extracts the code from these blocks
27+
4. It applies the code to the corresponding files in your filesystem
3628

3729
## Examples
3830

@@ -52,14 +44,6 @@ Preview changes without applying them:
5244
cat llm_response.md | ./apply-md --dry-run --verbose
5345
```
5446

55-
### With Backups
56-
57-
Make backups before applying changes:
58-
59-
```bash
60-
cat llm_response.md | ./apply-md --backup
61-
```
62-
6347
### Creating New Files
6448

6549
Allow creating files that don't exist:
@@ -68,27 +52,10 @@ Allow creating files that don't exist:
6852
cat llm_response.md | ./apply-md --create-missing
6953
```
7054

71-
### Selective Application
72-
73-
Only apply changes to specific files:
74-
75-
```bash
76-
cat llm_response.md | ./apply-md --only-files="*.js"
77-
```
78-
79-
### Using Absolute Paths
80-
81-
Apply changes using absolute paths relative to git root:
82-
83-
```bash
84-
echo -e "```bash /scripts/test.sh\necho 'test'\n```" | ./apply-md --create-missing
85-
```
86-
8755
## Expected Markdown Format
8856

89-
The script expects code blocks in these formats:
57+
The script expects code blocks in this format:
9058

91-
### Relative Path
9259
```markdown
9360
```javascript src/utils.js
9461
function add(a, b) {
@@ -97,32 +64,10 @@ The script expects code blocks in these formats:
9764
```
9865
```
9966

100-
### Absolute Path (from git root)
101-
```markdown
102-
```bash /scripts/deploy.sh
103-
#!/bin/bash
104-
echo "Deploying..."
105-
```
106-
```
107-
108-
The language specification is optional, but the filename is required. Absolute paths (starting with /) will be resolved relative to the git repository root when run within a git repository.
67+
The language specification is optional, but the filename is required.
10968

11069
## Tips
11170

11271
- Always use `--dry-run` first to preview changes
113-
- Use `--verbose` to see the detected git root and normalized paths
114-
- Consider using `--backup` for important changes
115-
- Use `--confirm` to review each change individually
116-
- When using absolute paths, ensure you're running from within a git repository
117-
- If not in a git repository, absolute paths will be treated as system paths
118-
119-
## Git Integration
120-
121-
When run within a git repository:
122-
- Detects the repository root automatically
123-
- Converts absolute paths (e.g., `/src/main.js`) to relative paths from the git root
124-
- Shows the detected git root in verbose mode
125-
126-
If not in a git repository:
127-
- Absolute paths are treated as system absolute paths
128-
- A warning is shown in verbose mode
72+
- Use `--verbose` to see detailed information about changes
73+
- When creating new files, ensure the `--create-missing` flag is set

0 commit comments

Comments
 (0)