-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshared_utils.py
More file actions
128 lines (109 loc) · 4.91 KB
/
shared_utils.py
File metadata and controls
128 lines (109 loc) · 4.91 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import subprocess
import sys
from pathlib import Path
def format_size(size_bytes: int) -> str:
"""Converts a size in bytes to a human-readable string (KB, MB, GB)."""
if size_bytes == 0:
return "0 B"
power = 1024
n = 0
power_labels = {0: 'B', 1: 'KB', 2: 'MB', 3: 'GB', 4: 'TB'}
while size_bytes >= power and n < len(power_labels) - 1:
size_bytes /= power
n += 1
return f"{size_bytes:.2f} {power_labels[n]}" if n > 0 else f"{int(size_bytes)} {power_labels[n]}"
def run_command(command, cwd=None):
"""Executes a shell command safely and returns its output."""
try:
result = subprocess.run(
command,
shell=True,
check=True,
capture_output=True,
text=True,
cwd=cwd
)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error executing command: {e.cmd}", file=sys.stderr)
err_msg = f"{e.stderr.strip()}"
print(f"{err_msg}", file=sys.stderr)
return err_msg
except FileNotFoundError:
print("Error: Command not found.", file=sys.stderr)
sys.exit(1)
def get_git_state(target_dir="."):
"""Safely attempts to get the current Git repository state for a given directory."""
try:
target_path = str(target_dir)
# Check if we are inside a git repository
run_command('git rev-parse --is-inside-work-tree', cwd=target_path)
# Get short commit ID
short_id = run_command('git rev-parse --short HEAD', cwd=target_path)
# Get the commit message
commit_msg = run_command('git log -1 --pretty=%s', cwd=target_path)
# Check for untracked or uncommitted changes
status = run_command('git status --porcelain', cwd=target_path)
is_dirty = len(status) > 0
return short_id, commit_msg, is_dirty
except Exception:
# Fails silently if Git isn't installed or we aren't in a repo
return None, None, None
def summary(command_args, files_with_sizes, commit_id=None, target_dir="."):
"""
Generates a formatted summary string of the execution.
files_with_sizes: list of tuples (file_path_string, size_in_bytes)
"""
total_size_bytes = sum(size for _, size in files_with_sizes)
sorted_files = sorted(files_with_sizes, key=lambda x: x[1], reverse=True)
lines = [
"=== EXECUTION SUMMARY ===",
f"Command Arguments : {' '.join(command_args)}"
]
# Add target commit parameter (mostly used by save_commits.py)
if commit_id:
lines.append(f"Target Commit(s) : {commit_id}")
# Dynamically inject current workspace Git context using the target directory
short_id, commit_msg, is_dirty = get_git_state(target_dir)
if short_id:
lines.append(f"Current Repo HEAD : {short_id} {commit_msg}")
lines.append(f"Uncommitted Changes : {'Yes' if is_dirty else 'No'}")
lines.append(f"Total Size : {format_size(total_size_bytes)}")
lines.append(f"Total Files : {len(sorted_files)}")
lines.append("Files Included :")
if not sorted_files:
lines.append(" (No files)")
else:
for f_path, f_size in sorted_files:
lines.append(f" - [{format_size(f_size).rjust(10)}] {f_path}")
lines.append("=" * 80 + "\n")
return "\n".join(lines)
def write_concatenated_artifact(output_file, file_items, summary_text):
"""
Standardized writer for concatenated scripts.
file_items should be a list of tuples: (display_path, absolute_file_path)
"""
print(f"\n📝 Writing files to '{output_file}'...")
try:
with open(output_file, 'w', encoding='utf-8', errors='ignore') as outfile:
outfile.write(f"--- START OF FILE {output_file} ---\n\n")
outfile.write("# This file was generated by concatenating specified files and folders.\n")
outfile.write(f"# Total files included: {len(file_items)}\n\n")
for display_path, file_path in file_items:
header = "=" * 80 + "\n"
header += f"cat {display_path}\n"
header += "=" * 80 + "\n\n"
outfile.write(header)
try:
with open(file_path, 'r', encoding='utf-8') as infile:
outfile.write(infile.read())
except Exception as e:
error_message = f"--> [Error] Could not read file '{display_path}': {e}\n"
print(error_message, end='')
outfile.write(error_message)
outfile.write("\n\n")
outfile.write(summary_text)
print(f"✅ Success! Content concatenated into '{output_file}'.")
except IOError as e:
print(f"❌ Error: Could not write to output file '{output_file}': {e}")
sys.exit(1)