polygit 0.2.0__tar.gz → 0.3.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polygit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Manage multiple git repos from a single .pgit config file.
5
5
  Project-URL: Repository, https://gitlab.com/gary.schaetz/public/polygit
6
6
  Author-email: Gary Schaetz <gary@schaetzkc.com>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "polygit"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Manage multiple git repos from a single .pgit config file."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE.txt" }
@@ -1,4 +1,5 @@
1
1
  import subprocess
2
+ import sys
2
3
  import threading
3
4
  from concurrent.futures import ThreadPoolExecutor, as_completed
4
5
  from datetime import datetime
@@ -8,6 +9,20 @@ from .config import HOSTS
8
9
  _print_lock = threading.Lock()
9
10
  MAX_WORKERS = 8
10
11
 
12
+ _USE_COLOR = sys.stdout.isatty()
13
+
14
+ _G = "\033[32m" if _USE_COLOR else "" # green
15
+ _R = "\033[31m" if _USE_COLOR else "" # red
16
+ _C = "\033[36m" if _USE_COLOR else "" # cyan
17
+ _Y = "\033[33m" if _USE_COLOR else "" # yellow
18
+ _DIM = "\033[2m" if _USE_COLOR else "" # dim
19
+ _RST = "\033[0m" if _USE_COLOR else "" # reset
20
+
21
+ OK = f"{_G}✓{_RST}"
22
+ UPD = f"{_C}↓{_RST}"
23
+ ERR = f"{_R}✗{_RST}"
24
+ NEW = f"{_C}+{_RST}"
25
+
11
26
 
12
27
  def _emit(lines):
13
28
  """Print a block of lines atomically."""
@@ -53,36 +68,39 @@ def is_dirty(d):
53
68
 
54
69
 
55
70
  def _commit_and_push(d, label, msg):
56
- lines = [f"Committing {label}..."]
71
+ lines = [f" Committing {label}..."]
57
72
  subprocess.run(["git", "-C", str(d), "add", "-A"], capture_output=True)
58
73
  subprocess.run(["git", "-C", str(d), "commit", "-m", msg], capture_output=True)
59
74
  result = subprocess.run(["git", "-C", str(d), "push"], capture_output=True, text=True)
60
75
  if result.returncode != 0:
61
- lines.append(f" Push failed: {result.stderr.strip()}")
76
+ lines.append(f"{ERR} {label}: push failed — {result.stderr.strip().splitlines()[0]}")
62
77
  else:
63
- lines.append(f" Pushed.")
78
+ lines.append(f"{UPD} {label}: pushed")
64
79
  _emit(lines)
65
80
 
66
81
 
67
82
  def _sync_one(platform, local_path, remote_path, d):
68
83
  url = f"{HOSTS[platform]}:{remote_path}.git"
84
+ label = f"{platform}/{local_path}"
69
85
  if (d / ".git").exists():
70
86
  result = subprocess.run(
71
87
  ["git", "-C", str(d), "fetch", "--all", "-q"],
72
88
  capture_output=True, text=True
73
89
  )
74
- lines = [f"Fetched {platform}/{local_path}"]
75
- if result.stderr.strip():
76
- lines.append(f" {result.stderr.strip()}")
90
+ if result.returncode != 0:
91
+ lines = [f"{ERR} {label}: {result.stderr.strip().splitlines()[0]}"]
92
+ else:
93
+ lines = [f"{OK} {_DIM}{label}{_RST}"]
77
94
  else:
78
95
  d.parent.mkdir(parents=True, exist_ok=True)
79
96
  result = subprocess.run(
80
97
  ["git", "clone", url, str(d)],
81
98
  capture_output=True, text=True
82
99
  )
83
- lines = [f"Cloned {platform}/{local_path}"]
84
100
  if result.returncode != 0:
85
- lines.append(f" Error: {result.stderr.strip()}")
101
+ lines = [f"{ERR} {label}: {result.stderr.strip().splitlines()[0]}"]
102
+ else:
103
+ lines = [f"{NEW} {label}: cloned"]
86
104
  _emit(lines)
87
105
 
88
106
 
@@ -98,20 +116,26 @@ def _pull_one(platform, local_path, d):
98
116
  capture_output=True, text=True
99
117
  )
100
118
  if result.returncode != 0:
101
- lines.append(f"{label}: error — {result.stderr.strip()}")
119
+ err = result.stderr.strip()
120
+ if "no tracking information" in err or "no upstream" in err.lower():
121
+ lines.append(f"{ERR} {label}: no upstream branch set")
122
+ else:
123
+ lines.append(f"{ERR} {label}: {err.splitlines()[0]}")
102
124
  elif result.stdout.strip() and result.stdout.strip() != "Already up to date.":
103
- lines.append(f"{label}: {result.stdout.strip()}")
125
+ lines.append(f"{UPD} {label}:")
126
+ for ln in result.stdout.strip().splitlines():
127
+ lines.append(f" {ln}")
104
128
  else:
105
- lines.append(f"{label}: up to date")
129
+ lines.append(f"{OK} {_DIM}{label}{_RST}")
106
130
  if stashed:
107
131
  pop = subprocess.run(
108
132
  ["git", "-C", str(d), "stash", "pop"],
109
133
  capture_output=True, text=True
110
134
  )
111
135
  if pop.returncode != 0:
112
- lines.append(f" Warning: stash pop had conflicts")
136
+ lines.append(f" {_Y}warning:{_RST} stash pop had conflicts in {label}")
113
137
  else:
114
- lines.append(f" Stash restored.")
138
+ lines.append(f" stash restored")
115
139
  _emit(lines)
116
140
 
117
141
 
@@ -143,11 +167,11 @@ def cmd_status(config, base):
143
167
  for platform, local_path, output in sorted(results):
144
168
  if output:
145
169
  found_dirty = True
146
- print(f"\n{platform}/{local_path}:")
170
+ print(f"\n{_Y}~{_RST} {platform}/{local_path}:")
147
171
  for line in output.splitlines():
148
172
  print(f" {line}")
149
173
  if not found_dirty:
150
- print("All repos are clean.")
174
+ print(f"{OK} All repos are clean.")
151
175
 
152
176
 
153
177
  def cmd_pull(config, base):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes