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