download patch
commit cae29bfa94f697a9e8a08c4277b031065b080ea8
Author: tri <tri@thac.loan>
Date: Tue Sep 30 18:01:14 2025 +0700
read repo description from .git/description
diff --git a/Makefile b/Makefile
index 107a7ea..714a392 100644
--- a/Makefile
+++ b/Makefile
+ZIGARGS = -Doptimize=ReleaseSafe -Dcpu=baseline
+
+build:
+ zig build $(ZIGARGS)
+
watch:
zig build run --watch -- demo http://localhost:8000
-watch2:
- zig build run --watch -- demo2 http://localhost:8000
-
# TODO: write a simple zig server instead
serve:
python -m http.server -b localhost -d demo 8000
-# TODO: write a simple zig server instead
-serve2:
- python -m http.server -b localhost -d demo2 8000
-
test:
zig build test --watch
-deploy:
- zig build -Doptimize=ReleaseSafe -Dcpu=baseline
+deploy: build
scp zig-out/bin/khoe root@khoe:/usr/local/bin/
diff --git a/src/assets/style.css b/src/assets/style.css
index dcea7d1..9521153 100644
--- a/src/assets/style.css
+++ b/src/assets/style.css
tbody tr:hover {
}
td,
th {
- padding: 0.1rem 10px;
+ padding: 0.1rem 1rem;
}
table {
- margin-left: -10px;
+ margin-left: -1rem;
font-variant-numeric: tabular-nums;
}
diff --git a/src/git.zig b/src/git.zig
index e2bc7e7..a91299e 100644
--- a/src/git.zig
+++ b/src/git.zig
pub fn getLatestCommit(arena: mem.Allocator, dir: fs.Dir) !?Commit {
};
}
+pub fn getDescription(arena: mem.Allocator, git_dir: fs.Dir) ![]const u8 {
+ const description = git_dir.readFileAlloc(
+ "description",
+ arena,
+ .limited(4096),
+ ) catch |err| {
+ switch (err) {
+ error.FileNotFound => return "",
+ else => return err,
+ }
+ };
+ if (mem.startsWith(u8, description, "Unnamed repository;")) return "";
+ return description;
+}
+
/// If found, return the exact readme filename.
pub fn findReadme(arena: mem.Allocator, dir: fs.Dir) !?[]const u8 {
var proc = try std.process.Child.run(.{
diff --git a/src/main.zig b/src/main.zig
index 228bb7e..8ede4ba 100644
--- a/src/main.zig
+++ b/src/main.zig
const assets_path = web_path ++ "/_khoe-hang";
const Mode = union(enum) {
all: void,
- single_repo: []const u8,
+ single_repo: [*:0]const u8,
};
pub fn main() !u8 {
pub fn main() !u8 {
const commits = try git.getCommits(repo_arena, repo_dir);
println("Found repo {s}: {d} commits", .{ entry.name, commits.len });
+ var git_dir = try repo_dir.openDir(git_dir_path, .{});
+ defer git_dir.close();
+
+ const repo_description = try git.getDescription(arena, git_dir);
+
try repo_summaries.append(arena, .{
.name = try arena.dupe(u8, entry.name),
+ .description = repo_description,
.commit_count = commits.len,
.last_commit_msg = if (commits.len == 0) "" else try arena.dupe(u8, commits[0].subject),
.last_commit_time = if (commits.len == 0) "" else try arena.dupe(u8, commits[0].time),
pub fn main() !u8 {
.arena = repo_arena,
.site_url = site_url,
.repo_name = entry.name,
+ .description = repo_description,
.target_dir = target_dir,
.in_repo_dir = repo_dir,
.commits = commits,
pub fn main() !u8 {
std.mem.sortUnstable(RepoSummary, repo_summaries.items, {}, RepoSummary.lessThan);
- try writeHomePage(target_dir, repo_summaries.items);
+ try writeHomePage(arena, target_dir, repo_summaries.items);
var assets_dir = try target_dir.makeOpenPath(assets_path, .{});
inline for (.{ "style.css", "script.js" }) |asset_name| {
pub fn main() !u8 {
const RepoSummary = struct {
name: []const u8,
+ description: []const u8 = "",
commit_count: usize,
last_commit_time: []const u8,
last_commit_msg: []const u8,
const RepoSummary = struct {
// TODO: decide on some sort of templating system
// FIXME: no html escape is being done
-pub fn writeHomePage(dir: fs.Dir, repos: []RepoSummary) !void {
+pub fn writeHomePage(arena: mem.Allocator, dir: fs.Dir, repos: []RepoSummary) !void {
var file = try dir.createFile("index.html", .{});
defer file.close();
pub fn writeHomePage(dir: fs.Dir, repos: []RepoSummary) !void {
\\ <thead>
\\ <tr>
\\ <th>name</th>
+ \\ <th>description</th>
\\ <th>commits</th>
\\ <th>last commit</th>
\\ <th>last modified</th>
pub fn writeHomePage(dir: fs.Dir, repos: []RepoSummary) !void {
try writer.interface.print(
\\<tr>
\\ <td><a href="/{0s}/{1s}/">{1s}</a></td>
- \\ <td>{2d}</td>
- \\ <td>{3s}</td>
- \\ <td><time class="relative" datetime="{4s}" title="{4s}">{4s}</time></td>
+ \\ <td>{2s}</td>
+ \\ <td>{3d}</td>
+ \\ <td>{4s}</td>
+ \\ <td><time class="relative" datetime="{5s}" title="{5s}">{5s}</time></td>
\\</tr>
\\
,
.{
web_path, // 0
- repo.name, // 1
- repo.commit_count, // 2
- repo.last_commit_msg, // 3
- repo.last_commit_time, // 4
+ try html.escapeAlloc(arena, repo.name), // 1
+ if (repo.description.len == 0)
+ "-"
+ else
+ try html.escapeAlloc(arena, repo.description), // 2
+ repo.commit_count, // 3
+ repo.last_commit_msg, // 4
+ repo.last_commit_time, // 5
},
);
}
const RepoArgs = struct {
arena: std.mem.Allocator,
site_url: [*:0]const u8,
repo_name: []const u8,
+ description: []const u8,
target_dir: fs.Dir,
in_repo_dir: fs.Dir,
commits: []git.Commit,
pub fn writeRepoPage(args: RepoArgs) !void {
const arena = args.arena;
const site_url = args.site_url;
const repo_name = args.repo_name;
+ const description = args.description;
const target_dir = args.target_dir;
const in_repo_dir = args.in_repo_dir;
const commits = args.commits;
pub fn writeRepoPage(args: RepoArgs) !void {
\\ /<a href="/">repos</a>/<h1>{0s}</h1>/
\\ </div>
\\ </header>
+ \\ <p>{4s}</p>
\\
\\ <p>
\\ clone: <code>git clone {2s}/{3s}</code><br>
pub fn writeRepoPage(args: RepoArgs) !void {
repo_name
else
try std.fmt.bufPrint(&buf, "{s}/{s}", .{ repo_name, git_dir_path }),
+ try html.escapeAlloc(arena, description),
});
// If there's a readme file, include it in repo index: