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