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