use std::fs;
use std::path::Path;
use miette::{IntoDiagnostic, Result};
use rayon::Scope;
use crate::dirs::*;
use crate::env::{XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME};
use crate::file;
pub fn run() {
if let Err(err) = migrate_rtx() {
eprintln!("[WARN] migrate: {}", err);
}
rayon::scope(|s| {
task(s, || rename_plugin("nodejs", "node"));
task(s, || rename_plugin("golang", "go"));
task(s, migrate_trusted_configs);
task(s, migrate_tracked_configs);
task(s, || remove_deprecated_plugin("node", "rtx-nodejs"));
task(s, || remove_deprecated_plugin("python", "rtx-golang"));
task(s, || remove_deprecated_plugin("python", "rtx-java"));
task(s, || remove_deprecated_plugin("python", "rtx-python"));
task(s, || remove_deprecated_plugin("python", "rtx-ruby"));
});
}
fn task(s: &Scope, job: impl FnOnce() -> Result<()> + Send + 'static) {
s.spawn(|_| {
if let Err(err) = job() {
eprintln!("[WARN] migrate: {}", err);
}
});
}
fn move_subdirs(from: &Path, to: &Path) -> Result<()> {
if from.exists() {
eprintln!("migrating {} to {}", from.display(), to.display());
file::create_dir_all(to)?;
for f in from.read_dir().into_diagnostic()? {
let f = f.into_diagnostic()?.file_name();
let from_file = from.join(&f);
let to_file = to.join(&f);
if !to_file.exists() {
eprintln!("moving {} to {}", from_file.display(), to_file.display());
file::rename(from_file, to_file)?;
}
}
file::remove_all(from)?;
}
Ok(())
}
fn rename_plugin(from: &str, to: &str) -> Result<()> {
move_subdirs(&INSTALLS.join(from), &INSTALLS.join(to))?;
move_subdirs(&PLUGINS.join(from), &PLUGINS.join(to))?;
Ok(())
}
fn migrate_rtx() -> Result<()> {
let mut migrated = false;
let rtx_data = XDG_DATA_HOME.join("rtx");
if rtx_data.exists() {
let installs = rtx_data.join("installs");
for plugin in file::dir_subdirs(&installs)? {
if plugin == "python" || plugin == "ruby" {
continue;
}
migrated = move_dirs(&installs.join(&plugin), &INSTALLS.join(plugin))? || migrated;
}
migrated = move_dirs(&rtx_data.join("plugins"), &DATA.join("plugins"))? || migrated;
}
migrated = move_dirs(&XDG_CONFIG_HOME.join("rtx"), &CONFIG)? || migrated;
migrated = move_dirs(&XDG_STATE_HOME.join("rtx"), &STATE)? || migrated;
if migrated {
eprintln!("migrated rtx directories to mise");
eprintln!("see https://mise.jdx.dev/rtx.html")
}
Ok(())
}
fn migrate_tracked_configs() -> Result<()> {
move_dirs(&DATA.join("tracked_config_files"), &TRACKED_CONFIGS)?;
move_dirs(&DATA.join("tracked-config-files"), &TRACKED_CONFIGS)?;
Ok(())
}
fn migrate_trusted_configs() -> Result<()> {
move_dirs(&CACHE.join("trusted-configs"), &TRUSTED_CONFIGS)?;
move_dirs(&CONFIG.join("trusted-configs"), &TRUSTED_CONFIGS)?;
move_dirs(&DATA.join("trusted-configs"), &TRUSTED_CONFIGS)?;
Ok(())
}
fn move_dirs(from: &Path, to: &Path) -> Result<bool> {
if from.exists() && !to.exists() {
eprintln!("migrating {} to {}", from.display(), to.display());
file::create_dir_all(to.parent().unwrap())?;
file::rename(from, to)?;
Ok(true)
} else {
Ok(false)
}
}
fn remove_deprecated_plugin(name: &str, plugin_name: &str) -> Result<()> {
let plugin_root = PLUGINS.join(name);
let gitconfig = plugin_root.join(".git").join("config");
let gitconfig_body = fs::read_to_string(gitconfig).unwrap_or_default();
if !gitconfig_body.contains(&format!("github.com/mise-plugins/{plugin_name}")) {
return Ok(());
}
eprintln!("removing deprecated plugin {plugin_name}, will use core {name} plugin from now on");
file::remove_all(plugin_root)?;
Ok(())
}