Skip to content

Releases: guilyx/rostree

v0.4.0

Choose a tag to compare

@guilyx guilyx released this 10 Aug 12:53
e7e5a19

v0.3.0 made big trees fast. This one makes them yours: on a sourced ROS 2
machine most of what rostree can see belongs to the distro, and until now there
was no way to say so.

Added

  • Scope filters on every command that walks the graph (tree, graph, why,
    rdeps, check, diff):
    • -w/--only-workspace — ignore packages installed under /opt/ros
    • --include GLOB / --exclude GLOB — repeatable shell globs on package names
      (--include 'nav2_*', --exclude '*_msgs'); excludes win over includes
    • A filtered-out package is neither shown nor followed, so anything reachable
      only through it disappears with it. Commands report what was hidden rather
      than silently presenting a smaller tree as the whole truth.
  • --dep-type runtime|build|test|all to choose which package.xml tags to
    follow. -r/--runtime stays as a shorthand for --dep-type runtime.
  • rostree diff — what did this package gain, lose or bump?
    • rostree diff <a> <b> compares two packages
    • rostree diff <pkg> --save FILE snapshots the current dependency set, and
      --against FILE compares against it after a rebuild
    • Reports added / removed / version-changed and exits non-zero on any drift
  • rostree check --junit FILE writes a JUnit XML report for CI dashboards.
  • DependencyNode.hidden_children records how many dependencies a truncated node
    is not showing, so … N more never promises more than the tree would print.
  • build_dependency_tree() and build_dependency_graph() accept package_filter,
    report and (on the tree) include_tags.
  • Bandit runs in CI and pre-commit and is in the dev extra, so
    bandit -c pyproject.toml -r src tests reproduces the security scan that gates
    pull requests instead of it existing only in a dashboard. .codacy.yaml records
    which rules are switched off for the test suite and why; accepted findings under
    src/ carry an inline suppression with its reason, and
    development.md writes down where those
    comments have to sit, which is less obvious than it sounds.

Changed

  • rdeps --workspace-only is now --only-workspace; the old spelling still works.
  • The JUnit writer moved out of cli.py into core/junit.py. It is the only code
    in rostree that writes XML and never reads any, and keeping it separate lets that
    argument be made once, at the top of a short file, instead of on every line of a
    1,300-line module.
  • The TUI's widget guards no longer catch bare Exception. Eleven try/except Exception: pass blocks around query_one became
    contextlib.suppress(QueryError, ScreenStackError), so a bug inside a guarded
    block raises instead of disappearing. The two guards that are deliberately
    broad — best-effort tree expansion and collapse, which a background rebuild can
    interrupt — say so in a comment.

Security

  • package.xml is now parsed with defusedxml,
    a new runtime dependency. core/parser.py is the only place rostree reads XML it
    did not write, and a manifest is just a file in a workspace: one declaring
    entities could previously make the parser expand them until it ran out of memory.
    Such a manifest is now refused, which reports the package as unreadable instead
    of hanging. A DOCTYPE that declares nothing still parses, so this drops no
    package that used to work.

v0.3.0

Choose a tag to compare

@guilyx guilyx released this 10 Aug 12:52
42c0e8b

Large trees used to take tens of seconds — or never finish. This release makes
them near-instant and reworks the interface around them.

Performance

  • Dependency trees are linear, not exponential. A ROS dependency graph is a
    DAG: rcutils sits under nearly every branch. Expanding every path separately
    produced tens of thousands of duplicate nodes. Each package is now expanded once,
    where it first appears, and marked ↩ see above elsewhere — the same convention
    cargo tree uses. Measured on a 135-package install space plus a 24-package
    source workspace, resolving nav2_bringup with -r:

    depth before after
    5 4,152 nodes / 1.02 s 475 nodes / 0.02 s
    6 18,273 nodes / 4.44 s 548 nodes / 0.02 s
    7 68,081 nodes / 17.41 s 552 nodes / 0.02 s
    unlimited (the CLI default) did not finish in 4 minutes 552 nodes / 0.02 s

    Pass --full to rostree tree for the old fully-expanded behaviour.

  • Package discovery happens once. New rostree.core.index.PackageIndex scans
    every install prefix and source tree a single time and resolves names from memory.
    Previously every node of a tree could trigger a fresh recursive os.walk.

  • package.xml parsing is memoized by path, mtime and size.

  • Source scans prune build/, install/, log/, VCS metadata and directories
    marked COLCON_IGNORE/AMENT_IGNORE, and stop descending once a manifest is found.

  • rostree graph resolves the whole DAG in one breadth-first pass instead of
    building a separate full tree per package.

Added

  • rostree why <package> <dependency> — shortest dependency paths between two
    packages, answering "why is this in my tree at all?".
  • rostree rdeps <package> — reverse dependency lookup, with --transitive
    and --workspace-only.
  • rostree check — reports dependency cycles and unresolved dependencies and
    exits non-zero, so it can gate CI.
  • rostree list --filter TEXT to narrow the package list.
  • rostree tree --full, --expand-repeats, --max-nodes and -v for descriptions.
  • --no-color on all commands (NO_COLOR is honoured too).
  • NodeStatus enum on DependencyNode (ok, repeat, cycle, missing,
    parse_error, truncated) plus is_error/is_placeholder, replacing string
    markers stuffed into description. to_dict() now includes status.
  • Public API: build_graph(), reverse_dependencies(), get_index(), tree_stats().
  • TUI: live filter over every package, reverse-dependency view (v), dependency
    scope toggle (t), and a help screen (?).

