diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a5db44b3..fe32613e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -23,9 +23,9 @@ on: env: OPERATOR_NAME: "superset-operator" - RUST_NIGHTLY_TOOLCHAIN_VERSION: "nightly-2026-02-24" + RUST_NIGHTLY_TOOLCHAIN_VERSION: "nightly-2026-07-01" NIX_PKG_MANAGER_VERSION: "2.33.3" - RUST_TOOLCHAIN_VERSION: "1.93.0" + RUST_TOOLCHAIN_VERSION: "1.95.0" HADOLINT_VERSION: "v2.14.0" PYTHON_VERSION: "3.14" CARGO_TERM_COLOR: always diff --git a/.github/workflows/pr_prek.yaml b/.github/workflows/pr_prek.yaml index 21af8922..16606c35 100644 --- a/.github/workflows/pr_prek.yaml +++ b/.github/workflows/pr_prek.yaml @@ -10,7 +10,7 @@ permissions: {} env: CARGO_TERM_COLOR: always NIX_PKG_MANAGER_VERSION: "2.33.3" - RUST_TOOLCHAIN_VERSION: "nightly-2026-02-24" + RUST_TOOLCHAIN_VERSION: "nightly-2026-07-01" HADOLINT_VERSION: "v2.14.0" JINJA2_CLI_VERSION: "1.0.0" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a689b7b..15f4e2ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: - id: detect-private-key - repo: https://github.com/EmbarkStudios/cargo-deny - rev: 8d76e7e991107da82c4a59cdc362a2739539f55d # 0.18.9 + rev: 1c9ca2b643ee15722178c1350501aabb024dd6f3 # 0.19.9 hooks: - id: cargo-deny args: ["--all-features", "check", "advisories", "bans", "licenses", "sources"] @@ -27,7 +27,7 @@ repos: args: ["--strict"] - repo: https://github.com/igorshubovych/markdownlint-cli - rev: 192ad822316c3a22fb3d3cc8aa6eafa0b8488360 # 0.45.0 + rev: a4d5d37e66ebcd6b3705204a1d6dbb56dea66338 # 0.49.0 hooks: - id: markdownlint types: [text] @@ -47,7 +47,7 @@ repos: # If you do not, you will need to delete the cached ruff binary shown in the # error message - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 3b4bc031619cde2e0a9f3c4441ac7cc8227245a4 # 0.14.1 + rev: c59bba8fb259db0fec2bbb77ad8ba51ea7341b56 # 0.15.20 hooks: # Run the linter. - id: ruff-check @@ -55,7 +55,7 @@ repos: - id: ruff-format - repo: https://github.com/rhysd/actionlint - rev: e7d448ef7507c20fc4c88a95d0c448b848cd6127 # 1.7.8 + rev: 914e7df21a07ef503a81201c76d2b11c789d3fca # 1.7.12 hooks: - id: actionlint @@ -109,7 +109,7 @@ repos: - id: cargo-rustfmt name: cargo-rustfmt language: system - entry: cargo +nightly-2026-02-24 fmt --all -- --check + entry: cargo +nightly-2026-07-01 fmt --all -- --check stages: [pre-commit, pre-merge-commit] pass_filenames: false files: \.rs$ diff --git a/.vscode/settings.json b/.vscode/settings.json index b59f2a53..bb5c7580 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "rust-analyzer.rustfmt.overrideCommand": [ "rustfmt", - "+nightly-2026-02-24", + "+nightly-2026-07-01", "--edition", "2024", "--" diff --git a/Cargo.nix b/Cargo.nix index 4a322b93..48c0d5a9 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -14874,7 +14874,15 @@ rec { ) crateConfigs; target = makeTarget pkgs.stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; + # Build-time dependency graph (for proc-macros and build + # dependencies). When not cross-compiling it equals the host + # graph, so reuse `self`; otherwise build it for + # `pkgs.buildPackages`. + build = + if pkgs.stdenv.buildPlatform.config == pkgs.stdenv.hostPlatform.config then + self + else + mkBuiltByPackageIdByPkgs pkgs.buildPackages; }; in self; @@ -14890,38 +14898,35 @@ rec { devDependencies = lib.optionals (runTests && packageId == rootPackageId) ( crateConfig'.devDependencies or [ ] ); - dependencies = dependencyDerivations { + # Enabled (platform- and feature-filtered) dependency lists, reused + # for both derivation wiring and the crate renames below. + enabledDependencies = filterEnabledDependencies { inherit features; inherit (self) target; - buildByPackageId = - depPackageId: - # proc_macro crates must be compiled for the build architecture - if crateConfigs.${depPackageId}.procMacro or false then - self.build.crates.${depPackageId} - else - self.crates.${depPackageId}; dependencies = (crateConfig.dependencies or [ ]) ++ devDependencies; }; - buildDependencies = dependencyDerivations { + enabledBuildDependencies = filterEnabledDependencies { inherit features; inherit (self.build) target; - buildByPackageId = depPackageId: self.build.crates.${depPackageId}; dependencies = crateConfig.buildDependencies or [ ]; }; + dependencies = map + ( + dependency: + # proc_macro crates must be compiled for the build architecture + if crateConfigs.${dependency.packageId}.procMacro or false then + self.build.crates.${dependency.packageId} + else + self.crates.${dependency.packageId} + ) + enabledDependencies; + buildDependencies = map + (dependency: self.build.crates.${dependency.packageId}) + enabledBuildDependencies; + # Order (build dependencies, then normal dependencies) feeds the + # crateRenames grouping below. dependenciesWithRenames = - let - buildDeps = filterEnabledDependencies { - inherit features; - inherit (self) target; - dependencies = crateConfig.dependencies or [ ] ++ devDependencies; - }; - hostDeps = filterEnabledDependencies { - inherit features; - inherit (self.build) target; - dependencies = crateConfig.buildDependencies or [ ]; - }; - in - lib.filter (d: d ? "rename") (hostDeps ++ buildDeps); + lib.filter (d: d ? "rename") (enabledBuildDependencies ++ enabledDependencies); # Crate renames have the form: # # { @@ -15093,6 +15098,17 @@ rec { corresponding feature sets are merged. Features in rust are additive. */ mergePackageFeatures = + args: builtins.mapAttrs (_packageId: builtins.attrNames) (mergePackageFeaturesImpl args); + + /* + Core of the feature-resolution fixpoint. The cache (`featuresByPackageId`) + maps each packageId to a feature *set* (an attrset `feature -> 1`) rather + than a sorted list, so the fold merges with `//` and detects convergence + with attrset equality instead of re-concatenating and re-sorting the + accumulated feature list on every step. `mergePackageFeatures` projects the + result back to canonical sorted lists. + */ + mergePackageFeaturesImpl = { crateConfigs ? crates , packageId , rootPackageId ? packageId @@ -15141,14 +15157,15 @@ rec { cache: { packageId, features }: let - cacheFeatures = cache.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ features); + cacheFeatures = cache.${packageId} or { }; + # `features` is the (small) incoming list; merge it into the set. + combinedFeatures = cacheFeatures // listToSet features; in - if cache ? ${packageId} && cache.${packageId} == combinedFeatures then + if cache ? ${packageId} && cacheFeatures == combinedFeatures then cache else - mergePackageFeatures { - features = combinedFeatures; + mergePackageFeaturesImpl { + features = builtins.attrNames combinedFeatures; featuresByPackageId = cache; inherit crateConfigs @@ -15161,8 +15178,8 @@ rec { ); cacheWithSelf = let - cacheFeatures = featuresByPackageId.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ enabledFeatures); + cacheFeatures = featuresByPackageId.${packageId} or { }; + combinedFeatures = cacheFeatures // listToSet enabledFeatures; in featuresByPackageId // { @@ -15189,27 +15206,31 @@ rec { assert (builtins.isList features); assert (builtins.isAttrs target); + let + # Identical for every dep in this call; build the predicate arg once. + targetArgs = { inherit features target; }; + in lib.filter ( dep: - let - targetFunc = dep.target or (features: true); - in - targetFunc { inherit features target; } + (dep.target or (features: true)) targetArgs && (!(dep.optional or false) || builtins.any (doesFeatureEnableDependency dep) features) ) dependencies; # Returns whether the given feature should enable the given dependency. doesFeatureEnableDependency = - dependency: feature: + dependency: + # Callers partially apply this once per dependency, then test every feature, + # so hoist the dep-invariant strings out of the per-feature comparison. let name = dependency.rename or dependency.name; + depName = "dep:" + name; prefix = "${name}/"; len = builtins.stringLength prefix; - startsWithPrefix = builtins.substring 0 len feature == prefix; in - feature == name || feature == "dep:" + name || startsWithPrefix; + feature: + feature == name || feature == depName || builtins.substring 0 len feature == prefix; /* Returns the expanded features for the given inputFeatures by applying the @@ -15223,29 +15244,24 @@ rec { assert (builtins.isAttrs featureMap); assert (builtins.isList inputFeatures); let + # Transitive closure of `inputFeatures` under `featureMap`. `seen` + # tracks already-expanded features so each is visited at most once; + # this also breaks feature cycles (issue #209). expandFeaturesNoCycle = - oldSeen: inputFeatures: - if inputFeatures != [ ] then - let - # The feature we're currently expanding. - feature = builtins.head inputFeatures; - # All the features we've seen/expanded so far, including the one - # we're currently processing. - seen = oldSeen // { - ${feature} = 1; - }; - # Expand the feature but be careful to not re-introduce a feature - # that we've already seen: this can easily cause a cycle, see issue - # #209. - enables = builtins.filter (f: !(seen ? "${f}")) (featureMap."${feature}" or [ ]); - in - [ feature ] ++ (expandFeaturesNoCycle seen (builtins.tail inputFeatures ++ enables)) - # No more features left, nothing to expand to. - else - [ ]; - outFeatures = expandFeaturesNoCycle { } inputFeatures; + seen: features: + builtins.foldl' + ( + acc: feature: + if acc ? ${feature} then + acc + else + expandFeaturesNoCycle (acc // { ${feature} = 1; }) (featureMap.${feature} or [ ]) + ) + seen + features; + seen = expandFeaturesNoCycle { } inputFeatures; in - sortedUnique outFeatures; + sortedUnique (builtins.attrNames seen); /* This function adds optional dependencies as features if they are enabled @@ -15304,16 +15320,19 @@ rec { in defaultOrNil ++ explicitFeatures ++ additionalDependencyFeatures; + # Builds a feature set (attrset `feature -> 1`) from a list of feature names. + listToSet = + features: + builtins.listToAttrs (map (feature: { name = feature; value = 1; }) features); + # Sorts and removes duplicates from a list of strings. sortedUnique = features: assert (builtins.isList features); - assert (builtins.all builtins.isString features); - let - outFeaturesSet = lib.foldl (set: feature: set // { "${feature}" = 1; }) { } features; - outFeaturesUnique = builtins.attrNames outFeaturesSet; - in - builtins.sort (a: b: a < b) outFeaturesUnique; + # attrNames returns keys in ascending string order, so the result is + # sorted and deduplicated. The feature-merge fixpoint relies on this + # canonical order to detect convergence. + builtins.attrNames (listToSet features); deprecationWarning = message: value: diff --git a/nix/sources.json b/nix/sources.json index 10cce14f..150ec884 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -17,10 +17,10 @@ "homepage": "", "owner": "kolloch", "repo": "crate2nix", - "rev": "26b698e804dd32dc5bb1995028fef00cc87d603a", - "sha256": "13jgy25yjd1m42xam6zri8vwx0n2qbwvpad2cmkhkrlx913n79ni", + "rev": "5e1ecfd2d15b34ec90c2e51fdffbe8116595a767", + "sha256": "1kgzi3r7714v957w2qnisc9axlrymrqaz5qqclzay1d83jzzp7nv", "type": "tarball", - "url": "https://github.com/kolloch/crate2nix/archive/26b698e804dd32dc5bb1995028fef00cc87d603a.tar.gz", + "url": "https://github.com/kolloch/crate2nix/archive/5e1ecfd2d15b34ec90c2e51fdffbe8116595a767.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "nixpkgs": { @@ -29,10 +29,10 @@ "homepage": "", "owner": "NixOS", "repo": "nixpkgs", - "rev": "26eaeac4e409d7b5a6bf6f90a2a2dc223c78d915", - "sha256": "1knl8dcr5ip70a2vbky3q844212crwrvybyw2nhfmgm1mvqry963", + "rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b", + "sha256": "0jx39hv3n59r7rkwyaz5qiz8dl15bvcylva06f6y2yrg5c6j9l7w", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/26eaeac4e409d7b5a6bf6f90a2a2dc223c78d915.tar.gz", + "url": "https://github.com/NixOS/nixpkgs/archive/f205b5574fd0cb7da5b702a2da51507b7f4fdd1b.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index eecd346c..4619553c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ # DO NOT EDIT, this file is generated by operator-templating [toolchain] -channel = "1.93.0" +channel = "1.95.0" profile = "default"