Skip to content
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

chromium: replace update.nix with Python impl #72932

Merged
merged 4 commits into from Sep 5, 2020

Conversation

alyssais
Copy link
Member

@alyssais alyssais commented Nov 6, 2019

update.nix was a huuuuge hack, abusing checksum collisions, etc., and
was extremely difficult to read and maintain, especially because
values from update.nix were also used in the derivations themselves!

I've replaced this with an implementation in Python, which I chose for
readability. Chromium is quite big, and we have to download three of
them, so I added some parallelism. It could still be faster, but this
is good enough for now.

I also removed some stuff that didn't ever seem to have been used,
like i686 binary checksums (which didn't seem to exist even at the
time the script was written). Rather than generating Nix, I chose to
generate JSON, since Python can do that in the standard library and
Nix can read it.

I also set update.py as an updateScript, so Chromium can now
automatically be updated!

Fixes #89635.

Copy link
Member

@samueldr samueldr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without having ran it, simply reading, this passes the sniff test. This looks like a manageability improvement.

I'll leave the actual approval and validation to @aszlig :).

Copy link
Member

@aszlig aszlig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this, I guess it's time to get rid of the hash collision workaround :-)

While I'd be happy to merge this right in, this unfortunately is a step backwards from the updater we have so far, so I commented on the specifics accordingly. So while it's not necessary to be a 100% in parity with the previous updater, the new updater has a few particular annoyances that I think need to be addressed.

Also, since you changed a few things in the Nix expressions of Chromium itself, let's also ping @bendlas and @ivan here.

from urllib.request import urlopen

DEB_URL = "https://dl.google.com/linux/chrome/deb/pool/main/g"
BUCKET_URL = "https://commondatastorage.googleapis.com/chromium-browser-official";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
BUCKET_URL = "https://commondatastorage.googleapis.com/chromium-browser-official";
BUCKET_URL = "https://commondatastorage.googleapis.com/chromium-browser-official"

BUCKET_URL = "https://commondatastorage.googleapis.com/chromium-browser-official";