Fixed

  • Graphs no longer drop edges to unresolved packages. Dependencies without a
    manifest are drawn dashed and grey instead of being silently removed, which used
    to leave workspace graphs as a field of unconnected boxes. --hide-missing
    restores the old behaviour.
  • rostree graph -w PATH now works on a workspace that is not sourced — the
    workspace's own packages are added to the search path.
  • Unbuilt packages in a sourced workspace are found again. The source root was
    derived as <ws>/install/src instead of <ws>/src, so src-only packages were
    invisible whenever the workspace was discovered through AMENT_PREFIX_PATH or
    COLCON_PREFIX_PATH. Both the merged (<ws>/install) and isolated
    (<ws>/install/<pkg>) colcon layouts are now handled.
  • Packages named lib* are no longer discarded. libstatistics_collector and
    libyaml_vendor are real ROS 2 packages; only dashed rosdep keys
    (libboost-dev, python3-numpy) are treated as system dependencies, and those
    are now kept on PackageInfo.system_dependencies rather than dropped.
  • The TUI no longer freezes while a tree is built: resolution runs on a worker
    thread and rows are created only as nodes are expanded.
  • The TUI package list is no longer capped at 80 entries per source.
  • Text trees use correct box-drawing characters (└── for last children, proper
    vertical guides); previously every child was drawn as ├──.
  • An unknown package name is now an error with suggestions and a non-zero exit,
    instead of a one-node tree and exit 0.
  • The five duplicated hand-rolled <name> XML scrapers were replaced by a single
    quick_package_name() helper.
  • Worker results in the TUI are routed to the callback that asked for them, rather
    than to whichever handler saw the completion event first.
  • ↩ see above now always refers to something printed earlier. Expansion was
    chosen by shortest distance from the root while the tree renders depth-first, so
    a back-reference could point at a subtree printed below it. Each package is now
    expanded where the tree first prints it, which also removes a whole breadth-first
    pass from tree building.
  • Reverse dependencies were cached without keying on the dependency tag set, so a
    runtime-only lookup and a full lookup returned whichever ran first.
  • rostree why <pkg> <pkg> reported a dependency path for a package that does not
    exist; the validation loop skipped both arguments when they were equal.
  • Global flags such as --no-color are accepted after the subcommand too
    (rostree tree rclcpp --no-color used to be a usage error).
  • TUI: pressing e (expand all) or running a search no longer duplicates every
    row of an already-expanded tree.
  • TUI: selecting a second package while a tree is still building no longer leaves
    the app pointing at a tree it never rendered.
  • TUI: adding a source path while a tree is open now rescans, instead of leaving
    the new packages invisible.
  • TUI: Esc leaves the dependents view when it was opened from the package list.
  • --open no longer goes through a shell on Windows: it uses os.startfile, so a
    path containing shell metacharacters cannot be misinterpreted. External tools
    (dot, open, xdg-open) are resolved to absolute paths before being executed.

Changed

  • rostree tree groups sibling back-references onto one line
    (↩ 5 already shown above: …); --expand-repeats lists them individually.
  • Depth-limited nodes report how many dependencies are hidden (… 5 more).
  • rich is now a direct dependency (it was already installed via textual).
  • Lint rules are pinned in pyproject.toml so a new ruff release cannot change
    what CI enforces.

v0.2.2

Choose a tag to compare

@guilyx guilyx released this 05 Feb 12:46
744de00

Added

  • TUI background loading: Package scanning now starts immediately when app opens (before pressing Enter)
  • Loading indicator: Shows spinner and status while scanning for packages
  • Ready status: Welcome screen shows package count when scanning completes (e.g., "✓ 123 packages found")

Changed

  • TUI uses cached packages from background scan for instant navigation
  • Refresh action (r) now clears cache and rescans in background

v0.2.1

Choose a tag to compare

@guilyx guilyx released this 05 Feb 12:28
e72607c

Fixed

  • Dynamic versioning: rostree --version now correctly reads version from package metadata instead of hardcoded value
  • TUI banner alignment: Fixed ASCII art banner with inconsistent character alignment causing visual shifting

Changed

  • Version is now sourced from importlib.metadata for single source of truth (pyproject.toml)

v0.2.0

Choose a tag to compare

@guilyx guilyx released this 05 Feb 12:06

[0.2.0] - 2026-02-05

Added

  • rostree graph command: Generate dependency graphs in DOT (Graphviz) or Mermaid format
    • Direct image rendering: --render png|svg|pdf creates image files
    • Two rendering backends: Graphviz (system) or matplotlib (pip: rostree[viz])
    • Auto-open: --open opens the rendered image in default viewer
    • Single package: rostree graph rclpy --render png
    • Entire workspace: rostree graph --render png or rostree graph -w /path/to/ws --render svg
    • Output to file with -o/--output or stdout
    • Support for depth limiting with -d/--depth
    • Runtime-only dependencies with -r/--runtime
    • Formats: --format dot (default) or --format mermaid
    • Progress output when processing multiple packages
  • TUI improvements:
    • Full-page welcome screen with centered banner and app description
    • Search functionality (/ or f to search, n/N to navigate matches)
    • Details panel toggle (d to show/hide)
    • Keyboard-only navigation throughout

Changed

  • Welcome screen is now a full view instead of a modal overlay
  • Improved package source categorization display

v0.1.0

Choose a tag to compare

@guilyx guilyx released this 05 Feb 07:58
f01ddbb
Merge pull request #2 from guilyx/feat/add-badges

docs: add project badges to README