proto_pdk_api/api/mod.rs
1mod build;
2mod checksum;
3mod source;
4
5use crate::shapes::*;
6use derive_setters::Setters;
7use rustc_hash::FxHashMap;
8use schematic::Schema;
9use std::path::PathBuf;
10use version_spec::{CalVer, SemVer, SpecError, UnresolvedVersionSpec, VersionSpec};
11use warpgate_api::*;
12
13pub use build::*;
14pub use checksum::*;
15pub use semver::{Version, VersionReq};
16pub use source::*;
17
18/// Enumeration of all available plugin functions that can be implemented by plugins.
19///
20/// This enum provides type-safe access to plugin function names and eliminates
21/// the risk of typos when calling plugin functions. Each variant corresponds to
22/// a specific plugin function with its associated input/output types.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum PluginFunction {
25 /// Register and configure a tool with proto.
26 ///
27 /// Called when proto first loads a plugin to get basic metadata about the tool
28 /// including its name, type, and configuration schema.
29 ///
30 /// **Input:** [`RegisterToolInput`] | **Output:** [`RegisterToolOutput`]
31 RegisterTool,
32
33 /// Define the tool configuration schema.
34 ///
35 /// **Input:** [`DefineToolConfigInput`] | **Output:** [`DefineToolConfigOutput`]
36 DefineToolConfig,
37
38 /// Register a backend with proto.
39 ///
40 /// Allows plugins to define custom backends for sourcing tools from locations
41 /// other than the default registry.
42 ///
43 /// **Input:** [`RegisterBackendInput`] | **Output:** [`RegisterBackendOutput`]
44 RegisterBackend,
45
46 /// Define the backend configuration schema.
47 ///
48 /// **Input:** [`DefineBackendConfigInput`] | **Output:** [`DefineBackendConfigOutput`]
49 DefineBackendConfig,
50
51 /// Detect version files in a project.
52 ///
53 /// Returns a list of file patterns that should be checked for version information
54 /// when auto-detecting tool versions.
55 ///
56 /// **Input:** [`DetectVersionInput`] | **Output:** [`DetectVersionOutput`]
57 DetectVersionFiles,
58
59 /// Parse version information from files.
60 ///
61 /// Extracts version specifications from configuration files like `.nvmrc`,
62 /// `package.json`, `pyproject.toml`, etc.
63 ///
64 /// **Input:** [`ParseVersionFileInput`] | **Output:** [`ParseVersionFileOutput`]
65 ParseVersionFile,
66
67 /// Load available versions for a tool.
68 ///
69 /// Fetches the list of available versions that can be installed, including
70 /// version aliases like "latest" or "lts".
71 ///
72 /// **Input:** [`LoadVersionsInput`] | **Output:** [`LoadVersionsOutput`]
73 LoadVersions,
74
75 /// Resolve version specifications to concrete versions.
76 ///
77 /// Takes version requirements or aliases and resolves them to specific
78 /// installable versions.
79 ///
80 /// **Input:** [`ResolveVersionInput`] | **Output:** [`ResolveVersionOutput`]
81 ResolveVersion,
82
83 /// Download prebuilt tool archives.
84 ///
85 /// Provides URLs and metadata for downloading pre-compiled tool binaries
86 /// instead of building from source.
87 ///
88 /// **Input:** [`DownloadPrebuiltInput`] | **Output:** [`DownloadPrebuiltOutput`]
89 DownloadPrebuilt,
90
91 /// Provide build instructions for tools.
92 ///
93 /// Returns the steps needed to build a tool from source, including dependencies,
94 /// build commands, and environment requirements.
95 ///
96 /// **Input:** [`BuildInstructionsInput`] | **Output:** [`BuildInstructionsOutput`]
97 BuildInstructions,
98
99 /// Unpack downloaded archives.
100 ///
101 /// Handles custom unpacking logic for tool archives when the default extraction
102 /// methods are insufficient.
103 ///
104 /// **Input:** [`UnpackArchiveInput`] | **Output:** None
105 UnpackArchive,
106
107 /// Verify download checksums.
108 ///
109 /// Provides custom checksum verification logic for downloaded tool archives
110 /// to ensure integrity.
111 ///
112 /// **Input:** [`VerifyChecksumInput`] | **Output:** [`VerifyChecksumOutput`]
113 VerifyChecksum,
114
115 /// Native tool installation.
116 ///
117 /// Handles tool installation using the tool's own installation methods rather
118 /// than proto's standard process.
119 ///
120 /// **Input:** [`NativeInstallInput`] | **Output:** [`NativeInstallOutput`]
121 NativeInstall,
122
123 /// Native tool uninstallation.
124 ///
125 /// Handles tool removal using the tool's own uninstallation methods rather
126 /// than simple directory deletion.
127 ///
128 /// **Input:** [`NativeUninstallInput`] | **Output:** [`NativeUninstallOutput`]
129 NativeUninstall,
130
131 /// Locate tool executables.
132 ///
133 /// Identifies where executables are located within an installed tool and
134 /// configures them for proto's shim system.
135 ///
136 /// **Input:** [`LocateExecutablesInput`] | **Output:** [`LocateExecutablesOutput`]
137 LocateExecutables,
138
139 /// Sync the tool manifest.
140 ///
141 /// Allows plugins to update proto's inventory of installed versions with
142 /// external changes.
143 ///
144 /// **Input:** [`SyncManifestInput`] | **Output:** [`SyncManifestOutput`]
145 SyncManifest,
146
147 /// Sync shell profile configuration.
148 ///
149 /// Configures shell environment variables and PATH modifications needed for
150 /// the tool to work properly.
151 ///
152 /// **Input:** [`SyncShellProfileInput`] | **Output:** [`SyncShellProfileOutput`]
153 SyncShellProfile,
154
155 /// Setup the environment during activation or execution.
156 ///
157 /// **Input:** [`ActivateEnvironmentInput`] | **Output:** [`ActivateEnvironmentOutput`]
158 ActivateEnvironment,
159}
160
161impl PluginFunction {
162 /// Get the string representation of the plugin function name.
163 ///
164 /// This returns the actual function name that should be used when calling
165 /// the plugin function via WASM.
166 pub fn as_str(&self) -> &'static str {
167 match self {
168 Self::RegisterTool => "register_tool",
169 Self::DefineToolConfig => "define_tool_config",
170 Self::RegisterBackend => "register_backend",
171 Self::DefineBackendConfig => "define_backend_config",
172 Self::DetectVersionFiles => "detect_version_files",
173 Self::ParseVersionFile => "parse_version_file",
174 Self::LoadVersions => "load_versions",
175 Self::ResolveVersion => "resolve_version",
176 Self::DownloadPrebuilt => "download_prebuilt",
177 Self::BuildInstructions => "build_instructions",
178 Self::UnpackArchive => "unpack_archive",
179 Self::VerifyChecksum => "verify_checksum",
180 Self::NativeInstall => "native_install",
181 Self::NativeUninstall => "native_uninstall",
182 Self::LocateExecutables => "locate_executables",
183 Self::SyncManifest => "sync_manifest",
184 Self::SyncShellProfile => "sync_shell_profile",
185 Self::ActivateEnvironment => "activate_environment",
186 }
187 }
188}
189
190impl AsRef<str> for PluginFunction {
191 fn as_ref(&self) -> &str {
192 self.as_str()
193 }
194}
195
196pub(crate) fn is_false(value: &bool) -> bool {
197 !(*value)
198}
199
200pub(crate) fn is_default<T: Default + PartialEq>(value: &T) -> bool {
201 value == &T::default()
202}
203
204api_struct!(
205 /// Information about the current state of the plugin,
206 /// after a version has been resolved.
207 pub struct PluginContext {
208 /// The version of proto (the core crate) calling plugin functions.
209 #[serde(default, skip_serializing_if = "Option::is_none")]
210 pub proto_version: Option<Version>,
211
212 /// Virtual path to the tool's temporary directory.
213 pub temp_dir: VirtualPath,
214
215 /// Virtual path to the tool's installation directory.
216 pub tool_dir: VirtualPath,
217
218 /// Current version. Will be a "latest" alias if not resolved.
219 pub version: VersionSpec,
220 }
221);
222
223api_struct!(
224 /// Information about the current state of the plugin,
225 /// before a version has been resolved.
226 pub struct PluginUnresolvedContext {
227 /// The version of proto (the core crate) calling plugin functions.
228 #[serde(default, skip_serializing_if = "Option::is_none")]
229 pub proto_version: Option<Version>,
230
231 /// Virtual path to the tool's temporary directory.
232 pub temp_dir: VirtualPath,
233
234 /// Current version if defined.
235 #[serde(default, skip_serializing_if = "Option::is_none")]
236 pub version: Option<VersionSpec>,
237
238 // TODO: temporary compat with `ToolContext`
239 #[doc(hidden)]
240 pub tool_dir: VirtualPath,
241 }
242);
243
244api_unit_enum!(
245 /// Supported types of plugins.
246 pub enum PluginType {
247 #[serde(alias = "CLI", alias = "CommandLine")] // TEMP
248 CommandLine,
249 #[default]
250 #[serde(alias = "Language")]
251 Language,
252 #[serde(alias = "PM", alias = "DependencyManager")] // TEMP
253 DependencyManager,
254 #[serde(alias = "VM", alias = "VersionManager")] // TEMP
255 VersionManager,
256 }
257);
258
259api_struct!(
260 /// Input passed to the `register_tool` function.
261 pub struct RegisterToolInput {
262 /// ID of the tool, as it was configured.
263 pub id: Id,
264 }
265);
266
267#[deprecated(note = "Use `RegisterToolInput` instead.")]
268pub type ToolMetadataInput = RegisterToolInput;
269
270api_struct!(
271 /// Controls aspects of the tool inventory.
272 #[serde(default)]
273 pub struct ToolInventoryOptions {
274 /// Override the tool inventory directory (where all versions are installed).
275 /// This is an advanced feature and should only be used when absolutely necessary.
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub override_dir: Option<VirtualPath>,
278
279 /// When the inventory is backend managed, scope the inventory directory name
280 /// with the backend as a prefix.
281 #[serde(skip_serializing_if = "is_false")]
282 pub scoped_backend_dir: bool,
283
284 /// Suffix to append to all versions when labeling directories.
285 #[serde(skip_serializing_if = "Option::is_none")]
286 pub version_suffix: Option<String>,
287 }
288);
289
290api_unit_enum!(
291 /// Supported strategies for installing a tool.
292 pub enum InstallStrategy {
293 #[serde(alias = "BuildFromSource")] // TEMP
294 BuildFromSource,
295 #[default]
296 #[serde(alias = "DownloadPrebuilt")] // TEMP
297 DownloadPrebuilt,
298 }
299);
300
301api_struct!(
302 /// Options related to lockfile integration.
303 #[serde(default)]
304 pub struct ToolLockOptions {
305 /// Ignore operating system and architecture values
306 /// when matching against records in the lockfile.
307 #[serde(skip_serializing_if = "is_false")]
308 pub ignore_os_arch: bool,
309
310 /// Do not record the install in the lockfile.
311 #[serde(skip_serializing_if = "is_false")]
312 pub no_record: bool,
313 }
314);
315
316api_struct!(
317 /// Output returned by the `register_tool` function.
318 pub struct RegisterToolOutput {
319 /// Default strategy to use when installing a tool.
320 #[serde(default)]
321 pub default_install_strategy: InstallStrategy,
322
323 /// Default alias or version to use as a fallback.
324 #[serde(default, skip_serializing_if = "Option::is_none")]
325 pub default_version: Option<UnresolvedVersionSpec>,
326
327 /// List of deprecation messages that will be displayed to users
328 /// of this plugin.
329 #[serde(default, skip_serializing_if = "Vec::is_empty")]
330 pub deprecations: Vec<String>,
331
332 /// Controls aspects of the tool inventory.
333 #[serde(default, skip_serializing_if = "is_default", alias = "inventory")]
334 pub inventory_options: ToolInventoryOptions,
335
336 /// Options for integrating with a lockfile.
337 #[serde(default, skip_serializing_if = "is_default")]
338 pub lock_options: ToolLockOptions,
339
340 /// Minimum version of proto required to execute this plugin.
341 #[serde(default, skip_serializing_if = "Option::is_none")]
342 pub minimum_proto_version: Option<Version>,
343
344 /// Human readable name of the tool.
345 pub name: String,
346
347 /// Version of the plugin.
348 #[serde(default, skip_serializing_if = "Option::is_none")]
349 pub plugin_version: Option<Version>,
350
351 /// Other plugins that this plugin requires.
352 #[serde(default, skip_serializing_if = "Vec::is_empty")]
353 pub requires: Vec<String>,
354
355 /// Names of commands that will self-upgrade the tool,
356 /// and should be blocked from happening.
357 #[serde(default, skip_serializing_if = "Vec::is_empty")]
358 pub self_upgrade_commands: Vec<String>,
359
360 /// Type of the tool.
361 #[serde(rename = "type")]
362 pub type_of: PluginType,
363
364 /// Whether this plugin is unstable or not.
365 #[serde(default)]
366 pub unstable: Switch,
367 }
368);
369
370#[deprecated(note = "Use `RegisterToolOutput` instead.")]
371pub type ToolMetadataOutput = RegisterToolOutput;
372
373pub type ConfigSchema = Schema;
374
375api_struct!(
376 /// Output returned from the `define_tool_config` function.
377 pub struct DefineToolConfigOutput {
378 /// Schema shape of the tool's configuration.
379 pub schema: ConfigSchema,
380 }
381);
382
383// BACKEND
384
385api_struct!(
386 /// Input passed to the `register_backend` function.
387 pub struct RegisterBackendInput {
388 /// Current tool context.
389 pub context: PluginUnresolvedContext,
390
391 /// ID of the tool, as it was configured.
392 pub id: Id,
393 }
394);
395
396api_struct!(
397 /// Output returned by the `register_backend` function.
398 pub struct RegisterBackendOutput {
399 /// Unique identifier for this backend. Will be used as the folder name.
400 pub backend_id: Id,
401
402 /// List of executables, relative from the backend directory,
403 /// that will be executed in the context of proto.
404 #[serde(default, skip_serializing_if = "Vec::is_empty")]
405 pub exes: Vec<PathBuf>,
406
407 /// Location in which to acquire source files for the backend.
408 #[serde(default, skip_serializing_if = "Option::is_none")]
409 pub source: Option<SourceLocation>,
410 }
411);
412
413api_struct!(
414 /// Output returned from the `define_backend_config` function.
415 pub struct DefineBackendConfigOutput {
416 /// Schema shape of the backend's configuration.
417 pub schema: ConfigSchema,
418 }
419);
420
421// VERSION DETECTION
422
423api_struct!(
424 /// Input passed to the `detect_version_files` function.
425 pub struct DetectVersionInput {
426 /// Current tool context.
427 pub context: PluginUnresolvedContext,
428 }
429);
430
431api_struct!(
432 /// Output returned by the `detect_version_files` function.
433 #[serde(default)]
434 pub struct DetectVersionOutput {
435 /// List of files that should be checked for version information.
436 #[serde(skip_serializing_if = "Vec::is_empty")]
437 pub files: Vec<String>,
438
439 /// List of path patterns to ignore when traversing directories.
440 #[serde(skip_serializing_if = "Vec::is_empty")]
441 pub ignore: Vec<String>,
442 }
443);
444
445api_struct!(
446 /// Input passed to the `parse_version_file` function.
447 pub struct ParseVersionFileInput {
448 /// File contents to parse/extract a version from.
449 pub content: String,
450
451 /// Current tool context.
452 pub context: PluginUnresolvedContext,
453
454 /// Name of file that's being parsed.
455 pub file: String,
456
457 /// Virtual path to the file being parsed.
458 pub path: VirtualPath,
459 }
460);
461
462api_struct!(
463 /// Output returned by the `parse_version_file` function.
464 #[serde(default)]
465 pub struct ParseVersionFileOutput {
466 /// The version that was extracted from the file.
467 /// Can be a semantic version or a version requirement/range.
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub version: Option<UnresolvedVersionSpec>,
470 }
471);
472
473// DOWNLOAD, BUILD, INSTALL, VERIFY
474
475api_struct!(
476 /// Input passed to the `native_install` function.
477 pub struct NativeInstallInput {
478 /// Current tool context.
479 pub context: PluginContext,
480
481 /// Whether to force install or not.
482 pub force: bool,
483
484 /// Virtual directory to install to.
485 pub install_dir: VirtualPath,
486 }
487);
488
489api_struct!(
490 /// Output returned by the `native_install` function.
491 pub struct NativeInstallOutput {
492 /// A checksum/hash that was generated.
493 #[serde(default, skip_serializing_if = "Option::is_none")]
494 pub checksum: Option<Checksum>,
495
496 /// Error message if the install failed.
497 #[serde(default, skip_serializing_if = "Option::is_none")]
498 pub error: Option<String>,
499
500 /// Whether the install was successful.
501 pub installed: bool,
502
503 /// Whether to skip the install process or not.
504 #[serde(default)]
505 pub skip_install: bool,
506 }
507);
508
509api_struct!(
510 /// Input passed to the `native_uninstall` function.
511 pub struct NativeUninstallInput {
512 /// Current tool context.
513 pub context: PluginContext,
514
515 /// Virtual directory to uninstall from.
516 pub uninstall_dir: VirtualPath,
517 }
518);
519
520api_struct!(
521 /// Output returned by the `native_uninstall` function.
522 pub struct NativeUninstallOutput {
523 /// Error message if the uninstall failed.
524 #[serde(default, skip_serializing_if = "Option::is_none")]
525 pub error: Option<String>,
526
527 /// Whether the install was successful.
528 pub uninstalled: bool,
529
530 /// Whether to skip the uninstall process or not.
531 #[serde(default)]
532 pub skip_uninstall: bool,
533 }
534);
535
536api_struct!(
537 /// Input passed to the `download_prebuilt` function.
538 pub struct DownloadPrebuiltInput {
539 /// Current tool context.
540 pub context: PluginContext,
541
542 /// Virtual directory to install to.
543 pub install_dir: VirtualPath,
544 }
545);
546
547api_struct!(
548 /// Output returned by the `download_prebuilt` function.
549 pub struct DownloadPrebuiltOutput {
550 /// Name of the direct folder within the archive that contains the tool,
551 /// and will be removed when unpacking the archive.
552 #[serde(default, skip_serializing_if = "Option::is_none")]
553 pub archive_prefix: Option<String>,
554
555 /// The checksum hash itself.
556 #[serde(default, skip_serializing_if = "Option::is_none")]
557 pub checksum: Option<Checksum>,
558
559 /// File name of the checksum to download. If not provided,
560 /// will attempt to extract it from the URL.
561 #[serde(default, skip_serializing_if = "Option::is_none")]
562 pub checksum_name: Option<String>,
563
564 /// Public key to use for checksum verification.
565 #[serde(default, skip_serializing_if = "Option::is_none")]
566 pub checksum_public_key: Option<String>,
567
568 /// A secure URL to download the checksum file for verification.
569 /// If the tool does not support checksum verification, this setting can be omitted.
570 #[serde(default, skip_serializing_if = "Option::is_none")]
571 pub checksum_url: Option<String>,
572
573 /// File name of the archive to download. If not provided,
574 /// will attempt to extract it from the URL.
575 #[serde(default, skip_serializing_if = "Option::is_none")]
576 pub download_name: Option<String>,
577
578 /// A secure URL to download the tool/archive.
579 pub download_url: String,
580 }
581);
582
583api_struct!(
584 /// Input passed to the `unpack_archive` function.
585 pub struct UnpackArchiveInput {
586 /// Current tool context.
587 pub context: PluginContext,
588
589 /// Virtual path to the downloaded file.
590 pub input_file: VirtualPath,
591
592 /// Virtual directory to unpack the archive into, or copy the executable to.
593 pub output_dir: VirtualPath,
594 }
595);
596
597api_struct!(
598 /// Output returned by the `verify_checksum` function.
599 pub struct VerifyChecksumInput {
600 /// Current tool context.
601 pub context: PluginContext,
602
603 /// Virtual path to the checksum file.
604 pub checksum_file: VirtualPath,
605
606 /// A checksum of the downloaded file. The type of hash
607 /// is derived from the checksum file's extension, otherwise
608 /// it defaults to SHA256.
609 #[serde(default, skip_serializing_if = "Option::is_none")]
610 pub download_checksum: Option<Checksum>,
611
612 /// Virtual path to the downloaded file.
613 pub download_file: VirtualPath,
614 }
615);
616
617api_struct!(
618 /// Output returned by the `verify_checksum` function.
619 pub struct VerifyChecksumOutput {
620 /// Was the checksum correct?
621 pub verified: bool,
622 }
623);
624
625// EXECUTABLES, BINARYS, GLOBALS
626
627api_struct!(
628 /// Input passed to the `locate_executables` function.
629 pub struct LocateExecutablesInput {
630 /// Current tool context.
631 pub context: PluginContext,
632
633 /// Virtual directory the tool was installed to.
634 pub install_dir: VirtualPath,
635 }
636);
637
638api_struct!(
639 /// Configuration for generated shim and symlinked executable files.
640 #[derive(Setters)]
641 #[serde(default)]
642 pub struct ExecutableConfig {
643 /// The file to execute, relative from the tool directory.
644 /// Does *not* support virtual paths.
645 #[setters(strip_option)]
646 #[serde(skip_serializing_if = "Option::is_none")]
647 pub exe_path: Option<PathBuf>,
648
649 /// The executable path to use for symlinking instead of `exe_path`.
650 /// This should only be used when `exe_path` is a non-standard executable.
651 #[setters(strip_option)]
652 #[serde(skip_serializing_if = "Option::is_none")]
653 pub exe_link_path: Option<PathBuf>,
654
655 /// Do not symlink a binary in `~/.proto/bin`.
656 #[serde(skip_serializing_if = "is_false")]
657 pub no_bin: bool,
658
659 /// Do not generate a shim in `~/.proto/shims`.
660 #[serde(skip_serializing_if = "is_false")]
661 pub no_shim: bool,
662
663 /// List of arguments to append to the parent executable, but prepend before
664 /// all other arguments.
665 #[serde(skip_serializing_if = "Vec::is_empty")]
666 pub parent_exe_args: Vec<String>,
667
668 /// The parent executable name required to execute the local executable path.
669 #[setters(into, strip_option)]
670 #[serde(skip_serializing_if = "Option::is_none")]
671 pub parent_exe_name: Option<String>,
672
673 /// Whether this is the primary executable or not.
674 #[serde(skip_serializing_if = "is_false")]
675 pub primary: bool,
676
677 /// Custom args to prepend to user-provided args within the generated shim.
678 #[setters(strip_option)]
679 #[serde(skip_serializing_if = "Option::is_none")]
680 pub shim_before_args: Option<StringOrVec>,
681
682 /// Custom args to append to user-provided args within the generated shim.
683 #[setters(strip_option)]
684 #[serde(skip_serializing_if = "Option::is_none")]
685 pub shim_after_args: Option<StringOrVec>,
686
687 /// Custom environment variables to set when executing the shim.
688 #[setters(strip_option)]
689 #[serde(skip_serializing_if = "Option::is_none")]
690 pub shim_env_vars: Option<FxHashMap<String, String>>,
691
692 /// Update the file permissions to executable. This only exists as these
693 /// values cannot be changed from within WASM.
694 #[serde(skip_serializing_if = "is_false")]
695 pub update_perms: bool,
696 }
697);
698
699impl ExecutableConfig {
700 pub fn new<T: AsRef<str>>(exe_path: T) -> Self {
701 Self {
702 exe_path: Some(PathBuf::from(exe_path.as_ref())),
703 ..ExecutableConfig::default()
704 }
705 }
706
707 pub fn new_primary<T: AsRef<str>>(exe_path: T) -> Self {
708 Self {
709 exe_path: Some(PathBuf::from(exe_path.as_ref())),
710 primary: true,
711 ..ExecutableConfig::default()
712 }
713 }
714
715 pub fn with_parent<T: AsRef<str>, P: AsRef<str>>(exe_path: T, parent_exe: P) -> Self {
716 Self {
717 exe_path: Some(PathBuf::from(exe_path.as_ref())),
718 parent_exe_name: Some(parent_exe.as_ref().to_owned()),
719 ..ExecutableConfig::default()
720 }
721 }
722}
723
724api_struct!(
725 /// Output returned by the `locate_executables` function.
726 #[serde(default)]
727 pub struct LocateExecutablesOutput {
728 /// Configures executable information to be used as proto bins/shims.
729 /// The map key will be the name of the executable file.
730 #[serde(skip_serializing_if = "FxHashMap::is_empty")]
731 pub exes: FxHashMap<String, ExecutableConfig>,
732
733 #[deprecated(note = "Use `exes_dirs` instead.")]
734 #[serde(skip_serializing_if = "Option::is_none")]
735 pub exes_dir: Option<PathBuf>,
736
737 /// Relative directory path from the tool install directory in which
738 /// pre-installed executables can be located. This directory path
739 /// will be used during `proto activate`, but not for bins/shims.
740 #[serde(skip_serializing_if = "Vec::is_empty")]
741 pub exes_dirs: Vec<PathBuf>,
742
743 /// List of directory paths to find the globals installation directory.
744 /// Each path supports environment variable expansion.
745 #[serde(skip_serializing_if = "Vec::is_empty")]
746 pub globals_lookup_dirs: Vec<String>,
747
748 /// A string that all global executables are prefixed with, and will be removed
749 /// when listing and filtering available globals.
750 #[serde(skip_serializing_if = "Option::is_none")]
751 pub globals_prefix: Option<String>,
752 }
753);
754
755api_struct!(
756 /// Input passed to the `activate_environment` function.
757 pub struct ActivateEnvironmentInput {
758 /// Current tool context.
759 pub context: PluginContext,
760 }
761);
762
763api_struct!(
764 /// Output returned by the `activate_environment` function.
765 #[serde(default)]
766 pub struct ActivateEnvironmentOutput {
767 /// Additional environment variables to set. Will overwrite any existing variables.
768 pub env: FxHashMap<String, String>,
769
770 /// Additional paths to prepend to `PATH`. Tool specific executables
771 /// and globals directories do NOT need to be included here, as they
772 /// are automatically included.
773 pub paths: Vec<PathBuf>,
774 }
775);
776
777// VERSION RESOLVING
778
779api_struct!(
780 /// Input passed to the `load_versions` function.
781 pub struct LoadVersionsInput {
782 /// Current tool context.
783 pub context: PluginUnresolvedContext,
784
785 /// The alias or version currently being resolved.
786 pub initial: UnresolvedVersionSpec,
787 }
788);
789
790api_struct!(
791 /// Output returned by the `load_versions` function.
792 #[serde(default)]
793 pub struct LoadVersionsOutput {
794 /// Latest canary version.
795 #[serde(skip_serializing_if = "Option::is_none")]
796 pub canary: Option<UnresolvedVersionSpec>,
797
798 /// Latest stable version.
799 #[serde(skip_serializing_if = "Option::is_none")]
800 pub latest: Option<UnresolvedVersionSpec>,
801
802 /// Mapping of aliases (channels, etc) to a version.
803 #[serde(skip_serializing_if = "FxHashMap::is_empty")]
804 pub aliases: FxHashMap<String, UnresolvedVersionSpec>,
805
806 /// List of available production versions to install.
807 #[serde(skip_serializing_if = "Vec::is_empty")]
808 pub versions: Vec<VersionSpec>,
809 }
810);
811
812impl LoadVersionsOutput {
813 /// Create the output from a list of strings that'll be parsed as versions.
814 /// The latest version will be the highest version number.
815 pub fn from(values: Vec<String>) -> Result<Self, SpecError> {
816 let mut versions = vec![];
817
818 for value in values {
819 versions.push(VersionSpec::parse(&value)?);
820 }
821
822 Ok(Self::from_versions(versions))
823 }
824
825 /// Create the output from a list of version specifications.
826 /// The latest version will be the highest version number.
827 pub fn from_versions(versions: Vec<VersionSpec>) -> Self {
828 let mut output = LoadVersionsOutput::default();
829 let mut latest = Version::new(0, 0, 0);
830 let mut calver = false;
831
832 for version in versions {
833 if let Some(inner) = version.as_version() {
834 if inner.pre.is_empty() && inner.build.is_empty() && inner > &latest {
835 inner.clone_into(&mut latest);
836 calver = matches!(version, VersionSpec::Calendar(_));
837 }
838 }
839
840 output.versions.push(version);
841 }
842
843 output.latest = Some(if calver {
844 UnresolvedVersionSpec::Calendar(CalVer(latest))
845 } else {
846 UnresolvedVersionSpec::Semantic(SemVer(latest))
847 });
848
849 output
850 .aliases
851 .insert("latest".into(), output.latest.clone().unwrap());
852
853 output
854 }
855}
856
857api_struct!(
858 /// Input passed to the `resolve_version` function.
859 pub struct ResolveVersionInput {
860 /// Current tool context.
861 pub context: PluginUnresolvedContext,
862
863 /// The alias or version currently being resolved.
864 pub initial: UnresolvedVersionSpec,
865 }
866);
867
868api_struct!(
869 /// Output returned by the `resolve_version` function.
870 #[serde(default)]
871 pub struct ResolveVersionOutput {
872 /// New alias or version candidate to resolve.
873 #[serde(skip_serializing_if = "Option::is_none")]
874 pub candidate: Option<UnresolvedVersionSpec>,
875
876 /// An explicitly resolved version to be used as-is.
877 /// Note: Only use this field if you know what you're doing!
878 #[serde(skip_serializing_if = "Option::is_none")]
879 pub version: Option<VersionSpec>,
880 }
881);
882
883// MISCELLANEOUS
884
885api_struct!(
886 /// Input passed to the `sync_manifest` function.
887 pub struct SyncManifestInput {
888 /// Current tool context.
889 pub context: PluginContext,
890 }
891);
892
893api_struct!(
894 /// Output returned by the `sync_manifest` function.
895 #[serde(default)]
896 pub struct SyncManifestOutput {
897 /// List of versions that are currently installed. Will replace
898 /// what is currently in the manifest.
899 #[serde(skip_serializing_if = "Option::is_none")]
900 pub versions: Option<Vec<VersionSpec>>,
901
902 /// Whether to skip the syncing process or not.
903 pub skip_sync: bool,
904 }
905);
906
907api_struct!(
908 /// Input passed to the `sync_shell_profile` function.
909 pub struct SyncShellProfileInput {
910 /// Current tool context.
911 pub context: PluginContext,
912
913 /// Arguments passed after `--` that was directly passed to the tool's executable.
914 pub passthrough_args: Vec<String>,
915 }
916);
917
918api_struct!(
919 /// Output returned by the `sync_shell_profile` function.
920 pub struct SyncShellProfileOutput {
921 /// An environment variable to check for in the shell profile.
922 /// If the variable exists, injecting path and exports will be avoided.
923 pub check_var: String,
924
925 /// A mapping of environment variables that will be injected as exports.
926 #[serde(default, skip_serializing_if = "Option::is_none")]
927 pub export_vars: Option<FxHashMap<String, String>>,
928
929 /// A list of paths to prepend to the `PATH` environment variable.
930 #[serde(default, skip_serializing_if = "Option::is_none")]
931 pub extend_path: Option<Vec<String>>,
932
933 /// Whether to skip the syncing process or not.
934 #[serde(default)]
935 pub skip_sync: bool,
936 }
937);