From 48b7e9bece0a087b6d4b11dd15fabcbd2c62ab1f Mon Sep 17 00:00:00 2001 From: Pierre-Etienne Meunier Date: Tue, 17 Dec 2024 11:31:23 +0100 Subject: [PATCH 1/3] Make all functions overridable Currently, most functions take `pkgs` as an argument, and fail to use some of their other arguments, effectively replacing them with `pkgs.[blah]`. This commit fixes that. --- crate2nix/Cargo.nix | 22 +++++++++------ crate2nix/templates/Cargo.nix.tera | 20 ++++++++----- crate2nix/templates/nix/crate2nix/default.nix | 17 ++++++----- .../bin_with_git_submodule_dep/Cargo.nix | 26 ++++++++++------- sample_projects/codegen/Cargo.nix | 28 +++++++++++-------- sample_projects/sub_dir_crates/Cargo.nix | 26 ++++++++++------- 6 files changed, 86 insertions(+), 53 deletions(-) diff --git a/crate2nix/Cargo.nix b/crate2nix/Cargo.nix index cfdb08c8..4f23824e 100644 --- a/crate2nix/Cargo.nix +++ b/crate2nix/Cargo.nix @@ -4,10 +4,16 @@ # See https://github.com/kolloch/crate2nix for more info. { nixpkgs ? ../nix/nixpkgs.nix -, pkgs ? import nixpkgs { config = {}; } +, pkgs ? import nixpkgs { } , fetchurl ? pkgs.fetchurl +, fetchgit ? pkgs.fetchgit +, callPackage ? pkgs.callPackage , lib ? pkgs.lib +, buildPackages ? pkgs.buildPackages , stdenv ? pkgs.stdenv +, stdenvNoCC ? pkgs.stdenvNoCC +, symlinkJoin ? pkgs.symlinkJoin +, runCommand ? pkgs.runCommand , buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate # This is used as the `crateOverrides` argument for `buildRustCrate`. , defaultCrateOverrides ? pkgs.defaultCrateOverrides @@ -24,7 +30,7 @@ # Additional crate2nix configuration if it exists. , crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix {} + then callPackage ./crate-config.nix {} else {} }: @@ -65,7 +71,7 @@ rec { # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { + allWorkspaceMembers = symlinkJoin { name = "all-workspace-members"; paths = let members = builtins.attrValues workspaceMembers; @@ -3286,15 +3292,15 @@ rec { # If the user hasn't set any pre/post commands, we don't want to # insert empty lines. This means that any existing users of crate2nix # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" ( - pkgs.lib.filter (s: s != "") [ + testCommand = lib.concatStringsSep "\n" ( + lib.filter (s: s != "") [ testPreRun "$f $testCrateFlags 2>&1 | tee -a $out" testPostRun ] ); in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = "run-tests-${testCrate.name}"; inherit (crate) src; @@ -3330,7 +3336,7 @@ rec { ''; }; in - pkgs.runCommand "${crate.name}-linked" + runCommand "${crate.name}-linked" { inherit (crate) outputs crateName; passthru = (crate.passthru or { }) // { @@ -3469,7 +3475,7 @@ rec { ) crateConfigs; target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + build = mkBuiltByPackageIdByPkgs buildPackages; }; in self; diff --git a/crate2nix/templates/Cargo.nix.tera b/crate2nix/templates/Cargo.nix.tera index 980d5032..29b3f8b0 100644 --- a/crate2nix/templates/Cargo.nix.tera +++ b/crate2nix/templates/Cargo.nix.tera @@ -6,10 +6,16 @@ # See https://github.com/kolloch/crate2nix for more info. { nixpkgs ? {{config.nixpkgs_path | safe}} -, pkgs ? import nixpkgs { config = {}; } +, pkgs ? import nixpkgs { } , fetchurl ? pkgs.fetchurl +, fetchgit ? pkgs.fetchgit +, callPackage ? pkgs.callPackage , lib ? pkgs.lib +, buildPackages ? pkgs.buildPackages , stdenv ? pkgs.stdenv +, stdenvNoCC ? pkgs.stdenvNoCC +, symlinkJoin ? pkgs.symlinkJoin +, runCommand ? pkgs.runCommand , buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate # This is used as the `crateOverrides` argument for `buildRustCrate`. , defaultCrateOverrides ? pkgs.defaultCrateOverrides @@ -26,7 +32,7 @@ # Additional crate2nix configuration if it exists. , crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix {} + then callPackage ./crate-config.nix {} else {} }: @@ -74,7 +80,7 @@ rec { registries = { {%- for name, hash in registries %} {{name}} = builtins.fromJSON (builtins.readFile (fetchurl { - url = "{{name | safe}}/config.json"; + url = "{{name | trim_end_matches(pat="/") | safe}}/config.json"; sha256 = {{hash}}; })); {%- endfor %} @@ -82,7 +88,7 @@ rec { {%- endif %} # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { + allWorkspaceMembers = symlinkJoin { name = "all-workspace-members"; paths = let members = builtins.attrValues workspaceMembers; @@ -147,16 +153,16 @@ rec { {%- elif crate.source.Nix.file.import and crate.source.Nix.attr %} src = (import {{crate.source.Nix.file.import | safe}}).{{crate.source.Nix.attr | safe}}; {%- elif crate.source.Nix.file.package and crate.source.Nix.attr %} - src = (pkgs.callPackage {{crate.source.Nix.file.package | safe}} {}).{{crate.source.Nix.attr | safe}}; + src = (callPackage {{crate.source.Nix.file.package | safe}} {}).{{crate.source.Nix.attr | safe}}; {%- elif crate.source.Nix.file.import %} src = import {{crate.source.Nix.file.import | safe}}; {%- elif crate.source.Nix.file.package %} - src = pkgs.callPackage {{crate.source.Nix.file.package | safe}} {}; + src = callPackage {{crate.source.Nix.file.package | safe}} {}; {%- elif crate.source.LocalDirectory.path %} src = lib.cleanSourceWith { filter = sourceFilter; src = {{crate.source.LocalDirectory.path | safe}}; }; {%- elif crate.source.Git %} workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = {{crate.source.Git.url}}; rev = {{crate.source.Git.rev}}; {%- if crate.source.Git.sha256 %} diff --git a/crate2nix/templates/nix/crate2nix/default.nix b/crate2nix/templates/nix/crate2nix/default.nix index 3e088032..4d212974 100644 --- a/crate2nix/templates/nix/crate2nix/default.nix +++ b/crate2nix/templates/nix/crate2nix/default.nix @@ -1,15 +1,18 @@ # # crate2nix/default.nix (excerpt start) #{# -{ pkgs -, lib +{ lib +, pkgs , stdenv +, stdenvNoCC , buildRustCrate , buildRustCrateForPkgs ? if buildRustCrate != null then lib.warn "`buildRustCrate` is deprecated, use `buildRustCrateForPkgs` instead" (_: buildRustCrate) else pkgs: pkgs.buildRustCrate +, buildPackages , defaultCrateOverrides +, runCommand , strictDeprecation ? true , crates ? { } , rootFeatures ? [ ] @@ -157,15 +160,15 @@ rec { # If the user hasn't set any pre/post commands, we don't want to # insert empty lines. This means that any existing users of crate2nix # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" ( - pkgs.lib.filter (s: s != "") [ + testCommand = lib.concatStringsSep "\n" ( + lib.filter (s: s != "") [ testPreRun "$f $testCrateFlags 2>&1 | tee -a $out" testPostRun ] ); in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = "run-tests-${testCrate.name}"; inherit (crate) src; @@ -201,7 +204,7 @@ rec { ''; }; in - pkgs.runCommand "${crate.name}-linked" + runCommand "${crate.name}-linked" { inherit (crate) outputs crateName; passthru = (crate.passthru or { }) // { @@ -340,7 +343,7 @@ rec { ) crateConfigs; target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + build = mkBuiltByPackageIdByPkgs buildPackages; }; in self; diff --git a/sample_projects/bin_with_git_submodule_dep/Cargo.nix b/sample_projects/bin_with_git_submodule_dep/Cargo.nix index 34060349..0d08cb05 100644 --- a/sample_projects/bin_with_git_submodule_dep/Cargo.nix +++ b/sample_projects/bin_with_git_submodule_dep/Cargo.nix @@ -4,10 +4,16 @@ # See https://github.com/kolloch/crate2nix for more info. { nixpkgs ? -, pkgs ? import nixpkgs { config = {}; } +, pkgs ? import nixpkgs { } , fetchurl ? pkgs.fetchurl +, fetchgit ? pkgs.fetchgit +, callPackage ? pkgs.callPackage , lib ? pkgs.lib +, buildPackages ? pkgs.buildPackages , stdenv ? pkgs.stdenv +, stdenvNoCC ? pkgs.stdenvNoCC +, symlinkJoin ? pkgs.symlinkJoin +, runCommand ? pkgs.runCommand , buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate # This is used as the `crateOverrides` argument for `buildRustCrate`. , defaultCrateOverrides ? pkgs.defaultCrateOverrides @@ -24,7 +30,7 @@ # Additional crate2nix configuration if it exists. , crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix {} + then callPackage ./crate-config.nix {} else {} }: @@ -65,7 +71,7 @@ rec { # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { + allWorkspaceMembers = symlinkJoin { name = "all-workspace-members"; paths = let members = builtins.attrValues workspaceMembers; @@ -485,7 +491,7 @@ rec { edition = "2018"; links = "rocksdb"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/rust-rocksdb/rust-rocksdb"; rev = "66f04df013b6e6bd42b5a8c353406e09a7c7da2a"; sha256 = "1rchvjrjamdaznx26gy4bmjj10rrf00mgc1wvkc489r9z1nh4h1h"; @@ -837,7 +843,7 @@ rec { version = "0.21.0"; edition = "2018"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/rust-rocksdb/rust-rocksdb"; rev = "66f04df013b6e6bd42b5a8c353406e09a7c7da2a"; sha256 = "1rchvjrjamdaznx26gy4bmjj10rrf00mgc1wvkc489r9z1nh4h1h"; @@ -1504,15 +1510,15 @@ rec { # If the user hasn't set any pre/post commands, we don't want to # insert empty lines. This means that any existing users of crate2nix # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" ( - pkgs.lib.filter (s: s != "") [ + testCommand = lib.concatStringsSep "\n" ( + lib.filter (s: s != "") [ testPreRun "$f $testCrateFlags 2>&1 | tee -a $out" testPostRun ] ); in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = "run-tests-${testCrate.name}"; inherit (crate) src; @@ -1548,7 +1554,7 @@ rec { ''; }; in - pkgs.runCommand "${crate.name}-linked" + runCommand "${crate.name}-linked" { inherit (crate) outputs crateName; passthru = (crate.passthru or { }) // { @@ -1687,7 +1693,7 @@ rec { ) crateConfigs; target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + build = mkBuiltByPackageIdByPkgs buildPackages; }; in self; diff --git a/sample_projects/codegen/Cargo.nix b/sample_projects/codegen/Cargo.nix index 91bdd375..0181706f 100644 --- a/sample_projects/codegen/Cargo.nix +++ b/sample_projects/codegen/Cargo.nix @@ -4,10 +4,16 @@ # See https://github.com/kolloch/crate2nix for more info. { nixpkgs ? -, pkgs ? import nixpkgs { config = {}; } +, pkgs ? import nixpkgs { } , fetchurl ? pkgs.fetchurl +, fetchgit ? pkgs.fetchgit +, callPackage ? pkgs.callPackage , lib ? pkgs.lib +, buildPackages ? pkgs.buildPackages , stdenv ? pkgs.stdenv +, stdenvNoCC ? pkgs.stdenvNoCC +, symlinkJoin ? pkgs.symlinkJoin +, runCommand ? pkgs.runCommand , buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate # This is used as the `crateOverrides` argument for `buildRustCrate`. , defaultCrateOverrides ? pkgs.defaultCrateOverrides @@ -24,7 +30,7 @@ # Additional crate2nix configuration if it exists. , crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix {} + then callPackage ./crate-config.nix {} else {} }: @@ -65,7 +71,7 @@ rec { # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { + allWorkspaceMembers = symlinkJoin { name = "all-workspace-members"; paths = let members = builtins.attrValues workspaceMembers; @@ -249,7 +255,7 @@ rec { version = "0.9.7"; edition = "2018"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/diwic/dbus-rs.git"; rev = "618262f5e3217cdd173d46d705bbac26c5141e21"; sha256 = "0gvhz2knd1k799l7ssh4rdm5qw0vhazzr3bxpmlgq7fhy6hjazrs"; @@ -287,7 +293,7 @@ rec { edition = "2018"; crateBin = []; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/diwic/dbus-rs.git"; rev = "618262f5e3217cdd173d46d705bbac26c5141e21"; sha256 = "0gvhz2knd1k799l7ssh4rdm5qw0vhazzr3bxpmlgq7fhy6hjazrs"; @@ -362,7 +368,7 @@ rec { edition = "2015"; links = "dbus"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/diwic/dbus-rs.git"; rev = "618262f5e3217cdd173d46d705bbac26c5141e21"; sha256 = "0gvhz2knd1k799l7ssh4rdm5qw0vhazzr3bxpmlgq7fhy6hjazrs"; @@ -679,15 +685,15 @@ rec { # If the user hasn't set any pre/post commands, we don't want to # insert empty lines. This means that any existing users of crate2nix # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" ( - pkgs.lib.filter (s: s != "") [ + testCommand = lib.concatStringsSep "\n" ( + lib.filter (s: s != "") [ testPreRun "$f $testCrateFlags 2>&1 | tee -a $out" testPostRun ] ); in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = "run-tests-${testCrate.name}"; inherit (crate) src; @@ -723,7 +729,7 @@ rec { ''; }; in - pkgs.runCommand "${crate.name}-linked" + runCommand "${crate.name}-linked" { inherit (crate) outputs crateName; passthru = (crate.passthru or { }) // { @@ -862,7 +868,7 @@ rec { ) crateConfigs; target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + build = mkBuiltByPackageIdByPkgs buildPackages; }; in self; diff --git a/sample_projects/sub_dir_crates/Cargo.nix b/sample_projects/sub_dir_crates/Cargo.nix index 5b16ffb6..d0557121 100644 --- a/sample_projects/sub_dir_crates/Cargo.nix +++ b/sample_projects/sub_dir_crates/Cargo.nix @@ -4,10 +4,16 @@ # See https://github.com/kolloch/crate2nix for more info. { nixpkgs ? -, pkgs ? import nixpkgs { config = {}; } +, pkgs ? import nixpkgs { } , fetchurl ? pkgs.fetchurl +, fetchgit ? pkgs.fetchgit +, callPackage ? pkgs.callPackage , lib ? pkgs.lib +, buildPackages ? pkgs.buildPackages , stdenv ? pkgs.stdenv +, stdenvNoCC ? pkgs.stdenvNoCC +, symlinkJoin ? pkgs.symlinkJoin +, runCommand ? pkgs.runCommand , buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate # This is used as the `crateOverrides` argument for `buildRustCrate`. , defaultCrateOverrides ? pkgs.defaultCrateOverrides @@ -24,7 +30,7 @@ # Additional crate2nix configuration if it exists. , crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix {} + then callPackage ./crate-config.nix {} else {} }: @@ -65,7 +71,7 @@ rec { # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { + allWorkspaceMembers = symlinkJoin { name = "all-workspace-members"; paths = let members = builtins.attrValues workspaceMembers; @@ -93,7 +99,7 @@ rec { version = "0.1.0"; edition = "2018"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/kolloch/with_sub_crates.git"; rev = "f8ad2b98ff0eb5fea4962f55e3ced5b0b5afe973"; sha256 = "0nlw7rg28p6bya040cbipq4jdcdp4h3q9shdjygfk2xkva9bjl8w"; @@ -108,7 +114,7 @@ rec { version = "0.1.0"; edition = "2018"; workspace_member = null; - src = pkgs.fetchgit { + src = fetchgit { url = "https://github.com/kolloch/with_sub_crates.git"; rev = "f8ad2b98ff0eb5fea4962f55e3ced5b0b5afe973"; sha256 = "0nlw7rg28p6bya040cbipq4jdcdp4h3q9shdjygfk2xkva9bjl8w"; @@ -288,15 +294,15 @@ rec { # If the user hasn't set any pre/post commands, we don't want to # insert empty lines. This means that any existing users of crate2nix # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" ( - pkgs.lib.filter (s: s != "") [ + testCommand = lib.concatStringsSep "\n" ( + lib.filter (s: s != "") [ testPreRun "$f $testCrateFlags 2>&1 | tee -a $out" testPostRun ] ); in - pkgs.stdenvNoCC.mkDerivation { + stdenvNoCC.mkDerivation { name = "run-tests-${testCrate.name}"; inherit (crate) src; @@ -332,7 +338,7 @@ rec { ''; }; in - pkgs.runCommand "${crate.name}-linked" + runCommand "${crate.name}-linked" { inherit (crate) outputs crateName; passthru = (crate.passthru or { }) // { @@ -471,7 +477,7 @@ rec { ) crateConfigs; target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + build = mkBuiltByPackageIdByPkgs buildPackages; }; in self; From 3abe776ab41342ff80806c8c391819b99585811c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-=C3=89tienne=20Meunier?= Date: Fri, 20 Dec 2024 17:19:57 +0100 Subject: [PATCH 2/3] Allow overriding fetchurl --- crate2nix/templates/nix/crate2nix/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crate2nix/templates/nix/crate2nix/default.nix b/crate2nix/templates/nix/crate2nix/default.nix index 4d212974..f098e033 100644 --- a/crate2nix/templates/nix/crate2nix/default.nix +++ b/crate2nix/templates/nix/crate2nix/default.nix @@ -12,6 +12,7 @@ pkgs: pkgs.buildRustCrate , buildPackages , defaultCrateOverrides +, fetchurl , runCommand , strictDeprecation ? true , crates ? { } @@ -418,7 +419,7 @@ rec { crateConfig // { src = - crateConfig.src or (pkgs.fetchurl rec { + crateConfig.src or (fetchurl rec { name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; # https://www.pietroalbini.org/blog/downloading-crates-io/ # Not rate-limited, CDN URL. From 9671a1f3c4199016505addbd3a16b8c3c15034ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-=C3=89tienne=20Meunier?= Date: Fri, 20 Dec 2024 17:41:38 +0100 Subject: [PATCH 3/3] Fixing the tests --- crate2nix/Cargo.nix | 2 +- sample_projects/bin_with_git_submodule_dep/Cargo.nix | 2 +- sample_projects/codegen/Cargo.nix | 2 +- sample_projects/sub_dir_crates/Cargo.nix | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crate2nix/Cargo.nix b/crate2nix/Cargo.nix index 4f23824e..3b0647d7 100644 --- a/crate2nix/Cargo.nix +++ b/crate2nix/Cargo.nix @@ -3550,7 +3550,7 @@ rec { crateConfig // { src = - crateConfig.src or (pkgs.fetchurl rec { + crateConfig.src or (fetchurl rec { name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; # https://www.pietroalbini.org/blog/downloading-crates-io/ # Not rate-limited, CDN URL. diff --git a/sample_projects/bin_with_git_submodule_dep/Cargo.nix b/sample_projects/bin_with_git_submodule_dep/Cargo.nix index 0d08cb05..4dd57a6c 100644 --- a/sample_projects/bin_with_git_submodule_dep/Cargo.nix +++ b/sample_projects/bin_with_git_submodule_dep/Cargo.nix @@ -1768,7 +1768,7 @@ rec { crateConfig // { src = - crateConfig.src or (pkgs.fetchurl rec { + crateConfig.src or (fetchurl rec { name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; # https://www.pietroalbini.org/blog/downloading-crates-io/ # Not rate-limited, CDN URL. diff --git a/sample_projects/codegen/Cargo.nix b/sample_projects/codegen/Cargo.nix index 0181706f..2196d635 100644 --- a/sample_projects/codegen/Cargo.nix +++ b/sample_projects/codegen/Cargo.nix @@ -943,7 +943,7 @@ rec { crateConfig // { src = - crateConfig.src or (pkgs.fetchurl rec { + crateConfig.src or (fetchurl rec { name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; # https://www.pietroalbini.org/blog/downloading-crates-io/ # Not rate-limited, CDN URL. diff --git a/sample_projects/sub_dir_crates/Cargo.nix b/sample_projects/sub_dir_crates/Cargo.nix index d0557121..262f1d8a 100644 --- a/sample_projects/sub_dir_crates/Cargo.nix +++ b/sample_projects/sub_dir_crates/Cargo.nix @@ -552,7 +552,7 @@ rec { crateConfig // { src = - crateConfig.src or (pkgs.fetchurl rec { + crateConfig.src or (fetchurl rec { name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; # https://www.pietroalbini.org/blog/downloading-crates-io/ # Not rate-limited, CDN URL.