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