1use std::{
2 ffi::OsStr,
3 path::{Path, PathBuf},
4 process::{Child, Command, Stdio},
5};
6
7use super::{ExclusiveOption, SubCommand, Unselected};
8
9use crate::global::GlobalOpts;
10use crate::spawn::ParameterizedSpawn;
11
12#[derive(Debug, Clone, Default)]
18pub struct StandardPrintMode {
19 all_revisions: bool,
20
21 from_archive_depots: bool,
22
23 suppress_keyword_expansion: bool,
24
25 #[cfg(not(feature = "lt2023_1"))]
26 line_ending: Option<LineEnding>,
27
28 #[cfg(not(feature = "lt2023_1"))]
29 charset: Option<String>,
30
31 #[cfg(not(feature = "lt2023_1"))]
32 utf8bom: Option<Utf8Bom>,
33
34 limit: Option<u64>,
35
36 #[cfg(not(feature = "lt2022_1"))]
37 offset: Option<u64>,
38
39 #[cfg(not(feature = "lt2022_1"))]
40 size: Option<u64>,
41
42 redirect_output: Option<PathBuf>,
43
44 quiet_mode: bool,
45
46 #[cfg(not(feature = "lt2026_1"))]
47 ignore_changeview: bool,
48}
49
50impl ExclusiveOption for StandardPrintMode {
51 fn inject_args(&self, command: &mut Command) {
52 if self.all_revisions {
53 command.arg("-a");
54 }
55
56 if self.from_archive_depots {
57 command.arg("-A");
58 }
59
60 if self.suppress_keyword_expansion {
61 #[cfg(feature = "lt2022_1")]
62 {
63 command.arg("-k");
64 }
65 #[cfg(not(feature = "lt2022_1"))]
66 {
67 command.arg("-K");
68 }
69 }
70
71 if let Some(output) = &self.redirect_output {
72 command.arg("-o").arg(output);
73 }
74
75 if self.quiet_mode {
76 command.arg("-q");
77 }
78
79 if let Some(max) = self.limit {
80 command.arg("-m").arg(max.to_string());
81 }
82
83 #[cfg(not(feature = "lt2022_1"))]
84 {
85 if let Some(offset) = self.offset {
86 command.arg("--offset").arg(offset.to_string());
87 }
88
89 if let Some(size) = self.size {
90 command.arg("--size").arg(size.to_string());
91 }
92 }
93
94 #[cfg(not(feature = "lt2023_1"))]
95 {
96 if let Some(charset) = &self.charset {
97 command.arg("-Q").arg(charset);
98 }
99
100 if let Some(utf8bom) = &self.utf8bom {
101 command.arg("-B").arg(utf8bom.as_str());
102 }
103
104 if let Some(line_ending) = &self.line_ending {
105 command.arg("-L").arg(line_ending.as_str());
106 }
107 }
108
109 #[cfg(not(feature = "lt2026_1"))]
110 {
111 if self.ignore_changeview {
112 command.arg("--ignore-changeview");
113 }
114 }
115 }
116}
117
118#[derive(Debug, Clone, Copy, Default)]
124pub struct UnloadDepotMode;
125
126impl ExclusiveOption for UnloadDepotMode {
127 fn inject_args(&self, command: &mut Command) {
128 command.arg("-U");
129 }
130}
131
132#[cfg(not(feature = "lt2024_2"))]
138#[derive(Debug, Clone, Default)]
139pub struct AttributeTraitMode {
140 all_revisions: bool,
141
142 redirect_output: Option<PathBuf>,
143
144 quiet_mode: bool,
145
146 attribute: String,
147
148 #[cfg(not(feature = "lt2026_1"))]
149 ignore_changeview: bool,
150}
151
152#[cfg(not(feature = "lt2024_2"))]
153impl ExclusiveOption for AttributeTraitMode {
154 fn inject_args(&self, command: &mut Command) {
155 command.arg("-T").arg(&self.attribute);
156
157 if self.all_revisions {
158 command.arg("-a");
159 }
160
161 if let Some(output) = &self.redirect_output {
162 command.arg("-o").arg(output);
163 }
164
165 if self.quiet_mode {
166 command.arg("-q");
167 }
168
169 #[cfg(not(feature = "lt2026_1"))]
170 {
171 if self.ignore_changeview {
172 command.arg("--ignore-changeview");
173 }
174 }
175 }
176}
177
178#[cfg(not(feature = "lt2023_1"))]
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum Utf8Bom {
183 No,
185 Yes,
187 WindowsOnly,
189}
190
191#[cfg(not(feature = "lt2023_1"))]
192impl Utf8Bom {
193 pub fn as_str(&self) -> &'static str {
195 match self {
196 Utf8Bom::No => "0",
197 Utf8Bom::Yes => "1",
198 Utf8Bom::WindowsOnly => "2",
199 }
200 }
201}
202
203#[cfg(not(feature = "lt2023_1"))]
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
206pub enum LineEnding {
207 Unix,
209 Win,
211 Mac,
213}
214
215#[cfg(not(feature = "lt2023_1"))]
216impl LineEnding {
217 pub fn as_str(&self) -> &'static str {
219 match self {
220 LineEnding::Unix => "unix",
221 LineEnding::Win => "win",
222 LineEnding::Mac => "mac",
223 }
224 }
225}
226
227#[cfg_attr(
228 feature = "lt2015_1",
229 doc = "`p4 [g-opts] print [-a -A -k -o outfile -q -m max -U] file[revRange] ...`"
230)]
231#[cfg_attr(
232 all(feature = "lt2016_1", not(feature = "lt2015_1")),
233 doc = "`p4 [g-opts] print [-a -A -k -q] [-m max] [-o outfile] file[revRange] …`",
234 doc = "",
235 doc = "`p4 [g-opts] print -U unloadfile …`"
236)]
237#[cfg_attr(
238 all(feature = "lt2018_1", not(feature = "lt2016_1")),
239 doc = "`p4 [g-opts] print [-a -A -k -q] [-m max] [-o outfile] file[revRange] ...`",
240 doc = "",
241 doc = "`p4 [g-opts] print -U unloadfile ...`"
242)]
243#[cfg_attr(
244 all(feature = "lt2022_1", not(feature = "lt2018_1")),
245 doc = "`p4 [g-opts] print [-a -A -k -q] [-m max] [-o outfile] FileSpec[revSpec]`",
246 doc = "",
247 doc = "`p4 [g-opts] print -U unload[FileSpec]`"
248)]
249#[cfg_attr(
250 all(feature = "lt2023_1", not(feature = "lt2022_1")),
251 doc = "`p4 [g-opts] print [-a -A -K -q] [-m max] --offset bytesToSkip --size bytesToPrint [-o outfile] FileSpec[revSpec]`",
252 doc = "",
253 doc = "`p4 [g-opts] print -U unload[FileSpec]`"
254)]
255#[cfg_attr(
256 all(feature = "lt2024_2", not(feature = "lt2023_1")),
257 doc = "`p4 print [-a -A -K -o localFile -q -m max --offset offset --size size -Q charset -B utf8bom -L line-ending] file[revRange] ...`",
258 doc = "",
259 doc = "`p4 print -U unloadfile ...`"
260)]
261#[cfg_attr(
262 all(feature = "lt2026_1", not(feature = "lt2024_2")),
263 doc = "`p4 print [-a -A -K -o localFile -q -m max --offset offset --size size -Q charset -B utf8bom -L line-ending] file[revRange] ...`",
264 doc = "",
265 doc = "`p4 print -U unloadfile ...`",
266 doc = "",
267 doc = "`p4 print -T attribute [-a -q -o localFile] file ...`"
268)]
269#[cfg_attr(
270 not(feature = "lt2026_1"),
271 doc = "`p4 print [-a -A -K -o localFile -q -m max --offset offset --size size -Q charset -B utf8bom -L line-ending] [--ignore-changeview] file[revRange] ...`",
272 doc = "",
273 doc = "`p4 print -U unloadfile ...`",
274 doc = "",
275 doc = "`p4 print -T attribute [-a -q -o localFile] [--ignore-changeview] file ...`"
276)]
277#[cfg_attr(
281 feature = "lt2024_2",
282 doc = "The `M` type parameter tracks which of the two forms of the command is in use at compile time. The default [`Unselected`] state prints files without local options; setting any standard option such as [`Self::all_revisions`] transitions to [`StandardPrintMode`], and [`Self::from_unload_depot`] transitions to [`UnloadDepotMode`]."
283)]
284#[cfg_attr(
285 not(feature = "lt2024_2"),
286 doc = "The `M` type parameter tracks which of the three forms of the command is in use at compile time. The default [`Unselected`] state prints files without local options; setting any standard option such as [`Self::all_revisions`] transitions to [`StandardPrintMode`], [`Self::from_unload_depot`] transitions to [`UnloadDepotMode`], and [`Self::extract_attribute`] transitions to [`AttributeTraitMode`]."
287)]
288#[derive(Debug, Clone, Default)]
289pub struct Print<M = Unselected> {
290 bin: PathBuf,
291
292 global_opts: GlobalOpts,
293
294 mode: M,
295}
296
297impl Print<Unselected> {
298 pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
302 Self {
303 bin: bin.into(),
304 global_opts,
305 mode: Unselected,
306 }
307 }
308
309 pub fn from_unload_depot(self) -> Print<UnloadDepotMode> {
319 Print {
320 bin: self.bin,
321 global_opts: self.global_opts,
322 mode: UnloadDepotMode,
323 }
324 }
325
326 #[cfg(not(feature = "lt2024_2"))]
340 pub fn extract_attribute(self, name: impl Into<String>) -> Print<AttributeTraitMode> {
341 Print {
342 bin: self.bin,
343 global_opts: self.global_opts,
344 mode: AttributeTraitMode {
345 all_revisions: false,
346 redirect_output: None,
347 quiet_mode: false,
348 attribute: name.into(),
349 #[cfg(not(feature = "lt2026_1"))]
350 ignore_changeview: false,
351 },
352 }
353 }
354
355 pub fn all_revisions(self, v: bool) -> Print<StandardPrintMode> {
364 Print {
365 bin: self.bin,
366 global_opts: self.global_opts,
367 mode: StandardPrintMode {
368 all_revisions: v,
369 ..StandardPrintMode::default()
370 },
371 }
372 }
373
374 #[cfg_attr(
379 feature = "lt2023_1",
380 doc = "Attempt to print a file stored in an archive depot."
381 )]
382 #[cfg_attr(not(feature = "lt2023_1"), doc = "Print files in archive depots.")]
383 pub fn archive_depots(self, v: bool) -> Print<StandardPrintMode> {
386 Print {
387 bin: self.bin,
388 global_opts: self.global_opts,
389 mode: StandardPrintMode {
390 from_archive_depots: v,
391 ..StandardPrintMode::default()
392 },
393 }
394 }
395
396 #[cfg_attr(feature = "lt2022_1", doc = "-k")]
399 #[cfg_attr(not(feature = "lt2022_1"), doc = "-K")]
400 #[cfg_attr(feature = "lt2023_1", doc = "Suppress RCS keyword expansion.")]
402 #[cfg_attr(
403 not(feature = "lt2023_1"),
404 doc = "Suppress RCS keyword expansion. This replaced the `-k` flag in",
405 doc = "2022.1, which is now an alias for `-K` for backwards compatibility."
406 )]
407 pub fn suppress_keyword_expansion(self, v: bool) -> Print<StandardPrintMode> {
410 Print {
411 bin: self.bin,
412 global_opts: self.global_opts,
413 mode: StandardPrintMode {
414 suppress_keyword_expansion: v,
415 ..StandardPrintMode::default()
416 },
417 }
418 }
419
420 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
423 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
424 #[cfg_attr(
426 feature = "lt2018_2",
427 doc = "Redirect output to the specified output file on the local disk,",
428 doc = "preserving the same file type, attributes, and/or permission bits",
429 doc = "as the original file in the depot."
430 )]
431 #[cfg_attr(
432 all(feature = "lt2023_1", not(feature = "lt2018_2")),
433 doc = "Redirect output to the specified output file (`outfile`) on the",
434 doc = "local disk. This preserves the same file type, attributes, and/or",
435 doc = "permission bits as the original file (`FileSpec`) in the depot.",
436 doc = "Multiple files can be written by using wildcards in the",
437 doc = "`localFile` argument that match wildcards in the depot",
438 doc = "(`FileSpec`) argument. For example: To print the contents of a",
439 doc = "directory and directories under that directory, use the `...`",
440 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
441 doc = "print all files that match readme.txt or readme.pdf, you might",
442 doc = "specify `p4 print -o readme.* //depot/readme.*`"
443 )]
444 #[cfg_attr(
445 not(feature = "lt2023_1"),
446 doc = "Redirect output to the specified output file (`localfile`) on the",
447 doc = "local disk. This preserves the same file type, attributes, and/or",
448 doc = "permission bits as the original file (`FileSpec`) in the depot.",
449 doc = "Multiple files can be written by using wildcards in the",
450 doc = "`localFile` argument that match wildcards in the depot",
451 doc = "(`FileSpec`) argument. For example: To print the contents of a",
452 doc = "directory and directories under that directory, use the `...`",
453 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
454 doc = "print all files that match readme.txt or readme.pdf, you might",
455 doc = "specify `p4 print -o readme.* //depot/readme.*`"
456 )]
457 pub fn redirect_output(self, v: impl Into<PathBuf>) -> Print<StandardPrintMode> {
460 Print {
461 bin: self.bin,
462 global_opts: self.global_opts,
463 mode: StandardPrintMode {
464 redirect_output: Some(v.into()),
465 ..StandardPrintMode::default()
466 },
467 }
468 }
469
470 #[cfg_attr(feature = "lt2018_1", doc = "Perforce.")]
476 #[cfg_attr(
477 all(feature = "lt2019_1", not(feature = "lt2018_1")),
478 doc = "Helix Server."
479 )]
480 #[cfg_attr(
481 all(feature = "lt2021_1", not(feature = "lt2019_1")),
482 doc = "Helix server."
483 )]
484 #[cfg_attr(
485 all(feature = "lt2024_1", not(feature = "lt2021_1")),
486 doc = "Helix Server."
487 )]
488 #[cfg_attr(
489 all(feature = "lt2024_2", not(feature = "lt2024_1")),
490 doc = "Helix Core Server."
491 )]
492 #[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
493 pub fn quiet_mode(self, v: bool) -> Print<StandardPrintMode> {
496 Print {
497 bin: self.bin,
498 global_opts: self.global_opts,
499 mode: StandardPrintMode {
500 quiet_mode: v,
501 ..StandardPrintMode::default()
502 },
503 }
504 }
505
506 pub fn limit(self, v: u64) -> Print<StandardPrintMode> {
514 Print {
515 bin: self.bin,
516 global_opts: self.global_opts,
517 mode: StandardPrintMode {
518 limit: Some(v),
519 ..StandardPrintMode::default()
520 },
521 }
522 }
523
524 #[cfg(not(feature = "lt2022_1"))]
533 pub fn offset(self, v: u64) -> Print<StandardPrintMode> {
534 Print {
535 bin: self.bin,
536 global_opts: self.global_opts,
537 mode: StandardPrintMode {
538 offset: Some(v),
539 ..StandardPrintMode::default()
540 },
541 }
542 }
543
544 #[cfg(not(feature = "lt2022_1"))]
554 pub fn size(self, v: u64) -> Print<StandardPrintMode> {
555 Print {
556 bin: self.bin,
557 global_opts: self.global_opts,
558 mode: StandardPrintMode {
559 size: Some(v),
560 ..StandardPrintMode::default()
561 },
562 }
563 }
564
565 #[cfg(not(feature = "lt2023_1"))]
575 pub fn charset(self, v: impl Into<String>) -> Print<StandardPrintMode> {
576 Print {
577 bin: self.bin,
578 global_opts: self.global_opts,
579 mode: StandardPrintMode {
580 charset: Some(v.into()),
581 ..StandardPrintMode::default()
582 },
583 }
584 }
585
586 #[cfg(not(feature = "lt2023_1"))]
597 pub fn write_utf8bom(self, v: bool) -> Print<StandardPrintMode> {
598 Print {
599 bin: self.bin,
600 global_opts: self.global_opts,
601 mode: StandardPrintMode {
602 utf8bom: Some(if v { Utf8Bom::Yes } else { Utf8Bom::No }),
603 ..StandardPrintMode::default()
604 },
605 }
606 }
607
608 #[cfg(not(feature = "lt2023_1"))]
617 pub fn write_utf8bom_windows_only(self) -> Print<StandardPrintMode> {
618 Print {
619 bin: self.bin,
620 global_opts: self.global_opts,
621 mode: StandardPrintMode {
622 utf8bom: Some(Utf8Bom::WindowsOnly),
623 ..StandardPrintMode::default()
624 },
625 }
626 }
627
628 #[cfg(not(feature = "lt2023_1"))]
637 pub fn line_ending_unix(self) -> Print<StandardPrintMode> {
638 Print {
639 bin: self.bin,
640 global_opts: self.global_opts,
641 mode: StandardPrintMode {
642 line_ending: Some(LineEnding::Unix),
643 ..StandardPrintMode::default()
644 },
645 }
646 }
647
648 #[cfg(not(feature = "lt2023_1"))]
657 pub fn line_ending_win(self) -> Print<StandardPrintMode> {
658 Print {
659 bin: self.bin,
660 global_opts: self.global_opts,
661 mode: StandardPrintMode {
662 line_ending: Some(LineEnding::Win),
663 ..StandardPrintMode::default()
664 },
665 }
666 }
667
668 #[cfg(not(feature = "lt2023_1"))]
677 pub fn line_ending_mac(self) -> Print<StandardPrintMode> {
678 Print {
679 bin: self.bin,
680 global_opts: self.global_opts,
681 mode: StandardPrintMode {
682 line_ending: Some(LineEnding::Mac),
683 ..StandardPrintMode::default()
684 },
685 }
686 }
687
688 #[cfg(not(feature = "lt2026_1"))]
697 pub fn ignore_changeview(self, v: bool) -> Print<StandardPrintMode> {
698 Print {
699 bin: self.bin,
700 global_opts: self.global_opts,
701 mode: StandardPrintMode {
702 ignore_changeview: v,
703 ..StandardPrintMode::default()
704 },
705 }
706 }
707}
708
709impl<M: ExclusiveOption, S, I> ParameterizedSpawn<(S,)> for Print<M>
710where
711 S: IntoIterator<Item = I>,
712 I: AsRef<OsStr>,
713{
714 type Output = Child;
715 type Error = std::io::Error;
716
717 fn spawn_with(&mut self, (files,): (S,)) -> Result<Self::Output, Self::Error> {
721 self.setup_command(&self.bin)
722 .args(files)
723 .stdout(Stdio::piped())
724 .stderr(Stdio::piped())
725 .spawn()
726 }
727}
728
729impl<M: ExclusiveOption> Print<M> {
730 pub fn get_bin(&self) -> &Path {
732 &self.bin
733 }
734
735 pub fn set_bin(&mut self, bin: impl Into<PathBuf>) -> &mut Self {
737 self.bin = bin.into();
738 self
739 }
740
741 pub fn bin(mut self, bin: impl Into<PathBuf>) -> Self {
743 self.set_bin(bin);
744 self
745 }
746
747 #[cfg_attr(
752 feature = "lt2014_2",
753 doc = "See the [Global Options](GlobalOpts) section."
754 )]
755 #[cfg_attr(
756 all(feature = "lt2015_1", not(feature = "lt2014_2")),
757 doc = "See the [“Global Options”](GlobalOpts) section."
758 )]
759 #[cfg_attr(
760 all(feature = "lt2017_1", not(feature = "lt2015_1")),
761 doc = "See [“Global Options”](GlobalOpts)."
762 )]
763 #[cfg_attr(
764 all(feature = "lt2018_2", not(feature = "lt2017_1")),
765 doc = "See [Global Options](GlobalOpts)."
766 )]
767 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
768 pub fn get_global_opts(&self) -> &GlobalOpts {
769 &self.global_opts
770 }
771
772 #[cfg_attr(
777 feature = "lt2014_2",
778 doc = "See the [Global Options](GlobalOpts) section."
779 )]
780 #[cfg_attr(
781 all(feature = "lt2015_1", not(feature = "lt2014_2")),
782 doc = "See the [“Global Options”](GlobalOpts) section."
783 )]
784 #[cfg_attr(
785 all(feature = "lt2017_1", not(feature = "lt2015_1")),
786 doc = "See [“Global Options”](GlobalOpts)."
787 )]
788 #[cfg_attr(
789 all(feature = "lt2018_2", not(feature = "lt2017_1")),
790 doc = "See [Global Options](GlobalOpts)."
791 )]
792 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
793 pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
794 self.global_opts = v;
795 self
796 }
797
798 #[cfg_attr(
803 feature = "lt2014_2",
804 doc = "See the [Global Options](GlobalOpts) section."
805 )]
806 #[cfg_attr(
807 all(feature = "lt2015_1", not(feature = "lt2014_2")),
808 doc = "See the [“Global Options”](GlobalOpts) section."
809 )]
810 #[cfg_attr(
811 all(feature = "lt2017_1", not(feature = "lt2015_1")),
812 doc = "See [“Global Options”](GlobalOpts)."
813 )]
814 #[cfg_attr(
815 all(feature = "lt2018_2", not(feature = "lt2017_1")),
816 doc = "See [Global Options](GlobalOpts)."
817 )]
818 #[cfg_attr(not(feature = "lt2018_2"), doc = "See [Global options](GlobalOpts).")]
819 pub fn global_opts(mut self, v: GlobalOpts) -> Self {
820 self.global_opts = v;
821 self
822 }
823}
824
825impl Print<StandardPrintMode> {
826 pub fn get_all_revisions(&self) -> bool {
833 self.mode.all_revisions
834 }
835
836 pub fn set_all_revisions(&mut self, v: bool) -> &mut Self {
843 self.mode.all_revisions = v;
844 self
845 }
846
847 pub fn all_revisions(mut self, v: bool) -> Self {
854 self.mode.all_revisions = v;
855 self
856 }
857
858 #[cfg_attr(
863 feature = "lt2023_1",
864 doc = "Attempt to print a file stored in an archive depot."
865 )]
866 #[cfg_attr(not(feature = "lt2023_1"), doc = "Print files in archive depots.")]
867 pub fn get_archive_depots(&self) -> bool {
868 self.mode.from_archive_depots
869 }
870
871 #[cfg_attr(
876 feature = "lt2023_1",
877 doc = "Attempt to print a file stored in an archive depot."
878 )]
879 #[cfg_attr(not(feature = "lt2023_1"), doc = "Print files in archive depots.")]
880 pub fn set_archive_depots(&mut self, v: bool) -> &mut Self {
881 self.mode.from_archive_depots = v;
882 self
883 }
884
885 #[cfg_attr(
890 feature = "lt2023_1",
891 doc = "Attempt to print a file stored in an archive depot."
892 )]
893 #[cfg_attr(not(feature = "lt2023_1"), doc = "Print files in archive depots.")]
894 pub fn archive_depots(mut self, v: bool) -> Self {
895 self.mode.from_archive_depots = v;
896 self
897 }
898
899 #[cfg_attr(feature = "lt2022_1", doc = "-k")]
902 #[cfg_attr(not(feature = "lt2022_1"), doc = "-K")]
903 #[cfg_attr(feature = "lt2023_1", doc = "Suppress RCS keyword expansion.")]
905 #[cfg_attr(
906 not(feature = "lt2023_1"),
907 doc = "Suppress RCS keyword expansion. This replaced the `-k` flag in",
908 doc = "2022.1, which is now an alias for `-K` for backwards compatibility."
909 )]
910 pub fn get_suppress_keyword_expansion(&self) -> bool {
911 self.mode.suppress_keyword_expansion
912 }
913
914 #[cfg_attr(feature = "lt2022_1", doc = "-k")]
917 #[cfg_attr(not(feature = "lt2022_1"), doc = "-K")]
918 #[cfg_attr(feature = "lt2023_1", doc = "Suppress RCS keyword expansion.")]
920 #[cfg_attr(
921 not(feature = "lt2023_1"),
922 doc = "Suppress RCS keyword expansion. This replaced the `-k` flag in",
923 doc = "2022.1, which is now an alias for `-K` for backwards compatibility."
924 )]
925 pub fn set_suppress_keyword_expansion(&mut self, v: bool) -> &mut Self {
926 self.mode.suppress_keyword_expansion = v;
927 self
928 }
929
930 #[cfg_attr(feature = "lt2022_1", doc = "-k")]
933 #[cfg_attr(not(feature = "lt2022_1"), doc = "-K")]
934 #[cfg_attr(feature = "lt2023_1", doc = "Suppress RCS keyword expansion.")]
936 #[cfg_attr(
937 not(feature = "lt2023_1"),
938 doc = "Suppress RCS keyword expansion. This replaced the `-k` flag in",
939 doc = "2022.1, which is now an alias for `-K` for backwards compatibility."
940 )]
941 pub fn suppress_keyword_expansion(mut self, v: bool) -> Self {
942 self.mode.suppress_keyword_expansion = v;
943 self
944 }
945
946 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
949 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
950 #[cfg_attr(
952 feature = "lt2018_2",
953 doc = "Redirect output to the specified output file on the local disk,",
954 doc = "preserving the same file type, attributes, and/or permission bits",
955 doc = "as the original file in the depot."
956 )]
957 #[cfg_attr(
958 all(feature = "lt2023_1", not(feature = "lt2018_2")),
959 doc = "Redirect output to the specified output file (`outfile`) on the",
960 doc = "local disk. This preserves the same file type, attributes, and/or",
961 doc = "permission bits as the original file (`FileSpec`) in the depot.",
962 doc = "Multiple files can be written by using wildcards in the",
963 doc = "`localFile` argument that match wildcards in the depot",
964 doc = "(`FileSpec`) argument. For example: To print the contents of a",
965 doc = "directory and directories under that directory, use the `...`",
966 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
967 doc = "print all files that match readme.txt or readme.pdf, you might",
968 doc = "specify `p4 print -o readme.* //depot/readme.*`"
969 )]
970 #[cfg_attr(
971 not(feature = "lt2023_1"),
972 doc = "Redirect output to the specified output file (`localfile`) on the",
973 doc = "local disk. This preserves the same file type, attributes, and/or",
974 doc = "permission bits as the original file (`FileSpec`) in the depot.",
975 doc = "Multiple files can be written by using wildcards in the",
976 doc = "`localFile` argument that match wildcards in the depot",
977 doc = "(`FileSpec`) argument. For example: To print the contents of a",
978 doc = "directory and directories under that directory, use the `...`",
979 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
980 doc = "print all files that match readme.txt or readme.pdf, you might",
981 doc = "specify `p4 print -o readme.* //depot/readme.*`"
982 )]
983 pub fn get_redirect_output(&self) -> Option<&PathBuf> {
984 self.mode.redirect_output.as_ref()
985 }
986
987 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
990 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
991 #[cfg_attr(
993 feature = "lt2018_2",
994 doc = "Redirect output to the specified output file on the local disk,",
995 doc = "preserving the same file type, attributes, and/or permission bits",
996 doc = "as the original file in the depot."
997 )]
998 #[cfg_attr(
999 all(feature = "lt2023_1", not(feature = "lt2018_2")),
1000 doc = "Redirect output to the specified output file (`outfile`) on the",
1001 doc = "local disk. This preserves the same file type, attributes, and/or",
1002 doc = "permission bits as the original file (`FileSpec`) in the depot.",
1003 doc = "Multiple files can be written by using wildcards in the",
1004 doc = "`localFile` argument that match wildcards in the depot",
1005 doc = "(`FileSpec`) argument. For example: To print the contents of a",
1006 doc = "directory and directories under that directory, use the `...`",
1007 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
1008 doc = "print all files that match readme.txt or readme.pdf, you might",
1009 doc = "specify `p4 print -o readme.* //depot/readme.*`"
1010 )]
1011 #[cfg_attr(
1012 not(feature = "lt2023_1"),
1013 doc = "Redirect output to the specified output file (`localfile`) on the",
1014 doc = "local disk. This preserves the same file type, attributes, and/or",
1015 doc = "permission bits as the original file (`FileSpec`) in the depot.",
1016 doc = "Multiple files can be written by using wildcards in the",
1017 doc = "`localFile` argument that match wildcards in the depot",
1018 doc = "(`FileSpec`) argument. For example: To print the contents of a",
1019 doc = "directory and directories under that directory, use the `...`",
1020 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
1021 doc = "print all files that match readme.txt or readme.pdf, you might",
1022 doc = "specify `p4 print -o readme.* //depot/readme.*`"
1023 )]
1024 pub fn set_redirect_output(&mut self, v: impl Into<PathBuf>) -> &mut Self {
1025 self.mode.redirect_output = Some(v.into());
1026 self
1027 }
1028
1029 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
1032 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
1033 #[cfg_attr(
1035 feature = "lt2018_2",
1036 doc = "Redirect output to the specified output file on the local disk,",
1037 doc = "preserving the same file type, attributes, and/or permission bits",
1038 doc = "as the original file in the depot."
1039 )]
1040 #[cfg_attr(
1041 all(feature = "lt2023_1", not(feature = "lt2018_2")),
1042 doc = "Redirect output to the specified output file (`outfile`) on the",
1043 doc = "local disk. This preserves the same file type, attributes, and/or",
1044 doc = "permission bits as the original file (`FileSpec`) in the depot.",
1045 doc = "Multiple files can be written by using wildcards in the",
1046 doc = "`localFile` argument that match wildcards in the depot",
1047 doc = "(`FileSpec`) argument. For example: To print the contents of a",
1048 doc = "directory and directories under that directory, use the `...`",
1049 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
1050 doc = "print all files that match readme.txt or readme.pdf, you might",
1051 doc = "specify `p4 print -o readme.* //depot/readme.*`"
1052 )]
1053 #[cfg_attr(
1054 not(feature = "lt2023_1"),
1055 doc = "Redirect output to the specified output file (`localfile`) on the",
1056 doc = "local disk. This preserves the same file type, attributes, and/or",
1057 doc = "permission bits as the original file (`FileSpec`) in the depot.",
1058 doc = "Multiple files can be written by using wildcards in the",
1059 doc = "`localFile` argument that match wildcards in the depot",
1060 doc = "(`FileSpec`) argument. For example: To print the contents of a",
1061 doc = "directory and directories under that directory, use the `...`",
1062 doc = "wildcard: `p4 print -o c:/tmp/main-copy/... //depot/main/...` To",
1063 doc = "print all files that match readme.txt or readme.pdf, you might",
1064 doc = "specify `p4 print -o readme.* //depot/readme.*`"
1065 )]
1066 pub fn redirect_output(mut self, v: impl Into<PathBuf>) -> Self {
1067 self.mode.redirect_output = Some(v.into());
1068 self
1069 }
1070
1071 #[cfg_attr(feature = "lt2018_1", doc = "Perforce.")]
1077 #[cfg_attr(
1078 all(feature = "lt2019_1", not(feature = "lt2018_1")),
1079 doc = "Helix Server."
1080 )]
1081 #[cfg_attr(
1082 all(feature = "lt2021_1", not(feature = "lt2019_1")),
1083 doc = "Helix server."
1084 )]
1085 #[cfg_attr(
1086 all(feature = "lt2024_1", not(feature = "lt2021_1")),
1087 doc = "Helix Server."
1088 )]
1089 #[cfg_attr(
1090 all(feature = "lt2024_2", not(feature = "lt2024_1")),
1091 doc = "Helix Core Server."
1092 )]
1093 #[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
1094 pub fn get_quiet_mode(&self) -> bool {
1095 self.mode.quiet_mode
1096 }
1097
1098 #[cfg_attr(feature = "lt2018_1", doc = "Perforce.")]
1104 #[cfg_attr(
1105 all(feature = "lt2019_1", not(feature = "lt2018_1")),
1106 doc = "Helix Server."
1107 )]
1108 #[cfg_attr(
1109 all(feature = "lt2021_1", not(feature = "lt2019_1")),
1110 doc = "Helix server."
1111 )]
1112 #[cfg_attr(
1113 all(feature = "lt2024_1", not(feature = "lt2021_1")),
1114 doc = "Helix Server."
1115 )]
1116 #[cfg_attr(
1117 all(feature = "lt2024_2", not(feature = "lt2024_1")),
1118 doc = "Helix Core Server."
1119 )]
1120 #[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
1121 pub fn set_quiet_mode(&mut self, v: bool) -> &mut Self {
1122 self.mode.quiet_mode = v;
1123 self
1124 }
1125
1126 #[cfg_attr(feature = "lt2018_1", doc = "Perforce.")]
1132 #[cfg_attr(
1133 all(feature = "lt2019_1", not(feature = "lt2018_1")),
1134 doc = "Helix Server."
1135 )]
1136 #[cfg_attr(
1137 all(feature = "lt2021_1", not(feature = "lt2019_1")),
1138 doc = "Helix server."
1139 )]
1140 #[cfg_attr(
1141 all(feature = "lt2024_1", not(feature = "lt2021_1")),
1142 doc = "Helix Server."
1143 )]
1144 #[cfg_attr(
1145 all(feature = "lt2024_2", not(feature = "lt2024_1")),
1146 doc = "Helix Core Server."
1147 )]
1148 #[cfg_attr(not(feature = "lt2024_2"), doc = "P4 Server.")]
1149 pub fn quiet_mode(mut self, v: bool) -> Self {
1150 self.mode.quiet_mode = v;
1151 self
1152 }
1153
1154 pub fn get_limit(&self) -> Option<u64> {
1160 self.mode.limit
1161 }
1162
1163 pub fn set_limit(&mut self, v: u64) -> &mut Self {
1169 self.mode.limit = Some(v);
1170 self
1171 }
1172
1173 pub fn limit(mut self, v: u64) -> Self {
1179 self.mode.limit = Some(v);
1180 self
1181 }
1182
1183 #[cfg(not(feature = "lt2022_1"))]
1190 pub fn get_offset(&self) -> Option<u64> {
1191 self.mode.offset
1192 }
1193
1194 #[cfg(not(feature = "lt2022_1"))]
1201 pub fn set_offset(&mut self, v: u64) -> &mut Self {
1202 self.mode.offset = Some(v);
1203 self
1204 }
1205
1206 #[cfg(not(feature = "lt2022_1"))]
1213 pub fn offset(mut self, v: u64) -> Self {
1214 self.mode.offset = Some(v);
1215 self
1216 }
1217
1218 #[cfg(not(feature = "lt2022_1"))]
1226 pub fn get_size(&self) -> Option<u64> {
1227 self.mode.size
1228 }
1229
1230 #[cfg(not(feature = "lt2022_1"))]
1238 pub fn set_size(&mut self, v: u64) -> &mut Self {
1239 self.mode.size = Some(v);
1240 self
1241 }
1242
1243 #[cfg(not(feature = "lt2022_1"))]
1251 pub fn size(mut self, v: u64) -> Self {
1252 self.mode.size = Some(v);
1253 self
1254 }
1255
1256 #[cfg(not(feature = "lt2023_1"))]
1264 pub fn get_charset(&self) -> Option<&str> {
1265 self.mode.charset.as_deref()
1266 }
1267
1268 #[cfg(not(feature = "lt2023_1"))]
1276 pub fn set_charset(&mut self, v: impl Into<String>) -> &mut Self {
1277 self.mode.charset = Some(v.into());
1278 self
1279 }
1280
1281 #[cfg(not(feature = "lt2023_1"))]
1289 pub fn charset(mut self, v: impl Into<String>) -> Self {
1290 self.mode.charset = Some(v.into());
1291 self
1292 }
1293
1294 #[cfg(not(feature = "lt2023_1"))]
1301 pub fn get_utf8bom(&self) -> Option<Utf8Bom> {
1302 self.mode.utf8bom
1303 }
1304
1305 #[cfg(not(feature = "lt2023_1"))]
1314 pub fn set_write_utf8bom(&mut self, v: bool) -> &mut Self {
1315 self.mode.utf8bom = Some(if v { Utf8Bom::Yes } else { Utf8Bom::No });
1316 self
1317 }
1318
1319 #[cfg(not(feature = "lt2023_1"))]
1328 pub fn write_utf8bom(mut self, v: bool) -> Self {
1329 self.mode.utf8bom = Some(if v { Utf8Bom::Yes } else { Utf8Bom::No });
1330 self
1331 }
1332
1333 #[cfg(not(feature = "lt2023_1"))]
1340 pub fn set_write_utf8bom_windows_only(&mut self) -> &mut Self {
1341 self.mode.utf8bom = Some(Utf8Bom::WindowsOnly);
1342 self
1343 }
1344
1345 #[cfg(not(feature = "lt2023_1"))]
1352 pub fn write_utf8bom_windows_only(mut self) -> Self {
1353 self.mode.utf8bom = Some(Utf8Bom::WindowsOnly);
1354 self
1355 }
1356
1357 #[cfg(not(feature = "lt2023_1"))]
1367 pub fn get_line_ending(&self) -> Option<LineEnding> {
1368 self.mode.line_ending
1369 }
1370
1371 #[cfg(not(feature = "lt2023_1"))]
1378 pub fn set_line_ending_unix(&mut self) -> &mut Self {
1379 self.mode.line_ending = Some(LineEnding::Unix);
1380 self
1381 }
1382
1383 #[cfg(not(feature = "lt2023_1"))]
1390 pub fn line_ending_unix(mut self) -> Self {
1391 self.mode.line_ending = Some(LineEnding::Unix);
1392 self
1393 }
1394
1395 #[cfg(not(feature = "lt2023_1"))]
1402 pub fn set_line_ending_win(&mut self) -> &mut Self {
1403 self.mode.line_ending = Some(LineEnding::Win);
1404 self
1405 }
1406
1407 #[cfg(not(feature = "lt2023_1"))]
1414 pub fn line_ending_win(mut self) -> Self {
1415 self.mode.line_ending = Some(LineEnding::Win);
1416 self
1417 }
1418
1419 #[cfg(not(feature = "lt2023_1"))]
1426 pub fn set_line_ending_mac(&mut self) -> &mut Self {
1427 self.mode.line_ending = Some(LineEnding::Mac);
1428 self
1429 }
1430
1431 #[cfg(not(feature = "lt2023_1"))]
1438 pub fn line_ending_mac(mut self) -> Self {
1439 self.mode.line_ending = Some(LineEnding::Mac);
1440 self
1441 }
1442
1443 #[cfg(not(feature = "lt2026_1"))]
1450 pub fn get_ignore_changeview(&self) -> bool {
1451 self.mode.ignore_changeview
1452 }
1453
1454 #[cfg(not(feature = "lt2026_1"))]
1461 pub fn set_ignore_changeview(&mut self, v: bool) -> &mut Self {
1462 self.mode.ignore_changeview = v;
1463 self
1464 }
1465
1466 #[cfg(not(feature = "lt2026_1"))]
1473 pub fn ignore_changeview(mut self, v: bool) -> Self {
1474 self.mode.ignore_changeview = v;
1475 self
1476 }
1477}
1478
1479#[cfg(not(feature = "lt2024_2"))]
1480impl Print<AttributeTraitMode> {
1481 pub fn get_attribute(&self) -> &str {
1488 &self.mode.attribute
1489 }
1490
1491 pub fn set_attribute(&mut self, v: impl Into<String>) -> &mut Self {
1498 self.mode.attribute = v.into();
1499 self
1500 }
1501
1502 pub fn attribute(mut self, v: impl Into<String>) -> Self {
1509 self.mode.attribute = v.into();
1510 self
1511 }
1512
1513 pub fn get_all_revisions(&self) -> bool {
1520 self.mode.all_revisions
1521 }
1522
1523 pub fn set_all_revisions(&mut self, v: bool) -> &mut Self {
1530 self.mode.all_revisions = v;
1531 self
1532 }
1533
1534 pub fn all_revisions(mut self, v: bool) -> Self {
1541 self.mode.all_revisions = v;
1542 self
1543 }
1544
1545 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
1548 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
1549 pub fn get_redirect_output(&self) -> Option<&PathBuf> {
1554 self.mode.redirect_output.as_ref()
1555 }
1556
1557 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
1560 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
1561 pub fn set_redirect_output(&mut self, v: impl Into<PathBuf>) -> &mut Self {
1566 self.mode.redirect_output = Some(v.into());
1567 self
1568 }
1569
1570 #[cfg_attr(feature = "lt2023_1", doc = "-o outfile")]
1573 #[cfg_attr(not(feature = "lt2023_1"), doc = "-o localfile")]
1574 pub fn redirect_output(mut self, v: impl Into<PathBuf>) -> Self {
1579 self.mode.redirect_output = Some(v.into());
1580 self
1581 }
1582
1583 pub fn get_quiet_mode(&self) -> bool {
1590 self.mode.quiet_mode
1591 }
1592
1593 pub fn set_quiet_mode(&mut self, v: bool) -> &mut Self {
1600 self.mode.quiet_mode = v;
1601 self
1602 }
1603
1604 pub fn quiet_mode(mut self, v: bool) -> Self {
1611 self.mode.quiet_mode = v;
1612 self
1613 }
1614
1615 #[cfg(not(feature = "lt2026_1"))]
1622 pub fn get_ignore_changeview(&self) -> bool {
1623 self.mode.ignore_changeview
1624 }
1625
1626 #[cfg(not(feature = "lt2026_1"))]
1633 pub fn set_ignore_changeview(&mut self, v: bool) -> &mut Self {
1634 self.mode.ignore_changeview = v;
1635 self
1636 }
1637
1638 #[cfg(not(feature = "lt2026_1"))]
1645 pub fn ignore_changeview(mut self, v: bool) -> Self {
1646 self.mode.ignore_changeview = v;
1647 self
1648 }
1649}
1650
1651impl<M: ExclusiveOption> SubCommand for Print<M> {
1652 fn name(&self) -> &str {
1653 "print"
1654 }
1655
1656 fn inject_local_args(&self, command: &mut Command) {
1657 self.mode.inject_args(command);
1658 }
1659
1660 fn global_opts(&self) -> Option<&GlobalOpts> {
1661 Some(&self.global_opts)
1662 }
1663}
1664
1665#[cfg(test)]
1666mod tests {
1667 use super::*;
1668 use crate::cmd::args_of;
1669
1670 #[test]
1671 fn bin_accessors_update_executable_path() {
1672 let mut command = Print::new("p4", GlobalOpts::new());
1673 assert_eq!(command.get_bin(), Path::new("p4"));
1674
1675 command.set_bin("/usr/local/bin/p4");
1676 assert_eq!(command.get_bin(), Path::new("/usr/local/bin/p4"));
1677
1678 let command = command.bin("p4.exe");
1679 assert_eq!(command.get_bin(), Path::new("p4.exe"));
1680 }
1681
1682 #[test]
1685 fn without_options() {
1686 let print = Print::new("p4", GlobalOpts::new());
1687
1688 assert_eq!(args_of(&print.setup_command("p4")), ["print"]);
1689 }
1690
1691 #[test]
1692 fn standard_mode_all_options() {
1693 let print = Print::new("p4", GlobalOpts::new())
1694 .all_revisions(true)
1695 .archive_depots(true)
1696 .suppress_keyword_expansion(true)
1697 .redirect_output("out.bin")
1698 .quiet_mode(true)
1699 .limit(5);
1700 #[cfg(not(feature = "lt2022_1"))]
1701 let print = print.offset(100).size(200);
1702 #[cfg(not(feature = "lt2023_1"))]
1703 let print = print.charset("utf8").write_utf8bom(true).line_ending_unix();
1704 #[cfg(not(feature = "lt2026_1"))]
1705 let print = print.ignore_changeview(true);
1706
1707 let mut expected = vec!["print", "-a", "-A"];
1708 #[cfg(feature = "lt2022_1")]
1709 expected.push("-k");
1710 #[cfg(not(feature = "lt2022_1"))]
1711 expected.push("-K");
1712 expected.extend(["-o", "out.bin", "-q", "-m", "5"]);
1713 #[cfg(not(feature = "lt2022_1"))]
1714 expected.extend(["--offset", "100", "--size", "200"]);
1715 #[cfg(not(feature = "lt2023_1"))]
1716 expected.extend(["-Q", "utf8", "-B", "1", "-L", "unix"]);
1717 #[cfg(not(feature = "lt2026_1"))]
1718 expected.push("--ignore-changeview");
1719
1720 assert_eq!(args_of(&print.setup_command("p4")), expected);
1721 }
1722
1723 #[test]
1724 fn standard_mode_set_style() {
1725 let mut print = Print::new("p4", GlobalOpts::new()).limit(5);
1726 print.set_all_revisions(true).set_quiet_mode(true);
1727 #[cfg(not(feature = "lt2022_1"))]
1728 print.set_offset(100).set_size(200);
1729
1730 let expected = {
1731 #[cfg_attr(feature = "lt2022_1", allow(unused_mut))]
1732 let mut v = vec!["print", "-a", "-q", "-m", "5"];
1733 #[cfg(not(feature = "lt2022_1"))]
1734 v.extend(["--offset", "100", "--size", "200"]);
1735 v
1736 };
1737
1738 assert_eq!(args_of(&print.setup_command("p4")), expected);
1739 }
1740
1741 #[test]
1742 fn unload_depot_mode() {
1743 let print = Print::new("p4", GlobalOpts::new()).from_unload_depot();
1744
1745 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-U"]);
1746 }
1747
1748 #[cfg(not(feature = "lt2023_1"))]
1749 #[test]
1750 fn line_ending_is_passed_as_separate_args() {
1751 let print = Print::new("p4", GlobalOpts::new()).line_ending_win();
1752
1753 assert_eq!(print.get_line_ending(), Some(LineEnding::Win));
1754 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-L", "win"]);
1755 }
1756
1757 #[cfg(not(feature = "lt2023_1"))]
1758 #[test]
1759 fn write_utf8bom_bool() {
1760 let yes = Print::new("p4", GlobalOpts::new()).write_utf8bom(true);
1761 assert_eq!(yes.get_utf8bom(), Some(Utf8Bom::Yes));
1762 assert_eq!(args_of(&yes.setup_command("p4")), ["print", "-B", "1"]);
1763
1764 let no = Print::new("p4", GlobalOpts::new()).write_utf8bom(false);
1765 assert_eq!(no.get_utf8bom(), Some(Utf8Bom::No));
1766 assert_eq!(args_of(&no.setup_command("p4")), ["print", "-B", "0"]);
1767 }
1768
1769 #[cfg(not(feature = "lt2023_1"))]
1770 #[test]
1771 fn write_utf8bom_windows_only() {
1772 let print = Print::new("p4", GlobalOpts::new()).write_utf8bom_windows_only();
1773
1774 assert_eq!(print.get_utf8bom(), Some(Utf8Bom::WindowsOnly));
1775 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-B", "2"]);
1776 }
1777
1778 #[cfg(not(feature = "lt2023_1"))]
1779 #[test]
1780 fn utf8bom_set_style_can_replace() {
1781 let mut print = Print::new("p4", GlobalOpts::new()).write_utf8bom(true);
1782 print.set_write_utf8bom(false);
1783 assert_eq!(print.get_utf8bom(), Some(Utf8Bom::No));
1784
1785 print.set_write_utf8bom_windows_only();
1786 assert_eq!(print.get_utf8bom(), Some(Utf8Bom::WindowsOnly));
1787 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-B", "2"]);
1788 }
1789
1790 #[cfg(not(feature = "lt2024_2"))]
1791 #[test]
1792 fn attribute_trait_mode() {
1793 let print = Print::new("p4", GlobalOpts::new()).extract_attribute("desc");
1794
1795 assert_eq!(print.get_attribute(), "desc");
1796 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-T", "desc"]);
1797 }
1798
1799 #[cfg(not(feature = "lt2024_2"))]
1800 #[test]
1801 fn attribute_trait_mode_with_allowed_options() {
1802 let print = Print::new("p4", GlobalOpts::new())
1803 .extract_attribute("desc")
1804 .all_revisions(true)
1805 .quiet_mode(true)
1806 .redirect_output("out.bin");
1807 #[cfg(not(feature = "lt2026_1"))]
1808 let print = print.ignore_changeview(true);
1809
1810 let mut expected = vec!["print", "-T", "desc", "-a", "-o", "out.bin", "-q"];
1811 #[cfg(not(feature = "lt2026_1"))]
1812 expected.push("--ignore-changeview");
1813
1814 assert_eq!(args_of(&print.setup_command("p4")), expected);
1815 }
1816
1817 #[cfg(not(feature = "lt2024_2"))]
1818 #[test]
1819 fn attribute_name_can_be_replaced() {
1820 let mut print = Print::new("p4", GlobalOpts::new()).extract_attribute("old");
1821 print.set_attribute("new");
1822
1823 assert_eq!(print.get_attribute(), "new");
1824 assert_eq!(args_of(&print.setup_command("p4")), ["print", "-T", "new"]);
1825 }
1826
1827 #[cfg(not(feature = "lt2026_1"))]
1828 #[test]
1829 fn ignore_changeview_standard_mode() {
1830 let print = Print::new("p4", GlobalOpts::new()).ignore_changeview(true);
1831
1832 assert!(print.get_ignore_changeview());
1833 assert_eq!(
1834 args_of(&print.setup_command("p4")),
1835 ["print", "--ignore-changeview"]
1836 );
1837 }
1838}