dart-lang / pub

The pub command line tool
https://dart.dev/tools/pub/cmd
BSD 3-Clause "New" or "Revised" License
1.04k stars 224 forks source link

`dart pub global activate` rebuilding unnecessarily #4334

Open liamappelbe opened 1 month ago

liamappelbe commented 1 month ago

I've used dart pub global activate to make a tool usable directly from the command line. It works, but it's rebuilding the tool every time I invoke it. The tool (named qq) is just a thin git wrapper I wrote, customized to my workflow. It's unpublished, I just clone its git repo.

Here's an example output. It says Building package executable... Built qq:qq every time I invoke it:

image

My Dart SDK comes from Flutter. My Flutter SDK is from a cloned git repo:

liama@liama-macbookpro ~/d/n/p/ffigen (swiftgen2)> flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[!] Flutter (Channel master, 3.23.0-13.0.pre.117, on macOS 14.5 23F79 darwin-x64, locale en)
    ! Upstream repository git@github.com:liamappelbe/flutter.git is not a standard remote.
      Set environment variable "FLUTTER_GIT_URL" to git@github.com:liamappelbe/flutter.git to dismiss this error.
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[!] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    ! CocoaPods 1.11.2 out of date (1.13.0 is recommended).
        CocoaPods is a package manager for iOS or macOS platform code.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To update CocoaPods, see https://guides.cocoapods.org/using/getting-started.html#updating-cocoapods
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.91.0)
[✓] VS Code (version 1.74.2)
[✓] Connected device (2 available)            
    ! Error: Browsing on the local area network for iPhone. Ensure the device is unlocked and attached with a cable or associated with the
      same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources

! Doctor found issues in 2 categories.
dart-github-bot commented 1 month ago

Summary: The user is experiencing unnecessary rebuilds of a custom tool (qq) activated globally using dart pub global activate. The tool is a thin git wrapper and is not published, but rather cloned from a git repository. Every invocation of the tool triggers a rebuild, even though no changes have been made.

liamappelbe commented 1 month ago

The bug seems to have gotten worse overnight. Today it's resolving dependencies twice before starting to rebuild the tool:

image

jonasfj commented 1 month ago

@liamappelbe feel free to share a minimally reproduciable example. Actually if you're activating from path I wouldn't be surprised if we throw away the precompilation everytime.

But double resolution of dependencies is weird :rofl:

Also include dart --version.

liamappelbe commented 1 month ago

Minimal example:

dart create -t cli testcli
dart pub global activate --source path testcli
dart pub global run testcli
dart pub global run testcli  # Rebuilds unnecessarily

Dart version: Dart SDK version: 3.6.0-78.0.dev (dev) (Wed Jul 24 13:03:02 2024 -0700) on "macos_x64"

sigurdm commented 1 month ago

When you are activating from path, the package is considered "mutable" so we rebuild the executable each time.

We should though be using incremental compilation, so the second build should be much faster - are you seeing that?

But double resolution of dependencies is weird 🤣

Yeah - that seems wrong.

I was however not able to reproduce this.

> dart create -t cli testcli
Creating testcli using template cli...
[...]
> dart pub global activate -spath testcli
Resolving dependencies in `testcli`... 
Downloading packages... 
Got dependencies in `testcli`!
Activated testcli 0.0.1 at path "/usr/local/google/home/sigurdm/projects/blah/testcli".
> dart pub global run testcli
Building package executable... 
Built testcli:testcli.
Positional arguments: []
> dart pub global run testcli
Building package executable... 
Built testcli:testcli.
Positional arguments: []

@liamappelbe can you give a simple reproduction of the reresolution of dependencies?

As a workaround for global activateing a local package and avoiding recompilation you can check your app into git, and run

dart pub global activate --source git testcli/

This will activate a static view of the testcli package (and thus not reflect local updates to the package without reactivation).

sigurdm commented 1 month ago

Also note that the "Building package executable... " output from pub is suppressed when no terminal is attached to the process.

liamappelbe commented 1 month ago

When you are activating from path, the package is considered "mutable" so we rebuild the executable each time.

Could we add a flag to dart pub global activate to disable rebuilding for path activations? A flag to replicate the behaviour we get for a git activation?

We should though be using incremental compilation, so the second build should be much faster - are you seeing that?

The build is small enough that I'm not noticing any difference between the first and second runs. It's about 2 seconds each time to build and execute the script (this is true of both the testcli example, and my qq script).

If I write a bash script that just checks whether the snapshot exists, and runs it directly if it does, then the time reduces to 1 second (and I don't get spurious prints). But I think it'd be better if this behavior was simply a flag in the activate command.

@liamappelbe can you give a simple reproduction of the reresolution of dependencies?

Not really. It seems to just happen randomly on my Mac. The steps I outlined above are enough to reproduce it flakily on my Mac.