diff --git a/snack-lib/default.nix b/snack-lib/default.nix index 30ba062..5adce7a 100644 --- a/snack-lib/default.nix +++ b/snack-lib/default.nix @@ -16,9 +16,10 @@ with (callPackage ./lib.nix {}); with (callPackage ./modules.nix {}); with (callPackage ./module-spec.nix {}); with (callPackage ./package-spec.nix {}); -with (callPackage ./hpack.nix {}); -let +with rec +{ + hpack = callPackage ./hpack.nix { inherit pkgDescriptionsFromPath; }; # Derivation that creates a binary in a 'bin' folder. executable = packageFile: @@ -119,31 +120,66 @@ let in modSpecs.${mainModName}; in mainModSpec; - # Get a list of package specs from a file (.nix or .yaml) - specsFromPackageFile = packageFile: - let - basename = builtins.baseNameOf packageFile; - components = pkgs.lib.strings.splitString "." basename; - ext = - if pkgs.lib.length components <= 1 - then abort ("File " ++ packageFile ++ " does not have an extension") - else pkgs.lib.last components; - fromNix = [(mkPackageSpec (import packageFile))]; - fromHPack = builtins.map mkPackageSpec (pkgSpecsFromHPack packageFile); - specs = + # Get a list of package descriptions from a path + # This can be + # - a path, relative or absolute, to a directory that contains either a + # package.yaml or a package.nix + # - a path, relative or absolute, to a file with either .nix or .yaml or + # .yml extension + + pkgDescriptionsFromPath = + with rec + { + pkgDescriptionsFromFile = packageFile: + with rec + { + basename = builtins.baseNameOf packageFile; + components = pkgs.lib.strings.splitString "." basename; + ext = + if pkgs.lib.length components <= 1 + then abort ("File " ++ packageFile ++ " does not have an extension") + else pkgs.lib.last components; + fromNix = [(import packageFile)]; + fromHPack = hpack.pkgDescriptionsFromHPack packageFile; + }; if ext == "nix" then fromNix else if ext == "yaml" then fromHPack else if ext == "yml" then fromHPack - else abort ("Unknown extension " ++ ext ++ " of file " ++ packageFile); - in specs; + else abort ("Unknown extension " ++ ext ++ " of file " ++ packagePath); + pkgDescriptionsFromDir = packageDir: + with rec + { dirContent = builtins.readDir packageDir; + hasPackageYaml = builtins.hasAttr "package.yaml" dirContent; + hasPackageNix = builtins.hasAttr "package.nix" dirContent; + }; + if hasPackageYaml && hasPackageNix + then abort "Found both package.yaml and package.nix in ${packageDir}" + else if ! (hasPackageYaml || hasPackageNix) + then abort "Couldn't find package.yaml or package.nix in ${packageDir}" + else if hasPackageYaml + then pkgDescriptionsFromFile + "${builtins.toString packageDir}/package.yaml" + else pkgDescriptionsFromFile + "${builtins.toString packageDir}/package.nix"; + }; -in - { - inherit - inferBuild - inferGhci - buildAsExecutable - buildAsLibrary - executable - ; - } + packagePath: + with { pathType = pkgs.lib.pathType packagePath ; } ; + if pathType == "directory" + then pkgDescriptionsFromDir packagePath + else if pathType == "regular" + then pkgDescriptionsFromFile packagePath + else abort "Don't know how to load package path of type ${pathType}"; + + specsFromPackageFile = packagePath: + map mkPackageSpec (pkgDescriptionsFromPath packagePath); +}; +{ + inherit + inferBuild + inferGhci + buildAsExecutable + buildAsLibrary + executable + ; +} diff --git a/snack-lib/hpack.nix b/snack-lib/hpack.nix index 2cb7616..c4afeea 100644 --- a/snack-lib/hpack.nix +++ b/snack-lib/hpack.nix @@ -1,4 +1,11 @@ -{ lib, glibcLocales, callPackage, writeText, runCommand, haskellPackages }: +{ lib +, glibcLocales +, callPackage +, writeText +, runCommand +, haskellPackages +, pkgDescriptionsFromPath +}: with (callPackage ./lib.nix {}); with (callPackage ./modules.nix {}); @@ -22,10 +29,7 @@ let in builtins.fromJSON json; in rec { - # Returns an attribute set with two fields: - # - library: a package spec - # - executable: an attr set of executable name to package spec - pkgSpecsFromHPack = packageYaml: + pkgDescriptionsFromHPack = packageYaml: let package = fromYAML (builtins.readFile packageYaml); base = builtins.dirOf packageYaml; @@ -70,11 +74,10 @@ in rec # This is extremely brittle: # - there could be more than one package # - this needs to make sure it only picks libraries - # - it only works with "package.yaml" [ (lib.head - ( pkgSpecsFromHPack - ("${builtins.toString base}/${x}/package.yaml") + ( pkgDescriptionsFromPath + ("${builtins.toString base}/${x}") ) ) ] diff --git a/tests/packages-2/Main.hs b/tests/packages-2/Main.hs index 55bea88..a36370b 100644 --- a/tests/packages-2/Main.hs +++ b/tests/packages-2/Main.hs @@ -1,3 +1,4 @@ import Lib (fromLib) +import Lib2 (fromLib2) -main = putStrLn fromLib +main = putStrLn (fromLib <> fromLib2) diff --git a/tests/packages-2/lib/Lib.hs b/tests/packages-2/lib/Lib.hs index 5d4b957..2a0ef17 100644 --- a/tests/packages-2/lib/Lib.hs +++ b/tests/packages-2/lib/Lib.hs @@ -1,4 +1,4 @@ module Lib (fromLib) where fromLib :: String -fromLib = "hello" +fromLib = "hel" diff --git a/tests/packages-2/lib/package.yaml b/tests/packages-2/lib/package.yaml index 456af76..4161f22 100644 --- a/tests/packages-2/lib/package.yaml +++ b/tests/packages-2/lib/package.yaml @@ -1,4 +1,4 @@ -name: snack-packages-2 +name: snack-packages-2-lib # NOTE: should not fail if library is empty # For some reason, Nix returns null as opposed to {} diff --git a/tests/packages-2/lib2/Lib2.hs b/tests/packages-2/lib2/Lib2.hs new file mode 100644 index 0000000..b232437 --- /dev/null +++ b/tests/packages-2/lib2/Lib2.hs @@ -0,0 +1,4 @@ +module Lib2 (fromLib2) where + +fromLib2 :: String +fromLib2 = "lo" diff --git a/tests/packages-2/lib2/package.yaml b/tests/packages-2/lib2/package.yaml new file mode 100644 index 0000000..a64a63a --- /dev/null +++ b/tests/packages-2/lib2/package.yaml @@ -0,0 +1,6 @@ +name: snack-packages-2-lib2 + +# NOTE: should not fail if library is empty +# For some reason, Nix returns null as opposed to {} +library: + source-dirs: . diff --git a/tests/packages-2/package.yaml b/tests/packages-2/package.yaml index 7e1f437..344b7bd 100644 --- a/tests/packages-2/package.yaml +++ b/tests/packages-2/package.yaml @@ -4,3 +4,4 @@ executable: main: Main.hs dependencies: - ./lib + - ./lib2/package.yaml