diff --git a/default.nix b/default.nix index fb12aa75c..a664529aa 100644 --- a/default.nix +++ b/default.nix @@ -163,38 +163,7 @@ rec { }; }; - projects = make-projects raw-projects; - - # TODO: remove after migrating to modules - # === - - raw-projects-new = import ./projects/default-module.nix { - inherit lib; - pkgs = pkgs // ngipkgs; - sources = { - inputs = sources; - modules = nixos-modules; - inherit examples; - }; - }; - - # TODO: delete the file after migrating to modules - projects-new = make-projects raw-projects-new.config.projects; - - # TODO: - # === - - project-models = import ./projects/models.nix { inherit lib pkgs sources; }; - - # we mainly care about the types being checked - templates.project = - let - project-metadata = - (project-models.project (import ./maintainers/templates/project { inherit lib pkgs sources; })) - .metadata; - in - # fake derivation for flake check - pkgs.writeText "dummy" (lib.strings.toJSON project-metadata); + projects = make-projects raw-projects.config.projects; # TODO: find a better place for this make-projects = diff --git a/flake.lock b/flake.lock index 926568250..910cebf4c 100644 --- a/flake.lock +++ b/flake.lock @@ -267,8 +267,7 @@ "nixpkgs-stable": "nixpkgs-stable", "pre-commit-hooks": "pre-commit-hooks", "sops-nix": "sops-nix", - "systems": "systems", - "yants": "yants" + "systems": "systems" } }, "slimlock": { @@ -348,22 +347,6 @@ "repo": "treefmt-nix", "type": "github" } - }, - "yants": { - "flake": false, - "locked": { - "lastModified": 1645270620, - "narHash": "sha256-wwkl3K200UbW9Z7BRlVH8HOEXCaVYP2MqZpsF9EhgZg=", - "ref": "refs/heads/canon", - "rev": "efeb6dc11eb1a1e88d41dc2093fc5aa31f7abd35", - "revCount": 15, - "type": "git", - "url": "https://code.tvl.fyi/depot.git:/nix/yants.git" - }, - "original": { - "type": "git", - "url": "https://code.tvl.fyi/depot.git:/nix/yants.git" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8fc49bac2..6b6da059a 100644 --- a/flake.nix +++ b/flake.nix @@ -13,8 +13,6 @@ inputs.sops-nix.url = "github:Mic92/sops-nix"; inputs.buildbot-nix.inputs.nixpkgs.follows = "nixpkgs"; inputs.buildbot-nix.url = "github:nix-community/buildbot-nix"; - inputs.yants.url = "git+https://code.tvl.fyi/depot.git:/nix/yants.git"; - inputs.yants.flake = false; # See for plans to support Darwin. inputs.systems.url = "github:nix-systems/default-linux"; @@ -79,36 +77,18 @@ in rec { packages = ngipkgs // { - overview = - let - overview-new = import ./overview { - inherit - lib - lib' - self - nixpkgs - system - ; - pkgs = pkgs // ngipkgs; - projects = classic.projects-new; - options = optionsDoc.optionsNix; - }; - overview-old = import ./overview { - inherit - lib - lib' - self - nixpkgs - system - ; - pkgs = pkgs // ngipkgs; - projects = ngiProjects; - options = optionsDoc.optionsNix; - }; - in - # TODO: switch to overview-new - assert overview-old == overview-new; - overview-old; + overview = import ./overview { + inherit + lib + lib' + self + nixpkgs + system + ; + pkgs = pkgs // ngipkgs; + projects = classic.projects; + options = optionsDoc.optionsNix; + }; options = pkgs.runCommand "options.json" @@ -169,7 +149,6 @@ }; "infra/makemake" = toplevel self.nixosConfigurations.makemake; "infra/overview" = self.packages.${system}.overview; - "infra/templates" = classic.templates.project; }; in checksForInfrastructure // checksForAllProjects // checksForAllPackages; diff --git a/projects/default-module.nix b/projects/default-module.nix deleted file mode 100644 index 40a6862ef..000000000 --- a/projects/default-module.nix +++ /dev/null @@ -1,130 +0,0 @@ -{ - lib, - pkgs, - sources, - types' ? import ./types.nix { inherit lib; }, -}: -let - inherit (builtins) - elem - readDir - trace - ; - - inherit (lib) - types - mkOption - ; - - inherit (lib.attrsets) - concatMapAttrs - mapAttrs - ; - - baseDirectory = ./.; - - projectDirectories = - let - names = - name: type: - if type == "directory" then - { ${name} = baseDirectory + "/${name}"; } - # nothing else should be kept in this directory reserved for projects - else - assert elem name allowedFiles; - { }; - allowedFiles = - [ - "README.md" - "default.nix" - "models.nix" - ] - # TODO: remove after fully migrating types to the module system - ++ [ - "default-module.nix" - "types.nix" - ]; - in - # TODO: use fileset and filter for `gitTracked` files - concatMapAttrs names (readDir baseDirectory); -in -{ - options.projects = mkOption { - type = - with types; - attrsOf ( - submodule ( - { name, ... }: - { - name = mkOption { - type = with types; nullOr str; - default = name; - }; - metadata = mkOption { - type = - with types; - nullOr (submodule { - options = { - summary = mkOption { - type = nullOr str; - default = null; - }; - # TODO: convert all subgrants to `subgrant`, remove listOf - subgrants = mkOption { - type = either (listOf str) types'.subgrant; - default = null; - }; - links = mkOption { - type = attrsOf types'.link; - default = { }; - }; - }; - }); - default = null; - }; - binary = mkOption { - type = with types; attrsOf types'.binary; - default = { }; - }; - nixos = mkOption { - type = - with types; - submodule { - options = { - services = mkOption { - type = nullOr (attrsOf (nullOr types'.service)); - default = null; - }; - programs = mkOption { - type = nullOr (attrsOf (nullOr types'.program)); - default = null; - }; - # An application component may have examples using it in isolation, - # but examples may involve multiple application components. - # Having examples at both layers allows us to trace coverage more easily. - # If this tends to be too cumbersome for package authors and we find a way obtain coverage information programmatically, - # we can still reduce granularity and move all examples to the application level. - examples = mkOption { - type = nullOr (attrsOf types'.example); - default = null; - }; - # TODO: Tests should really only be per example, in order to clarify that we care about tested examples more than merely tests. - # But reality is such that most NixOS tests aren't based on self-contained, minimal examples, or if they are they can't be extracted easily. - # Without this field, many applications will appear entirely untested although there's actually *some* assurance that *something* works. - # Eventually we want to move to documentable tests exclusively, and then remove this field, but this may take a very long time. - tests = mkOption { - type = nullOr (attrsOf types'.test); - default = null; - }; - }; - }; - }; - } - ) - ); - }; - - config.projects = mapAttrs ( - name: directory: import directory { inherit lib pkgs sources; } - ) projectDirectories; -} diff --git a/projects/default.nix b/projects/default.nix index 435e1bd6d..9c9d2440d 100644 --- a/projects/default.nix +++ b/projects/default.nix @@ -2,10 +2,7 @@ lib, pkgs, sources, - models ? import ./models.nix { - inherit lib pkgs; - sources = sources.inputs; - }, + types' ? import ./types.nix { inherit lib; }, }: let inherit (builtins) @@ -14,14 +11,14 @@ let trace ; + inherit (lib) + types + mkOption + ; + inherit (lib.attrsets) concatMapAttrs mapAttrs - filterAttrs - ; - - inherit (models) - project ; baseDirectory = ./.; @@ -36,21 +33,92 @@ let else assert elem name allowedFiles; { }; - allowedFiles = - [ - "README.md" - "default.nix" - "models.nix" - ] - # TODO: remove after fully migrating types to the module system - ++ [ - "default-module.nix" - "types.nix" - ]; + allowedFiles = [ + "README.md" + "default.nix" + "types.nix" + ]; in # TODO: use fileset and filter for `gitTracked` files concatMapAttrs names (readDir baseDirectory); in -mapAttrs ( - name: directory: project (import directory { inherit lib pkgs sources; }) -) projectDirectories +{ + options.projects = mkOption { + type = + with types; + attrsOf ( + submodule ( + { name, ... }: + { + name = mkOption { + type = with types; nullOr str; + default = name; + }; + metadata = mkOption { + type = + with types; + nullOr (submodule { + options = { + summary = mkOption { + type = nullOr str; + default = null; + }; + # TODO: convert all subgrants to `subgrant`, remove listOf + subgrants = mkOption { + type = either (listOf str) types'.subgrant; + default = null; + }; + links = mkOption { + type = attrsOf types'.link; + default = { }; + }; + }; + }); + default = null; + }; + binary = mkOption { + type = with types; attrsOf types'.binary; + default = { }; + }; + nixos = mkOption { + type = + with types; + submodule { + options = { + services = mkOption { + type = nullOr (attrsOf (nullOr types'.service)); + default = null; + }; + programs = mkOption { + type = nullOr (attrsOf (nullOr types'.program)); + default = null; + }; + # An application component may have examples using it in isolation, + # but examples may involve multiple application components. + # Having examples at both layers allows us to trace coverage more easily. + # If this tends to be too cumbersome for package authors and we find a way obtain coverage information programmatically, + # we can still reduce granularity and move all examples to the application level. + examples = mkOption { + type = nullOr (attrsOf types'.example); + default = null; + }; + # TODO: Tests should really only be per example, in order to clarify that we care about tested examples more than merely tests. + # But reality is such that most NixOS tests aren't based on self-contained, minimal examples, or if they are they can't be extracted easily. + # Without this field, many applications will appear entirely untested although there's actually *some* assurance that *something* works. + # Eventually we want to move to documentable tests exclusively, and then remove this field, but this may take a very long time. + tests = mkOption { + type = nullOr (attrsOf types'.test); + default = null; + }; + }; + }; + }; + } + ) + ); + }; + + config.projects = mapAttrs ( + name: directory: import directory { inherit lib pkgs sources; } + ) projectDirectories; +} diff --git a/projects/models.nix b/projects/models.nix deleted file mode 100644 index 1bb92f5bd..000000000 --- a/projects/models.nix +++ /dev/null @@ -1,203 +0,0 @@ -{ - lib, - pkgs, - sources, - # TODO: arguably we can eventually translate this to the module system: - # - we only need to type-check in CI (e.g. by rendering the overview) and expose the values as regular attrs, so performance is not an issue - # - the module system has much more powerful types - # - the module system is maintained - yants ? import sources.yants { inherit lib; }, -}: -let - inherit (yants) - string - list - option - attrs - either - eitherN - struct - drv - path - restrict - function - any - ; - - subgrantType = struct "subgrant" { - Commons = option (list string); - Core = option (list string); - Entrust = option (list string); - Review = option (list string); - }; - - urlType = struct "URL" { - # link text - text = string; - # could be a hover/alternative text or simply a long-form description of a non-trivial resource - description = option string; - # we may later want to do a fancy syntax check in a custom `typdef` - url = string; - }; - - moduleType = eitherN [ - absPath - function - (attrs any) - ]; - - binaryType = struct "binary" { - name = option string; - data = option (either absPath drv); - }; - - # TODO: plugins are actually component *extensions* that are of component-specific type, - # and which compose in application-specific ways defined in the application module. - # we can't express that with yants, but with the module system, which gives us a bit of dependent typing. - # this also means that there's no fundamental difference between programs and services, - # and even languages: libraries are just extensions of compilers. - pluginType = any; - - # TODO: make use of modular services https://github.com/NixOS/nixpkgs/pull/372170 - serviceType = struct "service" { - name = option string; - module = moduleType; - links = optionalAttrs (option urlType); - examples = optionalAttrs (option exampleType); - extensions = optionalAttrs (option pluginType); - }; - - # TODO: port modular services to programs - programType = struct "program" { - name = option string; - module = moduleType; - links = optionalAttrs (option urlType); - examples = optionalAttrs (option exampleType); - extensions = optionalAttrs (option pluginType); - }; - - exampleType = struct "example" { - description = string; - module = absPath; - links = optionalAttrs (option urlType); - tests = nonEmtpyAttrs testType; - }; - - # NixOS tests are modules that boil down to a derivation - testType = option (either moduleType drv); - - optionalStruct = set: option (struct set); - optionalAttrs = set: option (attrs set); - nonEmtpyAttrs = t: restrict "non-empty attribute set" (a: a != { }) (attrs t); - absPath = restrict "absolute path" (p: lib.pathExists p) (either path string); -in -rec { - project = struct { - name = option string; - metadata = optionalStruct { - summary = option string; - # TODO: convert all subgrants to `subgrantType` and document how to find and structure them - subgrants = either (list string) subgrantType; - links = optionalAttrs (option urlType); - }; - nixos = struct "nixos" { - # TODO: Tests should really only be per example, in order to clarify that we care about tested examples more than merely tests. - # But reality is such that most NixOS tests aren't based on self-contained, minimal examples, or if they are they can't be extracted easily. - # Without this field, many applications will appear entirely untested although there's actually *some* assurance that *something* works. - # Eventually we want to move to documentable tests exclusively, and then remove this field, but this may take a very long time. - tests = option (attrs testType); - modules = option ( - struct "modules" { - programs = optionalAttrs (option programType); - services = optionalAttrs (option serviceType); - } - ); - # An application component may have examples using it in isolation, - # but examples may involve multiple application components. - # Having examples at both layers allows us to trace coverage more easily. - # If this tends to be too cumbersome for package authors and we find a way obtain coverage information programmatically, - # we can still reduce granularity and move all examples to the application level. - examples = option (attrs exampleType); - }; - binary = optionalAttrs binaryType; - }; - - example = - let - dummyDerivation = derivation { - name = "myname"; - builder = "mybuilder"; - system = "mysystem"; - }; - in - project { - name = "foobar"; - nixos = rec { - examples = { - foobar-cli = { - description = '' - This is how you can run `foobar` in the terminal. - ''; - module = ./default.nix; - links = { - website = { - text = "FooBar Documentation"; - url = "https://foo.bar/docs"; - }; - }; - tests = { - # Each example must have at least one test. - # If the line below is commented out, an error will be raised. - inherit (tests) foobar-cli; - }; - }; - }; - tests = { - # Set to `null`: needed, but not available - basic = null; - - # Needs to be a derivation. Error raised otherwise. - #simple = "This will fail."; - - foobar-cli = dummyDerivation; - }; - modules = { - # Attributes not defined in the data structure are not allowed. - # Uncommenting the line below will raise an error. - #hello = { }; - - programs = { - # Set to `null`: needed, but not available - foobar = null; - - foobar-cli = { - name = "foobar-cli"; - module = - { lib, ... }: - { - options.programs.foobar-cli.enable = lib.mkEnableOption "foobar CLI"; - }; - # Each program must have at least one example. - # Examples can be null to indicate that they're needed. - examples = { - inherit (examples) foobar-cli; - - # needed, not available - foobar-tui = null; - }; - }; - - # Not set: not needed - }; - }; - }; - binary = { - "foobar.img" = { - data = dummyDerivation; - }; - "foobar-boot.img" = { - data = null; # needed, not available - }; - }; - }; -}