spin_plugins/
catalogue.rs1use crate::{git::GitSource, manifest::PluginManifest};
2use anyhow::Context;
3use semver::Version;
4use std::path::{Path, PathBuf};
5use url::Url;
6
7const SPIN_PLUGINS_REPO: &str = "https://github.com/spinframework/spin-plugins/";
8
9pub(crate) fn plugins_repo_url() -> Result<Url, url::ParseError> {
10 Url::parse(SPIN_PLUGINS_REPO)
11}
12
13pub struct Catalogue {
15 git_root: PathBuf,
16 manifests_root: PathBuf,
17}
18
19const LOCAL_CATALOGUE_MANIFESTS_DIRECTORY: &str = "manifests";
21
22impl Catalogue {
23 pub fn new(git_root: PathBuf) -> Self {
24 let manifests_root = git_root.join(LOCAL_CATALOGUE_MANIFESTS_DIRECTORY);
25 Self {
26 git_root,
27 manifests_root,
28 }
29 }
30
31 pub fn manifests(&self) -> anyhow::Result<Vec<PluginManifest>> {
32 let catalogue_manifests_dir = &self.manifests_root;
41
42 if !catalogue_manifests_dir.exists() {
44 return Ok(Vec::new());
45 }
46
47 let plugin_dirs = catalogue_manifests_dir
48 .read_dir()
49 .with_context(|| format!("reading manifest catalogue at {catalogue_manifests_dir:?}"))?
50 .filter_map(|d| d.ok())
51 .map(|d| d.path())
52 .filter(|p| p.is_dir());
53 let manifest_paths = plugin_dirs.flat_map(|path| crate::util::json_files_in(&path));
54 let manifests: Vec<_> = manifest_paths
55 .filter_map(|path| crate::util::try_read_manifest_from(&path))
56 .collect();
57 Ok(manifests)
58 }
59
60 pub(crate) fn manifest_path(
63 &self,
64 plugin_name: &str,
65 plugin_version: &Option<Version>,
66 ) -> PathBuf {
67 self.manifests_root
68 .join(plugin_name)
69 .join(crate::util::manifest_file_name_version(
70 plugin_name,
71 plugin_version,
72 ))
73 }
74
75 pub(crate) async fn fetch_from_remote(&self, repo_url: &Url) -> anyhow::Result<()> {
80 let git_root = &self.git_root;
81 let git_source = GitSource::new(repo_url, None, git_root);
82 if accept_as_repo(git_root) {
83 git_source.pull().await?;
84 } else {
85 git_source.clone_repo().await?;
86 }
87 Ok(())
88 }
89
90 pub(crate) async fn ensure_inited(&self, repo_url: &Url) -> anyhow::Result<()> {
91 let git_root = &self.git_root;
92 let git_source = GitSource::new(repo_url, None, git_root);
93 if !accept_as_repo(git_root) {
94 git_source.clone_repo().await?;
95 }
96 Ok(())
97 }
98}
99
100#[cfg(not(test))]
101fn accept_as_repo(git_root: &Path) -> bool {
102 git_root.join(".git").exists()
103}
104
105#[cfg(test)]
106fn accept_as_repo(git_root: &Path) -> bool {
107 git_root.join(".git").exists() || git_root.join("_spin_test_dot_git").exists()
108}