1use std::ffi::OsStr;
2
3use std::path::{Path, PathBuf};
4use std::process::{Child, Command, Stdio};
5
6use super::{ExclusiveOption, SubCommand, Unselected};
7
8use crate::global::GlobalOpts;
9use crate::spawn::ParameterizedSpawn;
10
11#[cfg_attr(
20 not(feature = "lt2015_1"),
21 doc = " [`setldapusers`](Self::setldapusers),"
22)]
23#[cfg_attr(
24 not(feature = "lt2018_1"),
25 doc = " [`end_journal`](Self::end_journal),"
26)]
27#[cfg_attr(
28 not(feature = "lt2023_1"),
29 doc = " [`sysinfo`](Self::sysinfo), [`resource_monitor`](Self::resource_monitor),"
30)]
31#[cfg_attr(
32 not(feature = "lt2025_2"),
33 doc = " [`replica_filter_reconcile`](Self::replica_filter_reconcile),"
34)]
35#[derive(Debug, Clone, Default)]
37pub struct AdminEntry {
38 bin: PathBuf,
39
40 global_opts: GlobalOpts,
41}
42
43impl AdminEntry {
44 pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
48 Self {
49 bin: bin.into(),
50 global_opts,
51 }
52 }
53
54 pub fn get_bin(&self) -> &Path {
56 &self.bin
57 }
58
59 pub fn set_bin(&mut self, bin: impl Into<PathBuf>) -> &mut Self {
61 self.bin = bin.into();
62 self
63 }
64
65 pub fn bin(mut self, bin: impl Into<PathBuf>) -> Self {
67 self.set_bin(bin);
68 self
69 }
70
71 pub fn checkpoint(self) -> Admin<CheckPoint<Unselected>> {
77 Admin::new(self.bin, self.global_opts, CheckPoint::default())
78 }
79
80 pub fn journal(self) -> Admin<Journal> {
85 Admin::new(self.bin, self.global_opts, Journal::default())
86 }
87
88 pub fn stop(self) -> Admin<Stop> {
93 Admin::new(self.bin, self.global_opts, Stop)
94 }
95
96 pub fn restart(self) -> Admin<Restart> {
101 Admin::new(self.bin, self.global_opts, Restart)
102 }
103
104 pub fn updatespecdepot(self) -> Admin<UpdateSpecDepot<Unselected>> {
111 Admin::new(self.bin, self.global_opts, UpdateSpecDepot::default())
112 }
113
114 pub fn resetpassword(self) -> Admin<ResetPassword<Unselected>> {
119 Admin::new(self.bin, self.global_opts, ResetPassword::default())
120 }
121
122 #[cfg(not(feature = "lt2015_1"))]
129 pub fn setldapusers(self) -> Admin<SetLdapUsers> {
130 Admin::new(self.bin, self.global_opts, SetLdapUsers)
131 }
132
133 #[cfg(not(feature = "lt2018_1"))]
140 pub fn end_journal(self) -> Admin<EndJournal> {
141 Admin::new(self.bin, self.global_opts, EndJournal)
142 }
143
144 #[cfg_attr(
150 all(not(feature = "lt2023_1"), feature = "lt2024_2"),
151 doc = "Helix Core Server."
152 )]
153 #[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
154 #[cfg(not(feature = "lt2023_1"))]
155 pub fn sysinfo(self) -> Admin<SysInfo> {
156 Admin::new(self.bin, self.global_opts, SysInfo)
157 }
158
159 #[cfg_attr(
164 all(not(feature = "lt2023_1"), feature = "lt2024_1"),
165 doc = "Helix Core Server",
166 doc = "Administrator Guide."
167 )]
168 #[cfg_attr(
169 all(not(feature = "lt2024_1"), feature = "lt2024_2"),
170 doc = "the Helix Core Server Administrator Guide."
171 )]
172 #[cfg_attr(
173 not(feature = "lt2024_2"),
174 doc = "P4 Server",
175 doc = "Administration Documentation."
176 )]
177 #[cfg(not(feature = "lt2023_1"))]
178 pub fn resource_monitor(self) -> Admin<ResourceMonitor> {
179 Admin::new(self.bin, self.global_opts, ResourceMonitor)
180 }
181
182 #[cfg(not(feature = "lt2025_2"))]
189 pub fn replica_filter_reconcile(self) -> Admin<ReplicaFilterReconcile<Unselected>> {
190 Admin::new(
191 self.bin,
192 self.global_opts,
193 ReplicaFilterReconcile::default(),
194 )
195 }
196}
197
198#[derive(Debug, Clone, Default)]
200pub struct Admin<T: SubCommand> {
201 bin: PathBuf,
202
203 global_opts: GlobalOpts,
204
205 sub_command: T,
206}
207
208impl<T: SubCommand> SubCommand for Admin<T> {
209 fn name(&self) -> &str {
210 "admin"
211 }
212
213 fn inject_local_args(&self, command: &mut Command) {
214 self.sub_command.inject_args(command);
215 }
216
217 fn global_opts(&self) -> Option<&GlobalOpts> {
218 Some(&self.global_opts)
219 }
220}
221
222impl<T: SubCommand> Admin<T> {
229 fn spawn_piped(&mut self) -> Result<Child, std::io::Error> {
233 self.setup_command(&self.bin)
234 .stdout(Stdio::piped())
235 .stderr(Stdio::piped())
236 .spawn()
237 }
238}
239
240impl ParameterizedSpawn<()> for Admin<Stop> {
241 type Output = Child;
242 type Error = std::io::Error;
243
244 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
248 self.spawn_piped()
249 }
250}
251
252impl ParameterizedSpawn<()> for Admin<Restart> {
253 type Output = Child;
254 type Error = std::io::Error;
255
256 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
260 self.spawn_piped()
261 }
262}
263
264impl<S: ExclusiveOption> ParameterizedSpawn<()> for Admin<UpdateSpecDepot<S>> {
265 type Output = Child;
266 type Error = std::io::Error;
267
268 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
272 self.spawn_piped()
273 }
274}
275
276impl<T: ExclusiveOption> ParameterizedSpawn<()> for Admin<ResetPassword<T>> {
277 type Output = Child;
278 type Error = std::io::Error;
279
280 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
284 self.spawn_piped()
285 }
286}
287
288#[cfg(not(feature = "lt2015_1"))]
289impl ParameterizedSpawn<()> for Admin<SetLdapUsers> {
290 type Output = Child;
291 type Error = std::io::Error;
292
293 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
297 self.spawn_piped()
298 }
299}
300
301#[cfg(not(feature = "lt2018_1"))]
302impl ParameterizedSpawn<()> for Admin<EndJournal> {
303 type Output = Child;
304 type Error = std::io::Error;
305
306 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
310 self.spawn_piped()
311 }
312}
313
314#[cfg(not(feature = "lt2023_1"))]
315impl ParameterizedSpawn<()> for Admin<SysInfo> {
316 type Output = Child;
317 type Error = std::io::Error;
318
319 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
323 self.spawn_piped()
324 }
325}
326
327#[cfg(not(feature = "lt2023_1"))]
328impl ParameterizedSpawn<()> for Admin<ResourceMonitor> {
329 type Output = Child;
330 type Error = std::io::Error;
331
332 fn spawn_with(&mut self, (): ()) -> Result<Self::Output, Self::Error> {
336 self.spawn_piped()
337 }
338}
339
340impl<T: SubCommand> Admin<T> {
341 pub fn get_bin(&self) -> &Path {
343 &self.bin
344 }
345
346 pub fn set_bin(&mut self, bin: impl Into<PathBuf>) -> &mut Self {
348 self.bin = bin.into();
349 self
350 }
351
352 pub fn bin(mut self, bin: impl Into<PathBuf>) -> Self {
354 self.set_bin(bin);
355 self
356 }
357
358 pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts, sub_command: T) -> Self {
362 Self {
363 bin: bin.into(),
364 global_opts,
365 sub_command,
366 }
367 }
368
369 #[cfg_attr(
374 feature = "lt2014_2",
375 doc = "See the [Global Options](GlobalOpts) section."
376 )]
377 #[cfg_attr(
378 all(feature = "lt2015_1", not(feature = "lt2014_2")),
379 doc = "See the [“Global Options”](GlobalOpts) section."
380 )]
381 #[cfg_attr(
382 all(feature = "lt2017_1", not(feature = "lt2015_1")),
383 doc = "See [“Global Options”](GlobalOpts)."
384 )]
385 #[cfg_attr(
386 all(feature = "lt2018_2", not(feature = "lt2017_1")),
387 doc = "See [Global Options](GlobalOpts)."
388 )]
389 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
390 pub fn get_global_opts(&self) -> &GlobalOpts {
391 &self.global_opts
392 }
393
394 #[cfg_attr(
399 feature = "lt2014_2",
400 doc = "See the [Global Options](GlobalOpts) section."
401 )]
402 #[cfg_attr(
403 all(feature = "lt2015_1", not(feature = "lt2014_2")),
404 doc = "See the [“Global Options”](GlobalOpts) section."
405 )]
406 #[cfg_attr(
407 all(feature = "lt2017_1", not(feature = "lt2015_1")),
408 doc = "See [“Global Options”](GlobalOpts)."
409 )]
410 #[cfg_attr(
411 all(feature = "lt2018_2", not(feature = "lt2017_1")),
412 doc = "See [Global Options](GlobalOpts)."
413 )]
414 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
415 pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
416 self.global_opts = v;
417 self
418 }
419
420 #[cfg_attr(
425 feature = "lt2014_2",
426 doc = "See the [Global Options](GlobalOpts) section."
427 )]
428 #[cfg_attr(
429 all(feature = "lt2015_1", not(feature = "lt2014_2")),
430 doc = "See the [“Global Options”](GlobalOpts) section."
431 )]
432 #[cfg_attr(
433 all(feature = "lt2017_1", not(feature = "lt2015_1")),
434 doc = "See [“Global Options”](GlobalOpts)."
435 )]
436 #[cfg_attr(
437 all(feature = "lt2018_2", not(feature = "lt2017_1")),
438 doc = "See [Global Options](GlobalOpts)."
439 )]
440 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
441 pub fn global_opts(mut self, v: GlobalOpts) -> Self {
442 self.global_opts = v;
443 self
444 }
445}
446
447pub mod compression {
448 #[derive(Debug, Clone, Copy, Default)]
450 pub struct Both;
451
452 #[derive(Debug, Clone, Copy, Default)]
455 pub struct CheckPointOnly;
456}
457
458impl ExclusiveOption for compression::Both {
459 fn inject_args(&self, command: &mut Command) {
460 command.arg("-z");
461 }
462}
463
464impl ExclusiveOption for compression::CheckPointOnly {
465 fn inject_args(&self, command: &mut Command) {
466 command.arg("-Z");
467 }
468}
469
470#[cfg_attr(
471 feature = "lt2022_2",
472 doc = "`p4 admin checkpoint [-z | -Z] [prefix]`: take a checkpoint."
473)]
474#[cfg_attr(
475 all(feature = "lt2023_1", not(feature = "lt2022_2")),
476 doc = "`p4 admin checkpoint [[-z | -Z]] [prefix]`: take a checkpoint."
477)]
478#[cfg_attr(
479 not(feature = "lt2023_1"),
480 doc = "`p4 admin checkpoint [-z | -Z] [-p [-N threads] [-m]] [prefix]`: take a checkpoint."
481)]
482#[derive(Debug, Clone, Default)]
485pub struct CheckPoint<C = Unselected> {
486 compression: C,
487
488 #[cfg(not(feature = "lt2023_1"))]
490 parallel: bool,
491
492 #[cfg(not(feature = "lt2023_1"))]
494 threads: Option<u32>,
495
496 #[cfg(not(feature = "lt2023_1"))]
498 multiple_files: bool,
499}
500
501impl<C: ExclusiveOption> SubCommand for CheckPoint<C> {
502 fn name(&self) -> &str {
503 "checkpoint"
504 }
505
506 fn inject_local_args(&self, command: &mut Command) {
507 self.compression.inject_args(command);
508
509 #[cfg(not(feature = "lt2023_1"))]
510 {
511 if self.parallel {
512 command.arg("-p");
513 }
514 if let Some(threads) = self.threads {
515 command.arg("-N").arg(threads.to_string());
516 }
517 if self.multiple_files {
518 command.arg("-m");
519 }
520 }
521 }
522}
523
524impl<C: ExclusiveOption, I> ParameterizedSpawn<(I,)> for Admin<CheckPoint<C>>
525where
526 I: AsRef<OsStr>,
527{
528 type Output = Child;
529 type Error = std::io::Error;
530
531 fn spawn_with(&mut self, (prefix,): (I,)) -> Result<Self::Output, Self::Error> {
538 self.setup_command(&self.bin)
539 .arg(prefix)
540 .stdout(Stdio::piped())
541 .stderr(Stdio::piped())
542 .spawn()
543 }
544}
545
546impl<C: ExclusiveOption> ParameterizedSpawn<()> for Admin<CheckPoint<C>> {
547 type Output = Child;
548 type Error = std::io::Error;
549
550 fn spawn_with(&mut self, _: ()) -> Result<Self::Output, Self::Error> {
557 self.setup_command(&self.bin)
558 .stdout(Stdio::piped())
559 .stderr(Stdio::piped())
560 .spawn()
561 }
562}
563
564impl<C: ExclusiveOption> Admin<CheckPoint<C>> {
565 #[cfg(not(feature = "lt2023_1"))]
571 pub fn get_parallel(&self) -> bool {
572 self.sub_command.parallel
573 }
574
575 #[cfg(not(feature = "lt2023_1"))]
581 pub fn set_parallel(&mut self, parallel: bool) -> &mut Self {
582 self.sub_command.parallel = parallel;
583 self
584 }
585
586 #[cfg(not(feature = "lt2023_1"))]
592 pub fn parallel(mut self, parallel: bool) -> Self {
593 self.sub_command.parallel = parallel;
594 self
595 }
596
597 #[cfg(not(feature = "lt2023_1"))]
603 pub fn get_threads(&self) -> Option<&u32> {
604 self.sub_command.threads.as_ref()
605 }
606
607 #[cfg(not(feature = "lt2023_1"))]
613 pub fn set_threads(&mut self, threads: u32) -> &mut Self {
614 self.sub_command.threads = Some(threads);
615 self
616 }
617
618 #[cfg(not(feature = "lt2023_1"))]
624 pub fn threads(mut self, threads: u32) -> Self {
625 self.sub_command.threads = Some(threads);
626 self
627 }
628
629 #[cfg_attr(
637 all(not(feature = "lt2023_1"), feature = "lt2024_1"),
638 doc = "in Helix Core",
639 doc = "Server Administrator Guide. See also checkpoint examples."
640 )]
641 #[cfg_attr(
642 all(not(feature = "lt2024_1"), feature = "lt2024_2"),
643 doc = "in the Helix",
644 doc = "Core Server Administrator Guide. See also checkpoint examples."
645 )]
646 #[cfg_attr(
647 all(not(feature = "lt2024_2"), feature = "lt2025_1"),
648 doc = "in the P4",
649 doc = "Server Administration Documentation. See also checkpoint examples."
650 )]
651 #[cfg_attr(
652 not(feature = "lt2025_1"),
653 doc = "in the P4",
654 doc = "Server Administration Documentation. See also Checkpoint examples."
655 )]
656 #[cfg(not(feature = "lt2023_1"))]
657 pub fn get_multiple_files(&self) -> bool {
658 self.sub_command.multiple_files
659 }
660
661 #[cfg_attr(
669 all(not(feature = "lt2023_1"), feature = "lt2024_1"),
670 doc = "in Helix Core",
671 doc = "Server Administrator Guide. See also checkpoint examples."
672 )]
673 #[cfg_attr(
674 all(not(feature = "lt2024_1"), feature = "lt2024_2"),
675 doc = "in the Helix",
676 doc = "Core Server Administrator Guide. See also checkpoint examples."
677 )]
678 #[cfg_attr(
679 all(not(feature = "lt2024_2"), feature = "lt2025_1"),
680 doc = "in the P4",
681 doc = "Server Administration Documentation. See also checkpoint examples."
682 )]
683 #[cfg_attr(
684 not(feature = "lt2025_1"),
685 doc = "in the P4",
686 doc = "Server Administration Documentation. See also Checkpoint examples."
687 )]
688 #[cfg(not(feature = "lt2023_1"))]
689 pub fn set_multiple_files(&mut self, multiple_files: bool) -> &mut Self {
690 self.sub_command.multiple_files = multiple_files;
691 self
692 }
693
694 #[cfg_attr(
702 all(not(feature = "lt2023_1"), feature = "lt2024_1"),
703 doc = "in Helix Core",
704 doc = "Server Administrator Guide. See also checkpoint examples."
705 )]
706 #[cfg_attr(
707 all(not(feature = "lt2024_1"), feature = "lt2024_2"),
708 doc = "in the Helix",
709 doc = "Core Server Administrator Guide. See also checkpoint examples."
710 )]
711 #[cfg_attr(
712 all(not(feature = "lt2024_2"), feature = "lt2025_1"),
713 doc = "in the P4",
714 doc = "Server Administration Documentation. See also checkpoint examples."
715 )]
716 #[cfg_attr(
717 not(feature = "lt2025_1"),
718 doc = "in the P4",
719 doc = "Server Administration Documentation. See also Checkpoint examples."
720 )]
721 #[cfg(not(feature = "lt2023_1"))]
722 pub fn multiple_files(mut self, multiple_files: bool) -> Self {
723 self.sub_command.multiple_files = multiple_files;
724 self
725 }
726}
727
728impl Admin<CheckPoint<Unselected>> {
729 #[cfg_attr(
734 feature = "lt2022_2",
735 doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
736 doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
737 doc = "suffix to the files."
738 )]
739 #[cfg_attr(
740 all(feature = "lt2023_1", not(feature = "lt2022_2")),
741 doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
742 doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
743 doc = "appended to compressed journals and checkpoint files, which are in",
744 doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
745 )]
746 #[cfg_attr(
747 not(feature = "lt2023_1"),
748 doc = "Save the checkpoint and journal file in compressed format. The `.gz`",
749 doc = "suffix is appended to compressed journals and checkpoint files, which",
750 doc = "are in gzip format. If you do not specify `-z` or `-Z`, no compression",
751 doc = "occurs."
752 )]
753 pub fn compress_both(self) -> Admin<CheckPoint<compression::Both>> {
754 Admin {
755 bin: self.bin,
756 global_opts: self.global_opts,
757 sub_command: CheckPoint::<compression::Both> {
758 compression: compression::Both,
759 #[cfg(not(feature = "lt2023_1"))]
760 parallel: self.sub_command.parallel,
761 #[cfg(not(feature = "lt2023_1"))]
762 threads: self.sub_command.threads,
763 #[cfg(not(feature = "lt2023_1"))]
764 multiple_files: self.sub_command.multiple_files,
765 },
766 }
767 }
768
769 #[cfg_attr(
774 feature = "lt2017_2",
775 doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
776 doc = "in compressed (gzip) format, appending the `.gz` suffix to the file, but",
777 doc = "leave the journal uncompressed for use by replica servers."
778 )]
779 #[cfg_attr(
780 all(feature = "lt2022_2", not(feature = "lt2017_2")),
781 doc = "For `p4 admin checkpoint`, save the checkpoint in compressed (gzip)",
782 doc = "format, appending the `.gz` suffix to the file, but leave the journal",
783 doc = "uncompressed for use by replica servers."
784 )]
785 #[cfg_attr(
786 all(feature = "lt2023_1", not(feature = "lt2022_2")),
787 doc = "For `p4 admin checkpoint -Z`, save the checkpoint in compressed format,",
788 doc = "but leave the journal uncompressed for use by replica servers."
789 )]
790 #[cfg_attr(
791 not(feature = "lt2023_1"),
792 doc = "For `p4 admin checkpoint -Z`, save the checkpoint in compressed format,",
793 doc = "but leave the journal uncompressed for use by replica servers. The",
794 doc = "`.gz` suffix is appended to compressed journals and checkpoint files,",
795 doc = "which are in gzip format. If you do not specify `-z` or `-Z`, no",
796 doc = "compression occurs."
797 )]
798 pub fn compress_checkpoint_only(self) -> Admin<CheckPoint<compression::CheckPointOnly>> {
799 Admin {
800 bin: self.bin,
801 global_opts: self.global_opts,
802 sub_command: CheckPoint::<compression::CheckPointOnly> {
803 compression: compression::CheckPointOnly,
804 #[cfg(not(feature = "lt2023_1"))]
805 parallel: self.sub_command.parallel,
806 #[cfg(not(feature = "lt2023_1"))]
807 threads: self.sub_command.threads,
808 #[cfg(not(feature = "lt2023_1"))]
809 multiple_files: self.sub_command.multiple_files,
810 },
811 }
812 }
813}
814
815#[derive(Debug, Clone, Default)]
817pub struct Journal {
818 gzip: bool,
819}
820
821impl SubCommand for Journal {
822 fn name(&self) -> &str {
823 "journal"
824 }
825
826 fn inject_local_args(&self, command: &mut Command) {
827 if self.gzip {
828 command.arg("-z");
829 }
830 }
831}
832
833impl<I> ParameterizedSpawn<(I,)> for Admin<Journal>
834where
835 I: AsRef<OsStr>,
836{
837 type Output = Child;
838 type Error = std::io::Error;
839
840 fn spawn_with(&mut self, (prefix,): (I,)) -> Result<Self::Output, Self::Error> {
847 self.setup_command(&self.bin)
848 .arg(prefix)
849 .stdout(Stdio::piped())
850 .stderr(Stdio::piped())
851 .spawn()
852 }
853}
854
855impl ParameterizedSpawn<()> for Admin<Journal> {
856 type Output = Child;
857 type Error = std::io::Error;
858
859 fn spawn_with(&mut self, _: ()) -> Result<Self::Output, Self::Error> {
864 self.setup_command(&self.bin)
865 .stdout(Stdio::piped())
866 .stderr(Stdio::piped())
867 .spawn()
868 }
869}
870
871impl Admin<Journal> {
872 #[cfg_attr(
877 feature = "lt2022_2",
878 doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
879 doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
880 doc = "suffix to the files."
881 )]
882 #[cfg_attr(
883 all(feature = "lt2023_1", not(feature = "lt2022_2")),
884 doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
885 doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
886 doc = "appended to compressed journals and checkpoint files, which are in",
887 doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
888 )]
889 #[cfg_attr(
890 not(feature = "lt2023_1"),
891 doc = "Save the journal file in compressed format. The `.gz` suffix is",
892 doc = "appended to compressed journals and checkpoint files, which are in",
893 doc = "gzip format. If you do not specify `-z`, no compression occurs."
894 )]
895 pub fn get_gzip(&self) -> bool {
896 self.sub_command.gzip
897 }
898
899 #[cfg_attr(
904 feature = "lt2022_2",
905 doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
906 doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
907 doc = "suffix to the files."
908 )]
909 #[cfg_attr(
910 all(feature = "lt2023_1", not(feature = "lt2022_2")),
911 doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
912 doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
913 doc = "appended to compressed journals and checkpoint files, which are in",
914 doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
915 )]
916 #[cfg_attr(
917 not(feature = "lt2023_1"),
918 doc = "Save the journal file in compressed format. The `.gz` suffix is",
919 doc = "appended to compressed journals and checkpoint files, which are in",
920 doc = "gzip format. If you do not specify `-z`, no compression occurs."
921 )]
922 pub fn set_gzip(&mut self, gzip: bool) -> &mut Self {
923 self.sub_command.gzip = gzip;
924 self
925 }
926
927 #[cfg_attr(
932 feature = "lt2022_2",
933 doc = "For `p4 admin checkpoint` and `p4 admin journal`, save the checkpoint",
934 doc = "and saved journal file in compressed (gzip) format, appending the `.gz`",
935 doc = "suffix to the files."
936 )]
937 #[cfg_attr(
938 all(feature = "lt2023_1", not(feature = "lt2022_2")),
939 doc = "For `p4 admin checkpoint -z` and `p4 admin journal -z`, save the",
940 doc = "checkpoint and journal file in compressed format. The `.gz` suffix is",
941 doc = "appended to compressed journals and checkpoint files, which are in",
942 doc = "gzip format. If you do not specify `-z` or `-Z`, no compression occurs."
943 )]
944 #[cfg_attr(
945 not(feature = "lt2023_1"),
946 doc = "Save the journal file in compressed format. The `.gz` suffix is",
947 doc = "appended to compressed journals and checkpoint files, which are in",
948 doc = "gzip format. If you do not specify `-z`, no compression occurs."
949 )]
950 pub fn gzip(mut self, gzip: bool) -> Self {
951 self.sub_command.gzip = gzip;
952 self
953 }
954}
955
956#[derive(Debug, Clone, Default)]
958pub struct Stop;
959
960impl SubCommand for Stop {
961 fn name(&self) -> &str {
962 "stop"
963 }
964
965 fn inject_local_args(&self, _: &mut Command) {}
966}
967
968#[derive(Debug, Clone, Default)]
970pub struct Restart;
971
972impl SubCommand for Restart {
973 fn name(&self) -> &str {
974 "restart"
975 }
976
977 fn inject_local_args(&self, _: &mut Command) {}
978}
979
980#[derive(Debug, Clone)]
982pub enum SpecifiedType {
983 Client,
984 Depot,
985 #[cfg(not(feature = "lt2018_1"))]
987 Repo,
988 Branch,
989 Label,
990 TypeMap,
991 Group,
992 User,
993 Job,
994 #[cfg(not(feature = "lt2016_1"))]
996 Stream,
997 #[cfg(not(feature = "lt2016_1"))]
999 Triggers,
1000 #[cfg(not(feature = "lt2016_1"))]
1002 Protect,
1003 #[cfg(not(feature = "lt2016_1"))]
1005 Server,
1006 #[cfg(not(feature = "lt2016_1"))]
1008 License,
1009 #[cfg(not(feature = "lt2016_1"))]
1011 JobSpec,
1012}
1013
1014impl SpecifiedType {
1015 pub(crate) fn to_str(&self) -> &str {
1017 match self {
1018 Self::Client => "client",
1019 Self::Depot => "depot",
1020 #[cfg(not(feature = "lt2018_1"))]
1021 Self::Repo => "repo",
1022 Self::Branch => "branch",
1023 Self::Label => "label",
1024 Self::TypeMap => "typemap",
1025 Self::Group => "group",
1026 Self::User => "user",
1027 Self::Job => "job",
1028 #[cfg(not(feature = "lt2016_1"))]
1029 Self::Stream => "stream",
1030 #[cfg(not(feature = "lt2016_1"))]
1031 Self::Triggers => "triggers",
1032 #[cfg(not(feature = "lt2016_1"))]
1033 Self::Protect => "protect",
1034 #[cfg(not(feature = "lt2016_1"))]
1035 Self::Server => "server",
1036 #[cfg(not(feature = "lt2016_1"))]
1037 Self::License => "license",
1038 #[cfg(not(feature = "lt2016_1"))]
1039 Self::JobSpec => "jobspec",
1040 }
1041 }
1042}
1043
1044pub mod spec {
1047 use super::SpecifiedType;
1048
1049 #[derive(Debug, Clone, Copy, Default)]
1051 pub struct All;
1052
1053 #[derive(Debug, Clone)]
1055 pub struct Selected(pub SpecifiedType);
1056}
1057
1058impl ExclusiveOption for spec::All {
1059 fn inject_args(&self, command: &mut Command) {
1060 command.arg("-a");
1061 }
1062}
1063
1064impl ExclusiveOption for spec::Selected {
1065 fn inject_args(&self, command: &mut Command) {
1066 command.arg("-s").arg(self.0.to_str());
1067 }
1068}
1069
1070#[derive(Debug, Clone, Default)]
1076pub struct UpdateSpecDepot<S = Unselected> {
1077 spec: S,
1078}
1079
1080impl<S: ExclusiveOption> SubCommand for UpdateSpecDepot<S> {
1081 fn name(&self) -> &str {
1082 "updatespecdepot"
1083 }
1084
1085 fn inject_local_args(&self, command: &mut Command) {
1086 self.spec.inject_args(command);
1087 }
1088}
1089
1090impl Admin<UpdateSpecDepot<Unselected>> {
1091 #[cfg_attr(
1096 feature = "lt2022_2",
1097 doc = "For `p4 admin updatespecdepot`, update the spec depot with all current",
1098 doc = "forms."
1099 )]
1100 #[cfg_attr(
1101 not(feature = "lt2022_2"),
1102 doc = "For `p4 admin updatespecdepot -a`, update the spec depot with all",
1103 doc = "current forms."
1104 )]
1105 pub fn all(self) -> Admin<UpdateSpecDepot<spec::All>> {
1106 Admin {
1107 bin: self.bin,
1108 global_opts: self.global_opts,
1109 sub_command: UpdateSpecDepot { spec: spec::All },
1110 }
1111 }
1112
1113 #[cfg_attr(
1118 feature = "lt2016_1",
1119 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1120 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1121 doc = "`label`, `typemap`, `group`, `user`, or `job`."
1122 )]
1123 #[cfg_attr(
1124 all(feature = "lt2018_1", not(feature = "lt2016_1")),
1125 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1126 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1127 doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
1128 doc = "`protect`, `server`, `license`, or `jobspec`."
1129 )]
1130 #[cfg_attr(
1131 all(feature = "lt2022_2", not(feature = "lt2018_1")),
1132 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1133 doc = "specified type, where type is one of `client`, `depot`, `repo`,",
1134 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1135 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1136 )]
1137 #[cfg_attr(
1138 not(feature = "lt2022_2"),
1139 doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
1140 doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
1141 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1142 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1143 )]
1144 pub fn specified_type(
1145 self,
1146 specified_type: SpecifiedType,
1147 ) -> Admin<UpdateSpecDepot<spec::Selected>> {
1148 Admin {
1149 bin: self.bin,
1150 global_opts: self.global_opts,
1151 sub_command: UpdateSpecDepot {
1152 spec: spec::Selected(specified_type),
1153 },
1154 }
1155 }
1156}
1157
1158impl Admin<UpdateSpecDepot<spec::Selected>> {
1159 #[cfg_attr(
1164 feature = "lt2016_1",
1165 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1166 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1167 doc = "`label`, `typemap`, `group`, `user`, or `job`."
1168 )]
1169 #[cfg_attr(
1170 all(feature = "lt2018_1", not(feature = "lt2016_1")),
1171 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1172 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1173 doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
1174 doc = "`protect`, `server`, `license`, or `jobspec`."
1175 )]
1176 #[cfg_attr(
1177 all(feature = "lt2022_2", not(feature = "lt2018_1")),
1178 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1179 doc = "specified type, where type is one of `client`, `depot`, `repo`,",
1180 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1181 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1182 )]
1183 #[cfg_attr(
1184 not(feature = "lt2022_2"),
1185 doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
1186 doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
1187 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1188 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1189 )]
1190 pub fn get_specified_type(&self) -> &SpecifiedType {
1191 &self.sub_command.spec.0
1192 }
1193
1194 #[cfg_attr(
1199 feature = "lt2016_1",
1200 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1201 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1202 doc = "`label`, `typemap`, `group`, `user`, or `job`."
1203 )]
1204 #[cfg_attr(
1205 all(feature = "lt2018_1", not(feature = "lt2016_1")),
1206 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1207 doc = "specified type, where type is one of `client`, `depot`, `branch`,",
1208 doc = "`label`, `typemap`, `group`, `user`, `job`, `stream`, `triggers`,",
1209 doc = "`protect`, `server`, `license`, or `jobspec`."
1210 )]
1211 #[cfg_attr(
1212 all(feature = "lt2022_2", not(feature = "lt2018_1")),
1213 doc = "For `p4 admin updatespecdepot`, update the spec depot with forms of the",
1214 doc = "specified type, where type is one of `client`, `depot`, `repo`,",
1215 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1216 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1217 )]
1218 #[cfg_attr(
1219 not(feature = "lt2022_2"),
1220 doc = "For `p4 admin updatespecdepot -s`, update the spec depot with forms of",
1221 doc = "the specified type, where type is one of `client`, `depot`, `repo`,",
1222 doc = "`branch`, `label`, `typemap`, `group`, `user`, `job`, `stream`,",
1223 doc = "`triggers`, `protect`, `server`, `license`, or `jobspec`."
1224 )]
1225 pub fn set_specified_type(&mut self, specified_type: SpecifiedType) -> &mut Self {
1226 self.sub_command.spec = spec::Selected(specified_type);
1227 self
1228 }
1229}
1230
1231pub mod set_password {
1234 #[derive(Debug, Clone, Copy, Default)]
1236 pub struct All;
1237
1238 #[derive(Debug, Clone)]
1240 pub struct User(pub String);
1241}
1242
1243impl ExclusiveOption for set_password::All {
1244 fn inject_args(&self, command: &mut Command) {
1245 command.arg("-a");
1246 }
1247}
1248
1249impl ExclusiveOption for set_password::User {
1250 fn inject_args(&self, command: &mut Command) {
1251 command.arg("-u").arg(&self.0);
1252 }
1253}
1254
1255#[cfg_attr(
1261 feature = "lt2025_2",
1262 doc = "`p4 admin resetpassword -a | -u user`: force users to reset their passwords."
1263)]
1264#[cfg_attr(
1265 not(feature = "lt2025_2"),
1266 doc = "`p4 admin resetpassword {-a | -u user} [-l]`: force users to reset their passwords."
1267)]
1268#[derive(Debug, Clone, Default)]
1269pub struct ResetPassword<T = Unselected> {
1270 set_password: T,
1271
1272 #[cfg(not(feature = "lt2025_2"))]
1274 super_user: bool,
1275}
1276
1277impl<T: ExclusiveOption> SubCommand for ResetPassword<T> {
1278 fn name(&self) -> &str {
1279 "resetpassword"
1280 }
1281
1282 fn inject_local_args(&self, command: &mut Command) {
1283 self.set_password.inject_args(command);
1284 #[cfg(not(feature = "lt2025_2"))]
1285 if self.super_user {
1286 command.arg("-l");
1287 }
1288 }
1289}
1290
1291impl Admin<ResetPassword<Unselected>> {
1292 #[cfg_attr(
1297 feature = "lt2023_1",
1298 doc = "Force password reset of all users with passwords, including the",
1299 doc = "superuser who issued the command. Only the passwords of users who",
1300 doc = "presently exist (and who have passwords) are reset."
1301 )]
1302 #[cfg_attr(not(feature = "lt2023_1"), doc = "All users.")]
1303 pub fn all(self) -> Admin<ResetPassword<set_password::All>> {
1304 Admin {
1305 bin: self.bin,
1306 global_opts: self.global_opts,
1307 sub_command: ResetPassword {
1308 set_password: set_password::All,
1309 #[cfg(not(feature = "lt2025_2"))]
1310 super_user: self.sub_command.super_user,
1311 },
1312 }
1313 }
1314
1315 #[cfg_attr(
1320 feature = "lt2023_1",
1321 doc = "Force a single user with an existing password to reset their password",
1322 doc = "before they can run another command."
1323 )]
1324 #[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
1325 pub fn user(self, user: impl Into<String>) -> Admin<ResetPassword<set_password::User>> {
1326 Admin {
1327 bin: self.bin,
1328 global_opts: self.global_opts,
1329 sub_command: ResetPassword {
1330 set_password: set_password::User(user.into()),
1331 #[cfg(not(feature = "lt2025_2"))]
1332 super_user: self.sub_command.super_user,
1333 },
1334 }
1335 }
1336}
1337
1338impl Admin<ResetPassword<set_password::User>> {
1339 #[cfg_attr(
1344 feature = "lt2023_1",
1345 doc = "Force a single user with an existing password to reset their password",
1346 doc = "before they can run another command."
1347 )]
1348 #[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
1349 pub fn get_user(&self) -> &str {
1350 &self.sub_command.set_password.0
1351 }
1352
1353 #[cfg_attr(
1358 feature = "lt2023_1",
1359 doc = "Force a single user with an existing password to reset their password",
1360 doc = "before they can run another command."
1361 )]
1362 #[cfg_attr(not(feature = "lt2023_1"), doc = "The specified user.")]
1363 pub fn set_user(&mut self, user: impl Into<String>) -> &mut Self {
1364 self.sub_command.set_password.0 = user.into();
1365 self
1366 }
1367}
1368
1369impl<T: ExclusiveOption> Admin<ResetPassword<T>> {
1370 #[cfg(not(feature = "lt2025_2"))]
1376 pub fn get_super_user(&self) -> bool {
1377 self.sub_command.super_user
1378 }
1379
1380 #[cfg(not(feature = "lt2025_2"))]
1386 pub fn set_super_user(&mut self, super_user: bool) -> &mut Self {
1387 self.sub_command.super_user = super_user;
1388 self
1389 }
1390
1391 #[cfg(not(feature = "lt2025_2"))]
1397 pub fn super_user(mut self, super_user: bool) -> Self {
1398 self.sub_command.super_user = super_user;
1399 self
1400 }
1401}
1402
1403#[cfg(not(feature = "lt2015_1"))]
1406#[derive(Debug, Clone, Default)]
1407pub struct SetLdapUsers;
1408
1409#[cfg(not(feature = "lt2015_1"))]
1410impl SubCommand for SetLdapUsers {
1411 fn name(&self) -> &str {
1412 "setldapusers"
1413 }
1414
1415 fn inject_local_args(&self, _: &mut Command) {}
1416}
1417
1418#[cfg(not(feature = "lt2018_1"))]
1421#[derive(Debug, Clone, Default)]
1422pub struct EndJournal;
1423
1424#[cfg(not(feature = "lt2018_1"))]
1425impl SubCommand for EndJournal {
1426 fn name(&self) -> &str {
1427 "end-journal"
1428 }
1429
1430 fn inject_local_args(&self, _: &mut Command) {}
1431}
1432
1433#[cfg(not(feature = "lt2023_1"))]
1436#[derive(Debug, Clone, Default)]
1437pub struct SysInfo;
1438
1439#[cfg(not(feature = "lt2023_1"))]
1440impl SubCommand for SysInfo {
1441 fn name(&self) -> &str {
1442 "sysinfo"
1443 }
1444
1445 fn inject_local_args(&self, _: &mut Command) {}
1446}
1447
1448#[cfg(not(feature = "lt2023_1"))]
1451#[derive(Debug, Clone, Default)]
1452pub struct ResourceMonitor;
1453
1454#[cfg(not(feature = "lt2023_1"))]
1455impl SubCommand for ResourceMonitor {
1456 fn name(&self) -> &str {
1457 "resource-monitor"
1458 }
1459
1460 fn inject_local_args(&self, _: &mut Command) {}
1461}
1462
1463#[cfg(not(feature = "lt2025_2"))]
1466pub mod reconcile {
1467 #[derive(Debug, Clone, Copy, Default)]
1469 pub struct RestrictOnly;
1470
1471 #[derive(Debug, Clone, Copy, Default)]
1473 pub struct ExpandOnly;
1474}
1475
1476#[cfg(not(feature = "lt2025_2"))]
1477impl ExclusiveOption for reconcile::RestrictOnly {
1478 fn inject_args(&self, command: &mut Command) {
1479 command.arg("--restrict-only");
1480 }
1481}
1482
1483#[cfg(not(feature = "lt2025_2"))]
1484impl ExclusiveOption for reconcile::ExpandOnly {
1485 fn inject_args(&self, command: &mut Command) {
1486 command.arg("--expand-only");
1487 }
1488}
1489
1490#[cfg(not(feature = "lt2025_2"))]
1498#[derive(Debug, Clone, Default)]
1499pub struct ReplicaFilterReconcile<M = Unselected> {
1500 reconcile: M,
1501}
1502
1503#[cfg(not(feature = "lt2025_2"))]
1504impl<M: ExclusiveOption> SubCommand for ReplicaFilterReconcile<M> {
1505 fn name(&self) -> &str {
1506 "replica-filter-reconcile"
1507 }
1508
1509 fn inject_local_args(&self, command: &mut Command) {
1510 self.reconcile.inject_args(command);
1511 }
1512}
1513
1514#[cfg(not(feature = "lt2025_2"))]
1515impl Admin<ReplicaFilterReconcile<Unselected>> {
1516 pub fn restrict_only(self) -> Admin<ReplicaFilterReconcile<reconcile::RestrictOnly>> {
1523 Admin {
1524 bin: self.bin,
1525 global_opts: self.global_opts,
1526 sub_command: ReplicaFilterReconcile {
1527 reconcile: reconcile::RestrictOnly,
1528 },
1529 }
1530 }
1531
1532 pub fn expand_only(self) -> Admin<ReplicaFilterReconcile<reconcile::ExpandOnly>> {
1539 Admin {
1540 bin: self.bin,
1541 global_opts: self.global_opts,
1542 sub_command: ReplicaFilterReconcile {
1543 reconcile: reconcile::ExpandOnly,
1544 },
1545 }
1546 }
1547}
1548
1549#[cfg(not(feature = "lt2025_2"))]
1550impl<M: ExclusiveOption, S, I> ParameterizedSpawn<(S,)> for Admin<ReplicaFilterReconcile<M>>
1551where
1552 S: IntoIterator<Item = I>,
1553 I: AsRef<OsStr>,
1554{
1555 type Output = Child;
1556 type Error = std::io::Error;
1557
1558 fn spawn_with(&mut self, (tables,): (S,)) -> Result<Self::Output, Self::Error> {
1564 self.setup_command(&self.bin)
1565 .args(tables)
1566 .stdout(Stdio::piped())
1567 .stderr(Stdio::piped())
1568 .spawn()
1569 }
1570}
1571
1572#[cfg(test)]
1573mod tests {
1574 use super::*;
1575 use crate::cmd::args_of;
1576
1577 #[test]
1578 fn bin_accessors_update_executable_path() {
1579 let mut entry = AdminEntry::new("p4", GlobalOpts::new());
1580 assert_eq!(entry.get_bin(), Path::new("p4"));
1581
1582 entry.set_bin("/usr/local/bin/p4");
1583 assert_eq!(entry.get_bin(), Path::new("/usr/local/bin/p4"));
1584
1585 let command = entry.bin("p4.exe").stop();
1587 assert_eq!(command.get_bin(), Path::new("p4.exe"));
1588 }
1589
1590 #[test]
1593 fn stop() {
1594 let admin = AdminEntry::new("p4", GlobalOpts::new()).stop();
1595
1596 assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "stop"]);
1597 }
1598
1599 #[test]
1600 fn restart() {
1601 let admin = AdminEntry::new("p4", GlobalOpts::new()).restart();
1602
1603 assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "restart"]);
1604 }
1605
1606 #[cfg(not(feature = "lt2015_1"))]
1607 #[test]
1608 fn setldapusers() {
1609 let admin = AdminEntry::new("p4", GlobalOpts::new()).setldapusers();
1610
1611 assert_eq!(
1612 args_of(&admin.setup_command("p4")),
1613 ["admin", "setldapusers"]
1614 );
1615 }
1616
1617 #[cfg(not(feature = "lt2018_1"))]
1618 #[test]
1619 fn end_journal() {
1620 let admin = AdminEntry::new("p4", GlobalOpts::new()).end_journal();
1621
1622 assert_eq!(
1623 args_of(&admin.setup_command("p4")),
1624 ["admin", "end-journal"]
1625 );
1626 }
1627
1628 #[cfg(not(feature = "lt2023_1"))]
1629 #[test]
1630 fn sysinfo() {
1631 let admin = AdminEntry::new("p4", GlobalOpts::new()).sysinfo();
1632
1633 assert_eq!(args_of(&admin.setup_command("p4")), ["admin", "sysinfo"]);
1634 }
1635
1636 #[cfg(not(feature = "lt2023_1"))]
1637 #[test]
1638 fn resource_monitor() {
1639 let admin = AdminEntry::new("p4", GlobalOpts::new()).resource_monitor();
1640
1641 assert_eq!(
1642 args_of(&admin.setup_command("p4")),
1643 ["admin", "resource-monitor"]
1644 );
1645 }
1646
1647 #[test]
1648 fn checkpoint_compress_both() {
1649 let admin = AdminEntry::new("p4", GlobalOpts::new())
1650 .checkpoint()
1651 .compress_both();
1652
1653 assert_eq!(
1654 args_of(&admin.setup_command("p4")),
1655 ["admin", "checkpoint", "-z"]
1656 );
1657 }
1658
1659 #[test]
1660 fn checkpoint_compress_checkpoint_only() {
1661 let admin = AdminEntry::new("p4", GlobalOpts::new())
1662 .checkpoint()
1663 .compress_checkpoint_only();
1664
1665 assert_eq!(
1666 args_of(&admin.setup_command("p4")),
1667 ["admin", "checkpoint", "-Z"]
1668 );
1669 }
1670
1671 #[test]
1672 fn checkpoint_with_prefix() {
1673 let admin = AdminEntry::new("p4", GlobalOpts::new())
1674 .checkpoint()
1675 .compress_both();
1676
1677 let mut command = admin.setup_command("p4");
1680 command.arg("ckp");
1681
1682 assert_eq!(args_of(&command), ["admin", "checkpoint", "-z", "ckp"]);
1683 }
1684
1685 #[cfg(not(feature = "lt2023_1"))]
1686 #[test]
1687 fn checkpoint_parallel_options() {
1688 let mut admin = AdminEntry::new("p4", GlobalOpts::new()).checkpoint();
1689 admin
1690 .set_parallel(true)
1691 .set_threads(4)
1692 .set_multiple_files(true);
1693
1694 assert_eq!(
1695 args_of(&admin.setup_command("p4")),
1696 ["admin", "checkpoint", "-p", "-N", "4", "-m"]
1697 );
1698 }
1699
1700 #[test]
1701 fn journal_gzip() {
1702 let mut admin = AdminEntry::new("p4", GlobalOpts::new()).journal();
1703 admin.set_gzip(true);
1704
1705 assert_eq!(
1706 args_of(&admin.setup_command("p4")),
1707 ["admin", "journal", "-z"]
1708 );
1709 }
1710
1711 #[test]
1712 fn updatespecdepot_all() {
1713 let admin = AdminEntry::new("p4", GlobalOpts::new())
1714 .updatespecdepot()
1715 .all();
1716
1717 assert_eq!(
1718 args_of(&admin.setup_command("p4")),
1719 ["admin", "updatespecdepot", "-a"]
1720 );
1721 }
1722
1723 #[test]
1726 fn updatespecdepot_specified_type() {
1727 let admin = AdminEntry::new("p4", GlobalOpts::new())
1728 .updatespecdepot()
1729 .specified_type(SpecifiedType::Client);
1730
1731 assert_eq!(
1732 args_of(&admin.setup_command("p4")),
1733 ["admin", "updatespecdepot", "-s", "client"]
1734 );
1735 }
1736
1737 #[test]
1738 fn resetpassword_all() {
1739 let admin = AdminEntry::new("p4", GlobalOpts::new())
1740 .resetpassword()
1741 .all();
1742
1743 assert_eq!(
1744 args_of(&admin.setup_command("p4")),
1745 ["admin", "resetpassword", "-a"]
1746 );
1747 }
1748
1749 #[test]
1750 fn resetpassword_single_user() {
1751 let admin = AdminEntry::new("p4", GlobalOpts::new())
1752 .resetpassword()
1753 .user("bruno");
1754
1755 assert_eq!(
1756 args_of(&admin.setup_command("p4")),
1757 ["admin", "resetpassword", "-u", "bruno"]
1758 );
1759 }
1760
1761 #[cfg(not(feature = "lt2025_2"))]
1762 #[test]
1763 fn resetpassword_super_user() {
1764 let admin = AdminEntry::new("p4", GlobalOpts::new())
1765 .resetpassword()
1766 .super_user(true);
1767
1768 assert_eq!(
1769 args_of(&admin.setup_command("p4")),
1770 ["admin", "resetpassword", "-l"]
1771 );
1772 }
1773
1774 #[cfg(not(feature = "lt2025_2"))]
1775 #[test]
1776 fn replica_filter_reconcile_restrict_only() {
1777 let admin = AdminEntry::new("p4", GlobalOpts::new())
1778 .replica_filter_reconcile()
1779 .restrict_only();
1780
1781 assert_eq!(
1782 args_of(&admin.setup_command("p4")),
1783 ["admin", "replica-filter-reconcile", "--restrict-only"]
1784 );
1785 }
1786
1787 #[cfg(not(feature = "lt2025_2"))]
1788 #[test]
1789 fn replica_filter_reconcile_expand_only() {
1790 let admin = AdminEntry::new("p4", GlobalOpts::new())
1791 .replica_filter_reconcile()
1792 .expand_only();
1793
1794 assert_eq!(
1795 args_of(&admin.setup_command("p4")),
1796 ["admin", "replica-filter-reconcile", "--expand-only"]
1797 );
1798 }
1799
1800 #[test]
1801 fn global_opts_are_injected_once() {
1802 let global_opts = GlobalOpts::new().port("localhost:1666");
1803 let admin = AdminEntry::new("p4", global_opts).checkpoint();
1804
1805 assert_eq!(
1808 args_of(&admin.setup_command("p4")),
1809 ["-p", "localhost:1666", "admin", "checkpoint"]
1810 );
1811 }
1812}