1use std::{
2 ffi::OsStr,
3 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 ParallelConfig {
19 pub threads: u64,
21
22 pub batch_files: Option<u64>,
24
25 pub batch_size_bytes: Option<u64>,
27
28 pub min_files: Option<u64>,
30
31 pub min_size_bytes: Option<u64>,
33}
34
35impl ParallelConfig {
36 pub fn as_arg(&self) -> String {
39 let mut parts = vec![format!("threads={}", self.threads)];
40
41 if let Some(v) = self.batch_files {
42 parts.push(format!("batch={}", v));
43 }
44 if let Some(v) = self.batch_size_bytes {
45 parts.push(format!("batchsize={}", v));
46 }
47 if let Some(v) = self.min_files {
48 parts.push(format!("min={}", v));
49 }
50 if let Some(v) = self.min_size_bytes {
51 parts.push(format!("minsize={}", v));
52 }
53
54 parts.join(",")
55 }
56}
57
58#[derive(Debug, Clone, Copy)]
61pub enum StreamSpecVersion {
62 MaxInFilelists,
65 Current,
67 ChangeNumber(u32),
70}
71
72impl StreamSpecVersion {
73 pub fn max_in_filelists() -> Self {
76 StreamSpecVersion::MaxInFilelists
77 }
78
79 pub fn current() -> Self {
81 StreamSpecVersion::Current
82 }
83
84 pub fn at_change(n: u32) -> Self {
87 StreamSpecVersion::ChangeNumber(n)
88 }
89
90 pub fn inject_arg(&self, command: &mut Command) {
92 match self {
93 StreamSpecVersion::MaxInFilelists => {
94 command.arg("--use-stream-change");
95 }
96 StreamSpecVersion::Current => {
97 command.arg("--use-stream-change=0");
98 }
99 StreamSpecVersion::ChangeNumber(n) => {
100 command.arg(format!("--use-stream-change={}", n));
101 }
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, Default)]
112pub struct PreviewResult;
113
114impl ExclusiveOption for PreviewResult {
115 fn inject_args(&self, command: &mut Command) {
116 command.arg("-n");
117 }
118}
119
120#[derive(Debug, Clone, Copy, Default)]
126pub struct PreviewNetworkTraffic;
127
128impl ExclusiveOption for PreviewNetworkTraffic {
129 fn inject_args(&self, command: &mut Command) {
130 command.arg("-N");
131 }
132}
133
134#[derive(Debug, Clone, Default)]
140pub struct ForceRegularMode {
141 force: bool,
142
143 metadata_only: bool,
144
145 reopen_moved_files: bool,
146}
147
148impl ExclusiveOption for ForceRegularMode {
149 fn inject_args(&self, command: &mut Command) {
150 if self.force {
151 command.arg("-f");
152 }
153
154 if self.metadata_only {
155 command.arg("-k");
156 }
157
158 if self.reopen_moved_files {
159 command.arg("-r");
160 }
161 }
162}
163
164#[derive(Debug, Clone, Copy, Default)]
170pub struct SafeCheckMode;
171
172impl ExclusiveOption for SafeCheckMode {
173 fn inject_args(&self, command: &mut Command) {
174 command.arg("-s");
175 }
176}
177
178#[derive(Debug, Clone, Copy, Default)]
183pub struct PopulateMode;
184
185impl ExclusiveOption for PopulateMode {
186 fn inject_args(&self, command: &mut Command) {
187 command.arg("-p");
188 }
189}
190
191#[derive(Debug, Clone, Default)]
206pub struct RegularMode<Mode = Unselected, P = Unselected> {
207 verify_edge_replication: bool,
208
209 script_list_mode: bool,
210
211 suppress_keyword_expansion: bool,
212
213 quiet_mode: bool,
214
215 limit: Option<u64>,
216
217 parallel: Option<ParallelConfig>,
218
219 stream_spec_version: Option<StreamSpecVersion>,
220
221 mode: Mode,
222
223 preview: P,
224}
225
226impl<Mode: ExclusiveOption, P: ExclusiveOption> ExclusiveOption for RegularMode<Mode, P> {
227 fn inject_args(&self, command: &mut Command) {
228 if self.verify_edge_replication {
229 command.arg("-E");
230 }
231
232 if self.script_list_mode {
233 command.arg("-L");
234 }
235
236 if self.suppress_keyword_expansion {
237 command.arg("-K");
238 }
239
240 if self.quiet_mode {
241 command.arg("-q");
242 }
243
244 self.mode.inject_args(command);
245
246 self.preview.inject_args(command);
247
248 if let Some(max) = self.limit {
249 command.arg("-m").arg(max.to_string());
250 }
251
252 if let Some(parallel) = &self.parallel {
253 command.arg(format!("--parallel={}", parallel.as_arg()));
254 }
255
256 if let Some(version) = &self.stream_spec_version {
257 version.inject_arg(command);
258 }
259 }
260}
261
262#[derive(Debug, Clone)]
269pub struct SyncTimeMode {
270 sync_time: String,
271}
272
273impl ExclusiveOption for SyncTimeMode {
274 fn inject_args(&self, command: &mut Command) {
275 command
276 .arg("-k")
277 .arg(format!("--sync-time={}", self.sync_time));
278 }
279}
280
281#[derive(Debug, Clone, Default)]
289pub struct Sync<M = Unselected> {
290 bin: PathBuf,
291
292 global_opts: GlobalOpts,
293
294 mode: M,
295}
296
297impl Sync<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 sync_time(self, time: impl Into<String>) -> Sync<SyncTimeMode> {
320 Sync {
321 bin: self.bin,
322 global_opts: self.global_opts,
323 mode: SyncTimeMode {
324 sync_time: time.into(),
325 },
326 }
327 }
328
329 pub fn enable_safe_check(self) -> Sync<RegularMode<SafeCheckMode>> {
341 Sync {
342 bin: self.bin,
343 global_opts: self.global_opts,
344 mode: RegularMode {
345 mode: SafeCheckMode,
346 ..RegularMode::default()
347 },
348 }
349 }
350
351 pub fn populate_client_workspace(self) -> Sync<RegularMode<PopulateMode>> {
362 Sync {
363 bin: self.bin,
364 global_opts: self.global_opts,
365 mode: RegularMode {
366 mode: PopulateMode,
367 ..RegularMode::default()
368 },
369 }
370 }
371
372 pub fn verify_edge_replication(self, v: bool) -> Sync<RegularMode> {
382 Sync {
383 bin: self.bin,
384 global_opts: self.global_opts,
385 mode: RegularMode {
386 verify_edge_replication: v,
387 ..RegularMode::default()
388 },
389 }
390 }
391
392 pub fn script_list_mode(self, v: bool) -> Sync<RegularMode> {
401 Sync {
402 bin: self.bin,
403 global_opts: self.global_opts,
404 mode: RegularMode {
405 script_list_mode: v,
406 ..RegularMode::default()
407 },
408 }
409 }
410
411 pub fn suppress_keyword_expansion(self, v: bool) -> Sync<RegularMode> {
420 Sync {
421 bin: self.bin,
422 global_opts: self.global_opts,
423 mode: RegularMode {
424 suppress_keyword_expansion: v,
425 ..RegularMode::default()
426 },
427 }
428 }
429
430 pub fn quiet_mode(self, v: bool) -> Sync<RegularMode> {
439 Sync {
440 bin: self.bin,
441 global_opts: self.global_opts,
442 mode: RegularMode {
443 quiet_mode: v,
444 ..RegularMode::default()
445 },
446 }
447 }
448
449 pub fn limit(self, v: u64) -> Sync<RegularMode> {
457 Sync {
458 bin: self.bin,
459 global_opts: self.global_opts,
460 mode: RegularMode {
461 limit: Some(v),
462 ..RegularMode::default()
463 },
464 }
465 }
466
467 pub fn parallel(self, v: ParallelConfig) -> Sync<RegularMode> {
475 Sync {
476 bin: self.bin,
477 global_opts: self.global_opts,
478 mode: RegularMode {
479 parallel: Some(v),
480 ..RegularMode::default()
481 },
482 }
483 }
484
485 pub fn stream_spec_version(self, v: StreamSpecVersion) -> Sync<RegularMode> {
494 Sync {
495 bin: self.bin,
496 global_opts: self.global_opts,
497 mode: RegularMode {
498 stream_spec_version: Some(v),
499 ..RegularMode::default()
500 },
501 }
502 }
503
504 pub fn sc_max_change_number(self) -> Sync<RegularMode> {
509 self.stream_spec_version(StreamSpecVersion::MaxInFilelists)
510 }
511
512 pub fn sc_current_stream_spec(self) -> Sync<RegularMode> {
516 self.stream_spec_version(StreamSpecVersion::Current)
517 }
518
519 pub fn sc_change_number(self, n: u32) -> Sync<RegularMode> {
524 self.stream_spec_version(StreamSpecVersion::ChangeNumber(n))
525 }
526
527 pub fn preview_result(self) -> Sync<RegularMode<Unselected, PreviewResult>> {
537 Sync {
538 bin: self.bin,
539 global_opts: self.global_opts,
540 mode: RegularMode {
541 preview: PreviewResult,
542 ..RegularMode::default()
543 },
544 }
545 }
546
547 pub fn preview_network_traffic(self) -> Sync<RegularMode<Unselected, PreviewNetworkTraffic>> {
557 Sync {
558 bin: self.bin,
559 global_opts: self.global_opts,
560 mode: RegularMode {
561 preview: PreviewNetworkTraffic,
562 ..RegularMode::default()
563 },
564 }
565 }
566
567 pub fn force(self, v: bool) -> Sync<RegularMode<ForceRegularMode>> {
578 Sync {
579 bin: self.bin,
580 global_opts: self.global_opts,
581 mode: RegularMode {
582 mode: ForceRegularMode {
583 force: v,
584 ..ForceRegularMode::default()
585 },
586 ..RegularMode::default()
587 },
588 }
589 }
590
591 pub fn metadata_only(self, v: bool) -> Sync<RegularMode<ForceRegularMode>> {
602 Sync {
603 bin: self.bin,
604 global_opts: self.global_opts,
605 mode: RegularMode {
606 mode: ForceRegularMode {
607 metadata_only: v,
608 ..ForceRegularMode::default()
609 },
610 ..RegularMode::default()
611 },
612 }
613 }
614
615 pub fn reopen_moved_files(self, v: bool) -> Sync<RegularMode<ForceRegularMode>> {
626 Sync {
627 bin: self.bin,
628 global_opts: self.global_opts,
629 mode: RegularMode {
630 mode: ForceRegularMode {
631 reopen_moved_files: v,
632 ..ForceRegularMode::default()
633 },
634 ..RegularMode::default()
635 },
636 }
637 }
638}
639
640impl<Mode: ExclusiveOption, P: ExclusiveOption> Sync<RegularMode<Mode, P>> {
643 pub fn get_verify_edge_replication(&self) -> bool {
645 self.mode.verify_edge_replication
646 }
647
648 pub fn set_verify_edge_replication(&mut self, v: bool) -> &mut Self {
650 self.mode.verify_edge_replication = v;
651 self
652 }
653
654 pub fn verify_edge_replication(mut self, v: bool) -> Self {
656 self.mode.verify_edge_replication = v;
657 self
658 }
659
660 pub fn get_script_list_mode(&self) -> bool {
662 self.mode.script_list_mode
663 }
664
665 pub fn set_script_list_mode(&mut self, v: bool) -> &mut Self {
667 self.mode.script_list_mode = v;
668 self
669 }
670
671 pub fn script_list_mode(mut self, v: bool) -> Self {
673 self.mode.script_list_mode = v;
674 self
675 }
676
677 pub fn get_suppress_keyword_expansion(&self) -> bool {
679 self.mode.suppress_keyword_expansion
680 }
681
682 pub fn set_suppress_keyword_expansion(&mut self, v: bool) -> &mut Self {
684 self.mode.suppress_keyword_expansion = v;
685 self
686 }
687
688 pub fn suppress_keyword_expansion(mut self, v: bool) -> Self {
690 self.mode.suppress_keyword_expansion = v;
691 self
692 }
693
694 pub fn get_quiet_mode(&self) -> bool {
696 self.mode.quiet_mode
697 }
698
699 pub fn set_quiet_mode(&mut self, v: bool) -> &mut Self {
701 self.mode.quiet_mode = v;
702 self
703 }
704
705 pub fn quiet_mode(mut self, v: bool) -> Self {
707 self.mode.quiet_mode = v;
708 self
709 }
710
711 pub fn get_limit(&self) -> Option<u64> {
713 self.mode.limit
714 }
715
716 pub fn set_limit(&mut self, v: u64) -> &mut Self {
718 self.mode.limit = Some(v);
719 self
720 }
721
722 pub fn limit(mut self, v: u64) -> Self {
724 self.mode.limit = Some(v);
725 self
726 }
727
728 pub fn get_parallel(&self) -> Option<&ParallelConfig> {
730 self.mode.parallel.as_ref()
731 }
732
733 pub fn set_parallel(&mut self, v: ParallelConfig) -> &mut Self {
735 self.mode.parallel = Some(v);
736 self
737 }
738
739 pub fn parallel(mut self, v: ParallelConfig) -> Self {
741 self.mode.parallel = Some(v);
742 self
743 }
744
745 pub fn get_stream_spec_version(&self) -> Option<StreamSpecVersion> {
747 self.mode.stream_spec_version
748 }
749
750 pub fn set_stream_spec_version(&mut self, v: StreamSpecVersion) -> &mut Self {
752 self.mode.stream_spec_version = Some(v);
753 self
754 }
755
756 pub fn stream_spec_version(mut self, v: StreamSpecVersion) -> Self {
758 self.mode.stream_spec_version = Some(v);
759 self
760 }
761
762 pub fn set_sc_max_change_number(&mut self) -> &mut Self {
765 self.mode.stream_spec_version = Some(StreamSpecVersion::MaxInFilelists);
766 self
767 }
768
769 pub fn sc_max_change_number(mut self) -> Self {
772 self.mode.stream_spec_version = Some(StreamSpecVersion::MaxInFilelists);
773 self
774 }
775
776 pub fn set_sc_current_stream_spec(&mut self) -> &mut Self {
778 self.mode.stream_spec_version = Some(StreamSpecVersion::Current);
779 self
780 }
781
782 pub fn sc_current_stream_spec(mut self) -> Self {
784 self.mode.stream_spec_version = Some(StreamSpecVersion::Current);
785 self
786 }
787
788 pub fn set_sc_change_number(&mut self, n: u32) -> &mut Self {
791 self.mode.stream_spec_version = Some(StreamSpecVersion::ChangeNumber(n));
792 self
793 }
794
795 pub fn sc_change_number(mut self, n: u32) -> Self {
798 self.mode.stream_spec_version = Some(StreamSpecVersion::ChangeNumber(n));
799 self
800 }
801}
802
803impl<P: ExclusiveOption> Sync<RegularMode<Unselected, P>> {
806 pub fn force(self, v: bool) -> Sync<RegularMode<ForceRegularMode, P>> {
816 Sync {
817 bin: self.bin,
818 global_opts: self.global_opts,
819 mode: RegularMode {
820 verify_edge_replication: self.mode.verify_edge_replication,
821 script_list_mode: self.mode.script_list_mode,
822 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
823 quiet_mode: self.mode.quiet_mode,
824 limit: self.mode.limit,
825 parallel: self.mode.parallel,
826 stream_spec_version: self.mode.stream_spec_version,
827 mode: ForceRegularMode {
828 force: v,
829 ..ForceRegularMode::default()
830 },
831 preview: self.mode.preview,
832 },
833 }
834 }
835
836 pub fn metadata_only(self, v: bool) -> Sync<RegularMode<ForceRegularMode, P>> {
846 Sync {
847 bin: self.bin,
848 global_opts: self.global_opts,
849 mode: RegularMode {
850 verify_edge_replication: self.mode.verify_edge_replication,
851 script_list_mode: self.mode.script_list_mode,
852 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
853 quiet_mode: self.mode.quiet_mode,
854 limit: self.mode.limit,
855 parallel: self.mode.parallel,
856 stream_spec_version: self.mode.stream_spec_version,
857 mode: ForceRegularMode {
858 metadata_only: v,
859 ..ForceRegularMode::default()
860 },
861 preview: self.mode.preview,
862 },
863 }
864 }
865
866 pub fn reopen_moved_files(self, v: bool) -> Sync<RegularMode<ForceRegularMode, P>> {
876 Sync {
877 bin: self.bin,
878 global_opts: self.global_opts,
879 mode: RegularMode {
880 verify_edge_replication: self.mode.verify_edge_replication,
881 script_list_mode: self.mode.script_list_mode,
882 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
883 quiet_mode: self.mode.quiet_mode,
884 limit: self.mode.limit,
885 parallel: self.mode.parallel,
886 stream_spec_version: self.mode.stream_spec_version,
887 mode: ForceRegularMode {
888 reopen_moved_files: v,
889 ..ForceRegularMode::default()
890 },
891 preview: self.mode.preview,
892 },
893 }
894 }
895
896 pub fn safe_check(self) -> Sync<RegularMode<SafeCheckMode, P>> {
907 Sync {
908 bin: self.bin,
909 global_opts: self.global_opts,
910 mode: RegularMode {
911 verify_edge_replication: self.mode.verify_edge_replication,
912 script_list_mode: self.mode.script_list_mode,
913 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
914 quiet_mode: self.mode.quiet_mode,
915 limit: self.mode.limit,
916 parallel: self.mode.parallel,
917 stream_spec_version: self.mode.stream_spec_version,
918 mode: SafeCheckMode,
919 preview: self.mode.preview,
920 },
921 }
922 }
923
924 pub fn populate(self) -> Sync<RegularMode<PopulateMode, P>> {
934 Sync {
935 bin: self.bin,
936 global_opts: self.global_opts,
937 mode: RegularMode {
938 verify_edge_replication: self.mode.verify_edge_replication,
939 script_list_mode: self.mode.script_list_mode,
940 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
941 quiet_mode: self.mode.quiet_mode,
942 limit: self.mode.limit,
943 parallel: self.mode.parallel,
944 stream_spec_version: self.mode.stream_spec_version,
945 mode: PopulateMode,
946 preview: self.mode.preview,
947 },
948 }
949 }
950}
951
952impl<Mode: ExclusiveOption> Sync<RegularMode<Mode, Unselected>> {
955 pub fn preview_result(self) -> Sync<RegularMode<Mode, PreviewResult>> {
962 Sync {
963 bin: self.bin,
964 global_opts: self.global_opts,
965 mode: RegularMode {
966 verify_edge_replication: self.mode.verify_edge_replication,
967 script_list_mode: self.mode.script_list_mode,
968 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
969 quiet_mode: self.mode.quiet_mode,
970 limit: self.mode.limit,
971 parallel: self.mode.parallel,
972 stream_spec_version: self.mode.stream_spec_version,
973 mode: self.mode.mode,
974 preview: PreviewResult,
975 },
976 }
977 }
978
979 pub fn preview_network_traffic(self) -> Sync<RegularMode<Mode, PreviewNetworkTraffic>> {
986 Sync {
987 bin: self.bin,
988 global_opts: self.global_opts,
989 mode: RegularMode {
990 verify_edge_replication: self.mode.verify_edge_replication,
991 script_list_mode: self.mode.script_list_mode,
992 suppress_keyword_expansion: self.mode.suppress_keyword_expansion,
993 quiet_mode: self.mode.quiet_mode,
994 limit: self.mode.limit,
995 parallel: self.mode.parallel,
996 stream_spec_version: self.mode.stream_spec_version,
997 mode: self.mode.mode,
998 preview: PreviewNetworkTraffic,
999 },
1000 }
1001 }
1002}
1003
1004impl<P: ExclusiveOption> Sync<RegularMode<ForceRegularMode, P>> {
1007 pub fn get_force(&self) -> bool {
1009 self.mode.mode.force
1010 }
1011
1012 pub fn set_force(&mut self, v: bool) -> &mut Self {
1014 self.mode.mode.force = v;
1015 self
1016 }
1017
1018 pub fn force(mut self, v: bool) -> Self {
1020 self.mode.mode.force = v;
1021 self
1022 }
1023
1024 pub fn get_metadata_only(&self) -> bool {
1026 self.mode.mode.metadata_only
1027 }
1028
1029 pub fn set_metadata_only(&mut self, v: bool) -> &mut Self {
1031 self.mode.mode.metadata_only = v;
1032 self
1033 }
1034
1035 pub fn metadata_only(mut self, v: bool) -> Self {
1037 self.mode.mode.metadata_only = v;
1038 self
1039 }
1040
1041 pub fn get_reopen_moved_files(&self) -> bool {
1043 self.mode.mode.reopen_moved_files
1044 }
1045
1046 pub fn set_reopen_moved_files(&mut self, v: bool) -> &mut Self {
1048 self.mode.mode.reopen_moved_files = v;
1049 self
1050 }
1051
1052 pub fn reopen_moved_files(mut self, v: bool) -> Self {
1054 self.mode.mode.reopen_moved_files = v;
1055 self
1056 }
1057}
1058
1059impl Sync<SyncTimeMode> {
1062 pub fn get_sync_time(&self) -> &str {
1064 &self.mode.sync_time
1065 }
1066
1067 pub fn set_sync_time(&mut self, v: impl Into<String>) -> &mut Self {
1070 self.mode.sync_time = v.into();
1071 self
1072 }
1073
1074 pub fn sync_time(mut self, v: impl Into<String>) -> Self {
1077 self.mode.sync_time = v.into();
1078 self
1079 }
1080}
1081
1082impl<M: ExclusiveOption> ParameterizedSpawn for Sync<M> {
1085 type Input<'a> = &'a [&'a OsStr];
1086 type Output<'a> = Child;
1087 type Error = std::io::Error;
1088
1089 fn spawn_with<'a>(&mut self, files: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
1093 self.setup_command(&self.bin)
1094 .args(files)
1095 .stdout(Stdio::piped())
1096 .stderr(Stdio::piped())
1097 .spawn()
1098 }
1099}
1100
1101impl<M: ExclusiveOption> Sync<M> {
1102 pub fn get_global_opts(&self) -> &GlobalOpts {
1108 &self.global_opts
1109 }
1110
1111 pub fn set_global_opts(&mut self, v: GlobalOpts) -> &mut Self {
1117 self.global_opts = v;
1118 self
1119 }
1120
1121 pub fn global_opts(mut self, v: GlobalOpts) -> Self {
1127 self.global_opts = v;
1128 self
1129 }
1130}
1131
1132impl<M: ExclusiveOption> SubCommand for Sync<M> {
1133 fn name(&self) -> &str {
1134 "sync"
1135 }
1136
1137 fn inject_local_args(&self, command: &mut Command) {
1138 self.mode.inject_args(command);
1139 }
1140
1141 fn global_opts(&self) -> Option<&GlobalOpts> {
1142 Some(&self.global_opts)
1143 }
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148 use super::*;
1149 use crate::cmd::args_of;
1150
1151 #[test]
1152 fn without_options() {
1153 let sync = Sync::new("p4", GlobalOpts::new());
1154
1155 assert_eq!(args_of(&sync.setup_command("p4")), ["sync"]);
1156 }
1157
1158 #[test]
1159 fn sync_time_mode() {
1160 let sync = Sync::new("p4", GlobalOpts::new()).sync_time("2024/01/01");
1161
1162 assert_eq!(
1163 args_of(&sync.setup_command("p4")),
1164 ["sync", "-k", "--sync-time=2024/01/01"]
1165 );
1166 }
1167
1168 #[test]
1169 fn sync_time_mode_epoch() {
1170 let sync = Sync::new("p4", GlobalOpts::new()).sync_time("1700000000");
1171
1172 assert_eq!(
1173 args_of(&sync.setup_command("p4")),
1174 ["sync", "-k", "--sync-time=1700000000"]
1175 );
1176 }
1177
1178 #[test]
1179 fn sync_time_set_style() {
1180 let mut sync = Sync::new("p4", GlobalOpts::new()).sync_time("2024/01/01");
1181 sync.set_sync_time("2024/06/01");
1182
1183 assert_eq!(sync.get_sync_time(), "2024/06/01");
1184 assert_eq!(
1185 args_of(&sync.setup_command("p4")),
1186 ["sync", "-k", "--sync-time=2024/06/01"]
1187 );
1188 }
1189
1190 #[test]
1191 fn regular_mode_common_options() {
1192 let sync = Sync::new("p4", GlobalOpts::new())
1193 .verify_edge_replication(true)
1194 .script_list_mode(true)
1195 .suppress_keyword_expansion(true)
1196 .quiet_mode(true)
1197 .limit(5);
1198
1199 assert_eq!(
1200 args_of(&sync.setup_command("p4")),
1201 ["sync", "-E", "-L", "-K", "-q", "-m", "5"]
1202 );
1203 }
1204
1205 #[test]
1206 fn regular_mode_force_options() {
1207 let sync = Sync::new("p4", GlobalOpts::new())
1208 .force(true)
1209 .metadata_only(true)
1210 .reopen_moved_files(true);
1211
1212 assert_eq!(
1213 args_of(&sync.setup_command("p4")),
1214 ["sync", "-f", "-k", "-r"]
1215 );
1216 }
1217
1218 #[test]
1219 fn regular_mode_combined() {
1220 let sync = Sync::new("p4", GlobalOpts::new())
1221 .quiet_mode(true)
1222 .force(true)
1223 .limit(10);
1224
1225 assert_eq!(
1226 args_of(&sync.setup_command("p4")),
1227 ["sync", "-q", "-f", "-m", "10"]
1228 );
1229 }
1230
1231 #[test]
1232 fn regular_mode_preview_result() {
1233 let sync = Sync::new("p4", GlobalOpts::new()).preview_result();
1234
1235 assert_eq!(args_of(&sync.setup_command("p4")), ["sync", "-n"]);
1236 }
1237
1238 #[test]
1239 fn regular_mode_preview_network_traffic() {
1240 let sync = Sync::new("p4", GlobalOpts::new()).preview_network_traffic();
1241
1242 assert_eq!(args_of(&sync.setup_command("p4")), ["sync", "-N"]);
1243 }
1244
1245 #[test]
1246 fn regular_mode_preview_with_options() {
1247 let sync = Sync::new("p4", GlobalOpts::new())
1248 .quiet_mode(true)
1249 .preview_result()
1250 .limit(3);
1251
1252 assert_eq!(
1253 args_of(&sync.setup_command("p4")),
1254 ["sync", "-q", "-n", "-m", "3"]
1255 );
1256 }
1257
1258 #[test]
1259 fn regular_mode_parallel() {
1260 let sync = Sync::new("p4", GlobalOpts::new()).parallel(ParallelConfig {
1261 threads: 4,
1262 batch_files: Some(8),
1263 batch_size_bytes: None,
1264 min_files: Some(9),
1265 min_size_bytes: None,
1266 });
1267
1268 assert_eq!(
1269 args_of(&sync.setup_command("p4")),
1270 ["sync", "--parallel=threads=4,batch=8,min=9"]
1271 );
1272 }
1273
1274 #[test]
1275 fn regular_mode_stream_spec_auto() {
1276 let sync = Sync::new("p4", GlobalOpts::new())
1277 .stream_spec_version(StreamSpecVersion::MaxInFilelists);
1278
1279 assert_eq!(
1280 args_of(&sync.setup_command("p4")),
1281 ["sync", "--use-stream-change"]
1282 );
1283 }
1284
1285 #[test]
1286 fn regular_mode_stream_spec_current() {
1287 let sync =
1288 Sync::new("p4", GlobalOpts::new()).stream_spec_version(StreamSpecVersion::Current);
1289
1290 assert_eq!(
1291 args_of(&sync.setup_command("p4")),
1292 ["sync", "--use-stream-change=0"]
1293 );
1294 }
1295
1296 #[test]
1297 fn regular_mode_stream_spec_specific() {
1298 let sync = Sync::new("p4", GlobalOpts::new())
1299 .stream_spec_version(StreamSpecVersion::ChangeNumber(123));
1300
1301 assert_eq!(
1302 args_of(&sync.setup_command("p4")),
1303 ["sync", "--use-stream-change=123"]
1304 );
1305 }
1306
1307 #[test]
1308 fn safe_check_mode() {
1309 let sync = Sync::new("p4", GlobalOpts::new()).enable_safe_check();
1310
1311 assert_eq!(args_of(&sync.setup_command("p4")), ["sync", "-s"]);
1312 }
1313
1314 #[test]
1315 fn safe_check_mode_with_options() {
1316 let sync = Sync::new("p4", GlobalOpts::new())
1317 .enable_safe_check()
1318 .quiet_mode(true)
1319 .limit(5);
1320
1321 assert_eq!(
1322 args_of(&sync.setup_command("p4")),
1323 ["sync", "-q", "-s", "-m", "5"]
1324 );
1325 }
1326
1327 #[test]
1328 fn populate_mode() {
1329 let sync = Sync::new("p4", GlobalOpts::new()).populate_client_workspace();
1330
1331 assert_eq!(args_of(&sync.setup_command("p4")), ["sync", "-p"]);
1332 }
1333
1334 #[test]
1335 fn populate_mode_with_options() {
1336 let sync = Sync::new("p4", GlobalOpts::new())
1337 .populate_client_workspace()
1338 .quiet_mode(true)
1339 .limit(5);
1340
1341 assert_eq!(
1342 args_of(&sync.setup_command("p4")),
1343 ["sync", "-q", "-p", "-m", "5"]
1344 );
1345 }
1346
1347 #[test]
1348 fn transition_to_safe_check_from_regular() {
1349 let sync = Sync::new("p4", GlobalOpts::new())
1350 .quiet_mode(true)
1351 .limit(5)
1352 .safe_check();
1353
1354 assert_eq!(
1355 args_of(&sync.setup_command("p4")),
1356 ["sync", "-q", "-s", "-m", "5"]
1357 );
1358 }
1359
1360 #[test]
1361 fn transition_to_populate_from_regular() {
1362 let sync = Sync::new("p4", GlobalOpts::new())
1363 .quiet_mode(true)
1364 .limit(5)
1365 .populate();
1366
1367 assert_eq!(
1368 args_of(&sync.setup_command("p4")),
1369 ["sync", "-q", "-p", "-m", "5"]
1370 );
1371 }
1372
1373 #[test]
1374 fn transition_preserves_preview() {
1375 let sync = Sync::new("p4", GlobalOpts::new())
1376 .preview_result()
1377 .quiet_mode(true)
1378 .safe_check();
1379
1380 assert_eq!(
1381 args_of(&sync.setup_command("p4")),
1382 ["sync", "-q", "-s", "-n"]
1383 );
1384 }
1385
1386 #[test]
1387 fn force_mode_blocks_safe_check() {
1388 let sync = Sync::new("p4", GlobalOpts::new())
1391 .force(true)
1392 .quiet_mode(true);
1393
1394 assert_eq!(args_of(&sync.setup_command("p4")), ["sync", "-q", "-f"]);
1395 }
1396
1397 #[test]
1398 fn all_regular_options_order() {
1399 let sync = Sync::new("p4", GlobalOpts::new())
1400 .verify_edge_replication(true)
1401 .script_list_mode(true)
1402 .suppress_keyword_expansion(true)
1403 .quiet_mode(true)
1404 .force(true)
1405 .metadata_only(true)
1406 .reopen_moved_files(true)
1407 .limit(5)
1408 .parallel(ParallelConfig {
1409 threads: 2,
1410 batch_files: None,
1411 batch_size_bytes: None,
1412 min_files: None,
1413 min_size_bytes: None,
1414 })
1415 .stream_spec_version(StreamSpecVersion::Current);
1416
1417 assert_eq!(
1418 args_of(&sync.setup_command("p4")),
1419 [
1420 "sync",
1421 "-E",
1422 "-L",
1423 "-K",
1424 "-q",
1425 "-f",
1426 "-k",
1427 "-r",
1428 "-m",
1429 "5",
1430 "--parallel=threads=2",
1431 "--use-stream-change=0",
1432 ]
1433 );
1434 }
1435}