Skip to content

Commit a81ebd0

Browse files
authored
Merge pull request #350 from r-lib/feature/rig-system-dirs
Add rig system dirs subcommand
2 parents fbf27fe + b7048c1 commit a81ebd0

16 files changed

Lines changed: 742 additions & 5 deletions

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
* New `rig config` command to manage the rig configuration file.
1717

18+
* New `rig system dirs` command to show the directories rig uses. Also,
19+
`rig system r-dir`, `rig system binary-dir` and `rig system rtools-dir`
20+
(Windows only) commands each print a single path.
21+
1822
* New experimental `rig proj` command to manage R project dependencies.
1923

2024
* `rig run --cmd <command> [args...]` now runs `R CMD <command> [args...]`

src/args.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,58 @@ pub fn rig_app() -> Command {
801801

802802
cmd_system = cmd_system.subcommand(cmd_system_detect_platform);
803803

804+
// `--arch` only changes the answer on Windows, where the admin mode R
805+
// installation root is architecture dependent, so it is hidden elsewhere.
806+
// It is still defined on every platform, so that scripts do not break, and
807+
// it must not have a default value: `_default_arch` is empty on Linux and
808+
// would fail the value parser. (This is why `rig add --arch` and
809+
// `rig available --arch` need a `#[cfg]` block and this one does not.)
810+
fn arch_arg() -> Arg {
811+
Arg::new("arch")
812+
.help("Architecture of the R installation root (default: native arch).")
813+
.short('a')
814+
.long("arch")
815+
.required(false)
816+
.value_parser(["x86_64", "aarch64", "arm64"])
817+
.platform("windows")
818+
}
819+
820+
let cmd_system_dirs = Command::new("dirs")
821+
.about(ABOUT_SYSTEM_DIRS)
822+
.long_about(HELP_SYSTEM_DIRS)
823+
.display_order(0)
824+
.arg(
825+
Arg::new("json")
826+
.help("JSON output")
827+
.long("json")
828+
.num_args(0)
829+
.required(false),
830+
)
831+
.arg(arch_arg());
832+
833+
let cmd_system_r_dir = Command::new("r-dir")
834+
.about(ABOUT_SYSTEM_R_DIR)
835+
.long_about(HELP_SYSTEM_R_DIR)
836+
.display_order(0)
837+
.arg(arch_arg());
838+
839+
let cmd_system_rtools_dir = Command::new("rtools-dir")
840+
.about(ABOUT_SYSTEM_RTOOLS_DIR)
841+
.long_about(HELP_SYSTEM_RTOOLS_DIR)
842+
.display_order(0)
843+
.platform("windows");
844+
845+
let cmd_system_binary_dir = Command::new("binary-dir")
846+
.about(ABOUT_SYSTEM_BINARY_DIR)
847+
.long_about(HELP_SYSTEM_BINARY_DIR)
848+
.display_order(0);
849+
850+
cmd_system = cmd_system
851+
.subcommand(cmd_system_dirs)
852+
.subcommand(cmd_system_r_dir)
853+
.subcommand(cmd_system_rtools_dir)
854+
.subcommand(cmd_system_binary_dir);
855+
804856
cmd_system = cmd_system
805857
.subcommand(cmd_system_links)
806858
.subcommand(cmd_system_lib)
@@ -1868,4 +1920,62 @@ mod tests {
18681920
let cmdargs: Vec<&String> = run.get_many::<String>("command").unwrap().collect();
18691921
assert_eq!(cmdargs, ["check", "--no-manual", "."]);
18701922
}
1923+
1924+
// The `rig system dirs` family. These tests run on every platform, so they
1925+
// are also the guard that the items that are merely *hidden* off Windows
1926+
// stay defined everywhere.
1927+
1928+
fn sysargs(argv: &[&str]) -> ArgMatches {
1929+
let m = rig_app().try_get_matches_from(argv).unwrap();
1930+
m.subcommand_matches("system").unwrap().to_owned()
1931+
}
1932+
1933+
#[test]
1934+
fn test_system_dirs_args() {
1935+
let m = sysargs(&["rig", "system", "dirs"]);
1936+
let dirs = m.subcommand_matches("dirs").unwrap();
1937+
assert!(!dirs.get_flag("json"));
1938+
1939+
let m = sysargs(&["rig", "system", "dirs", "--json"]);
1940+
assert!(m.subcommand_matches("dirs").unwrap().get_flag("json"));
1941+
1942+
// The global --json also works, and must precede the subcommand.
1943+
let m = rig_app()
1944+
.try_get_matches_from(["rig", "--json", "system", "dirs"])
1945+
.unwrap();
1946+
assert!(m.get_flag("json"));
1947+
}
1948+
1949+
#[test]
1950+
fn test_system_dir_commands_are_defined_on_all_platforms() {
1951+
// `rtools-dir` is hidden off Windows, but it must still parse, so that
1952+
// scripts can call it unconditionally.
1953+
let m = sysargs(&["rig", "system", "rtools-dir"]);
1954+
assert!(m.subcommand_matches("rtools-dir").is_some());
1955+
1956+
let m = sysargs(&["rig", "system", "binary-dir"]);
1957+
assert!(m.subcommand_matches("binary-dir").is_some());
1958+
}
1959+
1960+
#[test]
1961+
fn test_system_r_dir_arch() {
1962+
// Same as above: --arch is hidden off Windows, but always defined.
1963+
let m = sysargs(&["rig", "system", "r-dir", "--arch", "aarch64"]);
1964+
let rdir = m.subcommand_matches("r-dir").unwrap();
1965+
assert_eq!(rdir.get_one::<String>("arch"), Some(&"aarch64".to_string()));
1966+
1967+
// No default value: an empty one would fail the value parser on Linux.
1968+
let m = sysargs(&["rig", "system", "r-dir"]);
1969+
let rdir = m.subcommand_matches("r-dir").unwrap();
1970+
assert_eq!(rdir.get_one::<String>("arch"), None);
1971+
1972+
// `dirs` takes --arch as well.
1973+
let m = sysargs(&["rig", "system", "dirs", "-a", "arm64"]);
1974+
let dirs = m.subcommand_matches("dirs").unwrap();
1975+
assert_eq!(dirs.get_one::<String>("arch"), Some(&"arm64".to_string()));
1976+
1977+
assert!(rig_app()
1978+
.try_get_matches_from(["rig", "system", "r-dir", "--arch", "amd64"])
1979+
.is_err());
1980+
}
18711981
}

src/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ fn rig_config_file() -> Result<PathBuf, Box<dyn Error>> {
3434
Ok(config_file)
3535
}
3636

37+
// The path of the rig configuration file. It does not need to exist.
38+
// Used by `rig config config-file-path` and `rig system dirs`.
39+
pub fn config_file_path() -> Result<PathBuf, Box<dyn Error>> {
40+
rig_config_file()
41+
}
42+
3743
impl Config {
3844
fn load() -> Result<Config, Box<dyn Error>> {
3945
let config_file = rig_config_file()?;

0 commit comments

Comments
 (0)