use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::{Child, Command, Stdio};
use super::{ExclusiveOption, SubCommand, Unselected};
use crate::global::GlobalOpts;
use crate::spawn::{ParameterizedSpawn, SpawnExt};
#[cfg_attr(
not(feature = "lt2015_1"),
doc = " [`setldapusers`](Self::setldapusers),"
)]
#[cfg_attr(
not(feature = "lt2018_1"),
doc = " [`end_journal`](Self::end_journal),"
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = " [`sysinfo`](Self::sysinfo), [`resource_monitor`](Self::resource_monitor),"
)]
#[cfg_attr(
not(feature = "lt2025_2"),
doc = " [`replica_filter_reconcile`](Self::replica_filter_reconcile),"
)]
#[derive(Debug, Clone, Default)]
pub struct AdminEntry {
bin: PathBuf,
global_opts: GlobalOpts,
}
impl AdminEntry {
pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
Self {
bin: bin.into(),
global_opts,
}
}
pub fn checkpoint(self) -> Admin<CheckPoint<Unselected>> {
Admin::new(self.bin, self.global_opts, CheckPoint::default())
}
pub fn journal(self) -> Admin<Journal> {
Admin::new(self.bin, self.global_opts, Journal::default())
}
pub fn stop(self) -> Admin<Stop> {
Admin::new(self.bin, self.global_opts, Stop)
}
pub fn restart(self) -> Admin<Restart> {
Admin::new(self.bin, self.global_opts, Restart)
}
pub fn updatespecdepot(self) -> Admin<UpdateSpecDepot<Unselected>> {
Admin::new(self.bin, self.global_opts, UpdateSpecDepot::default())
}
pub fn resetpassword(self) -> Admin<ResetPassword<Unselected>> {
Admin::new(self.bin, self.global_opts, ResetPassword::default())
}
#[cfg(not(feature = "lt2015_1"))]
pub fn setldapusers(self) -> Admin<SetLdapUsers> {
Admin::new(self.bin, self.global_opts, SetLdapUsers)
}
#[cfg(not(feature = "lt2018_1"))]
pub fn end_journal(self) -> Admin<EndJournal> {
Admin::new(self.bin, self.global_opts, EndJournal)
}
#[cfg_attr(
all(not(feature = "lt2023_1"), feature = "lt2024_2"),
doc = "Helix Core Server."
)]
#[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
#[cfg(not(feature = "lt2023_1"))]
pub fn sysinfo(self) -> Admin<SysInfo> {
Admin::new(self.bin, self.global_opts, SysInfo)
}
#[cfg_attr(
all(not(feature = "lt2023_1"), feature = "lt2024_1"),
doc = "Helix Core Server",
doc = "Administrator Guide."
)]
#[cfg_attr(
all(not(feature = "lt2024_1"), feature = "lt2024_2"),
doc = "the Helix Core Server Administrator Guide."
)]
#[cfg_attr(
not(feature = "lt2024_2"),
doc = "P4 Server",
doc = "Administration Documentation."
)]
#[cfg(not(feature = "lt2023_1"))]
pub fn resource_monitor(self) -> Admin<ResourceMonitor> {
Admin::new(self.bin, self.global_opts, ResourceMonitor)
}
#[cfg(not(feature = "lt2025_2"))]
pub fn replica_filter_reconcile(self) -> Admin<ReplicaFilterReconcile<Unselected>> {
Admin::new(
self.bin,
self.global_opts,
ReplicaFilterReconcile::default(),
)
}
}
#[derive(Debug, Clone, Default)]
pub struct Admin<T: SubCommand> {
bin: PathBuf,
global_opts: GlobalOpts,
sub_command: T,
}
impl<T: SubCommand> SubCommand for Admin<T> {
fn name(&self) -> &str {
"admin"
}
fn inject_local_args(&self, command: &mut Command) {
self.sub_command.inject_args(command);
}
fn global_opts(&self) -> Option<&GlobalOpts> {
Some(&self.global_opts)
}
}
impl<T: SubCommand> Admin<T> {
fn spawn_piped(&mut self) -> Result<Child, std::io::Error> {
self.setup_command(&self.bin)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl ParameterizedSpawn for Admin<Stop> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
impl ParameterizedSpawn for Admin<Restart> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
impl<S: ExclusiveOption> ParameterizedSpawn for Admin<UpdateSpecDepot<S>> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
impl<T: ExclusiveOption> ParameterizedSpawn for Admin<ResetPassword<T>> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
#[cfg(not(feature = "lt2015_1"))]
impl ParameterizedSpawn for Admin<SetLdapUsers> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
#[cfg(not(feature = "lt2018_1"))]
impl ParameterizedSpawn for Admin<EndJournal> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
#[cfg(not(feature = "lt2023_1"))]
impl ParameterizedSpawn for Admin<SysInfo> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
#[cfg(not(feature = "lt2023_1"))]
impl ParameterizedSpawn for Admin<ResourceMonitor> {
type Input<'a> = ();
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, (): Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.spawn_piped()
}
}
impl<T: SubCommand> Admin<T> {
pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts, sub_command: T) -> Self {
Self {
bin: bin.into(),
global_opts,
sub_command,
}
}
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn get_global_opts(&self) -> &GlobalOpts {
&self.global_opts
}
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
self.global_opts = v;
self
}
#[cfg_attr(
feature = "lt2014_2",
doc = "See the [Global Options](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2015_1", not(feature = "lt2014_2")),
doc = "See the [“Global Options”](GlobalOpts) section."
)]
#[cfg_attr(
all(feature = "lt2017_1", not(feature = "lt2015_1")),
doc = "See [“Global Options”](GlobalOpts)."
)]
#[cfg_attr(
all(feature = "lt2018_2", not(feature = "lt2017_1")),
doc = "See [Global Options](GlobalOpts)."
)]
#[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
pub fn global_opts(mut self, v: GlobalOpts) -> Self {
self.global_opts = v;
self
}
}
pub mod compression {
#[derive(Debug, Clone, Copy, Default)]
pub struct Both;
#[derive(Debug, Clone, Copy, Default)]
pub struct CheckPointOnly;
}
impl ExclusiveOption for compression::Both {
fn inject_args(&self, command: &mut Command) {
command.arg("-z");
}
}
impl ExclusiveOption for compression::CheckPointOnly {
fn inject_args(&self, command: &mut Command) {
command.arg("-Z");
}
}
#[cfg_attr(
feature = "lt2022_2",
doc = "`p4 admin checkpoint [-z | -Z] [prefix]`: take a checkpoint."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "`p4 admin checkpoint [[-z | -Z]] [prefix]`: take a checkpoint."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "`p4 admin checkpoint [-z | -Z] [-p [-N threads] [-m]] [prefix]`: take a checkpoint."
)]
#[derive(Debug, Clone, Default)]
pub struct CheckPoint<C = Unselected> {
compression: C,
#[cfg(not(feature = "lt2023_1"))]
parallel: bool,
#[cfg(not(feature = "lt2023_1"))]
threads: Option<u32>,
#[cfg(not(feature = "lt2023_1"))]
multiple_files: bool,
}
impl<C: ExclusiveOption> SubCommand for CheckPoint<C> {
fn name(&self) -> &str {
"checkpoint"
}
fn inject_local_args(&self, command: &mut Command) {
self.compression.inject_args(command);
#[cfg(not(feature = "lt2023_1"))]
{
if self.parallel {
command.arg("-p");
}
if let Some(threads) = self.threads {
command.arg("-N").arg(threads.to_string());
}
if self.multiple_files {
command.arg("-m");
}
}
}
}
impl<C: ExclusiveOption> ParameterizedSpawn for Admin<CheckPoint<C>> {
type Input<'a> = &'a OsStr;
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, prefix: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.setup_command(&self.bin)
.arg(prefix)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<C: ExclusiveOption> SpawnExt for Admin<CheckPoint<C>> {
fn spawn<'a>(&mut self) -> Result<Self::Output<'a>, Self::Error> {
self.setup_command(&self.bin)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl<C: ExclusiveOption> Admin<CheckPoint<C>> {
#[cfg(not(feature = "lt2023_1"))]
pub fn get_parallel(&self) -> bool {
self.sub_command.parallel
}
#[cfg(not(feature = "lt2023_1"))]
pub fn set_parallel(&mut self, parallel: bool) -> &mut Self {
self.sub_command.parallel = parallel;
self
}
#[cfg(not(feature = "lt2023_1"))]
pub fn parallel(mut self, parallel: bool) -> Self {
self.sub_command.parallel = parallel;
self
}
#[cfg(not(feature = "lt2023_1"))]
pub fn get_threads(&self) -> Option<&u32> {
self.sub_command.threads.as_ref()
}
#[cfg(not(feature = "lt2023_1"))]
pub fn set_threads(&mut self, threads: u32) -> &mut Self {
self.sub_command.threads = Some(threads);
self
}
#[cfg(not(feature = "lt2023_1"))]
pub fn threads(mut self, threads: u32) -> Self {
self.sub_command.threads = Some(threads);
self
}
#[cfg_attr(
all(not(feature = "lt2023_1"), feature = "lt2024_1"),
doc = "in Helix Core",
doc = "Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_1"), feature = "lt2024_2"),
doc = "in the Helix",
doc = "Core Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_2"), feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also checkpoint examples."
)]
#[cfg_attr(
not(feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also Checkpoint examples."
)]
#[cfg(not(feature = "lt2023_1"))]
pub fn get_multiple_files(&self) -> bool {
self.sub_command.multiple_files
}
#[cfg_attr(
all(not(feature = "lt2023_1"), feature = "lt2024_1"),
doc = "in Helix Core",
doc = "Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_1"), feature = "lt2024_2"),
doc = "in the Helix",
doc = "Core Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_2"), feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also checkpoint examples."
)]
#[cfg_attr(
not(feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also Checkpoint examples."
)]
#[cfg(not(feature = "lt2023_1"))]
pub fn set_multiple_files(&mut self, multiple_files: bool) -> &mut Self {
self.sub_command.multiple_files = multiple_files;
self
}
#[cfg_attr(
all(not(feature = "lt2023_1"), feature = "lt2024_1"),
doc = "in Helix Core",
doc = "Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_1"), feature = "lt2024_2"),
doc = "in the Helix",
doc = "Core Server Administrator Guide. See also checkpoint examples."
)]
#[cfg_attr(
all(not(feature = "lt2024_2"), feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also checkpoint examples."
)]
#[cfg_attr(
not(feature = "lt2025_1"),
doc = "in the P4",
doc = "Server Administration Documentation. See also Checkpoint examples."
)]
#[cfg(not(feature = "lt2023_1"))]
pub fn multiple_files(mut self, multiple_files: bool) -> Self {
self.sub_command.multiple_files = multiple_files;
self
}
}
impl Admin<CheckPoint<Unselected>> {
#[cfg_attr(
feature = "lt2022_2",
doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
doc = "suffix to the files."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "Save the checkpoint and journal file in compressed format. The `.gz`",
doc = "suffix is appended to compressed journals and checkpoint files, which",
doc = "are in gzip format. If you do not specify `-z` or `-Z`, no compression",
doc = "occurs."
)]
pub fn compress_both(self) -> Admin<CheckPoint<compression::Both>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: CheckPoint::<compression::Both> {
compression: compression::Both,
#[cfg(not(feature = "lt2023_1"))]
parallel: self.sub_command.parallel,
#[cfg(not(feature = "lt2023_1"))]
threads: self.sub_command.threads,
#[cfg(not(feature = "lt2023_1"))]
multiple_files: self.sub_command.multiple_files,
},
}
}
#[cfg_attr(
feature = "lt2017_2",
doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
doc = "in compressed (gzip) format, appending the `.gz` suffix to the file, but",
doc = "leave the journal uncompressed for use by replica servers."
)]
#[cfg_attr(
all(feature = "lt2022_2", not(feature = "lt2017_2")),
doc = "For `p4 admin checkpoint`, save the checkpoint in compressed (gzip)",
doc = "format, appending the `.gz` suffix to the file, but leave the journal",
doc = "uncompressed for use by replica servers."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "For `p4 admin checkpoint -Z`, save the checkpoint in compressed format,",
doc = "but leave the journal uncompressed for use by replica servers."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "For `p4 admin checkpoint -Z`, save the checkpoint in compressed format,",
doc = "but leave the journal uncompressed for use by replica servers. The",
doc = "`.gz` suffix is appended to compressed journals and checkpoint files,",
doc = "which are in gzip format. If you do not specify `-z` or `-Z`, no",
doc = "compression occurs."
)]
pub fn compress_checkpoint_only(self) -> Admin<CheckPoint<compression::CheckPointOnly>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: CheckPoint::<compression::CheckPointOnly> {
compression: compression::CheckPointOnly,
#[cfg(not(feature = "lt2023_1"))]
parallel: self.sub_command.parallel,
#[cfg(not(feature = "lt2023_1"))]
threads: self.sub_command.threads,
#[cfg(not(feature = "lt2023_1"))]
multiple_files: self.sub_command.multiple_files,
},
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Journal {
gzip: bool,
}
impl SubCommand for Journal {
fn name(&self) -> &str {
"journal"
}
fn inject_local_args(&self, command: &mut Command) {
if self.gzip {
command.arg("-z");
}
}
}
impl ParameterizedSpawn for Admin<Journal> {
type Input<'a> = &'a OsStr;
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, prefix: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.setup_command(&self.bin)
.arg(prefix)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl SpawnExt for Admin<Journal> {
fn spawn<'a>(&mut self) -> Result<Self::Output<'a>, Self::Error> {
self.setup_command(&self.bin)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
impl Admin<Journal> {
#[cfg_attr(
feature = "lt2022_2",
doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
doc = "suffix to the files."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "Save the journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z`, no compression occurs."
)]
pub fn get_gzip(&self) -> bool {
self.sub_command.gzip
}
#[cfg_attr(
feature = "lt2022_2",
doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
doc = "suffix to the files."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "Save the journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z`, no compression occurs."
)]
pub fn set_gzip(&mut self, gzip: bool) -> &mut Self {
self.sub_command.gzip = gzip;
self
}
#[cfg_attr(
feature = "lt2022_2",
doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
doc = "suffix to the files."
)]
#[cfg_attr(
all(feature = "lt2023_1", not(feature = "lt2022_2")),
doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
)]
#[cfg_attr(
not(feature = "lt2023_1"),
doc = "Save the journal file in compressed format. The `.gz` suffix is",
doc = "appended to compressed journals and checkpoint files, which are in",
doc = "gzip format. If you do not specify `-z`, no compression occurs."
)]
pub fn gzip(mut self, gzip: bool) -> Self {
self.sub_command.gzip = gzip;
self
}
}
#[derive(Debug, Clone, Default)]
pub struct Stop;
impl SubCommand for Stop {
fn name(&self) -> &str {
"stop"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[derive(Debug, Clone, Default)]
pub struct Restart;
impl SubCommand for Restart {
fn name(&self) -> &str {
"restart"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[derive(Debug, Clone)]
pub enum SpecifiedType {
Client,
Depot,
#[cfg(not(feature = "lt2018_1"))]
Repo,
Branch,
Label,
TypeMap,
Group,
User,
Job,
#[cfg(not(feature = "lt2016_1"))]
Stream,
#[cfg(not(feature = "lt2016_1"))]
Triggers,
#[cfg(not(feature = "lt2016_1"))]
Protect,
#[cfg(not(feature = "lt2016_1"))]
Server,
#[cfg(not(feature = "lt2016_1"))]
License,
#[cfg(not(feature = "lt2016_1"))]
JobSpec,
}
impl SpecifiedType {
pub(crate) fn to_str(&self) -> &str {
match self {
Self::Client => "client",
Self::Depot => "depot",
#[cfg(not(feature = "lt2018_1"))]
Self::Repo => "repo",
Self::Branch => "branch",
Self::Label => "label",
Self::TypeMap => "typemap",
Self::Group => "group",
Self::User => "user",
Self::Job => "job",
#[cfg(not(feature = "lt2016_1"))]
Self::Stream => "stream",
#[cfg(not(feature = "lt2016_1"))]
Self::Triggers => "triggers",
#[cfg(not(feature = "lt2016_1"))]
Self::Protect => "protect",
#[cfg(not(feature = "lt2016_1"))]
Self::Server => "server",
#[cfg(not(feature = "lt2016_1"))]
Self::License => "license",
#[cfg(not(feature = "lt2016_1"))]
Self::JobSpec => "jobspec",
}
}
}
pub mod spec {
use super::SpecifiedType;
#[derive(Debug, Clone, Copy, Default)]
pub struct All;
#[derive(Debug, Clone)]
pub struct Selected(pub SpecifiedType);
}
impl ExclusiveOption for spec::All {
fn inject_args(&self, command: &mut Command) {
command.arg("-a");
}
}
impl ExclusiveOption for spec::Selected {
fn inject_args(&self, command: &mut Command) {
command.arg("-s").arg(self.0.to_str());
}
}
#[derive(Debug, Clone, Default)]
pub struct UpdateSpecDepot<S = Unselected> {
spec: S,
}
impl<S: ExclusiveOption> SubCommand for UpdateSpecDepot<S> {
fn name(&self) -> &str {
"updatespecdepot"
}
fn inject_local_args(&self, command: &mut Command) {
self.spec.inject_args(command);
}
}
impl Admin<UpdateSpecDepot<Unselected>> {
#[cfg_attr(
feature = "lt2022_2",
doc = "For `p4 admin updatespecdepot`, update the spec depot with all current",
doc = "forms."
)]
#[cfg_attr(
not(feature = "lt2022_2"),
doc = "For `p4 admin updatespecdepot -a`, update the spec depot with all",
doc = "current forms."
)]
pub fn all(self) -> Admin<UpdateSpecDepot<spec::All>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: UpdateSpecDepot { spec: spec::All },
}
}
#[cfg_attr(
feature = "lt2016_1",
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, or `job`."
)]
#[cfg_attr(
all(feature = "lt2018_1", not(feature = "lt2016_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
doc = "`protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
all(feature = "lt2022_2", not(feature = "lt2018_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
not(feature = "lt2022_2"),
doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
pub fn specified_type(
self,
specified_type: SpecifiedType,
) -> Admin<UpdateSpecDepot<spec::Selected>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: UpdateSpecDepot {
spec: spec::Selected(specified_type),
},
}
}
}
impl Admin<UpdateSpecDepot<spec::Selected>> {
#[cfg_attr(
feature = "lt2016_1",
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, or `job`."
)]
#[cfg_attr(
all(feature = "lt2018_1", not(feature = "lt2016_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
doc = "`protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
all(feature = "lt2022_2", not(feature = "lt2018_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
not(feature = "lt2022_2"),
doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
pub fn get_specified_type(&self) -> &SpecifiedType {
&self.sub_command.spec.0
}
#[cfg_attr(
feature = "lt2016_1",
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, or `job`."
)]
#[cfg_attr(
all(feature = "lt2018_1", not(feature = "lt2016_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `branch`,",
doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
doc = "`protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
all(feature = "lt2022_2", not(feature = "lt2018_1")),
doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
doc = "specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
#[cfg_attr(
not(feature = "lt2022_2"),
doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
)]
pub fn set_specified_type(&mut self, specified_type: SpecifiedType) -> &mut Self {
self.sub_command.spec = spec::Selected(specified_type);
self
}
}
pub mod set_password {
#[derive(Debug, Clone, Copy, Default)]
pub struct All;
#[derive(Debug, Clone)]
pub struct User(pub String);
}
impl ExclusiveOption for set_password::All {
fn inject_args(&self, command: &mut Command) {
command.arg("-a");
}
}
impl ExclusiveOption for set_password::User {
fn inject_args(&self, command: &mut Command) {
command.arg("-u").arg(&self.0);
}
}
#[cfg_attr(
feature = "lt2025_2",
doc = "`p4 admin resetpassword -a | -u user`: force users to reset their passwords."
)]
#[cfg_attr(
not(feature = "lt2025_2"),
doc = "`p4 admin resetpassword {-a | -u user} [-l]`: force users to reset their passwords."
)]
#[derive(Debug, Clone, Default)]
pub struct ResetPassword<T = Unselected> {
set_password: T,
#[cfg(not(feature = "lt2025_2"))]
super_user: bool,
}
impl<T: ExclusiveOption> SubCommand for ResetPassword<T> {
fn name(&self) -> &str {
"resetpassword"
}
fn inject_local_args(&self, command: &mut Command) {
self.set_password.inject_args(command);
#[cfg(not(feature = "lt2025_2"))]
if self.super_user {
command.arg("-l");
}
}
}
impl Admin<ResetPassword<Unselected>> {
#[cfg_attr(
feature = "lt2023_1",
doc = "Force password reset of all users with passwords, including the",
doc = "superuser who issued the command. Only the passwords of users who",
doc = "presently exist (and who have passwords) are reset."
)]
#[cfg_attr(not(feature = "lt2023_1"), doc = "All users.")]
pub fn all(self) -> Admin<ResetPassword<set_password::All>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: ResetPassword {
set_password: set_password::All,
#[cfg(not(feature = "lt2025_2"))]
super_user: self.sub_command.super_user,
},
}
}
#[cfg_attr(
feature = "lt2023_1",
doc = "Force a single user with an existing password to reset their password",
doc = "before they can run another command."
)]
#[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
pub fn user(self, user: impl Into<String>) -> Admin<ResetPassword<set_password::User>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: ResetPassword {
set_password: set_password::User(user.into()),
#[cfg(not(feature = "lt2025_2"))]
super_user: self.sub_command.super_user,
},
}
}
}
impl Admin<ResetPassword<set_password::User>> {
#[cfg_attr(
feature = "lt2023_1",
doc = "Force a single user with an existing password to reset their password",
doc = "before they can run another command."
)]
#[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
pub fn get_user(&self) -> &str {
&self.sub_command.set_password.0
}
#[cfg_attr(
feature = "lt2023_1",
doc = "Force a single user with an existing password to reset their password",
doc = "before they can run another command."
)]
#[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
pub fn set_user(&mut self, user: impl Into<String>) -> &mut Self {
self.sub_command.set_password.0 = user.into();
self
}
}
impl<T: ExclusiveOption> Admin<ResetPassword<T>> {
#[cfg(not(feature = "lt2025_2"))]
pub fn get_super_user(&self) -> bool {
self.sub_command.super_user
}
#[cfg(not(feature = "lt2025_2"))]
pub fn set_super_user(&mut self, super_user: bool) -> &mut Self {
self.sub_command.super_user = super_user;
self
}
#[cfg(not(feature = "lt2025_2"))]
pub fn super_user(mut self, super_user: bool) -> Self {
self.sub_command.super_user = super_user;
self
}
}
#[cfg(not(feature = "lt2015_1"))]
#[derive(Debug, Clone, Default)]
pub struct SetLdapUsers;
#[cfg(not(feature = "lt2015_1"))]
impl SubCommand for SetLdapUsers {
fn name(&self) -> &str {
"setldapusers"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[cfg(not(feature = "lt2018_1"))]
#[derive(Debug, Clone, Default)]
pub struct EndJournal;
#[cfg(not(feature = "lt2018_1"))]
impl SubCommand for EndJournal {
fn name(&self) -> &str {
"end-journal"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[cfg(not(feature = "lt2023_1"))]
#[derive(Debug, Clone, Default)]
pub struct SysInfo;
#[cfg(not(feature = "lt2023_1"))]
impl SubCommand for SysInfo {
fn name(&self) -> &str {
"sysinfo"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[cfg(not(feature = "lt2023_1"))]
#[derive(Debug, Clone, Default)]
pub struct ResourceMonitor;
#[cfg(not(feature = "lt2023_1"))]
impl SubCommand for ResourceMonitor {
fn name(&self) -> &str {
"resource-monitor"
}
fn inject_local_args(&self, _: &mut Command) {}
}
#[cfg(not(feature = "lt2025_2"))]
pub mod reconcile {
#[derive(Debug, Clone, Copy, Default)]
pub struct RestrictOnly;
#[derive(Debug, Clone, Copy, Default)]
pub struct ExpandOnly;
}
#[cfg(not(feature = "lt2025_2"))]
impl ExclusiveOption for reconcile::RestrictOnly {
fn inject_args(&self, command: &mut Command) {
command.arg("--restrict-only");
}
}
#[cfg(not(feature = "lt2025_2"))]
impl ExclusiveOption for reconcile::ExpandOnly {
fn inject_args(&self, command: &mut Command) {
command.arg("--expand-only");
}
}
#[cfg(not(feature = "lt2025_2"))]
#[derive(Debug, Clone, Default)]
pub struct ReplicaFilterReconcile<M = Unselected> {
reconcile: M,
}
#[cfg(not(feature = "lt2025_2"))]
impl<M: ExclusiveOption> SubCommand for ReplicaFilterReconcile<M> {
fn name(&self) -> &str {
"replica-filter-reconcile"
}
fn inject_local_args(&self, command: &mut Command) {
self.reconcile.inject_args(command);
}
}
#[cfg(not(feature = "lt2025_2"))]
impl Admin<ReplicaFilterReconcile<Unselected>> {
pub fn restrict_only(self) -> Admin<ReplicaFilterReconcile<reconcile::RestrictOnly>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: ReplicaFilterReconcile {
reconcile: reconcile::RestrictOnly,
},
}
}
pub fn expand_only(self) -> Admin<ReplicaFilterReconcile<reconcile::ExpandOnly>> {
Admin {
bin: self.bin,
global_opts: self.global_opts,
sub_command: ReplicaFilterReconcile {
reconcile: reconcile::ExpandOnly,
},
}
}
}
#[cfg(not(feature = "lt2025_2"))]
impl<M: ExclusiveOption> ParameterizedSpawn for Admin<ReplicaFilterReconcile<M>> {
type Input<'a> = &'a [&'a OsStr];
type Output<'a> = Child;
type Error = std::io::Error;
fn spawn_with<'a>(&mut self, tables: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
self.setup_command(&self.bin)
.args(tables)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cmd::args_of;
#[test]
fn stop() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).stop();
assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "stop"]);
}
#[test]
fn restart() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).restart();
assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "restart"]);
}
#[cfg(not(feature = "lt2015_1"))]
#[test]
fn setldapusers() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).setldapusers();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "setldapusers"]
);
}
#[cfg(not(feature = "lt2018_1"))]
#[test]
fn end_journal() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).end_journal();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "end-journal"]
);
}
#[cfg(not(feature = "lt2023_1"))]
#[test]
fn sysinfo() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).sysinfo();
assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "sysinfo"]);
}
#[cfg(not(feature = "lt2023_1"))]
#[test]
fn resource_monitor() {
let admin = AdminEntry::new("p4", GlobalOpts::new()).resource_monitor();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "resource-monitor"]
);
}
#[test]
fn checkpoint_compress_both() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.checkpoint()
.compress_both();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "checkpoint", "-z"]
);
}
#[test]
fn checkpoint_compress_checkpoint_only() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.checkpoint()
.compress_checkpoint_only();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "checkpoint", "-Z"]
);
}
#[test]
fn checkpoint_with_prefix() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.checkpoint()
.compress_both();
let mut command = admin.setup_command("p4");
command.arg("ckp");
assert_eq!(args_of(&command), ["admin", "checkpoint", "-z", "ckp"]);
}
#[cfg(not(feature = "lt2023_1"))]
#[test]
fn checkpoint_parallel_options() {
let mut admin = AdminEntry::new("p4", GlobalOpts::new()).checkpoint();
admin
.set_parallel(true)
.set_threads(4)
.set_multiple_files(true);
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "checkpoint", "-p", "-N", "4", "-m"]
);
}
#[test]
fn journal_gzip() {
let mut admin = AdminEntry::new("p4", GlobalOpts::new()).journal();
admin.set_gzip(true);
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "journal", "-z"]
);
}
#[test]
fn updatespecdepot_all() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.updatespecdepot()
.all();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "updatespecdepot", "-a"]
);
}
#[test]
fn updatespecdepot_specified_type() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.updatespecdepot()
.specified_type(SpecifiedType::Client);
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "updatespecdepot", "-s", "client"]
);
}
#[test]
fn resetpassword_all() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.resetpassword()
.all();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "resetpassword", "-a"]
);
}
#[test]
fn resetpassword_single_user() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.resetpassword()
.user("bruno");
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "resetpassword", "-u", "bruno"]
);
}
#[cfg(not(feature = "lt2025_2"))]
#[test]
fn resetpassword_super_user() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.resetpassword()
.super_user(true);
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "resetpassword", "-l"]
);
}
#[cfg(not(feature = "lt2025_2"))]
#[test]
fn replica_filter_reconcile_restrict_only() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.replica_filter_reconcile()
.restrict_only();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "replica-filter-reconcile", "--restrict-only"]
);
}
#[cfg(not(feature = "lt2025_2"))]
#[test]
fn replica_filter_reconcile_expand_only() {
let admin = AdminEntry::new("p4", GlobalOpts::new())
.replica_filter_reconcile()
.expand_only();
assert_eq!(
args_of(&admin.setup_command("p4")),
["admin", "replica-filter-reconcile", "--expand-only"]
);
}
#[test]
fn global_opts_are_injected_once() {
let global_opts = GlobalOpts::new().port("localhost:1666");
let admin = AdminEntry::new("p4", global_opts).checkpoint();
assert_eq!(
args_of(&admin.setup_command("p4")),
["-p", "localhost:1666", "admin", "checkpoint"]
);
}
}