1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use color_eyre::eyre::Result;
use itertools::sorted;

use crate::cli::command::Command;
use crate::config::Config;
use crate::dirs;
use crate::env::PYENV_ROOT;
use crate::file;
use crate::output::Output;
use crate::plugins::PluginName;

/// Symlinks all tool versions from an external tool into rtx
///
/// For example, use this to import all pyenv installs into rtx
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct SyncPython {
    /// Get tool versions from pyenv
    #[clap(long, required = true)]
    pyenv: bool,
}

impl Command for SyncPython {
    fn run(self, mut config: Config, out: &mut Output) -> Result<()> {
        let python = config.get_or_create_tool(&PluginName::from("python"));

        let pyenv_versions_path = PYENV_ROOT.join("versions");
        let installed_python_versions_path = dirs::INSTALLS.join("python");

        file::remove_symlinks_with_target_prefix(
            &installed_python_versions_path,
            &pyenv_versions_path,
        )?;

        let subdirs = file::dir_subdirs(&pyenv_versions_path)?;
        for v in sorted(subdirs) {
            python.create_symlink(&v, &pyenv_versions_path.join(&v))?;
            rtxprintln!(out, "Synced python@{} from pyenv", v);
        }

        config.rebuild_shims_and_runtime_symlinks()
    }
}

static AFTER_LONG_HELP: &str = color_print::cstr!(
    r#"<bold><underline>Examples:</underline></bold>
  $ <bold>pyenv install 3.11.0</bold>
  $ <bold>rtx sync python --pyenv</bold>
  $ <bold>rtx use -g python@3.11.0</bold> - uses pyenv-provided python
"#
);

#[cfg(test)]
mod tests {
    use crate::assert_cli;

    #[test]
    fn test_pyenv() {
        assert_cli!("sync", "python", "--pyenv");
    }
}