-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(backend): add Backend trait methods for metadata fetching #6228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
1440f3d
ff07761
ce3b92b
ca81d96
4b7f66f
0c1db60
e06c661
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,8 @@ use crate::cmd::CmdLineRunner; | |
| use crate::config::{Config, Settings}; | ||
| use crate::file::{display_path, remove_all, remove_all_with_warning}; | ||
| use crate::install_context::InstallContext; | ||
| use crate::lockfile::PlatformInfo; | ||
| use crate::platform::Platform; | ||
| use crate::plugins::core::CORE_PLUGINS; | ||
| use crate::plugins::{PluginType, VERSION_REGEX}; | ||
| use crate::registry::{REGISTRY, tool_enabled}; | ||
|
|
@@ -57,6 +59,53 @@ pub type BackendMap = BTreeMap<String, ABackend>; | |
| pub type BackendList = Vec<ABackend>; | ||
| pub type VersionCacheManager = CacheManager<Vec<String>>; | ||
|
|
||
| /// Represents a target platform for lockfile metadata fetching | ||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||
| pub struct PlatformTarget { | ||
| pub platform: Platform, | ||
| } | ||
|
|
||
| impl PlatformTarget { | ||
| pub fn new(platform: Platform) -> Self { | ||
| Self { platform } | ||
| } | ||
|
|
||
| pub fn from_current() -> Self { | ||
| Self::new(Platform::current()) | ||
| } | ||
|
|
||
| pub fn os_name(&self) -> &str { | ||
| &self.platform.os | ||
| } | ||
|
|
||
| pub fn arch_name(&self) -> &str { | ||
| &self.platform.arch | ||
| } | ||
|
|
||
| pub fn qualifier(&self) -> Option<&str> { | ||
| self.platform.qualifier.as_deref() | ||
| } | ||
|
|
||
| pub fn to_key(&self) -> String { | ||
| self.platform.to_key() | ||
| } | ||
| } | ||
|
|
||
| /// Information about a GitHub/GitLab release for platform-specific tools | ||
| #[derive(Debug, Clone)] | ||
| pub struct GitHubReleaseInfo { | ||
| pub repo: String, | ||
| pub asset_pattern: Option<String>, | ||
| pub api_url: Option<String>, | ||
| pub release_type: ReleaseType, | ||
| } | ||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum ReleaseType { | ||
| GitHub, | ||
| GitLab, | ||
| } | ||
|
|
||
| static TOOLS: Mutex<Option<Arc<BackendMap>>> = Mutex::new(None); | ||
|
|
||
| pub async fn load_tools() -> Result<Arc<BackendMap>> { | ||
|
|
@@ -808,6 +857,119 @@ pub trait Backend: Debug + Send + Sync { | |
| ) -> Result<Option<OutdatedInfo>> { | ||
| Ok(None) | ||
| } | ||
|
|
||
| // ========== Lockfile Metadata Fetching Methods ========== | ||
|
|
||
| /// Optional: Provide tarball URL for platform-specific tool installation | ||
| /// Backends can implement this for simple tarball-based tools | ||
| async fn get_tarball_url( | ||
| &self, | ||
| _tv: &ToolVersion, | ||
| _target: &PlatformTarget, | ||
| ) -> Result<Option<String>> { | ||
| Ok(None) // Default: no tarball URL available | ||
| } | ||
|
|
||
| /// Optional: Provide GitHub/GitLab release info for platform-specific tool installation | ||
| /// Backends can implement this for GitHub/GitLab release-based tools | ||
| async fn get_github_release_info( | ||
| &self, | ||
| _tv: &ToolVersion, | ||
| _target: &PlatformTarget, | ||
| ) -> Result<Option<GitHubReleaseInfo>> { | ||
| Ok(None) // Default: no GitHub release info available | ||
| } | ||
|
|
||
| /// Resolve platform-specific lock information without installation | ||
| async fn resolve_lock_info( | ||
| &self, | ||
| tv: &ToolVersion, | ||
| target: &PlatformTarget, | ||
| ) -> Result<PlatformInfo> { | ||
| // Try simple tarball approach first | ||
| if let Some(tarball_url) = self.get_tarball_url(tv, target).await? { | ||
| return self | ||
| .resolve_lock_info_from_tarball(&tarball_url, tv, target) | ||
| .await; | ||
| } | ||
|
|
||
| // Try GitHub/GitLab release approach second | ||
| if let Some(release_info) = self.get_github_release_info(tv, target).await? { | ||
| return self | ||
| .resolve_lock_info_from_github_release(&release_info, tv, target) | ||
| .await; | ||
| } | ||
|
|
||
| // Fall back to basic platform info without URLs/metadata | ||
| self.resolve_lock_info_fallback(tv, target).await | ||
| } | ||
|
|
||
| /// Shared logic for processing tarball-based tools | ||
| /// Downloads tarball headers, extracts size and URL info, and populates PlatformInfo | ||
| async fn resolve_lock_info_from_tarball( | ||
| &self, | ||
| tarball_url: &str, | ||
| _tv: &ToolVersion, | ||
| _target: &PlatformTarget, | ||
| ) -> Result<PlatformInfo> { | ||
| // For now, just return basic info with the URL | ||
| // In a full implementation, this would: | ||
| // 1. Make HEAD request to get content-length | ||
| // 2. Potentially download to get checksum | ||
| // 3. Handle any URL-specific logic | ||
| Ok(PlatformInfo { | ||
| url: Some(tarball_url.to_string()), | ||
| checksum: None, // TODO: Implement checksum fetching | ||
| size: None, // TODO: Implement size fetching via HEAD request | ||
| }) | ||
| } | ||
|
|
||
| /// Shared logic for processing GitHub/GitLab release-based tools | ||
| /// Queries release API, finds platform-specific assets, and populates PlatformInfo | ||
| async fn resolve_lock_info_from_github_release( | ||
| &self, | ||
| release_info: &GitHubReleaseInfo, | ||
| _tv: &ToolVersion, | ||
| target: &PlatformTarget, | ||
| ) -> Result<PlatformInfo> { | ||
| // For now, just return basic info | ||
| // In a full implementation, this would: | ||
| // 1. Query GitHub/GitLab release API | ||
| // 2. Find matching asset for the target platform | ||
| // 3. Extract download URL, size, and checksums | ||
| let asset_url = if let Some(pattern) = &release_info.asset_pattern { | ||
| // Simple pattern replacement for demo | ||
| Some( | ||
| pattern | ||
| .replace("{os}", target.os_name()) | ||
| .replace("{arch}", target.arch_name()), | ||
| ) | ||
| } else { | ||
| None | ||
| }; | ||
|
|
||
| Ok(PlatformInfo { | ||
| url: asset_url, | ||
| checksum: None, // TODO: Implement checksum fetching from releases | ||
| size: None, // TODO: Implement size fetching from GitHub API | ||
|
Comment on lines
+917
to
+918
|
||
| }) | ||
| } | ||
|
|
||
| /// Fallback method when no specific metadata resolution is available | ||
| /// Returns minimal PlatformInfo without external URLs | ||
| async fn resolve_lock_info_fallback( | ||
| &self, | ||
| _tv: &ToolVersion, | ||
| _target: &PlatformTarget, | ||
| ) -> Result<PlatformInfo> { | ||
| // This is the fallback - no external metadata available | ||
| // The tool would need to be installed to generate platform info | ||
| Ok(PlatformInfo { | ||
| url: None, | ||
| checksum: None, | ||
| size: None, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| fn find_match_in_list(list: &[String], query: &str) -> Option<String> { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use std::collections::BTreeSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use std::path::PathBuf; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::backend::{PlatformTarget, get}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::backend::{PlatformTarget, get}; | |
| use crate::backend::PlatformTarget; | |
| use crate::backend::get; |
Copilot
AI
Sep 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The hardcoded limits of 2 tools and 2 platforms make this demonstration code brittle. Consider making these configurable constants or removing the limits for a more realistic demonstration.
| for tool_ba in tools.iter().take(2) { | |
| // Limit to 2 tools for demo | |
| if let Some(_backend) = get(tool_ba) { | |
| miseprintln!(" {} tool: {}", style("→").green(), tool_ba.short); | |
| for platform in parsed_platforms.iter().take(2) { | |
| // Limit to 2 platforms for demo | |
| for tool_ba in tools.iter() { | |
| if let Some(_backend) = get(tool_ba) { | |
| miseprintln!(" {} tool: {}", style("→").green(), tool_ba.short); | |
| for platform in parsed_platforms.iter() { |
Copilot
AI
Sep 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment indicates incomplete implementation. The demonstration creates unused variables (_backend, _target) and prints static messages instead of actually calling the new backend methods, which reduces the value of this demonstration.
| if let Some(_backend) = get(tool_ba) { | |
| miseprintln!(" {} tool: {}", style("→").green(), tool_ba.short); | |
| for platform in parsed_platforms.iter().take(2) { | |
| // Limit to 2 platforms for demo | |
| let _target = PlatformTarget::new(platform.clone()); | |
| miseprintln!(" {} platform: {}", style("→").blue(), platform.to_key()); | |
| // Demonstrate the new backend methods without full ToolVersion | |
| // For now, just show that the methods are available | |
| miseprintln!( | |
| " {} Backend supports metadata fetching methods:", | |
| style("✓").green() | |
| ); | |
| // We can't easily create a ToolVersion here without complex setup | |
| // But we can show that the backend has the new capabilities | |
| miseprintln!( | |
| " {} get_tarball_url() - implemented", | |
| style("•").dim() | |
| ); | |
| miseprintln!( | |
| " {} get_github_release_info() - implemented", | |
| style("•").dim() | |
| ); | |
| miseprintln!( | |
| " {} resolve_lock_info() - implemented", | |
| style("•").dim() | |
| ); | |
| if let Some(backend) = get(tool_ba) { | |
| miseprintln!(" {} tool: {}", style("→").green(), tool_ba.short); | |
| for platform in parsed_platforms.iter().take(2) { | |
| // Limit to 2 platforms for demo | |
| let target = PlatformTarget::new(platform.clone()); | |
| miseprintln!(" {} platform: {}", style("→").blue(), platform.to_key()); | |
| // Demonstrate the new backend methods with dummy or minimal arguments | |
| miseprintln!( | |
| " {} Backend supports metadata fetching methods:", | |
| style("✓").green() | |
| ); | |
| // Use dummy ToolVersion or Option as needed; here we use None or minimal | |
| let dummy_tool_version = None; | |
| match backend.get_tarball_url(dummy_tool_version.as_ref(), &target) { | |
| Ok(url) => miseprintln!( | |
| " {} get_tarball_url(): {}", | |
| style("•").dim(), | |
| url | |
| ), | |
| Err(e) => miseprintln!( | |
| " {} get_tarball_url() error: {}", | |
| style("•").dim(), | |
| e | |
| ), | |
| } | |
| match backend.get_github_release_info(dummy_tool_version.as_ref(), &target) { | |
| Ok(info) => miseprintln!( | |
| " {} get_github_release_info(): {:?}", | |
| style("•").dim(), | |
| info | |
| ), | |
| Err(e) => miseprintln!( | |
| " {} get_github_release_info() error: {}", | |
| style("•").dim(), | |
| e | |
| ), | |
| } | |
| match backend.resolve_lock_info(dummy_tool_version.as_ref(), &target) { | |
| Ok(info) => miseprintln!( | |
| " {} resolve_lock_info(): {:?}", | |
| style("•").dim(), | |
| info | |
| ), | |
| Err(e) => miseprintln!( | |
| " {} resolve_lock_info() error: {}", | |
| style("•").dim(), | |
| e | |
| ), | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple TODO comments indicate incomplete implementation of critical lockfile features. Consider implementing basic checksum and size fetching or documenting when these will be completed.