Skip to content

Commit cdaaaed

Browse files
FromCabal.Name: prefix pkg names with _ if they can't be identifiers
While we can quote attribute names, we can't use quoting to use arbitrary strings as function arguments in Nix unfortunately. This means we couldn't previously generate expressions for packages that depend on packages that start with numbers or clash with keywords. To fix this, we simply prefix the offending packages with an underscore. This mirrors an existing Nixpkgs convention (see e.g. pkgs._2bwm). This mapping work for all Hackage packages and is easily reversible by just removing the underscore. We can never introduce ambiguity this way since Cabal doesn't allow underscores in package names. Cabal packages not conforming to Hackage's restrictions won't work yet. For this, we would need to implement some kind of encoding. Resolves #163. Resolves #164.
1 parent e7ebafa commit cdaaaed

File tree

2 files changed

+75
-9
lines changed
  • cabal2nix

2 files changed

+75
-9
lines changed

cabal2nix/hackage2nix/Main.hs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,7 @@ main = do
8181
config <- sconcat <$> mapM (\file -> readConfiguration (nixpkgsRepository </> file)) configFiles
8282
nixpkgs <- readNixpkgPackageMap nixpkgsRepository (Just "{ config = { allowAliases = false; }; }")
8383
preferredVersions <- readPreferredVersions (fromMaybe (hackageRepository </> "preferred-versions") preferredVersionsFile)
84-
let fixup = Map.delete "acme-everything" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
85-
. Map.delete "type" -- TODO: https://github.com/NixOS/cabal2nix/issues/163
86-
. Map.delete "control-invariants" -- TODO: depends on "assert"
87-
. Map.delete "ConcurrentUtils" -- TODO: depends on "assert"
88-
. Map.delete "with" -- TODO: https://github.com/NixOS/cabal2nix/issues/164
89-
. over (at "hermes") (fmap (set (contains "1.3.4.3") False)) -- TODO: https://github.com/haskell/hackage-server/issues/436
84+
let fixup = over (at "hermes") (fmap (set (contains "1.3.4.3") False)) -- TODO: https://github.com/haskell/hackage-server/issues/436
9085
hackage <- fixup <$> readHackage hackageRepository
9186
let
9287
hackagePackagesFile :: FilePath

cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Name.hs

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,81 @@ import Distribution.Package
88
import Distribution.Text
99
import Language.Nix
1010

11-
-- | Map Cabal names to Nix attribute names.
11+
-- | Map Cabal names to Nix identifiers that don't need to be quoted.
12+
--
13+
-- Currently this only supports 'PackageName's that consist of nothing but ASCII
14+
-- characters (as needs to be the case with all Hackage packages).
15+
-- Cabal package names are not changed if they already are a Nix identifier
16+
-- that doesn't need quoting (with some notable exceptions). If they would need
17+
-- quoting, they are prefixed with an underscore.
18+
--
19+
-- >>> toNixName $ mkPackageName "cabal2nix"
20+
-- Identifier "cabal2nix"
21+
-- >>> toNixName $ mkPackageName "4Blocks"
22+
-- Identifier "_4Blocks"
23+
-- >>> toNixName $ mkPackageName "assert"
24+
-- Identifier "_assert"
25+
--
26+
-- Package names that clash with attribute names that have a special meaning
27+
-- to the Nix evaluator are also prefixed (e.g.
28+
-- [@type@ is evaluated eagerly]((https://github.com/NixOS/cabal2nix/issues/163)).
29+
--
30+
-- The mapping is intended to be reversible, but this isn't implemented by
31+
-- @cabal2nix@ yet (and untested). It also should not be considered
32+
-- stable yet, in particular the following may be changed:
33+
--
34+
-- - Future versions of @cabal2nix@ may prefix more 'PackageName's.
35+
-- - The mapping may be extended to support all possible 'PackageName's.
36+
--
37+
-- See also:
38+
--
39+
-- - [Cabal documentation on the package name field](https://cabal.readthedocs.io/en/stable/cabal-package-description-file.html#pkg-field-name)
40+
-- - "Language.Nix.Identifier"
41+
-- - [Nix documentation on identifiers](https://nix.dev/manual/nix/2.30/language/identifiers.html#identifier)
1242
toNixName :: PackageName -> Identifier
13-
toNixName "" = error "toNixName: invalid empty package name"
14-
toNixName n = fromString (unPackageName n)
43+
toNixName n = fromString $
44+
case unPackageName n of
45+
"" -> error "toNixName: BUG: received empty package name"
46+
'_':_ -> error "toNixName: BUG: PackageName starts with an underscore, but shouldn't"
47+
name
48+
-- From the Cabal documentation:
49+
--
50+
-- A valid package name comprises an alphanumeric ‘word’; or two or more
51+
-- such words separated by a hyphen character (-). A word cannot be
52+
-- comprised only of the digits 0 to 9.
53+
--
54+
-- Cabal also latin unicode characters while Hackage enforces that package
55+
-- names are ASCII.
56+
--
57+
-- If the package name comes from Hackage, the set of legal characters
58+
-- ([a-zA-Z0-9-]) is a subset of those permissible as a Nix identifier
59+
-- without quoting ([a-zA-Z0-9_'-]). The main difference are the rules
60+
-- governing what may go where. In the following cases a Hackage package
61+
-- name is not a simple identifier and 'needsQuoting' returns True:
62+
--
63+
-- - if the first “word” of the package name starts with a number, e.g. 4Blocks.
64+
-- - if the package name is the same one of the 'nixKeywords'.
65+
--
66+
-- If we prefix these strings with an underscore, they no longer need quoting.
67+
-- Because Cabal 'PackageName's may not contain underscores this mapped name
68+
-- can never clash. (Reversing the mapping is very simple at the moment as
69+
-- a result.)
70+
--
71+
-- We additionally prefix perfectly usable identifiers like type and
72+
-- recurseForDerivations if they have special meaning to the Nix evaluator
73+
-- (or Hydra etc.) since it may cause evaluation failures if we expose a
74+
-- package under haskellPackages instead of whatever value(s) Nix may
75+
-- expect.
76+
--
77+
-- TODO: Add mapping for non-ASCII 'PackageName's, using __ prefix (?)
78+
| needsQuoting name || name `elem` haveSpecialSemantics -> '_':name
79+
| otherwise -> name
80+
where
81+
-- Special attributes that affect the behavior of the Nix evaluator in some way.
82+
-- See https://github.com/NixOS/cabal2nix/issues/163.
83+
-- We can ignore underscore prefixed attrs like __toString, __functor.
84+
-- Only type is the name of a real package at the moment.
85+
haveSpecialSemantics = [ "type", "outPath", "recurseForDerivations" ]
1586

1687
-- | Map library names specified in Cabal files to Nix package identifiers.
1788
--

0 commit comments

Comments
 (0)