mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-01-26 22:23:16 -05:00
tweak bpaf usage message
As discussed here: https://github.com/pacak/bpaf/discussions/165#discussioncomment-4967176 I also snuck in a conversion from `lazy_static` to `once_cell`, rather than adding another usage of the former.
This commit is contained in:
parent
015dfef9c9
commit
2b27797f42
13
server/Cargo.lock
generated
13
server/Cargo.lock
generated
@ -146,8 +146,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bpaf"
|
||||
version = "0.7.8"
|
||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#77b8efc5d33adcf57901a03514a3ce6183144f8d"
|
||||
version = "0.7.9"
|
||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#5238a6069abca0d61cf1c000e56bbac946e7ee18"
|
||||
dependencies = [
|
||||
"bpaf_derive",
|
||||
"owo-colors",
|
||||
@ -155,8 +155,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bpaf_derive"
|
||||
version = "0.3.3"
|
||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#77b8efc5d33adcf57901a03514a3ce6183144f8d"
|
||||
version = "0.3.4"
|
||||
source = "git+https://github.com/pacak/bpaf.git?branch=exit_code#5238a6069abca0d61cf1c000e56bbac946e7ee18"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1101,7 +1101,6 @@ version = "0.0.1"
|
||||
dependencies = [
|
||||
"failure",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"nom",
|
||||
@ -1126,7 +1125,6 @@ dependencies = [
|
||||
"h264-reader",
|
||||
"hashlink",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"moonfire-base",
|
||||
@ -1134,6 +1132,7 @@ dependencies = [
|
||||
"nix",
|
||||
"num-rational",
|
||||
"odds",
|
||||
"once_cell",
|
||||
"pretty-hex",
|
||||
"protobuf",
|
||||
"protobuf-codegen",
|
||||
@ -1168,7 +1167,6 @@ dependencies = [
|
||||
"http-serve",
|
||||
"hyper",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"memchr",
|
||||
@ -1179,6 +1177,7 @@ dependencies = [
|
||||
"nix",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"once_cell",
|
||||
"password-hash",
|
||||
"protobuf",
|
||||
"reffers",
|
||||
|
@ -37,7 +37,6 @@ http = "0.2.3"
|
||||
http-serve = { version = "0.3.1", features = ["dir"] }
|
||||
hyper = { version = "0.14.2", features = ["http1", "server", "stream", "tcp"] }
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.0"
|
||||
libc = "0.2"
|
||||
log = { version = "0.4" }
|
||||
memchr = "2.0.2"
|
||||
@ -62,6 +61,7 @@ toml = "0.5"
|
||||
tracing = { version = "0.1", features = ["log"] }
|
||||
url = "2.1.1"
|
||||
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
||||
once_cell = "1.17.0"
|
||||
|
||||
[dev-dependencies]
|
||||
mp4 = { git = "https://github.com/scottlamb/mp4-rust", branch = "moonfire" }
|
||||
|
@ -15,7 +15,6 @@ path = "lib.rs"
|
||||
[dependencies]
|
||||
failure = "0.1.1"
|
||||
futures = "0.3"
|
||||
lazy_static = "1.0"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
nom = "7.0.0"
|
||||
|
@ -24,7 +24,6 @@ fnv = "1.0"
|
||||
futures = "0.3"
|
||||
h264-reader = "0.6.0"
|
||||
hashlink = "0.8.1"
|
||||
lazy_static = "1.0"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
mylog = { git = "https://github.com/scottlamb/mylog" }
|
||||
@ -46,6 +45,7 @@ tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "sync"] }
|
||||
url = { version = "2.1.1", features = ["serde"] }
|
||||
uuid = { version = "1.1.2", features = ["serde", "std", "v4"] }
|
||||
itertools = "0.10.0"
|
||||
once_cell = "1.17.0"
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.0"
|
||||
|
@ -9,7 +9,6 @@ use crate::schema::Permissions;
|
||||
use base::{bail_t, format_err_t, strutil, ErrorKind, ResultExt as _};
|
||||
use failure::{bail, format_err, Error, Fail, ResultExt as _};
|
||||
use fnv::FnvHashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use log::info;
|
||||
use protobuf::Message;
|
||||
use ring::rand::{SecureRandom, SystemRandom};
|
||||
@ -21,9 +20,8 @@ use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
static ref PARAMS: Mutex<scrypt::Params> = Mutex::new(scrypt::Params::recommended());
|
||||
}
|
||||
static PARAMS: once_cell::sync::Lazy<Mutex<scrypt::Params>> =
|
||||
once_cell::sync::Lazy::new(|| Mutex::new(scrypt::Params::recommended()));
|
||||
|
||||
/// For testing only: use fast but insecure hashes.
|
||||
/// Call via `testutil::init()`.
|
||||
|
@ -9,7 +9,9 @@ use db::check;
|
||||
use failure::Error;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Checks database integrity (like fsck).
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -40,6 +42,10 @@ pub struct Args {
|
||||
trash_corrupt_rows: bool,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "check")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
check::run(
|
||||
|
@ -19,7 +19,9 @@ mod cameras;
|
||||
mod dirs;
|
||||
mod users;
|
||||
|
||||
/// Interactively edits configuration.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -28,6 +30,10 @@ pub struct Args {
|
||||
db_dir: PathBuf,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "config")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
let clocks = clock::RealClocks {};
|
||||
|
@ -7,7 +7,9 @@ use failure::Error;
|
||||
use log::info;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Initializes a database.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -16,6 +18,10 @@ pub struct Args {
|
||||
db_dir: PathBuf,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "init")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::Create)?;
|
||||
|
||||
|
@ -24,7 +24,14 @@ fn parse_flags(flags: String) -> Result<Vec<SessionFlag>, Error> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Logs in a user, returning the session cookie.
|
||||
///
|
||||
///
|
||||
/// This is a privileged command that directly accesses the database. It doesn't check the
|
||||
/// user's password and even can be used to create sessions with permissions the user doesn't
|
||||
/// have.
|
||||
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -64,6 +71,10 @@ pub struct Args {
|
||||
username: String,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "login")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let clocks = clock::RealClocks {};
|
||||
let (_db_dir, conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
@ -148,12 +159,9 @@ fn curl_cookie(cookie: &str, flags: i32, domain: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use bpaf::Parser;
|
||||
|
||||
#[test]
|
||||
fn parse_args() {
|
||||
let args = args()
|
||||
.to_options()
|
||||
.run_inner(bpaf::Args::from(&[
|
||||
"--permissions",
|
||||
"{\"viewVideo\": true}",
|
||||
|
@ -25,7 +25,9 @@ use self::config::ConfigFile;
|
||||
|
||||
mod config;
|
||||
|
||||
/// Runs the server, saving recordings and allowing web access.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Path to configuration file.
|
||||
///
|
||||
@ -40,6 +42,10 @@ pub struct Args {
|
||||
read_only: bool,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "run")
|
||||
}
|
||||
|
||||
// These are used in a hack to get the name of the current time zone (e.g. America/Los_Angeles).
|
||||
// They seem to be correct for Linux and macOS at least.
|
||||
const LOCALTIME_PATH: &str = "/etc/localtime";
|
||||
|
@ -12,7 +12,13 @@ use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
/// Runs a SQLite3 shell on Moonfire NVR's index database.
|
||||
///
|
||||
///
|
||||
/// Note this locks the database to prevent simultaneous access with a running server. The
|
||||
/// server maintains cached state which could be invalidated otherwise.
|
||||
#[derive(Bpaf, Debug, PartialEq, Eq)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -33,6 +39,10 @@ pub struct Args {
|
||||
arg: Vec<OsString>,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "sql")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let mode = if args.read_only {
|
||||
OpenMode::ReadOnly
|
||||
@ -59,12 +69,9 @@ pub fn run(args: Args) -> Result<i32, Error> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use bpaf::Parser;
|
||||
|
||||
#[test]
|
||||
fn parse_args() {
|
||||
let args = args()
|
||||
.to_options()
|
||||
.run_inner(bpaf::Args::from(&[
|
||||
"--db-dir",
|
||||
"/foo/bar",
|
||||
|
@ -5,7 +5,9 @@
|
||||
use bpaf::Bpaf;
|
||||
use failure::Error;
|
||||
|
||||
/// Translates between integer and human-readable timestamps.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Timestamp(s) to translate.
|
||||
///
|
||||
@ -17,6 +19,10 @@ pub struct Args {
|
||||
timestamps: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "ts")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
for timestamp in &args.timestamps {
|
||||
let t = db::recording::Time::parse(timestamp)?;
|
||||
|
@ -8,7 +8,9 @@ use bpaf::Bpaf;
|
||||
/// See `guide/schema.md` for more information.
|
||||
use failure::Error;
|
||||
|
||||
/// Upgrades to the latest database schema.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options)]
|
||||
pub struct Args {
|
||||
/// Directory holding the SQLite3 index database.
|
||||
///
|
||||
@ -35,6 +37,10 @@ pub struct Args {
|
||||
no_vacuum: bool,
|
||||
}
|
||||
|
||||
pub fn subcommand() -> impl bpaf::Parser<Args> {
|
||||
crate::subcommand(args(), "upgrade")
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<i32, Error> {
|
||||
let (_db_dir, mut conn) = super::open_conn(&args.db_dir, super::OpenMode::ReadWrite)?;
|
||||
|
||||
|
@ -19,50 +19,43 @@ mod stream;
|
||||
mod streamer;
|
||||
mod web;
|
||||
|
||||
/// The program name, taken from the OS-provided arguments if available.
|
||||
///
|
||||
/// E.g. if invoked as `target/debug/nvr`, should return `nvr`.
|
||||
static PROGNAME: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| {
|
||||
std::env::args_os()
|
||||
.next()
|
||||
.and_then(|p| {
|
||||
let p = std::path::PathBuf::from(p);
|
||||
p.file_name().and_then(|f| {
|
||||
f.to_str()
|
||||
.map(|s| &*Box::leak(s.to_owned().into_boxed_str()))
|
||||
})
|
||||
})
|
||||
.unwrap_or(env!("CARGO_PKG_NAME"))
|
||||
});
|
||||
|
||||
fn subcommand<T: 'static>(
|
||||
parser: bpaf::OptionParser<T>,
|
||||
cmd: &'static str,
|
||||
) -> impl bpaf::Parser<T> {
|
||||
let usage = format!("Usage: {progname} {cmd} {{usage}}", progname = *PROGNAME);
|
||||
parser.usage(Box::leak(usage.into_boxed_str())).command(cmd)
|
||||
}
|
||||
|
||||
/// Moonfire NVR: security camera network video recorder.
|
||||
#[derive(Bpaf, Debug)]
|
||||
#[bpaf(options, version)]
|
||||
enum Args {
|
||||
/// Checks database integrity (like fsck).
|
||||
#[bpaf(command)]
|
||||
Check(#[bpaf(external(cmds::check::args))] cmds::check::Args),
|
||||
|
||||
/// Interactively edits configuration.
|
||||
#[bpaf(command)]
|
||||
Config(#[bpaf(external(cmds::config::args))] cmds::config::Args),
|
||||
|
||||
/// Initializes a database.
|
||||
#[bpaf(command)]
|
||||
Init(#[bpaf(external(cmds::init::args))] cmds::init::Args),
|
||||
|
||||
/// Logs in a user, returning the session cookie.
|
||||
///
|
||||
///
|
||||
/// This is a privileged command that directly accesses the database. It doesn't check the
|
||||
/// user's password and even can be used to create sessions with permissions the user doesn't
|
||||
/// have.
|
||||
#[bpaf(command)]
|
||||
Login(#[bpaf(external(cmds::login::args))] cmds::login::Args),
|
||||
|
||||
/// Runs the server, saving recordings and allowing web access.
|
||||
#[bpaf(command)]
|
||||
Run(#[bpaf(external(cmds::run::args))] cmds::run::Args),
|
||||
|
||||
/// Runs a SQLite3 shell on Moonfire NVR's index database.
|
||||
///
|
||||
///
|
||||
/// Note this locks the database to prevent simultaneous access with a running server. The
|
||||
/// server maintains cached state which could be invalidated otherwise.
|
||||
#[bpaf(command)]
|
||||
Sql(#[bpaf(external(cmds::sql::args))] cmds::sql::Args),
|
||||
|
||||
/// Translates between integer and human-readable timestamps.
|
||||
#[bpaf(command)]
|
||||
Ts(#[bpaf(external(cmds::ts::args))] cmds::ts::Args),
|
||||
|
||||
/// Upgrades to the latest database schema.
|
||||
#[bpaf(command)]
|
||||
Upgrade(#[bpaf(external(cmds::upgrade::args))] cmds::upgrade::Args),
|
||||
// See docstrings of `cmds::*::Args` structs for a description of the respective subcommands.
|
||||
Check(#[bpaf(external(cmds::check::subcommand))] cmds::check::Args),
|
||||
Config(#[bpaf(external(cmds::config::subcommand))] cmds::config::Args),
|
||||
Init(#[bpaf(external(cmds::init::subcommand))] cmds::init::Args),
|
||||
Login(#[bpaf(external(cmds::login::subcommand))] cmds::login::Args),
|
||||
Run(#[bpaf(external(cmds::run::subcommand))] cmds::run::Args),
|
||||
Sql(#[bpaf(external(cmds::sql::subcommand))] cmds::sql::Args),
|
||||
Ts(#[bpaf(external(cmds::ts::subcommand))] cmds::ts::Args),
|
||||
Upgrade(#[bpaf(external(cmds::upgrade::subcommand))] cmds::upgrade::Args),
|
||||
}
|
||||
|
||||
impl Args {
|
||||
@ -141,12 +134,15 @@ fn main() {
|
||||
.build();
|
||||
h.clone().install().unwrap();
|
||||
|
||||
let args = args().usage(Box::leak(
|
||||
format!("Usage: {progname} {{usage}}", progname = *PROGNAME).into_boxed_str(),
|
||||
));
|
||||
|
||||
// TODO: remove this when bpaf adds more direct support for defaulting to `--help`.
|
||||
// See discussion: <https://github.com/pacak/bpaf/discussions/165>.
|
||||
if std::env::args_os().len() < 2 {
|
||||
std::process::exit(
|
||||
args()
|
||||
.run_inner(bpaf::Args::from(&["--help"]))
|
||||
args.run_inner(bpaf::Args::from(&["--help"]))
|
||||
.unwrap_err()
|
||||
.exit_code(),
|
||||
);
|
||||
@ -159,7 +155,7 @@ fn main() {
|
||||
std::panic::set_hook(Box::new(&panic_hook));
|
||||
}
|
||||
|
||||
let args = args().run();
|
||||
let args = args.run();
|
||||
log::trace!("Parsed command-line arguments: {args:#?}");
|
||||
|
||||
let r = {
|
||||
|
@ -2979,11 +2979,10 @@ mod bench {
|
||||
use futures::future;
|
||||
use http_serve;
|
||||
use hyper;
|
||||
use lazy_static::lazy_static;
|
||||
use url::Url;
|
||||
|
||||
/// An HTTP server for benchmarking.
|
||||
/// It's used as a singleton via `lazy_static!` so that when getting a CPU profile of the
|
||||
/// It's used as a singleton so that when getting a CPU profile of the
|
||||
/// benchmark, more of the profile focuses on the HTTP serving rather than the setup.
|
||||
///
|
||||
/// Currently this only serves a single `.mp4` file but we could set up variations to benchmark
|
||||
@ -3029,9 +3028,8 @@ mod bench {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SERVER: BenchServer = BenchServer::new();
|
||||
}
|
||||
static SERVER: once_cell::sync::Lazy<BenchServer> =
|
||||
once_cell::sync::Lazy::new(BenchServer::new);
|
||||
|
||||
#[bench]
|
||||
fn build_index(b: &mut test::Bencher) {
|
||||
|
@ -183,7 +183,6 @@ mod tests {
|
||||
use crate::body::BoxedError;
|
||||
use db::testutil;
|
||||
use futures::stream::{self, Stream, TryStreamExt};
|
||||
use lazy_static::lazy_static;
|
||||
use std::ops::Range;
|
||||
use std::pin::Pin;
|
||||
|
||||
@ -224,18 +223,16 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
#[rustfmt::skip]
|
||||
static ref SLICES: Slices<FakeSlice> = {
|
||||
let mut s = Slices::new();
|
||||
s.append(FakeSlice { end: 5, name: "a" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13, name: "b" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7, name: "c" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17, name: "d" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17 + 19, name: "e" }).unwrap();
|
||||
s
|
||||
};
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
static SLICES: once_cell::sync::Lazy<Slices<FakeSlice>> = once_cell::sync::Lazy::new(|| {
|
||||
let mut s = Slices::new();
|
||||
s.append(FakeSlice { end: 5, name: "a" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13, name: "b" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7, name: "c" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17, name: "d" }).unwrap();
|
||||
s.append(FakeSlice { end: 5 + 13 + 7 + 17 + 19, name: "e" }).unwrap();
|
||||
s
|
||||
});
|
||||
|
||||
async fn get_range(r: Range<u64>) -> Vec<FakeChunk> {
|
||||
Pin::from(SLICES.get_range(&&*SLICES, r))
|
||||
|
@ -728,7 +728,6 @@ mod bench {
|
||||
|
||||
use db::testutil::{self, TestDb};
|
||||
use hyper;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -786,9 +785,7 @@ mod bench {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SERVER: Server = Server::new();
|
||||
}
|
||||
static SERVER: once_cell::sync::Lazy<Server> = once_cell::sync::Lazy::new(Server::new);
|
||||
|
||||
#[bench]
|
||||
fn serve_stream_recordings(b: &mut test::Bencher) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user