source: trunk/flake.nix

Last change on this file was 4de3508, checked in by Florian Sesser <florian@…>, at 2024-12-12T17:05:38Z

Make hatchling write us a _version.py when running the tests

Co-authored-by: Benoit Donneaux <benoit@…>

  • Property mode set to 100644
File size: 8.8 KB
Line 
1{
2  description = "Tahoe-LAFS, free and open decentralized data store";
3
4  inputs = {
5    # A couple possible nixpkgs pins.  Ideally these could be selected easily
6    # from the command line but there seems to be no syntax/support for that.
7    # However, these at least cause certain revisions to be pinned in our lock
8    # file where you *can* dig them out - and the CI configuration does.
9    #
10    # These are really just examples for the time being since neither of these
11    # releases contains a package set that is completely compatible with our
12    # requirements.  We could decide in the future that supporting multiple
13    # releases of NixOS at a time is worthwhile and then pins like these will
14    # help us test each of those releases.
15    "nixpkgs-24_11" = {
16      url = github:NixOS/nixpkgs?ref=nixos-24.11;
17    };
18
19    # Point the default nixpkgs at one of those.
20    nixpkgs.follows = "nixpkgs-24_11";
21
22    # Also get flake-utils for simplified multi-system definitions.
23    flake-utils = {
24      url = github:numtide/flake-utils;
25    };
26
27    # And get a helper that lets us easily continue to provide a default.nix.
28    flake-compat = {
29      url = "github:edolstra/flake-compat";
30      flake = false;
31    };
32  };
33
34  outputs = { self, nixpkgs, flake-utils, ... }:
35    {
36      # Expose an overlay which adds our version of Tahoe-LAFS to the Python
37      # package sets we specify, as well as all of the correct versions of its
38      # dependencies.
39      #
40      # We will also use this to define some other outputs since it gives us
41      # the most succinct way to get a working Tahoe-LAFS package.
42      overlays.default = import ./nix/overlay.nix;
43
44    } // (flake-utils.lib.eachDefaultSystem (system: let
45
46      # The package set for this system architecture.
47      pkgs = import nixpkgs {
48        inherit system;
49        # And include our Tahoe-LAFS package in that package set.
50        overlays = [ self.overlays.default ];
51      };
52
53      # pythonVersions :: [string]
54      #
55      # The version strings for the Python runtimes we'll work with.
56      pythonVersions =
57        let
58          # Match attribute names that look like a Python derivation - CPython
59          # or PyPy.  We take care to avoid things like "python-foo" and
60          # "python3Full-unittest" though.  We only want things like "pypy38"
61          # or "python311".
62          nameMatches = name: null != builtins.match "(python|pypy)3[[:digit:]]{0,2}" name;
63
64          # Sometimes an old version is left in the package set as an error
65          # saying something like "we remove this".  Make sure we whatever we
66          # found by name evaluates without error, too.
67          notError = drv: (builtins.tryEval drv).success;
68        in
69          # Discover all of the Python runtime derivations by inspecting names
70          # and filtering out derivations with errors.
71          builtins.attrNames (
72            pkgs.lib.attrsets.filterAttrs
73              (name: drv: nameMatches name && notError drv)
74              pkgs
75          );
76
77      # defaultPyVersion :: string
78      #
79      # An element of pythonVersions which we'll use for the default package.
80      defaultPyVersion = "python3";
81
82      # pythons :: [derivation]
83      #
84      # Retrieve the actual Python package for each configured version.  We
85      # already applied our overlay to pkgs so our packages will already be
86      # available.
87      pythons = builtins.map (pyVer: pkgs.${pyVer}) pythonVersions;
88
89      # packageName :: string -> string
90      #
91      # Construct the Tahoe-LAFS package name for the given Python runtime.
92      packageName = pyVersion: "${pyVersion}-tahoe-lafs";
93
94      # string -> string
95      #
96      # Construct the unit test application name for the given Python runtime.
97      unitTestName = pyVersion: "${pyVersion}-unittest";
98
99      # (string -> a) -> (string -> b) -> string -> attrset a b
100      #
101      # Make a singleton attribute set from the result of two functions.
102      singletonOf = f: g: x: { ${f x} = g x; };
103
104      # [attrset] -> attrset
105      #
106      # Merge a list of attrset into a single attrset with overlap preferring
107      # rightmost values.
108      mergeAttrs = pkgs.lib.foldr pkgs.lib.mergeAttrs {};
109
110      # makeRuntimeEnv :: string -> derivation
111      #
112      # Create a derivation that includes a Python runtime, Tahoe-LAFS, and
113      # all of its dependencies.
114      makeRuntimeEnv = singletonOf packageName makeRuntimeEnv';
115      makeRuntimeEnv' = pyVersion: (pkgs.${pyVersion}.withPackages (ps: with ps;
116        [ tahoe-lafs ] ++
117        tahoe-lafs.passthru.extras.i2p ++
118        tahoe-lafs.passthru.extras.tor
119      )).overrideAttrs (old: {
120        # By default, withPackages gives us a derivation with a fairly generic
121        # name (like "python-env").  Put our name in there for legibility.
122        # See the similar override in makeTestEnv.
123        name = packageName pyVersion;
124      });
125
126      # makeTestEnv :: string -> derivation
127      #
128      # Create a derivation that includes a Python runtime and all of the
129      # Tahoe-LAFS dependencies, but not Tahoe-LAFS itself, which we'll get
130      # from the working directory.
131      makeTestEnv = pyVersion: (pkgs.${pyVersion}.withPackages (ps: with ps;
132        [ tahoe-lafs ] ++
133        tahoe-lafs.passthru.extras.i2p ++
134        tahoe-lafs.passthru.extras.tor ++
135        tahoe-lafs.passthru.extras.unittest ++
136        [ hatchling hatch-vcs ]
137      )).overrideAttrs (old: {
138        # See the similar override in makeRuntimeEnv'.
139        name = packageName pyVersion;
140      });
141    in {
142      # Include a package set with out overlay on it in our own output.  This
143      # is mainly a development/debugging convenience as it will expose all of
144      # our Python package overrides beneath it.  The magic name
145      # "legacyPackages" is copied from nixpkgs and has special support in the
146      # nix command line tool.
147      legacyPackages = pkgs;
148
149      # The flake's package outputs.  We'll define one version of the package
150      # for each version of Python we could find.  We'll also point the
151      # flake's "default" package at the derivation corresponding to the
152      # default Python version we defined above.  The package consists of a
153      # Python environment with Tahoe-LAFS available to it.
154      packages =
155        mergeAttrs (
156          [ { default = self.packages.${system}.${packageName defaultPyVersion}; } ]
157          ++ (builtins.map makeRuntimeEnv pythonVersions)
158          ++ (builtins.map (singletonOf unitTestName makeTestEnv) pythonVersions)
159        );
160
161      # The flake's app outputs.  We'll define a version of an app for running
162      # the test suite for each version of Python we could find.  We'll also
163      # define a version of an app for running the "tahoe" command-line
164      # entrypoint for each version of Python we could find.
165      apps =
166        let
167          # writeScript :: string -> string -> path
168          #
169          # Write a shell program to a file so it can be run later.
170          #
171          # We avoid writeShellApplication here because it has ghc as a
172          # dependency but ghc has Python as a dependency and our Python
173          # package override triggers a rebuild of ghc and many Haskell
174          # packages which takes a looong time.
175          writeScript = name: text: "${pkgs.writeShellScript name text}";
176
177          # makeTahoeApp :: string -> attrset
178          #
179          # A helper function to define the Tahoe-LAFS runtime entrypoint for
180          # a certain Python runtime.
181          makeTahoeApp = pyVersion: {
182            "tahoe-${pyVersion}" = {
183              type = "app";
184              program =
185                writeScript "tahoe"
186                  ''
187                    ${makeRuntimeEnv' pyVersion}/bin/tahoe "$@"
188                  '';
189            };
190          };
191
192          # makeUnitTestsApp :: string -> attrset
193          #
194          # A helper function to define the Tahoe-LAFS unit test entrypoint
195          # for a certain Python runtime.
196          makeUnitTestsApp = pyVersion: {
197            "${unitTestName pyVersion}" = {
198              type = "app";
199              program =
200                let
201                  python = "${makeTestEnv pyVersion}/bin/python";
202                  hatchling = "${makeTestEnv pyVersion}/bin/hatchling";
203                in
204                  writeScript "unit-tests"
205                    ''
206                    ${hatchling} build --hooks-only # Write _version.py
207                    export TAHOE_LAFS_HYPOTHESIS_PROFILE=ci
208                    export PYTHONPATH=$PWD/src
209                    ${python} -m twisted.trial "$@"
210                  '';
211            };
212          };
213        in
214          # Merge a default app definition with the rest of the apps.
215          mergeAttrs (
216            [ { default = self.apps.${system}."tahoe-python3"; } ]
217            ++ (builtins.map makeUnitTestsApp pythonVersions)
218            ++ (builtins.map makeTahoeApp pythonVersions)
219          );
220    }));
221}
Note: See TracBrowser for help on using the repository browser.