def nix_prefetch_url(url, hash="sha256"):
out = subprocess.check_output(["nix-prefetch-url", "--type", hash, url])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will break the whole updating process if omahaproxy refers to a tarball that doesn't exist. That's why I did the md5/sha1 collision in the first place (it's basically the same as builtins.tryEval (builtins.fetchurl url)).

For example, right now the following is returned by omahaproxy:

os channel current_version previous_version current_reldate previous_reldate branch_base_commit branch_base_position branch_commit true_branch v8_version
linux dev 80.0.3955.4 79.0.3945.16 11/01/19 10/29/19 1be17a97af38b81c6b4bd01cd698e8329f62857b 710886 2fa66c8c902846e47cab48edf8aea6c8b4e3a2d8 3955 8.0.113
linux beta 79.0.3945.16 78.0.3904.85 10/31/19 10/30/19 e4635fff7defbae0f9c29e798349f6fc0cce4b1b 706915 66fad076c1051f8d10555c8fe1de36f6a8effc69 3945 7.9.317.14
linux stable 78.0.3904.97 78.0.3904.87 11/06/19 10/31/19 675968a8c657a3bd9c1c2c20c5d2935577bbc5e6 693954 2fa4ee555b8b5b382d68e1118ab7e6eac293a039 3904 7.8.279.23

However, https://commondatastorage.googleapis.com/chromium-browser-official/chromium-78.0.3904.97.tar.xz currently returns with HTTP 404.

Furthermore, the use of nix-prefetch-url here will shovel the whole tarball into memory, so executing these in parallel will cause trouble on machines with limited amount of memory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addendum to that and to explain the reason for the builtins.tryEval (builtins.fetchurl url) hack:

The old updater not only checked the main omahaproxy URL but also http://omahaproxy.appspot.com/history and whenever a given tarball doesn't exist in the main URL, the updater would walk back the history until it finds a version where the tarball actually exists.

This is done only via a curl -I (HTTP HEAD) request and is used to get an overview of all the latest versions that actually exist in the upstream bucket.

Only the result of this is compared against the existing upstream-info.nix, so that the updater always produced a valid result of the latest available versions, even if some upstream tarballs are non-existing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't nix-prefetch-url return an error if the url to be fetched shows a 404?

Other than that, yeah, the updater could be extended to also probe http://omahaproxy.appspot.com/history (and we'd need to add this to the src attribute too)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't nix-prefetch-url return an error if the url to be fetched shows a 404?

Of course and that's why I introduced that hash collision hack to do builtins.tryEval (builtins.fetchurl url) natively in Nix.

Other than that, yeah, the updater could be extended to also probe http://omahaproxy.appspot.com/history (and we'd need to add this to the src attribute too)

Especially since back in the days where I was maintaining Chromium, this happened very frequently (like on almost every single update). Not sure however if this is still the case, but from my comment above it still happened in November 2019.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we might want to have the update script figure out the real location where things can be downloaded from, and then just write that URL to upstream-info.json, removing all the complicated "look in many different places" logic at build time.

# binaries at the same. The tasks aren't dependent on each other
# -- it's just more annoying to assemble the final channels
# dictionary that way.
channels = dict(pool.starmap(prefetch_source, channels.items()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that upstream-info.json is not checked before, this will always download all the tarballs even though no update is needed, so I'd suggest reading upstream-info.json and only download tarballs if there is a new version available.

channels = dict(pool.starmap(prefetch_source, channels.items()))
channels = dict(pool.starmap(prefetch_bin, channels.items()))

argv = ['nix-instantiate', '--eval', '--json', '-A', 'chromium.meta.position']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail if the script is run from any other directory other than the repository root, so I'd instead use something like this:

os.path.dirname(os.path.abspath(__file__))

... which I think is also easier to see what this is supposed to do.

@@ -99,18 +100,22 @@ let
versionRange = min-version: upto-version:
let inherit (upstream-info) version;
result = versionAtLeast version min-version && versionOlder version upto-version;
stable-version = (import ./upstream-info.nix).stable.version;
stable-version = with builtins;
(fromJSON (readFile ./upstream-info.json)).stable.version;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using lib.importJSON here.

@@ -31,10 +31,11 @@ in let
chromium = {
inherit stdenv llvmPackages;

upstream-info = (callPackage ./update.nix {}).getChannel channel;
upstream-info = with builtins;
(fromJSON (readFile ./upstream-info.json)).${channel};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lib.importJSON again.

@aszlig aszlig requested review from ivan and bendlas November 6, 2019 21:30
@aszlig
Copy link
Member

aszlig commented Nov 6, 2019

@alyssais: Note also the eval error from ofborg.

@stale
Copy link

stale bot commented Jun 1, 2020

Thank you for your contributions.
This has been automatically marked as stale because it has had no activity for 180 days.
If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity.
Here are suggestions that might help resolve this more quickly:

  1. Search for maintainers and people that previously touched the
    related code and @ mention them in a comment.
  2. Ask on the NixOS Discourse. 3. Ask on the #nixos channel on
    irc.freenode.net.

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jun 1, 2020
@flokli
Copy link
Contributor

flokli commented Jun 6, 2020

@alyssais any chance you could address @aszlig's comments? I just opened #89635, not seeing this PR already exists.

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jun 6, 2020
@alyssais
Copy link
Member Author

@aszlig @flokli I think I’ve addressed everything now? It’s been a while since I last looked at this, though, so I’d appreciate some more eyes.

@flokli
Copy link
Contributor

flokli commented Aug 27, 2020

This needs another rebase, and I'd propose making update.py executable. Apart from that, LGTM! 🚀

@alyssais
Copy link
Member Author

This needs another rebase,

Done. Our chromiumDev was out of date, so I added a separate commit bumping that with the old one before running the new one so it wasn’t just upgraded silently.

and I'd propose making update.py executable.

It already is?

update.nix was a huuuuge hack, abusing checksum collisions, etc., and
was extremely difficult to read and maintain, especially because
values from update.nix were also used in the derivations themselves!

I've replaced this with an implementation in Python, which I chose for
readability.  Rather than generating Nix, I chose to
generate JSON, since Python can do that in the standard library and
Nix can read it.

I also set update.py as an updateScript, so Chromium can now
automatically be updated!

Fixes: NixOS#89635
@flokli
Copy link
Contributor

flokli commented Sep 5, 2020

Sorry, forgot to take a look at this again. Did the rebase, and ran the updater again.

@flokli flokli merged commit 1fbc28c into NixOS:master Sep 5, 2020
@Kazimazi
Copy link
Contributor

Kazimazi commented Sep 16, 2020

What does chromiumDev 87 need to start in native wayland? It always uses xwayland.
Edit: might be this issue Linux builds no longer respects --ozone-platform=wayland

@alyssais alyssais deleted the chromium-update branch April 9, 2021 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

chromium: use a less frightening updater script
5 participants