Skip to content

Commit 09c75b3

Browse files
authored
add timeout (#34)
1 parent 04296e3 commit 09c75b3

File tree

5 files changed

+112
-12
lines changed

5 files changed

+112
-12
lines changed

build.zig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ fn buildBinaries(
124124
"dark-mode",
125125
"repeat",
126126
"tcp-proxy",
127+
"timeout",
127128
}) |name| {
128129
try buildBinary(
129130
b,
@@ -207,7 +208,7 @@ fn makeCompileStep(
207208
// We can't use `target.result.isDarwin()` here
208209
// Since when cross compile to darwin, there is no framework in the host!
209210
const is_darwin = @import("builtin").os.tag == .macos;
210-
211+
const is_win = target.result.os.tag == .windows;
211212
if (!is_darwin) {
212213
if (std.mem.eql(u8, name, "night-shift") or std.mem.eql(u8, name, "dark-mode")) {
213214
return null;
@@ -229,6 +230,11 @@ fn makeCompileStep(
229230
exe.linkFramework("SkyLight");
230231
} else if (std.mem.eql(u8, name, "tcp-proxy")) {
231232
exe.linkLibC();
233+
} else if (std.mem.eql(u8, name, "timeout")) {
234+
if (is_win) { // error: TODO windows Sigaction definition
235+
return null;
236+
}
237+
exe.linkLibC();
232238
} else if (std.mem.eql(u8, name, "zigfetch")) {
233239
if (skip_zigfetch) {
234240
return null;

docs/content/programs/timeout.org

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#+TITLE: timeout
2+
#+DATE: 2025-01-23T22:28:53+0800
3+
#+LASTMOD: 2025-01-23T22:35:32+0800
4+
#+TYPE: docs
5+
#+DESCRIPTION: Run a command with bounded time
6+
7+
#+begin_example
8+
timeout SECONDS COMMAND [ARG]...
9+
#+end_example
10+
11+
Start a command, and kill it if the specified timeout expires.
12+
13+
The =timeout= command is crucial for:
14+
15+
- Process Control
16+
- Limits execution time of commands
17+
- Prevents resource-consuming tasks from running indefinitely
18+
- Provides automatic process termination

docs/content/programs/zigfetch.org

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#+TITLE: zigfetch
22
#+DATE: 2025-01-01T18:01:47+0800
3-
#+LASTMOD: 2025-01-04T09:46:39+0800
3+
#+LASTMOD: 2025-01-04T17:16:15+0800
44
#+TYPE: docs
55
#+DESCRIPTION: Fetch zig packages, utilizing libcurl.
66

7-
=zigfetch= behaves similarly to =zig fetch=, utilizing the capabilities of libcurl for its functionality.
7+
=zigfetch= behaves similarly to =zig fetch=, but utilizing the capabilities of libcurl for its functionality.
88

9-
Since the HTTP support within Zig's standard library isn't currently stable, [[https://github.com/ziglang/zig/issues/21792][this proxy issue]] make it even harder, resulting in multiple errors occurring during dependency downloads when building Zig projects.
9+
HTTP support within Zig's standard library isn't currently stable, [[https://github.com/ziglang/zig/issues/21792][this proxy issue]] make it even harder, resulting in multiple errors occurring during dependency downloads when building Zig projects.
1010

1111
{{< figure src="https://fs.liujiacai.net/cdn-img/zigcli/zig-fetch-errors.webp" >}}
1212

src/bin/timeout.zig

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! Run a command with bounded time
2+
//! https://github.com/coreutils/coreutils/blob/v9.6/src/timeout.c
3+
4+
const std = @import("std");
5+
const posix = std.posix;
6+
const Child = std.process.Child;
7+
8+
pub var child: Child = undefined;
9+
pub var spawn_success = false;
10+
11+
pub fn main() !void {
12+
try posix.sigaction(posix.SIG.ALRM, &posix.Sigaction{
13+
.handler = .{
14+
.handler = struct {
15+
pub fn handler(got: c_int) callconv(.C) void {
16+
std.debug.assert(got == posix.SIG.ALRM);
17+
_ = child.kill() catch |e| {
18+
std.log.err("Kill child failed, err:{any}", .{e});
19+
return;
20+
};
21+
posix.exit(124); // timeout
22+
}
23+
}.handler,
24+
},
25+
.mask = posix.empty_sigset,
26+
.flags = 0,
27+
}, null);
28+
29+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
30+
defer if (gpa.deinit() != .ok) @panic("leak");
31+
const allocator = gpa.allocator();
32+
33+
const args = try std.process.argsAlloc(allocator);
34+
defer std.process.argsFree(allocator, args);
35+
36+
if (args.len < 3) {
37+
std.debug.print(
38+
\\Usage:
39+
\\ {s} SECONDS COMMAND [ARG]...
40+
\\
41+
, .{args[0]});
42+
posix.exit(1);
43+
}
44+
45+
const ttl_seconds = try std.fmt.parseInt(c_uint, args[1], 10);
46+
const cmds = args[2..];
47+
const ret = std.c.alarm(ttl_seconds);
48+
if (ret != 0) {
49+
std.log.err("Set alarm signal failed, retcode:{d}", .{ret});
50+
posix.exit(1);
51+
}
52+
53+
child = Child.init(cmds, allocator);
54+
try child.spawn();
55+
spawn_success = true;
56+
const term = try child.wait();
57+
switch (term) {
58+
.Exited => |status| {
59+
posix.exit(status);
60+
},
61+
else => {
62+
std.log.err("Child internal error, term:{any}", .{term});
63+
posix.exit(125);
64+
},
65+
}
66+
}

src/bin/zigfetch.zig

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,15 @@ fn moveToCache(allocator: Allocator, src_dir: []const u8, hex: Manifest.MultiHas
365365
const dst = try std.fmt.allocPrint(allocator, "{s}/p/{s}", .{ cache_dirname, hex });
366366
defer allocator.free(dst);
367367

368-
_ = fs.openDirAbsolute(dst, .{}) catch |err| switch (err) {
369-
error.FileNotFound => {
370-
return fs.renameAbsolute(src_dir, dst);
371-
},
372-
else => return err,
373-
};
374-
if (args.verbose) {
375-
log.info("Dir({s}) already exists, skip copy...", .{dst});
368+
const found = try checkFileExists(dst);
369+
if (found) {
370+
if (args.verbose) {
371+
log.info("Dir({s}) already exists, skip copy...", .{dst});
372+
}
373+
return;
376374
}
375+
376+
try fs.renameAbsolute(src_dir, dst);
377377
}
378378

379379
fn fetchPackage(allocator: Allocator, url: [:0]const u8, out_dir: fs.Dir) ![]const u8 {
@@ -921,3 +921,13 @@ fn recursiveDirectoryCopy(allocator: Allocator, dir: fs.Dir, tmp_dir: fs.Dir) an
921921
}
922922
}
923923
}
924+
925+
// Returns true if path exists
926+
fn checkFileExists(path: []const u8) !bool {
927+
fs.cwd().access(path, .{}) catch |e| switch (e) {
928+
error.FileNotFound => return false,
929+
else => return e,
930+
};
931+
932+
return true;
933+
}

0 commit comments

Comments
 (0)