diff --git a/cabal2nix/hackage2nix/Main.hs b/cabal2nix/hackage2nix/Main.hs index 284bd264..acd89e4c 100644 --- a/cabal2nix/hackage2nix/Main.hs +++ b/cabal2nix/hackage2nix/Main.hs @@ -152,21 +152,24 @@ main = do attr :: Identifier attr = if isInDefaultPackageSet then toNixName name else mangle pkgId - drv :: Derivation - drv = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr - & src .~ urlDerivationSource ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") tarballSHA256 - & editedCabalFile .~ cabalSHA256 - -- If a list of platforms is set in the hackage2nix configuration file, prefer that. - -- Otherwise a list defined by PostProcess or Nothing is used. - & metaSection.platforms %~ (Map.lookup name (supportedPlatforms config) <|>) - & metaSection.badPlatforms %~ (Map.lookup name (unsupportedPlatforms config) <|>) - & metaSection.hydraPlatforms %~ (if isHydraEnabled then id else const (Just Set.empty)) - & metaSection.broken ||~ isBroken - & metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers - & metaSection.homepage .~ "" + drv :: FinalizedDerivation + drv = over finalized_derivation modifiers finalized + where + finalized = fromGenericPackageDescription haskellResolver nixpkgsResolver targetPlatform (compilerInfo config) flagAssignment [] descr + modifiers d = d + & src .~ urlDerivationSource ("mirror://hackage/" ++ display pkgId ++ ".tar.gz") tarballSHA256 + & editedCabalFile .~ cabalSHA256 + -- If a list of platforms is set in the hackage2nix configuration file, prefer that. + -- Otherwise a list defined by PostProcess or Nothing is used. + & metaSection.platforms %~ (Map.lookup name (supportedPlatforms config) <|>) + & metaSection.badPlatforms %~ (Map.lookup name (unsupportedPlatforms config) <|>) + & metaSection.hydraPlatforms %~ (if isHydraEnabled then id else const (Just Set.empty)) + & metaSection.broken ||~ isBroken + & metaSection.maintainers .~ Map.findWithDefault Set.empty name globalPackageMaintainers + & metaSection.homepage .~ "" overrides :: Doc - overrides = fcat $ punctuate space [ pPrint b <> semi | b <- Set.toList (view (dependencies . each) drv `Set.union` view extraFunctionArgs drv), not (isFromHackage b) ] + overrides = fcat $ punctuate space [ pPrint b <> semi | b <- Set.toList (view (finalized_derivation . dependencies . each) drv `Set.union` view (finalized_derivation . extraFunctionArgs) drv), not (isFromHackage b) ] return $ render $ nest 2 $ hang (pPrint attr <+> equals <+> text "callPackage") 2 (parens (pPrint drv)) <+> (braces overrides <> semi) diff --git a/cabal2nix/src/Cabal2nix.hs b/cabal2nix/src/Cabal2nix.hs index ab853713..49abad0c 100644 --- a/cabal2nix/src/Cabal2nix.hs +++ b/cabal2nix/src/Cabal2nix.hs @@ -175,9 +175,9 @@ main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> hpackOverrides :: Derivation -> Derivation hpackOverrides = over phaseOverrides (++ "prePatch = \"hpack\";") - . set (libraryDepends . tool . contains (PP.pkg "hpack")) True + . set (focusBuildInfo libraryDepends . tool . contains (PP.pkg "hpack")) True -cabal2nix' :: Options -> IO (Either Doc Derivation) +cabal2nix' :: Options -> IO (Either Doc FinalizedDerivation) cabal2nix' opts@Options{..} = do pkg <- getPackage optHpack optFetchSubmodules optHackageDb optHackageSnapshot $ Source { @@ -190,7 +190,7 @@ cabal2nix' opts@Options{..} = do } processPackage opts pkg -cabal2nixWithDB :: DB.HackageDB -> Options -> IO (Either Doc Derivation) +cabal2nixWithDB :: DB.HackageDB -> Options -> IO (Either Doc FinalizedDerivation) cabal2nixWithDB db opts@Options{..} = do when (isJust optHackageDb) $ colorStderrLn warningColor "WARN: HackageDB provided directly; ignoring --hackage-db" when (isJust optHackageSnapshot) $ colorStderrLn warningColor "WARN: HackageDB provided directly; ignoring --hackage-snapshot" @@ -205,7 +205,7 @@ cabal2nixWithDB db opts@Options{..} = do } processPackage opts pkg -processPackage :: Options -> Package -> IO (Either Doc Derivation) +processPackage :: Options -> Package -> IO (Either Doc FinalizedDerivation) processPackage Options{..} pkg = do let withHpackOverrides :: Derivation -> Derivation @@ -219,14 +219,18 @@ processPackage Options{..} pkg = do Nothing -> pkgSource pkg Just customExpr -> (pkgSource pkg) { derivCustomSrc = Just customExpr } - deriv :: Derivation - deriv = withHpackOverrides $ fromGenericPackageDescription (const True) - optNixpkgsIdentifier - optSystem - (unknownCompilerInfo optCompiler NoAbiTag) - flags - [] - (pkgCabal pkg) + deriv :: FinalizedDerivation + deriv = over finalized_derivation (withHpackOverrides . modifiers) finalized + where + finalized = fromGenericPackageDescription (const True) + optNixpkgsIdentifier + optSystem + (unknownCompilerInfo optCompiler NoAbiTag) + flags + [] + (pkgCabal pkg) + + modifiers d = d & src .~ finalSource & subpath .~ fromMaybe "." optSubpath & runHaddock %~ (optHaddock &&) @@ -240,6 +244,7 @@ processPackage Options{..} pkg = do & doBenchmark ||~ optDoBenchmark & extraFunctionArgs %~ Set.union (Set.fromList ("inherit lib":map (fromString . ("inherit " ++)) optExtraArgs)) + shell :: Doc shell = vcat [ text "{ nixpkgs ? import {}, compiler ? \"default\", doBenchmark ? false, inNixShell ? false }:" diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs index ed367d0a..9e87ae03 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/BuildInfo.hs @@ -42,9 +42,11 @@ instance Monoid BuildInfo where instance NFData BuildInfo pPrintBuildInfo :: String -> BuildInfo -> Doc -pPrintBuildInfo prefix bi = vcat - [ setattr (prefix++"HaskellDepends") empty (setOf (haskell.folded.localName.ident) bi) - , setattr (prefix++"SystemDepends") empty (setOf (system.folded.localName.ident) bi) - , setattr (prefix++"PkgconfigDepends") empty (setOf (pkgconfig.folded.localName.ident) bi) - , setattr (prefix++"ToolDepends") empty (setOf (tool.folded.localName.ident) bi) +pPrintBuildInfo prefix bi = onlyIf (bi /= mempty) $ vcat + [ pp haskell "HaskellDepends" + , pp system "SystemDepends" + , pp pkgconfig "PkgconfigDepends" + , pp tool "ToolDepends" ] + where + pp fld suffix = setattr (prefix++suffix) empty $ setOf (fld.folded.localName.ident) bi diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs index c8c85ef8..2569d644 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/Derivation.hs @@ -1,40 +1,60 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} module Distribution.Nixpkgs.Haskell.Derivation - ( Derivation, nullDerivation, pkgid, revision, src, subpath, isLibrary, isExecutable + ( FinalizedDerivation(..), finalized_compiler, finalized_derivation, finalized_flags, finalized_platform + , Derivation, nullDerivation, pkgid, revision, src, subpath, isLibrary, isExecutable , extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags , cabalFlags, runHaddock, jailbreak, doCheck, doBenchmark, testFlags, testTargets, hyperlinkSource , enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection , dependencies, setupDepends, benchmarkDepends, enableSeparateDataOutput, extraAttributes + , focusBuildInfo ) where import Prelude hiding ((<>)) +#if !MIN_VERSION_base(4,18,0) +import Control.Applicative (liftA2) +#endif import Control.DeepSeq import Control.Lens +import Data.Foldable import Data.List ( isPrefixOf ) import Data.Map ( Map ) import qualified Data.Map as Map import Data.Set ( Set ) import qualified Data.Set as Set import Data.Set.Lens +import Distribution.Compiler (CompilerInfo) import Distribution.Nixpkgs.Fetch import Distribution.Nixpkgs.Haskell.BuildInfo import Distribution.Nixpkgs.Haskell.OrphanInstances ( ) import Distribution.Nixpkgs.Meta import Distribution.Package -import Distribution.PackageDescription ( FlagAssignment, unFlagName, unFlagAssignment ) +import Distribution.PackageDescription (CondBranch (..), CondTree (..), Condition (..), ConfVar (..), FlagAssignment, FlagName, lookupFlagAssignment, unFlagAssignment, unFlagName) +import Distribution.System (Platform (..)) import GHC.Generics ( Generic ) import Language.Nix import Language.Nix.PrettyPrinting +import Data.Maybe (fromMaybe) +import Distribution.PackageDescription.Configuration (simplifyWithSysParams) -- | A represtation of Nix expressions for building Haskell packages. -- The data type correspond closely to the definition of -- 'PackageDescription' from Cabal. +data FinalizedDerivation = FinalizedDerivation + { _finalized_flags :: FlagAssignment + , _finalized_platform :: Platform + , _finalized_compiler :: CompilerInfo + , _finalized_derivation :: Derivation + } data Derivation = MkDerivation { _pkgid :: PackageIdentifier @@ -46,10 +66,10 @@ data Derivation = MkDerivation , _extraFunctionArgs :: Set Binding , _extraAttributes :: Map String String , _setupDepends :: BuildInfo - , _libraryDepends :: BuildInfo - , _executableDepends :: BuildInfo - , _testDepends :: BuildInfo - , _benchmarkDepends :: BuildInfo + , _libraryDepends :: [CondTree ConfVar [Dependency] (BuildInfo, Bool)] + , _executableDepends :: [CondTree ConfVar [Dependency] (BuildInfo, Bool)] + , _testDepends :: [CondTree ConfVar [Dependency] (BuildInfo, Bool)] + , _benchmarkDepends :: [CondTree ConfVar [Dependency] (BuildInfo, Bool)] , _configureFlags :: Set String , _cabalFlags :: FlagAssignment , _runHaddock :: Bool @@ -100,17 +120,26 @@ nullDerivation = MkDerivation , _metaSection = error "undefined Derivation.metaSection" } +makeLenses ''FinalizedDerivation + makeLenses ''Derivation -makeLensesFor [("_setupDepends", "dependencies"), ("_libraryDepends", "dependencies"), ("_executableDepends", "dependencies"), ("_testDepends", "dependencies"), ("_benchmarkDepends", "dependencies")] ''Derivation +makeLensesFor (fmap (,"nonSetupDependencies") ["_libraryDepends", "_executableDepends", "_testDepends", "_benchmarkDepends"]) ''Derivation + +dependencies :: Traversal' Derivation BuildInfo +dependencies = traversal $ \focus drv -> + liftA2 (set setupDepends) (focus $ view setupDepends drv) ((nonSetupDependencies . traverse . traverse . _1) focus drv) + +focusBuildInfo :: Lens' Derivation [CondTree ConfVar [Dependency] (BuildInfo, Bool)] -> Traversal' Derivation BuildInfo +focusBuildInfo l = l . traverse . traverse . _1 instance Package Derivation where packageId = view pkgid instance NFData Derivation -instance Pretty Derivation where - pPrint drv@MkDerivation {..} = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat +instance Pretty FinalizedDerivation where + pPrint (FinalizedDerivation flags (Platform arch os) compiler (MkDerivation {..})) = funargs (map text ("mkDerivation" : toAscList inputs)) $$ vcat [ text "mkDerivation" <+> lbrace , nest 2 $ vcat [ attr "pname" $ doubleQuotes $ pPrint (packageName _pkgid) @@ -123,11 +152,11 @@ instance Pretty Derivation where , boolattr "isLibrary" (not _isLibrary || _isExecutable) _isLibrary , boolattr "isExecutable" (not _isLibrary || _isExecutable) _isExecutable , boolattr "enableSeparateDataOutput" _enableSeparateDataOutput _enableSeparateDataOutput - , onlyIf (_setupDepends /= mempty) $ pPrintBuildInfo "setup" _setupDepends - , onlyIf (_libraryDepends /= mempty) $ pPrintBuildInfo "library" _libraryDepends - , onlyIf (_executableDepends /= mempty) $ pPrintBuildInfo "executable" _executableDepends - , onlyIf (_testDepends /= mempty) $ pPrintBuildInfo "test" _testDepends - , onlyIf (_benchmarkDepends /= mempty) $ pPrintBuildInfo "benchmark" _benchmarkDepends + , pPrintBuildInfo "setup" _setupDepends + , pPrintBuildInfo "library" lib + , pPrintBuildInfo "executable" exe + , pPrintBuildInfo "test" test + , pPrintBuildInfo "benchmark" bench , boolattr "enableLibraryProfiling" _enableLibraryProfiling _enableLibraryProfiling , boolattr "enableExecutableProfiling" _enableExecutableProfiling _enableExecutableProfiling , boolattr "doHaddock" (not _runHaddock) _runHaddock @@ -146,14 +175,44 @@ instance Pretty Derivation where where inputs :: Set String inputs = Set.unions [ Set.map (view (localName . ident)) _extraFunctionArgs - , setOf (dependencies . each . folded . localName . ident) drv + , setOf (each . folded . localName . ident) $ fold [_setupDepends, lib, exe, test, bench] , case derivKind _src of Nothing -> mempty Just derivKind' -> Set.fromList [derivKindFunction derivKind' | not isHackagePackage] ] + (lib, exe, test, bench) = over each (foldMap eval) + (_libraryDepends, _executableDepends, _testDepends, _benchmarkDepends) + renderedFlags = [ text "-f" <> (if enable then empty else char '-') <> text (unFlagName f) | (f, enable) <- unFlagAssignment _cabalFlags ] ++ map text (toAscList _configureFlags) isHackagePackage = "mirror://hackage/" `isPrefixOf` derivUrl _src postUnpack = string $ "sourceRoot+=/" ++ _subpath ++ "; echo source root reset to $sourceRoot" + + eval :: CondTree ConfVar c (BuildInfo, Bool) -> BuildInfo + eval = fold . evalTree + + evalTree :: CondTree ConfVar c (BuildInfo, Bool) -> Maybe BuildInfo + evalTree (CondNode (bi, buildable) _ branches) = case buildable of + False -> Nothing + True -> do + bs <- traverse evalBranch branches + pure $ fold $ bi : bs + + evalBranch :: CondBranch ConfVar c (BuildInfo, Bool) -> Maybe BuildInfo + evalBranch (CondBranch c t mf) = + if evalCondition c + then evalTree t + else maybe (Just mempty) evalTree mf + + evalCondition :: Condition ConfVar -> Bool + evalCondition = go . fst . simplifyWithSysParams os arch compiler + where + go :: Condition FlagName -> Bool + go = \case + Lit b -> b + CNot c -> not $ go c + COr a b -> go a || go b + CAnd a b -> go a && go b + Var fn -> fromMaybe False $ lookupFlagAssignment fn flags diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs index 91c9a254..da868dc0 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal.hs @@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TupleSections #-} module Distribution.Nixpkgs.Haskell.FromCabal ( HaskellResolver, NixpkgsResolver @@ -48,14 +49,14 @@ import Distribution.Types.MissingDependencyReason ( MissingDependencyReason(Wron type HaskellResolver = PackageVersionConstraint -> Bool type NixpkgsResolver = Identifier -> Maybe Binding -fromGenericPackageDescription :: HaskellResolver -> NixpkgsResolver -> Platform -> CompilerInfo -> FlagAssignment -> [Constraint] -> GenericPackageDescription -> Derivation -fromGenericPackageDescription haskellResolver nixpkgsResolver arch compiler flags constraints genDesc = - fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags descr +fromGenericPackageDescription :: HaskellResolver -> NixpkgsResolver -> Platform -> CompilerInfo -> FlagAssignment -> [Constraint] -> GenericPackageDescription -> FinalizedDerivation +fromGenericPackageDescription haskellResolver nixpkgsResolver platform compiler flags constraints genDesc = + FinalizedDerivation finalizedFlags platform compiler $ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags genDesc descr where - (descr, missingDeps) = finalizeGenericPackageDescription haskellResolver arch compiler flags constraints genDesc + (descr, finalizedFlags, missingDeps) = finalizeGenericPackageDescription haskellResolver platform compiler flags constraints genDesc -finalizeGenericPackageDescription :: HaskellResolver -> Platform -> CompilerInfo -> FlagAssignment -> [Constraint] -> GenericPackageDescription -> (PackageDescription, [Dependency]) -finalizeGenericPackageDescription haskellResolver arch compiler flags constraints genDesc = +finalizeGenericPackageDescription :: HaskellResolver -> Platform -> CompilerInfo -> FlagAssignment -> [Constraint] -> GenericPackageDescription -> (PackageDescription, FlagAssignment, [Dependency]) +finalizeGenericPackageDescription haskellResolver platform compiler flags constraints genDesc = let -- finalizePD incooperates the 'LibraryName' of a dependency -- which we always ignore, so the Cabal-compatible resolver @@ -85,7 +86,7 @@ finalizeGenericPackageDescription haskellResolver arch compiler flags constraint -- functions, and this convenience function makes our code shorter. finalize :: HaskellResolver -> Either [Dependency] (PackageDescription,FlagAssignment) finalize resolver = - case finalizePD flags requestedComponents (makeCabalResolver resolver) arch compiler (makeCabalConstraints constraints) genDesc of + case finalizePD flags requestedComponents (makeCabalResolver resolver) platform compiler (makeCabalConstraints constraints) genDesc of #if MIN_VERSION_Cabal(3,16,0) Left left -> Left (map (\(MissingDependency dependency _reason) -> dependency) left) #else @@ -112,11 +113,11 @@ finalizeGenericPackageDescription haskellResolver arch compiler flags constraint in case finalize (jailbroken (withInternalLibs haskellResolver)) of Left m -> case finalize (const True) of Left _ -> error ("Cabal cannot finalize " ++ display (packageId genDesc)) - Right (d,_) -> (d,m) - Right (d,_) -> (d,[]) + Right (d,f) -> (d,f,m) + Right (d,f) -> (d,f,[]) -fromPackageDescription :: HaskellResolver -> NixpkgsResolver -> [Dependency] -> FlagAssignment -> PackageDescription -> Derivation -fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags PackageDescription {..} = normalize $ postProcess $ nullDerivation +fromPackageDescription :: HaskellResolver -> NixpkgsResolver -> [Dependency] -> FlagAssignment -> GenericPackageDescription -> PackageDescription -> Derivation +fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags (GenericPackageDescription {..}) (PackageDescription {..}) = normalize $ postProcess $ nullDerivation & isLibrary .~ isJust library & pkgid .~ package & revision .~ xrev @@ -124,10 +125,10 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package & isExecutable .~ not (null executables) & extraFunctionArgs .~ mempty & extraAttributes .~ mempty - & libraryDepends .~ foldMap (convertBuildInfo . libBuildInfo) (maybeToList library ++ subLibraries) - & executableDepends .~ mconcat (map (convertBuildInfo . buildInfo) executables) - & testDepends .~ mconcat (map (convertBuildInfo . testBuildInfo) testSuites) - & benchmarkDepends .~ mconcat (map (convertBuildInfo . benchmarkBuildInfo) benchmarks) + & libraryDepends .~ deps libBuildInfo (maybeToList condLibrary ++ fmap snd condSubLibraries) + & executableDepends .~ deps buildInfo (fmap snd condExecutables) + & testDepends .~ deps testBuildInfo (fmap snd condTestSuites) + & benchmarkDepends .~ deps benchmarkBuildInfo (fmap snd condBenchmarks) & Nix.setupDepends .~ maybe mempty convertSetupBuildInfo setupBuildInfo & configureFlags .~ mempty & cabalFlags .~ flags @@ -163,6 +164,9 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package & Nix.broken .~ not (null missingDeps) ) where + deps :: Functor f => (a -> Cabal.BuildInfo) -> [f a] -> [f (Nix.BuildInfo, Bool)] + deps getBuildInfo = (fmap . fmap) (convertBuildInfo . getBuildInfo) + xrev = maybe 0 read (lookup "x-revision" customFieldsPD) nixLicense :: Nix.License @@ -208,9 +212,8 @@ fromPackageDescription haskellResolver nixpkgsResolver missingDeps flags Package | Just l <- library = not (null (exposedModules l)) | otherwise = True - convertBuildInfo :: Cabal.BuildInfo -> Nix.BuildInfo - convertBuildInfo Cabal.BuildInfo {..} | not buildable = mempty - convertBuildInfo Cabal.BuildInfo {..} = mempty + convertBuildInfo :: Cabal.BuildInfo -> (Nix.BuildInfo, Bool) + convertBuildInfo Cabal.BuildInfo {..} = (, buildable) $ mempty & haskell .~ Set.fromList [ resolveInHackage (toNixName x) | (Dependency x _ _) <- targetBuildDepends, x `notElem` internalLibNames ] & system .~ Set.fromList [ resolveInNixpkgs y | x <- extraLibs, y <- libNixName x ] & pkgconfig .~ Set.fromList [ resolveInNixpkgs y | PkgconfigDependency x _ <- pkgconfigDepends, y <- libNixName (unPkgconfigName x) ] diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs index a59aafcd..9e6e6c9b 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/Normalize.hs @@ -1,24 +1,29 @@ +{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} module Distribution.Nixpkgs.Haskell.FromCabal.Normalize ( normalize ) where import Control.Lens import qualified Data.Set as Set -import Data.String import Distribution.Nixpkgs.Haskell import Distribution.Nixpkgs.Haskell.FromCabal.Name (toNixName) import Distribution.Nixpkgs.Meta import Distribution.Package +import Distribution.PackageDescription (CondTree, ConfVar) import Language.Nix hiding ( quote ) normalize :: Derivation -> Derivation normalize drv = drv - & over libraryDepends (normalizeBuildInfo (packageName drv)) - & over executableDepends (normalizeBuildInfo (packageName drv)) - & over testDepends (normalizeBuildInfo (packageName drv)) - & over benchmarkDepends (normalizeBuildInfo (packageName drv)) + & deps libraryDepends + & deps executableDepends + & deps testDepends + & deps benchmarkDepends & over metaSection normalizeMeta & jailbreak %~ (&& (packageName drv /= "jailbreak-cabal")) + where + deps :: Lens' Derivation [CondTree ConfVar [Dependency] (BuildInfo, Bool)] -> Derivation -> Derivation + deps f = over (focusBuildInfo f) $ normalizeBuildInfo (packageName drv) normalizeBuildInfo :: PackageName -> BuildInfo -> BuildInfo normalizeBuildInfo pname bi = bi diff --git a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs index 83392fc2..453957eb 100644 --- a/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs +++ b/cabal2nix/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs @@ -4,7 +4,6 @@ module Distribution.Nixpkgs.Haskell.FromCabal.PostProcess ( postProcess, pkg ) where import Control.Lens -import Control.Monad.Trans.State import Data.List.Split import Data.Map ( Map ) import qualified Data.Map as Map @@ -15,6 +14,7 @@ import Distribution.Nixpkgs.Haskell import Distribution.Nixpkgs.Meta import Distribution.Nixpkgs.License import Distribution.Package +import Distribution.PackageDescription (CondTree, ConfVar) import Distribution.Types.PackageVersionConstraint import Distribution.Text import Distribution.Version @@ -58,27 +58,31 @@ fixGtkBuilds drv = drv & dependencies . pkgconfig %~ Set.filter (not . collidesW -- also work for Stack). Until that changes, we provide do this to work around -- those package's brokenness. fixBuildDependsForTools :: Derivation -> Derivation -fixBuildDependsForTools = foldr (.) id - [ fmap snd $ runState $ do - needs <- use $ cloneLens c . haskell . contains p - cloneLens c . tool . contains p ||= needs - | (c :: ALens' Derivation BuildInfo) <- [ testDepends, benchmarkDepends ] - , p <- self <$> [ "hspec-discover" - , "tasty-discover" - , "hsx2hs" - , "markdown-unlit" - ] - ] +fixBuildDependsForTools = foldr (.) id $ fmap go [ testDepends, benchmarkDepends ] + where + go :: ALens' Derivation [CondTree ConfVar [Dependency] (BuildInfo, Bool)] -> Derivation -> Derivation + go c drv = + over (l . tool) (Set.union needed) drv + where + l :: Traversal' Derivation BuildInfo + l = focusBuildInfo (cloneLens c) + needed = Set.intersection executables $ view (l . haskell) drv + executables = Set.fromList $ self <$> + [ "hspec-discover" + , "tasty-discover" + , "hsx2hs" + , "markdown-unlit" + ] hooks :: [(PackageVersionConstraint, Derivation -> Derivation)] hooks = - [ ("Agda < 2.5", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agdaPostInstall) - , ("Agda >= 2.5 && < 2.6", set (executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agda25PostInstall) - , ("Agda >= 2.6", set (executableDepends . tool . contains (pkg "emacs")) True) - , ("alex < 3.1.5", set (testDepends . tool . contains (pkg "perl")) True) - , ("alex", set (executableDepends . tool . contains (self "happy")) True) + [ ("Agda < 2.5", set (focusBuildInfo executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agdaPostInstall) + , ("Agda >= 2.5 && < 2.6", set (focusBuildInfo executableDepends . tool . contains (pkg "emacs")) True . set phaseOverrides agda25PostInstall) + , ("Agda >= 2.6", set (focusBuildInfo executableDepends . tool . contains (pkg "emacs")) True) + , ("alex < 3.1.5", set (focusBuildInfo testDepends . tool . contains (pkg "perl")) True) + , ("alex", set (focusBuildInfo executableDepends . tool . contains (self "happy")) True) , ("alsa-core", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "linux")))) - , ("bindings-GLFW", over (libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.libxext", bind "pkgs.libxfixes"]))) + , ("bindings-GLFW", over (focusBuildInfo libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.libxext", bind "pkgs.libxfixes"]))) , ("bindings-lxc", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "linux")))) , ("bustle", bustleOverrides) , ("Cabal", set doCheck False) -- test suite doesn't work in Nix @@ -92,7 +96,7 @@ hooks = , ("dns", set testTargets ["spec"]) -- don't execute tests that try to access the network , ("eventstore", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "x86_64")))) , ("freenect < 1.2.1", over configureFlags (Set.union (Set.fromList ["--extra-include-dirs=${lib.getDev pkgs.freenect}/include/libfreenect", "--extra-lib-dirs=${lib.getLib pkgs.freenect}/lib"]))) - , ("fltkhs", set (libraryDepends . system . contains (pkg "fltk_1_4")) True . over (libraryDepends . pkgconfig) (Set.union (pkgs ["libGLU", "libGL"]))) -- TODO: fltk14 belongs into the *setup* dependencies. + , ("fltkhs", set (focusBuildInfo libraryDepends . system . contains (pkg "fltk_1_4")) True . over (focusBuildInfo libraryDepends . pkgconfig) (Set.union (pkgs ["libGLU", "libGL"]))) -- TODO: fltk14 belongs into the *setup* dependencies. , ("gf", set phaseOverrides gfPhaseOverrides . set doCheck False) , ("gi-cairo", giCairoPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36 , ("gi-gdk", set runHaddock True ) @@ -107,75 +111,75 @@ hooks = , ("gi-pango", set runHaddock True ) , ("gi-pangocairo", giCairoPhaseOverrides) -- https://github.com/haskell-gi/haskell-gi/issues/36 , ("gi-vte", set runHaddock True ) - , ("gio", set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True) + , ("gio", set (focusBuildInfo libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True) , ("git", set doCheck False) -- https://github.com/vincenthz/hit/issues/33 , ("git-annex >= 6.20170925 && < 6.20171214", set doCheck False) -- some versions of git-annex require their test suite to be run inside of a git checkout - , ("github-backup", set (executableDepends . tool . contains (pkg "git")) True) - , ("GLFW", over (libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.libxext", bind "pkgs.libxfixes"]))) - , ("graphviz", set (testDepends . system . contains (pkg "graphviz")) True) + , ("github-backup", set (focusBuildInfo executableDepends . tool . contains (pkg "git")) True) + , ("GLFW", over (focusBuildInfo libraryDepends . system) (Set.union (Set.fromList [bind "pkgs.libxext", bind "pkgs.libxfixes"]))) + , ("graphviz", set (focusBuildInfo testDepends . system . contains (pkg "graphviz")) True) , ("gtk3", gtk3Hook) , ("gtkglext", gtkglextHook) - , ("hakyll", set (testDepends . tool . contains (pkg "util-linux")) True) -- test suite depends on "rev" + , ("hakyll", set (focusBuildInfo testDepends . tool . contains (pkg "util-linux")) True) -- test suite depends on "rev" , ("haskell-src-exts", set doCheck False) , ("hfsevents", hfseventsOverrides) , ("HFuse", set phaseOverrides hfusePreConfigure) - , ("hlibgit2 >= 0.18.0.14", set (testDepends . tool . contains (pkg "git")) True) + , ("hlibgit2 >= 0.18.0.14", set (focusBuildInfo testDepends . tool . contains (pkg "git")) True) , ("hmatrix < 0.18.1.1", set phaseOverrides "preConfigure = \"sed -i hmatrix.cabal -e '/\\\\/usr\\\\//D'\";") , ("holy-project", set doCheck False) -- attempts to access the network , ("hoogle", set testFlags ["--no-net"]) , ("hsignal < 0.2.7.4", set phaseOverrides "prePatch = \"rm -v Setup.lhs\";") -- https://github.com/amcphail/hsignal/issues/1 - , ("hslua < 0.9.3", over (libraryDepends . system) (replace (pkg "lua") (pkg "lua5_1"))) - , ("hslua >= 0.9.3 && < 2.0.0", over (libraryDepends . system) (replace (pkg "lua") (pkg "lua5_3"))) + , ("hslua < 0.9.3", over (focusBuildInfo libraryDepends . system) (replace (pkg "lua") (pkg "lua5_1"))) + , ("hslua >= 0.9.3 && < 2.0.0", over (focusBuildInfo libraryDepends . system) (replace (pkg "lua") (pkg "lua5_3"))) , ("hspec-core >= 2.4.4", hspecCoreOverrides) , ("http-client", set doCheck False) -- attempts to access the network , ("http-client-openssl >= 0.2.0.1", set doCheck False) -- attempts to access the network , ("http-client-tls >= 0.2.2", set doCheck False) -- attempts to access the network , ("http-conduit", set doCheck False) -- attempts to access the network - , ("imagemagick", set (libraryDepends . pkgconfig . contains (pkg "imagemagick")) True) -- https://github.com/NixOS/cabal2nix/issues/136 - , ("include-file <= 0.1.0.2", set (libraryDepends . haskell . contains (self "random")) True) -- https://github.com/Daniel-Diaz/include-file/issues/1 + , ("imagemagick", set (focusBuildInfo libraryDepends . pkgconfig . contains (pkg "imagemagick")) True) -- https://github.com/NixOS/cabal2nix/issues/136 + , ("include-file <= 0.1.0.2", set (focusBuildInfo libraryDepends . haskell . contains (self "random")) True) -- https://github.com/Daniel-Diaz/include-file/issues/1 , ("js-jquery", set doCheck False) -- attempts to access the network - , ("libconfig", over (libraryDepends . system) (replace "config = null" (pkg "libconfig"))) + , ("libconfig", over (focusBuildInfo libraryDepends . system) (replace "config = null" (pkg "libconfig"))) , ("libxml", set (configureFlags . contains "--extra-include-dir=${lib.getDev libxml2}/include/libxml2") True) - , ("liquidhaskell", set (testDepends . system . contains (pkg "z3")) True) - , ("lua >= 2.0.0 && < 2.2.0", over (libraryDepends . system) (replace (pkg "lua") (pkg "lua5_3"))) - , ("lua >= 2.2.0", over (libraryDepends . system) (replace (pkg "lua") (pkg "lua5_4"))) - , ("lzma-clib", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "windows"))) . set (libraryDepends . haskell . contains (self "only-buildable-on-windows")) False) - , ("MFlow < 4.6", set (libraryDepends . tool . contains (self "cpphs")) True) + , ("liquidhaskell", set (focusBuildInfo testDepends . system . contains (pkg "z3")) True) + , ("lua >= 2.0.0 && < 2.2.0", over (focusBuildInfo libraryDepends . system) (replace (pkg "lua") (pkg "lua5_3"))) + , ("lua >= 2.2.0", over (focusBuildInfo libraryDepends . system) (replace (pkg "lua") (pkg "lua5_4"))) + , ("lzma-clib", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "windows"))) . set (focusBuildInfo libraryDepends . haskell . contains (self "only-buildable-on-windows")) False) + , ("MFlow < 4.6", set (focusBuildInfo libraryDepends . tool . contains (self "cpphs")) True) , ("mwc-random", set doCheck False) - , ("mysql", set (libraryDepends . system . contains (pkg "libmysqlclient")) True) + , ("mysql", set (focusBuildInfo libraryDepends . system . contains (pkg "libmysqlclient")) True) , ("network-attoparsec", set doCheck False) -- test suite requires network access , ("numeric-qq", set doCheck False) -- test suite doesn't finish even after 1+ days , ("purescript", set doCheck False) -- test suite doesn't cope with Nix build env - , ("proto-lens-protobuf-types", set (libraryDepends . tool . contains (pkg "protobuf")) True) - , ("proto-lens-protoc", set (libraryDepends . tool . contains (pkg "protobuf")) True) - , ("qtah-cpp-qt5", set (libraryDepends . system . contains (bind "pkgs.qt5.qtbase")) True) - , ("qtah-qt5", set (libraryDepends . tool . contains (bind "pkgs.qt5.qtbase")) True) - , ("readline", over (libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"]))) + , ("proto-lens-protobuf-types", set (focusBuildInfo libraryDepends . tool . contains (pkg "protobuf")) True) + , ("proto-lens-protoc", set (focusBuildInfo libraryDepends . tool . contains (pkg "protobuf")) True) + , ("qtah-cpp-qt5", set (focusBuildInfo libraryDepends . system . contains (bind "pkgs.qt5.qtbase")) True) + , ("qtah-qt5", set (focusBuildInfo libraryDepends . tool . contains (bind "pkgs.qt5.qtbase")) True) + , ("readline", over (focusBuildInfo libraryDepends . system) (Set.union (pkgs ["readline", "ncurses"]))) , ("req", set doCheck False) -- test suite requires network access - , ("rest-rewrite", over (testDepends . system) (Set.union (pkgs ["graphviz", "z3"]))) - , ("sbv > 7", set (testDepends . system . contains (pkg "z3")) True) + , ("rest-rewrite", over (focusBuildInfo testDepends . system) (Set.union (pkgs ["graphviz", "z3"]))) + , ("sbv > 7", set (focusBuildInfo testDepends . system . contains (pkg "z3")) True) , ("sdr", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "x86_64")))) -- https://github.com/adamwalker/sdr/issues/2 , ("shake-language-c", set doCheck False) -- https://github.com/samplecount/shake-language-c/issues/26 , ("ssh", set doCheck False) -- test suite runs forever, probably can't deal with our lack of network access , ("stack", set phaseOverrides stackOverrides . set doCheck False) , ("stripe-http-streams", set doCheck False . set (metaSection . broken) False) - , ("target", set (testDepends . system . contains (pkg "z3")) True) - , ("terminfo", set (libraryDepends . system . contains (pkg "ncurses")) True) + , ("target", set (focusBuildInfo testDepends . system . contains (pkg "z3")) True) + , ("terminfo", set (focusBuildInfo libraryDepends . system . contains (pkg "ncurses")) True) , ("text", set doCheck False) -- break infinite recursion - , ("tensorflow-proto", set (libraryDepends . tool . contains (pkg "protobuf")) True) - , ("thyme", set (libraryDepends . tool . contains (self "cpphs")) True) -- required on Darwin + , ("tensorflow-proto", set (focusBuildInfo libraryDepends . tool . contains (pkg "protobuf")) True) + , ("thyme", set (focusBuildInfo libraryDepends . tool . contains (self "cpphs")) True) -- required on Darwin , ("twilio", set doCheck False) -- attempts to access the network , ("udev", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "linux")))) , ("websockets", set doCheck False) -- https://github.com/jaspervdj/websockets/issues/104 , ("Win32", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "windows")))) , ("Win32-shortcut", set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "windows")))) , ("wxc", wxcHook) - , ("wxcore", set (libraryDepends . pkgconfig . contains (pkg "wxGTK")) True) - , ("X11", over (libraryDepends . system) (Set.union (Set.fromList $ map bind ["pkgs.libxinerama","pkgs.libxext","pkgs.libxrender","pkgs.libxscrnsaver"]))) + , ("wxcore", set (focusBuildInfo libraryDepends . pkgconfig . contains (pkg "wxGTK")) True) + , ("X11", over (focusBuildInfo libraryDepends . system) (Set.union (Set.fromList $ map bind ["pkgs.libxinerama","pkgs.libxext","pkgs.libxrender","pkgs.libxscrnsaver"]))) , ("xmonad >= 0.14.2", set phaseOverrides xmonadPostInstall) - , ("zip-archive < 0.3.1", over (testDepends . tool) (replace (self "zip") (pkg "zip"))) - , ("zip-archive >= 0.3.1 && < 0.3.2.3", over (testDepends . tool) (Set.union (Set.fromList [pkg "zip", pkg "unzip"]))) -- https://github.com/jgm/zip-archive/issues/35 - , ("zip-archive >= 0.4", set (testDepends . tool . contains (pkg "which")) True) + , ("zip-archive < 0.3.1", over (focusBuildInfo testDepends . tool) (replace (self "zip") (pkg "zip"))) + , ("zip-archive >= 0.3.1 && < 0.3.2.3", over (focusBuildInfo testDepends . tool) (Set.union (Set.fromList [pkg "zip", pkg "unzip"]))) -- https://github.com/jgm/zip-archive/issues/35 + , ("zip-archive >= 0.4", set (focusBuildInfo testDepends . tool . contains (pkg "which")) True) ] pkg :: Identifier -> Binding @@ -201,8 +205,8 @@ replace :: Binding -> Binding -> Set Binding -> Set Binding replace old new = Set.map (\x -> if x == old then new else x) gtk3Hook :: Derivation -> Derivation -- https://github.com/NixOS/cabal2nix/issues/145 -gtk3Hook = set (libraryDepends . pkgconfig . contains (pkg "gtk3")) True - . over (libraryDepends . pkgconfig) (Set.filter (\b -> view localName b /= "gtk3")) +gtk3Hook = set (focusBuildInfo libraryDepends . pkgconfig . contains (pkg "gtk3")) True + . over (focusBuildInfo libraryDepends . pkgconfig) (Set.filter (\b -> view localName b /= "gtk3")) hfusePreConfigure :: String hfusePreConfigure = unlines @@ -226,8 +230,8 @@ gfPhaseOverrides = unlines ] wxcHook :: Derivation -> Derivation -wxcHook drv = drv & libraryDepends . system %~ Set.union (Set.fromList [pkg "libGL", bind "pkgs.libx11"]) - & libraryDepends . pkgconfig . contains (pkg "wxGTK") .~ True +wxcHook drv = drv & focusBuildInfo libraryDepends . system %~ Set.union (Set.fromList [pkg "libGL", bind "pkgs.libx11"]) + & focusBuildInfo libraryDepends . pkgconfig . contains (pkg "wxGTK") .~ True & phaseOverrides .~ wxcPostInstall (packageVersion drv) & runHaddock .~ False where @@ -297,11 +301,11 @@ stackOverrides = unlines -- Replace a binding for to one to pkgs.gst_all_1. giGstLibOverrides :: String -> Derivation -> Derivation giGstLibOverrides package - = over (libraryDepends . pkgconfig) (replace (nullBinding (ident # package)) (binding # (ident # package, path # ["pkgs","gst_all_1", ident # package]))) + = over (focusBuildInfo libraryDepends . pkgconfig) (replace (nullBinding (ident # package)) (binding # (ident # package, path # ["pkgs","gst_all_1", ident # package]))) giCairoPhaseOverrides :: Derivation -> Derivation giCairoPhaseOverrides = over phaseOverrides (++txt) - . set (libraryDepends . pkgconfig . contains (pkg "cairo")) True + . set (focusBuildInfo libraryDepends . pkgconfig . contains (pkg "cairo")) True where txt = unlines [ "preCompileBuildDriver = ''" , " PKG_CONFIG_PATH+=\":${lib.getDev cairo}/lib/pkgconfig\"" @@ -313,7 +317,7 @@ hfseventsOverrides :: Derivation -> Derivation hfseventsOverrides = set isLibrary True . set (metaSection . platforms) (Just $ Set.singleton (NixpkgsPlatformGroup (ident # "darwin"))) - . over (libraryDepends . haskell) (Set.union (Set.fromList (map bind ["self.base", "self.cereal", "self.mtl", "self.text", "self.bytestring"]))) + . over (focusBuildInfo libraryDepends . haskell) (Set.union (Set.fromList (map bind ["self.base", "self.cereal", "self.mtl", "self.text", "self.bytestring"]))) hspecCoreOverrides :: Derivation -> Derivation -- https://github.com/hspec/hspec/issues/330 hspecCoreOverrides = set testFlags [ "--skip", "'Test.Hspec.Core.Runner.hspecResult runs specs in parallel'" ] @@ -327,7 +331,7 @@ cabal2nixOverrides = set phaseOverrides $ unlines ] gtkglextHook :: Derivation -> Derivation -gtkglextHook = over (libraryDepends . system) (Set.union (Set.fromList deps)) +gtkglextHook = over (focusBuildInfo libraryDepends . system) (Set.union (Set.fromList deps)) where deps :: [Binding] deps = bind <$> [ "pkgs.gtk2" @@ -339,8 +343,8 @@ gtkglextHook = over (libraryDepends . system) (Set.union (Set.fromList deps)) ] bustleOverrides :: Derivation -> Derivation -bustleOverrides = set (libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True - . set (executableDepends . pkgconfig . contains "gio-unix = null") False +bustleOverrides = set (focusBuildInfo libraryDepends . pkgconfig . contains "system-glib = pkgs.glib") True + . set (focusBuildInfo executableDepends . pkgconfig . contains "gio-unix = null") False . set (metaSection . license) (Known "lib.licenses.lgpl21Plus") . set (metaSection . hydraPlatforms) Nothing diff --git a/cabal2nix/test/Main.hs b/cabal2nix/test/Main.hs index 7e5bbf64..39605fce 100644 --- a/cabal2nix/test/Main.hs +++ b/cabal2nix/test/Main.hs @@ -56,24 +56,27 @@ testLibrary cabalFile = do let nixFile = cabalFile `replaceExtension` "nix" goldenFile = nixFile `addExtension` "golden" - cabal2nix :: GenericPackageDescription -> Derivation - cabal2nix gpd = fromGenericPackageDescription - (const True) - (\i -> Just (binding # (i, path # [ident # "pkgs", i]))) - (Platform X86_64 Linux) - (unknownCompilerInfo (CompilerId GHC (mkVersion [8,2])) NoAbiTag) - (configureCabalFlags (packageId gpd)) - [] - gpd - & src .~ DerivationSource - { derivKind = Just (DerivKindUrl DontUnpackArchive ) - , derivUrl = "mirror://hackage/foo.tar.gz" - , derivRevision = "" - , derivHash = "deadbeef" - , derivSubmodule = Nothing - , derivCustomSrc = Nothing - } - & extraFunctionArgs %~ Set.union (Set.singleton "inherit lib") + cabal2nix :: GenericPackageDescription -> FinalizedDerivation + cabal2nix gpd = over finalized_derivation modifiers finalized + where + finalized = fromGenericPackageDescription + (const True) + (\i -> Just (binding # (i, path # [ident # "pkgs", i]))) + (Platform X86_64 Linux) + (unknownCompilerInfo (CompilerId GHC (mkVersion [8,2])) NoAbiTag) + (configureCabalFlags (packageId gpd)) + [] + gpd + modifiers d = d + & src .~ DerivationSource + { derivKind = Just (DerivKindUrl DontUnpackArchive ) + , derivUrl = "mirror://hackage/foo.tar.gz" + , derivRevision = "" + , derivHash = "deadbeef" + , derivSubmodule = Nothing + , derivCustomSrc = Nothing + } + & extraFunctionArgs %~ Set.union (Set.singleton "inherit lib") goldenVsFileDiff nixFile (\ref new -> ["diff", "-u", ref, new])