proto_pdk_api/api/
build.rs

1use super::source::*;
2use crate::PluginContext;
3use derive_setters::Setters;
4use rustc_hash::FxHashMap;
5use semver::VersionReq;
6use std::path::PathBuf;
7use system_env::SystemDependency;
8use warpgate_api::{Id, VirtualPath, api_enum, api_struct};
9
10api_struct!(
11    /// Input passed to the `build_instructions` function.
12    pub struct BuildInstructionsInput {
13        /// Current tool context.
14        pub context: PluginContext,
15
16        /// Virtual directory to install to.
17        pub install_dir: VirtualPath,
18    }
19);
20
21api_struct!(
22    /// A builder and its parameters for installing the builder.
23    #[derive(Setters)]
24    pub struct BuilderInstruction {
25        /// Unique identifier for this builder.
26        #[setters(into)]
27        pub id: Id,
28
29        /// Primary executable, relative from the source root.
30        pub exe: PathBuf,
31
32        /// Secondary executables, relative from the source root.
33        #[serde(default, skip_serializing_if = "FxHashMap::is_empty")]
34        pub exes: FxHashMap<String, PathBuf>,
35
36        /// The Git source location for the builder.
37        pub git: GitSource,
38    }
39);
40
41api_struct!(
42    /// A command and its parameters to be executed as a child process.
43    #[derive(Setters)]
44    pub struct CommandInstruction {
45        /// If the executable should reference a builder executable.
46        pub builder: bool,
47
48        /// List of arguments.
49        #[serde(default, skip_serializing_if = "Vec::is_empty")]
50        pub args: Vec<String>,
51
52        /// Map of environment variables.
53        #[serde(default, skip_serializing_if = "FxHashMap::is_empty")]
54        pub env: FxHashMap<String, String>,
55
56        /// The executable on `PATH`.
57        #[setters(into)]
58        #[serde(alias = "bin")]
59        pub exe: String,
60
61        /// The working directory.
62        #[setters(strip_option)]
63        #[serde(default, skip_serializing_if = "Option::is_none")]
64        pub cwd: Option<PathBuf>,
65    }
66);
67
68impl CommandInstruction {
69    /// Create a new command with the executable and arguments.
70    pub fn new<T: AsRef<str>, I: IntoIterator<Item = V>, V: AsRef<str>>(exe: T, args: I) -> Self {
71        Self {
72            builder: false,
73            exe: exe.as_ref().to_owned(),
74            args: args
75                .into_iter()
76                .map(|arg| arg.as_ref().to_owned())
77                .collect(),
78            env: FxHashMap::default(),
79            cwd: None,
80        }
81    }
82
83    /// Create a new command that executes an executable from a builder with the arguments.
84    pub fn with_builder<T: AsRef<str>, I: IntoIterator<Item = V>, V: AsRef<str>>(
85        id: T,
86        args: I,
87    ) -> Self {
88        let mut cmd = Self::new(id, args);
89        cmd.builder = true;
90        cmd
91    }
92}
93
94api_enum!(
95    /// An instruction to execute.
96    #[serde(tag = "type", content = "instruction", rename_all = "kebab-case")]
97    pub enum BuildInstruction {
98        /// Install a builder locally that can be referenced in subsequent instructions.
99        InstallBuilder(Box<BuilderInstruction>),
100
101        /// Update a file and make it executable.
102        MakeExecutable(PathBuf),
103
104        /// Move a file from source to destination.
105        MoveFile(PathBuf, PathBuf),
106
107        /// Remove all files except those matching the provided list.
108        RemoveAllExcept(Vec<PathBuf>),
109
110        /// Remove a directory.
111        RemoveDir(PathBuf),
112
113        /// Remove a file.
114        RemoveFile(PathBuf),
115
116        /// Request (curl, wget, etc) a script and download to the host.
117        RequestScript(String),
118
119        /// Execute a command as a child process.
120        #[cfg_attr(feature = "schematic", schema(nested))]
121        RunCommand(Box<CommandInstruction>),
122
123        /// Set an environment variable.
124        SetEnvVar(String, String),
125    }
126);
127
128api_enum!(
129    /// Is required and must exist in the current environment.
130    #[serde(tag = "type", content = "requirement", rename_all = "kebab-case")]
131    pub enum BuildRequirement {
132        CommandExistsOnPath(String),
133        CommandVersion(String, VersionReq, Option<String>),
134        ManualIntercept(String), // url
135        GitConfigSetting(String, String),
136        GitVersion(VersionReq),
137        // macOS
138        XcodeCommandLineTools,
139        // Windows
140        WindowsDeveloperMode,
141    }
142);
143
144api_struct!(
145    /// Output returned by the `build_instructions` function.
146    #[serde(default)]
147    pub struct BuildInstructionsOutput {
148        /// Link to the documentation/help.
149        #[serde(skip_serializing_if = "Option::is_none")]
150        pub help_url: Option<String>,
151
152        /// List of instructions to execute to build the tool, after system
153        /// dependencies have been installed.
154        #[serde(skip_serializing_if = "Vec::is_empty")]
155        pub instructions: Vec<BuildInstruction>,
156
157        /// List of requirements that must be met before dependencies are
158        /// installed and instructions are executed.
159        #[serde(skip_serializing_if = "Vec::is_empty")]
160        pub requirements: Vec<BuildRequirement>,
161
162        /// Location in which to acquire the source files.
163        #[serde(skip_serializing_if = "Option::is_none")]
164        pub source: Option<SourceLocation>,
165
166        /// List of system dependencies that are required for building from source.
167        /// If a dependency does not exist, it will be installed.
168        #[serde(skip_serializing_if = "Vec::is_empty")]
169        pub system_dependencies: Vec<SystemDependency>,
170    }
171);