dart-lang / pub

The pub command line tool

Home Page:https://dart.dev/tools/pub/cmd

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`getExecutableForCommand` requires reading pubspec.yaml

sigurdm opened this issue · comments

Discussion

Currently dart run package:command will only run commands if package is a direct (dev or non-dev) dependency of the current root package.

This convention makes sense. Only the packages you directly depend on are the ones you should rely on running tools from.

But deciding if a package is in dependencies requires parsing pubspec.yaml of the root package. As this is in the hot path of dart run we would like to only rely on information from .dart_tool/package_config.json. (json is faster to parse than yaml, it will be hot on the drive when passed to the VM that also needs the file).

One solution would be to add the names of dependencies of each package to the package listing in .dart_tool/package_config.json.

One concern with this, is that the size of .dart_tool/package_config.json potentially will be O(n^2) in the number of packages in the resolution.

This is information is also strictly more than we need. We really only need to know if a dependency is direct dependency of the root package or not. We could instead add a bit (is-direct-dependency-of-root) to each package listed in the file.

This is however not enough when we introduce workspaces to pub. Here a number of root packages share a .dart_tool/package_config.json, and when we do dart run inside a package a in a workspace, we only want access to the packages that are direct dependencies of a, not of every root in the workspace.

That leads to:

Proposal

Add the list of direct dependencies only to the root packages. dart run in a directory x would then need to find out which package is associated with x and could thus see if the package is one of its dependencies.

This would not have the O(n^2) behavior (unless o(n) of the packages are root packages...)

Example json:

{
  "configVersion": 2,
  "packages": [
    {
      "name": "dep",
      "rootUri": "file:///usr/local/google/home/sigurdm/.pub-cache/hosted/pub.dev/dep-1.0.0",
      "packageUri": "lib/",
      "languageVersion": "3.0" // Not a root package, no dependencies listing
    },
    {
      "name": "dev_dep",
      "rootUri": "file:///usr/local/google/home/sigurdm/.pub-cache/hosted/pub.dev/dev_dep-1.0.0",
      "packageUri": "lib/",
      "languageVersion": "3.0"  // Not a root package, no dependencies listing
    },
    {
      "name": "myapp",
      "rootUri": "../",
      "packageUri": "lib/",
      "languageVersion": "3.7"
      "dependencies": ["dep", "b"] // Depends on external dep, and workspace member b.
    },
    {
      "name": "b",
      "rootUri": "../pkgs/b",
      "packageUri": "lib/",
      "languageVersion": "3.7"
      "dependencies": ["dev_dep"] // Depends on external dev_dep
    },
    {
      "name": "a",
      "rootUri": "../pkgs/a",
      "packageUri": "lib/",
      "languageVersion": "3.7"
      "dependencies": [] // No dependencies
    }
  ],
  "generated": "2024-04-15T13:37:03.000003Z",
  "generator": "pub",
  "generatorVersion": "3.7.0",
  "pubCache": "file:///usr/local/google/home/sigurdm/.pub-cache"
}

If there are no dependencies associated with x we could either

  • fail (allow no packages)
  • allow all packages

Allowing all packages would be backwards compatible, but I'm not sure that is needed, as we rewrite package_config.json when the dart sdk is updated.

Alternatives

We could also just let dart run package:command run commands from any package. I think that would rarely give any problems, but might be slightly less disciplined.