aboutsummaryrefslogtreecommitdiffstats
path: root/gitctl-helper
diff options
context:
space:
mode:
Diffstat (limited to 'gitctl-helper')
-rwxr-xr-xgitctl-helper95
1 files changed, 90 insertions, 5 deletions
diff --git a/gitctl-helper b/gitctl-helper
index 8cdf460..6c6dbc3 100755
--- a/gitctl-helper
+++ b/gitctl-helper
@@ -65,8 +65,12 @@ def list_sections_from(lines):
return out
-def find_repo_section(lines, url):
- """Return the section a repo.url= belongs to, or None if absent."""
+def repo_sections_from(lines):
+ """Map every repo.url= in cgitrc to the section= it falls under (file order).
+
+ cgitrc lists only the repos exposed to the web (cgit auto-discovery is off),
+ so membership here is exactly what makes a repo public."""
+ out = {}
current = None
for line in lines:
s = SECTION_RE.match(line.rstrip("\n"))
@@ -74,9 +78,46 @@ def find_repo_section(lines, url):
current = s.group(1)
continue
u = URL_LINE_RE.match(line.rstrip("\n"))
- if u and u.group(1) == url:
- return current
- return None
+ if u:
+ out[u.group(1)] = current
+ return out
+
+
+def find_repo_section(lines, url):
+ """Return the section a repo.url= belongs to, or None if absent."""
+ return repo_sections_from(lines).get(url)
+
+
+DESC_MAX = 60
+
+
+def read_description(url):
+ """First line of the bare repo's description file, truncated. '' if missing
+ or the gitolite placeholder."""
+ try:
+ with open(os.path.join(repo_path_for(url), "description")) as f:
+ d = f.readline().strip()
+ except OSError:
+ return ""
+ if d.startswith("Unnamed repository"):
+ return ""
+ return d[:DESC_MAX - 1] + "…" if len(d) > DESC_MAX else d
+
+
+def list_repos(repo_base, cgitrc_lines):
+ """Every bare repo under repo_base (the full set, public and private), each
+ tagged public/private and with its section + description. Returns a list of
+ (name, public_bool, section, desc) sorted by name."""
+ public = repo_sections_from(cgitrc_lines)
+ out = []
+ for entry in sorted(os.listdir(repo_base)):
+ if not entry.endswith(".git"):
+ continue
+ if not os.path.isdir(os.path.join(repo_base, entry)):
+ continue
+ name = entry[:-4]
+ out.append((name, name in public, public.get(name) or "", read_description(name)))
+ return out
def repo_path_for(url):
@@ -212,6 +253,37 @@ def _self_test():
assert find_repo_section(fixture, "cad-projects") == "Generic Projects"
assert find_repo_section(fixture, "my-slackbuilds") == "SlackBuilds"
assert find_repo_section(fixture, "nope") is None
+ assert repo_sections_from(fixture) == {
+ "cad-projects": "Generic Projects",
+ "my-slackbuilds": "SlackBuilds",
+ }
+
+ # list_repos: scans a fake REPO_BASE, tags public/private by cgitrc and
+ # reads each description file. cad-projects is in the fixture (public),
+ # secret-stuff is not (private).
+ import tempfile
+ rb = tempfile.mkdtemp()
+ for n, d in [("cad-projects", "CAD work"), ("secret-stuff", "")]:
+ os.mkdir(os.path.join(rb, n + ".git"))
+ if d:
+ open(os.path.join(rb, n + ".git", "description"), "w").write(d + "\n")
+ open(os.path.join(rb, "not-a-repo"), "w").write("ignore me\n") # non-.git skipped
+ # repo_path_for/read_description read from the real REPO_BASE; point it here.
+ global REPO_BASE
+ saved_base, REPO_BASE = REPO_BASE, rb
+ rows = list_repos(rb, fixture)
+ REPO_BASE = saved_base
+ assert rows == [
+ ("cad-projects", True, "Generic Projects", "CAD work"),
+ ("secret-stuff", False, "", ""),
+ ], rows
+ # truncation: a long description is cut to DESC_MAX chars (ellipsis included).
+ os.mkdir(os.path.join(rb, "wordy.git"))
+ open(os.path.join(rb, "wordy.git", "description"), "w").write("x" * 100 + "\n")
+ REPO_BASE = rb
+ long = read_description("wordy")
+ REPO_BASE = saved_base
+ assert len(long) == DESC_MAX and long.endswith("…"), long
block = build_repo_block("publisher", "by Your Name")
assert block == [
@@ -390,6 +462,13 @@ def main():
"push until gitolite has built the bare repo.")
re_.add_argument("--url", required=True, help="repo name to test for (as <url>.git)")
+ sub.add_parser("list-repos",
+ help="list every bare repo, tagged public/private",
+ description="Scan the repository base for all bare repos (the full "
+ "set, not just the cgit-exposed ones), tag each public or "
+ "private by cgitrc membership, and print one "
+ "name<TAB>PUB|PRIV<TAB>section<TAB>description line each.")
+
a = p.parse_args(argv)
if a.verb == "list-sections":
@@ -413,6 +492,12 @@ def main():
if a.verb == "repo-exists":
validate_url(a.url)
return 0 if os.path.isdir(repo_path_for(a.url)) else 1
+ if a.verb == "list-repos":
+ with open(CGITRC) as f:
+ cgit = f.readlines()
+ for name, pub, section, desc in list_repos(REPO_BASE, cgit):
+ print(f"{name}\t{'PUB' if pub else 'PRIV'}\t{section}\t{desc}")
+ return 0
return 1