Skip to main content

perforce_cli/
lib.rs

1use std::path::{Path, PathBuf};
2
3use crate::cmd::Add;
4use crate::cmd::AdminEntry;
5#[cfg(not(feature = "lt2016_1"))]
6use crate::cmd::Aliases;
7use crate::cmd::Annotate;
8use crate::cmd::Archive;
9use crate::cmd::Attribute;
10#[cfg(not(feature = "lt2017_2"))]
11use crate::cmd::BackGroundTask;
12use crate::cmd::Branch;
13use crate::cmd::Branches;
14use crate::cmd::CachePurge;
15use crate::cmd::Change;
16use crate::cmd::Changes;
17use crate::cmd::Clean;
18use crate::cmd::Client;
19use crate::cmd::Clients;
20use crate::cmd::Describe;
21use crate::cmd::Diff;
22use crate::cmd::Diff2;
23use crate::cmd::Edit;
24use crate::cmd::FileLog;
25use crate::cmd::Print;
26use crate::cmd::Sync;
27use crate::cmd::Where;
28use crate::global::GlobalOpts;
29
30pub mod cmd;
31pub mod global;
32pub mod spawn;
33
34pub mod prelude {
35    pub use crate::cmd::*;
36    pub use crate::global::*;
37    pub use crate::spawn::*;
38}
39
40#[derive(Debug, Clone)]
41pub struct P4Cli {
42    bin: PathBuf,
43
44    global_opts: GlobalOpts,
45}
46
47impl Default for P4Cli {
48    fn default() -> Self {
49        Self {
50            bin: PathBuf::from("p4"),
51            global_opts: GlobalOpts::default(),
52        }
53    }
54}
55
56impl P4Cli {
57    /// Create a new Perforce command-line client.
58    ///
59    /// `bin` is the path to the Perforce command-line executable.
60    pub fn new(bin: impl Into<PathBuf>, global_opts: GlobalOpts) -> Self {
61        Self {
62            bin: bin.into(),
63            global_opts,
64        }
65    }
66
67    /// Set the Perforce command path.
68    pub fn bin(mut self, bin: impl Into<PathBuf>) -> Self {
69        self.set_bin(bin);
70        self
71    }
72
73    /// Set the global options.
74    pub fn global_opts(mut self, global_opts: GlobalOpts) -> Self {
75        self.set_global_opts(global_opts);
76        self
77    }
78
79    /// Get the Perforce command path.
80    pub fn get_bin(&self) -> &Path {
81        &self.bin
82    }
83
84    /// Get the global options.
85    pub fn get_global_opts(&self) -> &GlobalOpts {
86        &self.global_opts
87    }
88
89    /// Set the Perforce command path.
90    pub fn set_bin(&mut self, bin: impl Into<PathBuf>) {
91        self.bin = bin.into();
92    }
93
94    /// Set the global options.
95    pub fn set_global_opts(&mut self, global_opts: GlobalOpts) {
96        self.global_opts = global_opts;
97    }
98
99    /// Open files in a client workspace for addition to the depot.
100    pub fn add(&self) -> Add {
101        Add::new(self.bin.clone(), self.global_opts.clone())
102    }
103
104    /// Perform administrative operations on the server.
105    pub fn admin(&self) -> AdminEntry {
106        AdminEntry::new(self.bin.clone(), self.global_opts.clone())
107    }
108
109    /// Display command aliases that are currently defined in a .p4aliases file.
110    #[cfg(not(feature = "lt2016_1"))]
111    pub fn aliases(&self) -> Aliases {
112        Aliases::new(self.bin.clone(), self.global_opts.clone())
113    }
114
115    /// Print file lines along with their revisions.
116    pub fn annotate(&self) -> Annotate {
117        Annotate::new(self.bin.clone(), self.global_opts.clone())
118    }
119
120    /// Archive obsolete revisions to an archive depot.
121    pub fn archive(&self) -> Archive {
122        Archive::new(self.bin.clone(), self.global_opts.clone())
123    }
124
125    /// Set per-revision attributes on file revisions.
126    pub fn attribute(&self) -> Attribute {
127        Attribute::new(self.bin.clone(), self.global_opts.clone())
128    }
129
130    /// Run a background command or trigger on the server.
131    ///
132    /// The returned builder starts with no task target; call
133    /// [`BackGroundTask::execute`] (`-e`) or [`BackGroundTask::trigger`]
134    /// (`-t`) to select the required target before spawning.
135    #[cfg(not(feature = "lt2017_2"))]
136    pub fn bgtask(&self) -> BackGroundTask {
137        BackGroundTask::new(self.bin.clone(), self.global_opts.clone())
138    }
139
140    /// Create or edit a branch mapping and its view.
141    pub fn branch(&self) -> Branch {
142        Branch::new(self.bin.clone(), self.global_opts.clone())
143    }
144
145    /// List existing branch mappings.
146    pub fn branches(&self) -> Branches {
147        Branches::new(self.bin.clone(), self.global_opts.clone())
148    }
149
150    /// Reclaim disk space on a replicated server.
151    ///
152    /// The returned builder starts with no purge goal and has no effect;
153    /// call [`CachePurge::purge_all`] (`-a`), [`CachePurge::free_space`]
154    /// (`-f`), [`CachePurge::revision_count`] (`-m`), or
155    /// [`CachePurge::size`] (`-s`) to select the required goal before
156    /// spawning.
157    pub fn cachepurge(&self) -> CachePurge {
158        CachePurge::new(self.bin.clone(), self.global_opts.clone())
159    }
160
161    /// Restore client workspace files to match the state of corresponding
162    /// depot files.
163    ///
164    /// Without file arguments, the files in your local working directory are
165    /// used; pass file arguments to
166    /// [`ParameterizedSpawn::spawn_with`](crate::spawn::ParameterizedSpawn::spawn_with)
167    /// to limit the scope.
168    pub fn clean(&self) -> Clean {
169        Clean::new(self.bin.clone(), self.global_opts.clone())
170    }
171
172    /// Create or edit a client workspace specification and its view.
173    ///
174    /// The returned builder starts in the [`GeneralMode`](crate::cmd::client::GeneralMode)
175    /// state (`p4 client [-f] [-t template] [-T type] [name]`); call
176    /// transition methods such as [`Client::delete`](crate::cmd::client::Client::delete)
177    /// or [`Client::stdout`](crate::cmd::client::Client::stdout) to select
178    /// another syntax form.
179    pub fn client(&self) -> Client {
180        Client::new(self.bin.clone(), self.global_opts.clone())
181    }
182
183    /// List all client workspaces currently known to the system.
184    ///
185    /// The returned builder starts with no option selected and spawns the
186    /// bare `p4 clients` report as is; set any regular option or filter to
187    /// enter the [`RegularMode`](crate::cmd::clients::RegularMode) state, or
188    /// call [`Clients::unloaded`](crate::cmd::clients::Clients::unloaded)
189    /// (`-U`) to list only unloaded client workspaces.
190    pub fn clients(&self) -> Clients {
191        Clients::new(self.bin.clone(), self.global_opts.clone())
192    }
193
194    /// List all client workspaces currently known to the system.
195    ///
196    /// This is an alias for [`Self::clients`], corresponding to the `p4
197    /// workspaces` command.
198    pub fn workspaces(&self) -> Clients {
199        Clients::new(self.bin.clone(), self.global_opts.clone())
200    }
201
202    /// Create or edit a client workspace specification and its view.
203    ///
204    /// This is an alias for [`Self::client`], corresponding to the `p4
205    /// workspace` command.
206    pub fn workspace(&self) -> Client {
207        Client::new(self.bin.clone(), self.global_opts.clone())
208    }
209
210    /// Create or edit a changelist specification.
211    pub fn change(&self) -> Change {
212        Change::new(self.bin.clone(), self.global_opts.clone())
213    }
214
215    /// Create or edit a changelist specification.
216    ///
217    /// This is an alias for [`Self::change`], corresponding to the `p4
218    /// changelist` command.
219    pub fn changelist(&self) -> Change {
220        Change::new(self.bin.clone(), self.global_opts.clone())
221    }
222
223    /// List submitted and pending changelists.
224    pub fn changes(&self) -> Changes {
225        Changes::new(self.bin.clone(), self.global_opts.clone())
226    }
227
228    /// List submitted and pending changelists.
229    ///
230    /// This is an alias for [`Self::changes`], corresponding to the `p4
231    /// changelists` command.
232    pub fn changelists(&self) -> Changes {
233        Changes::new(self.bin.clone(), self.global_opts.clone())
234    }
235
236    /// Display the details of one or more changelists.
237    pub fn describe(&self) -> Describe {
238        Describe::new(self.bin.clone(), self.global_opts.clone())
239    }
240
241    /// Diff workspace content against depot content, or diff stream specs.
242    pub fn diff(&self) -> Diff {
243        Diff::new(self.bin.clone(), self.global_opts.clone())
244    }
245
246    /// Compare the content at two depot paths, or compare two stream specs.
247    pub fn diff2(&self) -> Diff2 {
248        Diff2::new(self.bin.clone(), self.global_opts.clone())
249    }
250
251    /// Open files in a client workspace for edit.
252    pub fn edit(&self) -> Edit {
253        Edit::new(self.bin.clone(), self.global_opts.clone())
254    }
255
256    /// Print detailed information about the revisions of files.
257    pub fn filelog(&self) -> FileLog {
258        FileLog::new(self.bin.clone(), self.global_opts.clone())
259    }
260
261    /// Print the contents of depot file revisions.
262    pub fn print(&self) -> Print {
263        Print::new(self.bin.clone(), self.global_opts.clone())
264    }
265
266    /// Update the client workspace to reflect the contents of the depot.
267    pub fn sync(&self) -> Sync {
268        Sync::new(self.bin.clone(), self.global_opts.clone())
269    }
270
271    /// Show where a particular file is located, as determined by the client view.
272    pub fn r#where(&self) -> Where {
273        Where::new(self.bin.clone(), self.global_opts.clone())
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use super::*;
280
281    #[test]
282    fn default_uses_p4_from_path() {
283        let p4 = P4Cli::default();
284
285        assert_eq!(p4.get_bin(), Path::new("p4"));
286    }
287
288    #[test]
289    fn accepts_custom_bin_path() {
290        let p4 = P4Cli::new("C:\\tools\\p4.exe", GlobalOpts::default());
291
292        assert_eq!(p4.get_bin(), Path::new("C:\\tools\\p4.exe"));
293    }
294}