Skip to content

(dev/core#5700) cv dl - Split download substeps. Fix upgrades of EFv1=>EFv2. #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 17, 2025

Conversation

totten
Copy link
Member

@totten totten commented Apr 10, 2025

Overview

cv dl (cv ext:download) allows you to download extension-upgrades. As presented in dev/core#5700, some upgrades are prone to sporadic failures. One reproducible version of this occurs when an extension transitions from "Entity Framework v1" (EFv1) to "Entity Framework v2" (EFv2).

In general, the technique to fix this is to split the download-workflow into multiple subprocesses. The basic issue has been addressed in the web-based downloader for 6.1+ (civicrm/civicrm-core#32285); and there is also a hotfix for the web-based downloader in older versions. This PR applies the same technique to CLI downloads

Before

Upgrading example extension (bottlecap) from v0.1 (EFv1) to v0.2 (EFv2) via cv dl leads to an error:

$ cv dl bottlecap
Using extension feed "https://think.hm/tmp/bottlecap/feed-0.2"
Downloading extension "bottlecap" (https://think.hm/tmp/bottlecap/bottlecap-0.2.zip)

In Bottlecap.php line 14:

  [Error]
  Class "CRM_Bottlecap_DAO_Base" not found

After

Similar commands pass. With verbose output, we see:

$ cv dl bottlecap -vf
Using extension feed "https://think.hm/tmp/bottlecap/feed-0.2"
Fetch "bottlecap" from "https://think.hm/tmp/bottlecap/bottlecap-0.2.zip"
Verify requirements
Swap folders
Rebuild system
Upgrade database
Cleanup workspace

Internally, this required a fair amount of work. For each of those lines ("Verify requirements", "Swap folders", etc), cv needs to open a subprocess to do the work -- and then report-back on its outcome. When there are errors, the errors should propagate back in a sensible way (e.g. being printed to the screen in conformance with usual verbose/non-verbose behavior -- and yielding a decent exit-code).

Comments

  • For testing, I focused on the bottlecap extension which can be used to reproduce upgrade problems.
  • The update is loosely coupled to (dev/core#5700) Extensions - "Add New" is supposed to install new extensions civicrm-core#32591:
    • Once 32591 is merged into core, cv will start using the core implementation of CRM_Extension_QueueDownloader.
    • However, on older versions of Civi, cv will use a backport that's included here (./src/ExtensionPolyfill/PfQueueDownloader). This copy should slowly become obsolete as older versions of Civi fade-out.
  • Locally, I've used both the raw cv src (bin/cv) and a compiled (bin/cv.phar). It seems to work with both. I've also spot-checked with builds of drupal-clean on 6.2 (with and with 32591), 6.1.0, 5.81, 5.75, 5.63, 5.57, and 5.45.

totten added 9 commits April 9, 2025 18:39
Currently, `cv` has a list of php-scoper rules to exclude certain classes from prefixing.
The same list has to be adapted to use in `civix` - so, presumbly, they'll have to be
sync'd over time.

The main reason for this is to allow the PHAR to call-out to the UF during bootstrap -- and
each UF has a different list of rules.

In theory, we could drop these rules -- and replace any lines like
`drupal_bootstrap()` with `Top::call('drupal_bootstrap')`. Then there would be no
need to keep the rules in sync.

Additionally, it would allow `cv.phar` to take advantage of libraries (like `symfony/event`)
that might be dual-purpose. (Ex: cv.phar and UF both have `EventDispatcher`s; and you want
to add listeners to both of them.)
* Pass-through the path of the current PHP and cv binaries
* Pass-through arguments like --level and --user
…check

The output gets quite annoying with (eg) `cv dl -vv` (where every task in the queue
gets run in a subprocess -- and winds up reprinting this message).
@totten
Copy link
Member Author

totten commented Apr 10, 2025

@demeritcowboy I'm curious if this patch works alright on Windows. I'm less concerned about the specific use-cases of dev/core#5700 -- and more concerned about general compatibility:

  • The workflow constructs some file-hierarchies while working on the download.
  • The patch relies on spawning subprocesses and passing some data back+forth.

I'm cautiously optimistic -- e.g. I avoided pcntl_fork() and used proc_open() (esp 87748d3) because that should have better portability. However, I don't have a good setup for testing on Windows.

@totten totten changed the title (dev/core#5700) Extension - Split download substeps. Fix upgrades of EFv1=>EFv2. (dev/core#5700) cv dl - Split download substeps. Fix upgrades of EFv1=>EFv2. Apr 10, 2025
@demeritcowboy
Copy link
Contributor

If you mean does just something like cv dl [some extses] work then yes. It leaves a staging folder behind though.

And by accident the first time I tried it I happened to pick some extensions I already had in the ext folder, as git checkouts, and then it gave php warnings and couldn't clean up the "old" subfolders properly because some git files there were read-only. That's probably an edge case. It all still works though.

But even later with no warnings it left an empty staging folder behind.

@totten
Copy link
Member Author

totten commented Apr 12, 2025

(@demeritcowboy) If you mean does just something like cv dl [some extses] work then yes.

Yes, exactly. 😄

But even later with no warnings it left an empty staging folder behind.

Ah, sure. I was thinking of .civicrm-staging/ as a general container that gets reused for multiple jobs, and then .civicrm-staging/XXXX/ (random ID) is the per-task workspace (to cleanup). But you're right -- most of the time, it's empty and safe to remove.

Added a commit to that bit of cleanup.

@totten totten merged commit 1accc92 into civicrm:master Apr 17, 2025
1 check passed
@totten totten deleted the master-dl-queue branch April 17, 2025 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants