Skip to main content

bob/
lib.rs

1/*
2 * Copyright (c) 2026 Jonathan Perkin <jonathan@perkin.org.uk>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#![cfg_attr(not(doctest), doc = include_str!("../README.md"))]
18
19pub mod action;
20pub mod build;
21pub mod config;
22pub mod cpu;
23pub mod db;
24pub mod logging;
25pub mod makejobs;
26pub mod sandbox;
27pub mod scan;
28pub mod scheduler;
29pub mod state;
30pub mod summary;
31pub mod vcs;
32
33mod history;
34mod init;
35mod pkgstate;
36mod tui;
37
38use std::io::{self, Write};
39
40/**
41 * Column alignment for tabular output.
42 */
43#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
44pub enum Align {
45    #[default]
46    Left,
47    Right,
48}
49
50/**
51 * Column alignment, driven by the strum `align` prop.
52 *
53 * Default to left alignment.
54 */
55pub trait ColumnAlign: strum::EnumProperty {
56    fn align(&self) -> Align {
57        match self.get_str("align") {
58            Some("right") => Align::Right,
59            _ => Align::Left,
60        }
61    }
62}
63
64/**
65 * Write a line to stdout, returning false on broken pipe.
66 *
67 * Use this in loops to gracefully handle SIGPIPE (e.g., when piped to `head`).
68 */
69pub fn try_println(s: &str) -> bool {
70    let result = writeln!(io::stdout(), "{}", s);
71    !matches!(result, Err(e) if e.kind() == io::ErrorKind::BrokenPipe)
72}
73
74/**
75 * Return the current time as seconds since the Unix epoch.
76 */
77pub fn epoch_secs() -> Result<i64, std::time::SystemTimeError> {
78    std::time::SystemTime::now()
79        .duration_since(std::time::UNIX_EPOCH)
80        .map(|d| d.as_secs() as i64)
81}
82
83/// Error indicating the operation was interrupted (e.g., by Ctrl+C).
84#[derive(Debug)]
85pub struct Interrupted;
86
87impl std::fmt::Display for Interrupted {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(f, "Interrupted")
90    }
91}
92
93impl std::error::Error for Interrupted {}
94
95// Re-export main types for convenience.
96//
97// The typical workflow is:
98//   Config::load() → Scan::new() → scan.start() → scan.resolve()
99//   → Build::new() → build.start()
100
101pub use action::{Action, ActionType, FSType};
102pub use build::{
103    Build, BuildCounts, BuildReason, BuildResult, BuildSummary, PkgBuildStats, Stage,
104    pkg_up_to_date,
105};
106pub use config::{
107    Config, DynamicConfig, Options, Pkgsrc, PkgsrcEnv, Sandboxes, Summary, WrkObjDir, WrkObjKind,
108};
109pub use cpu::{CpuSample, CpuSamplerHandle, start_cpu_sampler};
110pub use db::Database;
111pub use history::{History, HistoryKind, format_duration, format_size};
112pub use init::Init;
113pub use makejobs::PkgMakeJobs;
114pub use pkgstate::{
115    PackageCounts, PackageState, PackageStateAlias, PackageStateKind, parse_status_filter,
116};
117pub use sandbox::Sandbox;
118pub use scan::{ResolvedPackage, Scan, ScanResult, ScanSummary};
119pub use scheduler::{PackageNode, ScheduledPackage, Scheduler};
120pub use state::RunState;
121pub use summary::generate_pkg_summary;
122pub use tui::{print_elapsed, print_failed, print_status};