about summary refs log tree commit diff
path: root/pkgs/development/tools/build-managers/bazel/bazel_7/tests.nix
blob: 0976d1c2d5a6007cff5e5b2001403f0da3e370e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
{ lib
  # tooling
, callPackage
, fetchFromGitHub
, newScope
, recurseIntoAttrs
, runCommandCC
, stdenv
  # inputs
, Foundation
, bazel_self
, lr
, xe
, lockfile
, ...
}:
let
  inherit (stdenv.hostPlatform) isDarwin;

  testsDistDir = testsRepoCache;
  testsRepoCache = callPackage ./bazel-repository-cache.nix {
    # Bazel builtin tools versions are hard-coded in bazel. If the project
    # lockfile has not been generated by the same bazel version as this one
    # then it may be missing depeendencies for builtin tools. Export
    # dependencies from baazel itself here, and let projects also import their
    # own if need be. It's just a symlinkJoin after all. See ./cpp-test.nix
    inherit lockfile;

    # Take all the rules_ deps, bazel_ deps and their transitive dependencies,
    # but none of the platform-specific binaries, as they are large and useless.
    requiredDepNamePredicate = name:
      name == "_main~bazel_build_deps~workspace_repo_cache"
      || null == builtins.match ".*(macos|osx|linux|win|android|maven).*" name
      && null != builtins.match "(platforms|com_google_|protobuf|rules_|.*bazel_|apple_support).*" name;
  };

  runLocal = name: attrs: script:
    let
      attrs' = removeAttrs attrs [ "buildInputs" ];
      buildInputs = attrs.buildInputs or [ ];
    in
    runCommandCC name
      ({
        inherit buildInputs;
        preferLocalBuild = true;
        meta.platforms = bazel_self.meta.platforms;
      } // attrs')
      script;

  # bazel wants to extract itself into $install_dir/install every time it runs,
  # so let’s do that only once.
  extracted = bazelPkg:
    let
      install_dir =
        # `install_base` field printed by `bazel info`, minus the hash.
        # yes, this path is kinda magic. Sorry.
        "$HOME/.cache/bazel/_bazel_nixbld";
    in
    runLocal "bazel-extracted-homedir" { passthru.install_dir = install_dir; } ''
      export HOME=$(mktemp -d)
      touch WORKSPACE # yeah, everything sucks
      install_base="$(${bazelPkg}/bin/bazel info install_base)"
      # assert it’s actually below install_dir
      [[ "$install_base" =~ ${install_dir} ]] \
        || (echo "oh no! $install_base but we are \
      trying to copy ${install_dir} to $out instead!"; exit 1)
      cp -R ${install_dir} $out
    '';

  bazelTest = { name, bazelScript, workspaceDir, bazelPkg, buildInputs ? [ ] }:
    runLocal name
      {
        inherit buildInputs;
        # Necessary for the tests to pass on Darwin with sandbox enabled.
        __darwinAllowLocalNetworking = true;
      }
      ''
        # Bazel needs a real home for self-extraction and internal cache
        mkdir bazel_home
        export HOME=$PWD/bazel_home

        ${# Concurrent bazel invocations have the same workspace path.
          # On darwin, for some reason, it means they access and corrupt the
          # same outputRoot, outputUserRoot and outputBase
          # Ensure they use build-local outputRoot by setting TEST_TMPDIR
          lib.optionalString isDarwin ''
            export TEST_TMPDIR=$HOME/.cache/bazel
          ''
        }
        ${# Speed-up tests by caching bazel extraction.
          # Except on Darwin, because nobody knows how Darwin works.
          let bazelExtracted = extracted bazelPkg;
          in lib.optionalString (!isDarwin) ''
            mkdir -p ${bazelExtracted.install_dir}
            cp -R ${bazelExtracted}/install ${bazelExtracted.install_dir}

            # https://stackoverflow.com/questions/47775668/bazel-how-to-skip-corrupt-installation-on-centos6
            # Bazel checks whether the mtime of the install dir files
            # is >9 years in the future, otherwise it extracts itself again.
            # see PosixFileMTime::IsUntampered in src/main/cpp/util
            # What the hell bazel.
            ${lr}/bin/lr -0 -U ${bazelExtracted.install_dir} | ${xe}/bin/xe -N0 -0 touch --date="9 years 6 months" {}
          ''
        }
        ${# Note https://github.com/bazelbuild/bazel/issues/5763#issuecomment-456374609
          # about why to create a subdir for the workspace.
          '' cp -r ${workspaceDir} wd && chmod ug+rw -R wd && cd wd ''
        }
        ${# run the actual test snippet
          bazelScript
        }
        ${# Try to keep darwin clean of our garbage
          lib.optionalString isDarwin ''
            rm -rf $HOME || true
          ''
        }

        touch $out
      '';

  bazel-examples = fetchFromGitHub {
    owner = "bazelbuild";
    repo = "examples";
    rev = "93564e1f1e7a3c39d6a94acee12b8d7b74de3491";
    hash = "sha256-DaPKp7Sn5uvfZRjdDx6grot3g3B7trqCyL0TRIdwg98=";
  };

  callBazelTests = bazel:
    let
      callBazelTest = newScope {
        inherit runLocal bazelTest bazel-examples;
        inherit Foundation;
        inherit bazel;
        distDir = testsDistDir;
        extraBazelArgs = "--noenable_bzlmod";
        repoCache = testsRepoCache;
      };
    in
    recurseIntoAttrs (
      (lib.optionalAttrs (!isDarwin) {
        # `extracted` doesn’t work on darwin
        shebang = callBazelTest ../shebang-test.nix {
          inherit extracted;
          extraBazelArgs = "--noenable_bzlmod";
        };
      }) // {
        bashTools = callBazelTest ../bash-tools-test.nix { };
        cpp = callBazelTest ./cpp-test.nix {
          extraBazelArgs = "";
        };
        java = callBazelTest ./java-test.nix { };
        pythonBinPath = callBazelTest ../python-bin-path-test.nix { };
        protobuf = callBazelTest ./protobuf-test.nix { };
      }
    );

  bazelWithNixHacks = bazel_self.override { enableNixHacks = true; };

in
recurseIntoAttrs {
  distDir = testsDistDir;
  testsRepoCache = testsRepoCache;

  vanilla = callBazelTests bazel_self;
  withNixHacks = callBazelTests bazelWithNixHacks;

  # add some downstream packages using buildBazelPackage
  downstream = recurseIntoAttrs ({
    # TODO: fix bazel-watcher build with bazel 7, or find other packages
    #inherit bazel-watcher;
  });
}