Skip to content

Commit 7312e3c

Browse files
committed
Add 'rig proj tree'
1 parent ae2514b commit 7312e3c

11 files changed

Lines changed: 360 additions & 16 deletions

File tree

NEWS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
table, and `rig pkg tree` shows the same dependencies as a tree.
1111

1212
* `rig proj deps` has a new `--recursive` (`-r`) option, to show the whole
13-
dependency closure of the project, like `rig pkg deps --recursive` does
14-
for a package. Its table now has the same columns as `rig pkg deps`.
13+
dependency closure of the project.
14+
15+
* New `rig proj tree` shows the dependency closure of a project as a tree.
1516

1617
* `rig library add`, `rig library default`, `rig library list` and
1718
`rig library rm` have a new `--r-version` (`-r`) option, to operate on

src/args.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,41 @@ pub fn rig_app() -> Command {
13511351
.required(false),
13521352
),
13531353
)
1354+
.subcommand(
1355+
Command::new("tree")
1356+
.about(ABOUT_PROJ_TREE)
1357+
.long_about(HELP_PROJ_TREE)
1358+
.display_order(0)
1359+
.arg(
1360+
Arg::new("input")
1361+
.help("Project file to solve (e.g. DESCRIPTION)")
1362+
.long("input")
1363+
.short('i')
1364+
.num_args(1)
1365+
.required(false),
1366+
)
1367+
.arg(
1368+
Arg::new("dev")
1369+
.help("Include dev (development) dependencies")
1370+
.long("dev")
1371+
.num_args(0)
1372+
.required(false),
1373+
)
1374+
.arg(
1375+
Arg::new("no-base")
1376+
.help("Leave out R and the base packages")
1377+
.long("no-base")
1378+
.num_args(0)
1379+
.required(false),
1380+
)
1381+
.arg(
1382+
Arg::new("json")
1383+
.help("JSON output")
1384+
.long("json")
1385+
.num_args(0)
1386+
.required(false),
1387+
),
1388+
)
13541389
.subcommand(
13551390
Command::new("solve")
13561391
.about(ABOUT_PROJ_SOLVE)

src/help-generated.in

Lines changed: 5 additions & 3 deletions
Large diffs are not rendered by default.

src/help/pkg-tree.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ and the version requirement it is needed with, if it has one.
3535

3636
By default the tree of the latest version of the package is shown; use
3737
`--version` to ask about a specific one, including versions that CRAN has
38-
archived.
38+
archived. [`rig proj tree`](proj.qmd#rig-proj-tree) shows the same tree for the
39+
dependencies a project declares, instead of a package's.
3940

4041
## Repeated packages
4142

src/help/proj-deps.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ the `Depth` column giving its distance from the project, and the
2424
package metadata of the repositories, which rig downloads if it does not
2525
have it yet.
2626

27+
[`rig proj tree`](#rig-proj-tree) shows the same closure as a tree, laid
28+
out by the shape of the dependency graph, so you can see *how* each
29+
package is pulled in and not only *that* it is.
30+
2731
A recursive listing only ever follows hard dependencies, also below a
2832
development dependency added by `--dev`, so `--dev --recursive` means the
2933
project's own dev dependencies plus everything they need to be installed.

src/help/proj-tree.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Dependency tree of a project
2+
3+
## Description
4+
5+
Show everything an R project needs, directly or indirectly, as a tree, so you
6+
can see *how* each package is pulled in and not only *that* it is.
7+
8+
This is the same set of packages that
9+
[`rig proj deps --recursive`](#rig-proj-deps) lists in a flat table, laid out by
10+
the shape of the dependency graph instead. Use `--json` for machine readable
11+
output, as one nested object.
12+
13+
```
14+
myproject 0.1.0 — 3 direct, 24 total
15+
├── R (>= 4.1) [D]
16+
├── cli 3.6.4
17+
│ ├── R (>= 3.4) [D]
18+
│ └── utils
19+
└── dplyr 1.1.4 (>= 1.1.0)
20+
├── cli 3.6.4 (>= 3.4.0) (*)
21+
└── vctrs 0.6.5 (>= 0.6.4)
22+
└── cpp11 0.5.2 [L]
23+
[Suggests]
24+
└── testthat 3.2.3 (>= 3.1.5)
25+
```
26+
27+
The first line names the project and its version, how many dependencies it
28+
declares directly, and how many distinct packages there are in the whole tree.
29+
Each line below it names a package, the version currently in the repositories,
30+
and the version requirement it is needed with, if it has one.
31+
32+
By default rig reads the project manifest (e.g. `DESCRIPTION`) in the current
33+
directory; use `--input` to point to a different file. Unlike the plain
34+
[`rig proj deps`](#rig-proj-deps) listing, the tree needs the package metadata
35+
of the repositories, which rig downloads if it does not have it yet. It does
36+
not need R.
37+
38+
## Reading the tree
39+
40+
A package that several others need is expanded only once, under the first
41+
place it appears; later occurrences are a single line marked `(*)`, meaning
42+
"its dependencies are above". That is also what makes dependency cycles end on
43+
their own.
44+
45+
`--dev` adds the project's development dependencies, `Suggests` and `Enhances`,
46+
in their own `[Suggests]` and `[Enhances]` sections. As in `rig proj deps`,
47+
`--dev` applies to the project only: below a development dependency rig still
48+
follows hard dependencies only. `--no-base` leaves out R and the base packages
49+
altogether, which is much less to read if you only care about what would have
50+
to be installed. A package that is not in the repositories at all is shown with
51+
`?` for its version.
52+
53+
Among the hard dependencies, `Imports` is the common case and is not marked;
54+
`[D]` is a `Depends`, `[L]` a `LinkingTo`, `[DL]` both.
55+
[`rig pkg tree`](pkg.qmd#rig-pkg-tree), which shows the same tree for a package
56+
in the repositories, describes all of this in full.
57+
58+
rig follows the dependencies of the *latest* version of every package in the
59+
tree, so a version requirement that would force an older version, with
60+
different dependencies, is not taken into account. Use
61+
[`rig proj solve`](#rig-proj-solve) for a resolution that is consistent across
62+
versions.

src/help/proj.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ repositories and can install them into a project library.
1111

1212
`rig proj deps` shows the direct and recursive dependencies of the
1313
project.
14+
`rig proj tree` shows the recursive dependencies as a tree, so you can
15+
see how each package is pulled in.
1416
`rig proj solve` resolves the full dependency tree to a concrete set of
1517
package versions, and can write the result to an `renv.lock` file.
1618
`rig proj deploy` installs the resolved dependencies into a package
1719
library.
1820

1921
Dependencies are resolved with rig's built-in solver, so R does not need
20-
to be running for `rig proj deps` and `rig proj solve`.
22+
to be running for `rig proj deps`, `rig proj tree` and `rig proj solve`.
2123

2224
`rig proj` is currently experimental, and might change in future
2325
versions. Feedback is appreciated.

src/pkg/deps.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,14 @@ pub(super) fn recursive_dep_names(
212212
Ok(rows.into_iter().map(|row| row.name).collect())
213213
}
214214

215+
/// The packages of a [`walk_deps`] listing, by name. Lets [`super::tree`] check
216+
/// that a project tree walks the same closure `rig proj deps --recursive` does,
217+
/// without exposing [`DepRow`]'s fields outside the module.
218+
#[cfg(test)]
219+
pub(super) fn dep_row_names(rows: &[DepRow]) -> Vec<String> {
220+
rows.iter().map(|row| row.name.clone()).collect()
221+
}
222+
215223
/// Record `dep` as a dependency of `parent`, `depth` steps from the queried
216224
/// package, and return whether this is the first time we see it.
217225
///

src/pkg/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(crate) mod deps;
2323
mod manifest;
2424
#[cfg(test)]
2525
mod stub;
26-
mod tree;
26+
pub(crate) mod tree;
2727

2828
pub fn sc_pkg(args: &ArgMatches, mainargs: &ArgMatches) -> Result<(), Box<dyn Error>> {
2929
match args.subcommand() {

0 commit comments

Comments
 (0)