git.iko.soy/typeable/cabal2nix
on master help sign in
Add --subpath to support repos with Cabal files in subdirectories.

By default cabal2nix assumes the Cabal file will be found in the root directory of the repo, but that's not always the case. Example use case: cabal2nix --subpath servant-auth-server https://github.com/plow-technologies/servant-auth.git The work is delegated to sourceRoot in nix's stdenv mkDerivation, and manifests as the postUnpack attribute in the generated nix expression.

commit85a20766f212626b081945118b21c8a1e51a35b6 authorJacob Mitchell <jacob.mitchell@iohk.io> dateMon 1 May 2017, 11:31 (9 years ago) parentf4a9f3a
6 files changed+25−11
cabal2nix.cabal+1 cabal2nix/Main.hs+4−1 package.yaml+1 src/Distribution/Nixpkgs/Fetch.hs+3−2 src/Distribution/Nixpkgs/Haskell/Derivation.hs+9−1 src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs+7−7
cabal2nix.cabal+1
@@ -39,6 +39,7 @@ author: Peter Simons,
3939 Felix Kunzmann,
4040 Gabriel Ebner,
4141 Gergely Risko,
42+ Jacob Mitchell,
4243 Joachim Fasting,
4344 John Albietz,
4445 John Chee,
cabal2nix/Main.hs+4−1
@@ -45,6 +45,7 @@ data Options = Options
4545 , optFlags :: [String]
4646 , optCompiler :: CompilerId
4747 , optSystem :: Platform
48+ , optSubpath :: Maybe FilePath
4849 , optUrl :: String
4950 }
5051 deriving (Show)
@@ -68,6 +69,7 @@ options = Options
6869 <*> many (strOption $ short 'f' <> long "flag" <> help "Cabal flag (may be specified multiple times)")
6970 <*> option (readP parse) (long "compiler" <> help "compiler to use when evaluating the Cabal file" <> value buildCompilerId <> showDefaultWith display)
7071 <*> option (readP parsePlatform) (long "system" <> help "target system to use when evaluating the Cabal file" <> value buildPlatform <> showDefaultWith display)
72+ <*> optional (strOption $ long "subpath" <> metavar "PATH" <> help "Path to Cabal file's directory relative to the URI (default is root directory)")
7173 <*> strArgument (metavar "URI")
7274
7375readP :: P.ReadP a a -> ReadM a
@@ -112,7 +114,7 @@ main :: IO ()
112114main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
113115 Options {..} <- execParser pinfo
114116
115− pkg <- getPackage optHackageDb $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256)
117+ pkg <- getPackage optHackageDb $ Source optUrl (fromMaybe "" optRevision) (maybe UnknownHash Guess optSha256) (fromMaybe "." optSubpath)
116118
117119 let
118120 deriv :: Derivation
@@ -124,6 +126,7 @@ main = bracket (return ()) (\() -> hFlush stdout >> hFlush stderr) $ \() -> do
124126 []
125127 (pkgCabal pkg)
126128 & src .~ pkgSource pkg
129+ & subpath .~ (fromMaybe "." optSubpath)
127130 & runHaddock .~ optHaddock
128131 & jailbreak .~ optJailbreak
129132 & hyperlinkSource .~ optHyperlinkSource
package.yaml+1
@@ -29,6 +29,7 @@ author:
2929 - Felix Kunzmann
3030 - Gabriel Ebner
3131 - Gergely Risko
32+ - Jacob Mitchell
3233 - Joachim Fasting
3334 - John Albietz
3435 - John Chee
src/Distribution/Nixpkgs/Fetch.hs+3−2
@@ -31,6 +31,7 @@ data Source = Source
3131 , sourceRevision :: String -- ^ Revision to use. For protocols where this doesn't make sense (such as HTTP), this
3232 -- should be the empty string.
3333 , sourceHash :: Hash -- ^ The expected hash of the source, if available.
34+ , sourceCabalDir :: String -- ^ Directory where Cabal file is found.
3435 } deriving (Show, Eq, Ord, Generic)
3536
3637instance NFData Source
@@ -68,7 +69,7 @@ instance FromJSON DerivationSource where
6869 parseJSON _ = error "invalid DerivationSource"
6970
7071fromDerivationSource :: DerivationSource -> Source
71−fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision $ Certain derivHash
72+fromDerivationSource DerivationSource{..} = Source derivUrl derivRevision (Certain derivHash) "."
7273
7374-- | Fetch a source, trying any of the various nix-prefetch-* scripts.
7475fetch :: forall a. (String -> MaybeT IO a) -- ^ This function is passed the output path name as an argument.
@@ -104,7 +105,7 @@ fetch f = runMaybeT . fetchers where
104105 localArchive :: FilePath -> MaybeT IO (DerivationSource, a)
105106 localArchive path = do
106107 absolutePath <- liftIO $ canonicalizePath path
107− unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" UnknownHash)
108+ unpacked <- snd <$> fetchWith (False, "zip", []) (Source ("file://" ++ absolutePath) "" UnknownHash ".")
108109 process (DerivationSource "" absolutePath "" "", unpacked)
109110
110111 process :: (DerivationSource, FilePath) -> MaybeT IO (DerivationSource, a)
src/Distribution/Nixpkgs/Haskell/Derivation.hs+9−1
@@ -4,7 +4,7 @@
44{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
55
66module Distribution.Nixpkgs.Haskell.Derivation
7− ( Derivation, nullDerivation, pkgid, revision, src, isLibrary, isExecutable
7+ ( Derivation, nullDerivation, pkgid, revision, src, subpath, isLibrary, isExecutable
88 , extraFunctionArgs, libraryDepends, executableDepends, testDepends, configureFlags
99 , cabalFlags, runHaddock, jailbreak, doCheck, testTarget, hyperlinkSource, enableSplitObjs
1010 , enableLibraryProfiling, enableExecutableProfiling, phaseOverrides, editedCabalFile, metaSection
@@ -36,6 +36,7 @@ data Derivation = MkDerivation
3636 { _pkgid :: PackageIdentifier
3737 , _revision :: Int
3838 , _src :: DerivationSource
39+ , _subpath :: FilePath
3940 , _isLibrary :: Bool
4041 , _isExecutable :: Bool
4142 , _extraFunctionArgs :: Set Binding
@@ -65,6 +66,7 @@ nullDerivation = MkDerivation
6566 { _pkgid = error "undefined Derivation.pkgid"
6667 , _revision = error "undefined Derivation.revision"
6768 , _src = error "undefined Derivation.src"
69+ , _subpath = error "undefined Derivation.subpath"
6870 , _isLibrary = error "undefined Derivation.isLibrary"
6971 , _isExecutable = error "undefined Derivation.isExecutable"
7072 , _extraFunctionArgs = error "undefined Derivation.extraFunctionArgs"
@@ -104,6 +106,7 @@ instance Pretty Derivation where
104106 [ attr "pname" $ doubleQuotes $ disp (packageName _pkgid)
105107 , attr "version" $ doubleQuotes $ disp (packageVersion _pkgid)
106108 , sourceAttr _src
109+ , onlyIf (_subpath /= ".") $ attr "postUnpack" postUnpack
107110 , onlyIf (_revision > 0) $ attr "revision" $ doubleQuotes $ int _revision
108111 , onlyIf (not (null _editedCabalFile) && _revision > 0) $ attr "editedCabalFile" $ string _editedCabalFile
109112 , listattr "configureFlags" empty (map (show . show) renderedFlags)
@@ -149,3 +152,8 @@ instance Pretty Derivation where
149152 , rbrace <> semi
150153 ]
151154 | otherwise = attr "src" $ text derivUrl
155+
156+ postUnpack = doubleQuotes $ vcat
157+ [ text "sourceRoot=\\${sourceRoot}/" <> text _subpath
158+ , text "echo Source root reset to \\${sourceRoot}"
159+ ]
src/Distribution/Nixpkgs/Haskell/PackageSourceSpec.hs+7−7
@@ -32,18 +32,18 @@ data Package = Package
3232getPackage :: Maybe String -> Source -> IO Package
3333getPackage optHackageDB source = do
3434 (derivSource, pkgDesc) <- fetchOrFromDB optHackageDB source
35− flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) $ showPackageIdentifier pkgDesc) return derivSource
35+ flip Package pkgDesc <$> maybe (sourceFromHackage (sourceHash source) (showPackageIdentifier pkgDesc) $ sourceCabalDir source) return derivSource
3636
3737
3838fetchOrFromDB :: Maybe String -> Source -> IO (Maybe DerivationSource, Cabal.GenericPackageDescription)
3939fetchOrFromDB optHackageDB src
4040 | "cabal://" `isPrefixOf` sourceUrl src = fmap ((,) Nothing) . fromDB optHackageDB . drop (length "cabal://") $ sourceUrl src
4141 | otherwise = do
42− r <- fetch cabalFromPath src
42+ r <- fetch (\dir -> cabalFromPath (dir </> sourceCabalDir src)) src
4343 case r of
4444 Nothing ->
4545 hPutStrLn stderr "*** failed to fetch source. Does the URL exist?" >> exitFailure
46− Just (derivSource, (externalSource, pkgDesc)) ->
46+ Just (derivSource, (externalSource, pkgDesc)) -> do
4747 return (derivSource <$ guard externalSource, pkgDesc)
4848
4949fromDB :: Maybe String -> String -> IO Cabal.GenericPackageDescription
@@ -77,8 +77,8 @@ hashCachePath pid = do
7777 createDirectoryIfMissing True cacheDir
7878 return $ cacheDir </> pid <.> "sha256"
7979
80−sourceFromHackage :: Hash -> String -> IO DerivationSource
81−sourceFromHackage optHash pkgId = do
80+sourceFromHackage :: Hash -> String -> String -> IO DerivationSource
81+sourceFromHackage optHash pkgId cabalDir = do
8282 cacheFile <- hashCachePath pkgId
8383 cachedHash <-
8484 case optHash of
@@ -99,7 +99,7 @@ sourceFromHackage optHash pkgId = do
9999 seq (length hash) $
100100 DerivationSource "url" url "" hash <$ writeFile cacheFile hash
101101 UnknownHash -> do
102− maybeHash <- runMaybeT (derivHash . fst <$> fetchWith (False, "url", []) (Source url "" UnknownHash))
102+ maybeHash <- runMaybeT (derivHash . fst <$> fetchWith (False, "url", []) (Source url "" UnknownHash cabalDir))
103103 case maybeHash of
104104 Just hash ->
105105 seq (length hash) $
@@ -133,7 +133,7 @@ cabalFromDirectory dir = do
133133 cabals <- liftIO $ getDirectoryContents dir >>= filterM doesFileExist . map (dir </>) . filter (".cabal" `isSuffixOf`)
134134 case cabals of
135135 [cabalFile] -> cabalFromFile True cabalFile
136− _ -> liftIO $ hPutStrLn stderr "*** found zero or more than one cabal file. Exiting." >> exitFailure
136+ _ -> liftIO $ hPutStrLn stderr ("*** found zero or more than one cabal file (" ++ show cabals ++ "). Exiting.") >> exitFailure
137137
138138handleIO :: (Exception.IOException -> IO a) -> IO a -> IO a
139139handleIO = Exception.handle