summaryrefslogtreecommitdiff
path: root/build.rs
blob: 287f7fbe43bcdf0bff2570bf4b46cc371bc80a8f (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#[path = "src/cli.rs"]
mod cli;

use clap::CommandFactory as _;
use std::io::Write as _;

fn main() -> std::io::Result<()> {
    println!("cargo:rerun-if-changed=src/cli.rs");

    #[allow(clippy::expect_used)] // OUT_DIR is always set by cargo during build scripts
    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is set by cargo");
    let out_path = std::path::Path::new(&out_dir).join("witryna.1");

    let cmd = cli::Cli::command();
    let man = clap_mangen::Man::new(cmd).date(build_date());

    let mut buf: Vec<u8> = Vec::new();

    // Standard clap-generated sections
    man.render_title(&mut buf)?;
    man.render_name_section(&mut buf)?;
    man.render_synopsis_section(&mut buf)?;
    man.render_description_section(&mut buf)?;
    buf.write_all(SUBCOMMANDS)?;
    man.render_options_section(&mut buf)?;

    // Custom roff sections
    buf.write_all(SIGNALS)?;
    buf.write_all(EXIT_STATUS)?;
    buf.write_all(INSTALLATION)?;
    buf.write_all(FILES)?;
    buf.write_all(SEE_ALSO)?;

    man.render_version_section(&mut buf)?;
    man.render_authors_section(&mut buf)?;

    std::fs::write(&out_path, &buf)?;

    // Copy to stable path so cargo-deb and Justfile always find it
    let target_dir = std::path::Path::new("target/man");
    std::fs::create_dir_all(target_dir)?;
    std::fs::copy(&out_path, target_dir.join("witryna.1"))?;

    Ok(())
}

const SUBCOMMANDS: &[u8] = br#".SH "SUBCOMMANDS"
.TP
\fBserve\fR
Start the deployment server (foreground).
.TP
\fBvalidate\fR
Validate configuration file and print summary.
.TP
\fBrun\fR \fIsite\fR
Trigger a one\-off build for a site (synchronous, no server).
.TP
\fBstatus\fR
Show deployment status for configured sites.
"#;

const SIGNALS: &[u8] = br#".SH "SIGNALS"
.TP
\fBSIGHUP\fR
Reload configuration from \fIwitryna.toml\fR without restarting the server.
Sites can be added, removed, or modified on the fly.
Changes to \fBlisten_address\fR, \fBbase_dir\fR, \fBlog_dir\fR,
and \fBlog_level\fR are detected but require a full restart to take effect;
a warning is logged when these fields differ.
.TP
\fBSIGTERM\fR, \fBSIGINT\fR
Initiate graceful shutdown.
In\-progress builds are allowed to finish before the process exits.
"#;

const EXIT_STATUS: &[u8] = br#".SH "EXIT STATUS"
.TP
\fB0\fR
Clean shutdown after SIGTERM/SIGINT (\fBserve\fR), configuration valid (\fBvalidate\fR),
build succeeded (\fBrun\fR), or status displayed (\fBstatus\fR).
Post\-deploy hook failure is non\-fatal and still exits 0.
.TP
\fB1\fR
Startup failure, validation error, build failure, site not found, or configuration error.
.TP
\fB2\fR
Command\-line usage error (unknown flag, missing subcommand, etc.).
"#;

const INSTALLATION: &[u8] = br#".SH "INSTALLATION"
When installed via deb or rpm packages, the post\-install script automatically
detects the available container runtime and configures system\-level access:
.TP
\fBDocker\fR
The \fBwitryna\fR user is added to the \fBdocker\fR group and a systemd
override is installed at
\fI/etc/systemd/system/witryna.service.d/10\-runtime.conf\fR
granting access to the Docker socket.
.TP
\fBPodman\fR
Subordinate UID/GID ranges are allocated (100000\-165535), user lingering is
enabled, and a systemd override is installed that disables
\fBRestrictNamespaces\fR and sets \fBXDG_RUNTIME_DIR\fR.
.PP
If neither runtime is found at install time, a warning is printed.
Install a runtime and reinstall the package, or manually copy the appropriate
override template from \fI/usr/share/doc/witryna/examples/systemd/\fR to
\fI/etc/systemd/system/witryna.service.d/10\-runtime.conf\fR.
"#;

const FILES: &[u8] = br#".SH "FILES"
.TP
\fI/etc/witryna/witryna.toml\fR
Conventional configuration path for system\-wide installs.
The shipped systemd unit passes \fB\-\-config /etc/witryna/witryna.toml\fR
explicitly; without \fB\-\-config\fR the CLI defaults to \fIwitryna.toml\fR
in the current working directory.
.TP
\fI/var/lib/witryna/clones/<site>/\fR
Git repository clones.
.TP
\fI/var/lib/witryna/builds/<site>/<timestamp>/\fR
Timestamped build outputs.
.TP
\fI/var/lib/witryna/builds/<site>/current\fR
Symlink to the latest successful build.
.TP
\fI/var/lib/witryna/cache/<site>/\fR
Persistent build cache volumes.
.TP
\fI/var/log/witryna/<site>/<timestamp>.log\fR
Per\-build log files (site, timestamp, git commit, image, duration, status, stdout, stderr).
.TP
\fI/var/log/witryna/<site>/<timestamp>\-hook.log\fR
Post\-deploy hook output (if configured).
"#;

const SEE_ALSO: &[u8] = br#".SH "SEE ALSO"
\fBwitryna.toml\fR(5)
"#;

fn build_date() -> String {
    std::process::Command::new("date")
        .arg("+%Y-%m-%d")
        .output()
        .ok()
        .and_then(|o| String::from_utf8(o.stdout).ok())
        .map(|s| s.trim().to_owned())
        .unwrap_or_default()
}