use std::env;
use std::fs;
use std::path::Path;
use serde_json::Value;
use crate::installation::generation::{
write_new_generation_with_token_at, write_staged_generation_with_token,
};
use super::state::{PluginInstallOptions, PluginLayout, remove_path, write_json};
use super::{MARKETPLACE_NAME, MarketplaceHost, PLUGIN_NAME};
pub(super) fn write_plugin_marketplace(
host: impl MarketplaceHost,
layout: &PluginLayout,
relay: &Path,
options: &PluginInstallOptions,
) -> Result<(), String> {
write_plugin_marketplace_for_generation(
host,
layout,
relay,
&layout.generation_fence,
&layout.generation_lock,
true,
options,
)
}
pub(super) fn write_plugin_marketplace_for_generation(
host: impl MarketplaceHost,
layout: &PluginLayout,
relay: &Path,
active_generation_fence: &Path,
active_generation_lock: &Path,
initialize_generation_lock: bool,
options: &PluginInstallOptions,
) -> Result<(), String> {
if options.dry_run {
println!("write {}", layout.marketplace_manifest.display());
println!("write {}", layout.plugin_manifest.display());
println!("write {}", layout.mcp_config.display());
println!("write {}", layout.generation_fence.display());
println!("write {}", layout.hooks_path.display());
return Ok(());
}
remove_path(&layout.plugin_root, options)?;
fs::create_dir_all(
layout
.plugin_root
.parent()
.unwrap_or(&layout.marketplace_root),
)
.map_err(|error| format!("failed to create {}: {error}", layout.plugin_root.display()))?;
fs::create_dir_all(layout.hooks_path.parent().unwrap_or(&layout.plugin_root))
.map_err(|error| format!("failed to create {}: {error}", layout.hooks_path.display()))?;
write_json(&layout.marketplace_manifest, &marketplace_manifest(host))?;
write_json(&layout.plugin_manifest, &plugin_manifest(host))?;
let generation_token = if initialize_generation_lock {
write_new_generation_with_token_at(&layout.generation_fence, active_generation_lock)
} else {
write_staged_generation_with_token(&layout.generation_fence, active_generation_lock)
}?;
write_json(
&layout.mcp_config,
&plugin_mcp_config(host, relay, active_generation_fence, &generation_token)?,
)?;
write_json(
&layout.hooks_path,
&plugin_hooks(host, relay, active_generation_fence, &generation_token)?,
)?;
Ok(())
}
pub(super) fn marketplace_manifest(host: impl MarketplaceHost) -> Value {
host.marketplace_manifest(MARKETPLACE_NAME, PLUGIN_NAME)
}
pub(super) fn plugin_manifest(host: impl MarketplaceHost) -> Value {
host.plugin_manifest(PLUGIN_NAME)
}
pub(super) fn plugin_mcp_config(
host: impl MarketplaceHost,
relay: &Path,
generation_fence: &Path,
generation_token: &str,
) -> Result<Value, String> {
let generation_fence = absolute_or_self(generation_fence)?;
let server = crate::mcp::persistent_server(relay, &generation_fence, generation_token);
host.plugin_mcp_config(server)
}
fn absolute_or_self(path: &Path) -> Result<std::path::PathBuf, String> {
if path.is_absolute() {
return Ok(path.to_owned());
}
env::current_dir()
.map(|current| current.join(path))
.map_err(|error| format!("failed to resolve relative generation fence: {error}"))
}
pub(super) fn plugin_hooks(
host: impl MarketplaceHost,
relay: &Path,
generation_fence: &Path,
generation_token: &str,
) -> Result<Value, String> {
let generation_fence = absolute_or_self(generation_fence)?;
host.plugin_hooks(relay, &generation_fence, generation_token)
}