packages feed

nixfromnpm 0.1.0.6 → 0.1.0.7

raw patch · 4 files changed

+120/−75 lines, 4 filesdep +containersdep +hnixdep −simple-nixPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: containers, hnix

Dependencies removed: simple-nix

API changes (from Hackage documentation)

- NixFromNpm: mkDefault :: Record (HashMap SemVer a) -> NixExpr
+ NixFromNpm: callPackageWith :: [Binding NExpr] -> NExpr -> NExpr
+ NixFromNpm: callPackageWithRec :: [Binding NExpr] -> NExpr -> NExpr
+ NixFromNpm: mkDefaultNix :: Record (HashMap SemVer a) -> NExpr
+ NixFromNpm: str :: Text -> NExpr
- NixFromNpm: NpmFetcherState :: [URI] -> Maybe Text -> Record (HashMap SemVer (Either NixExpr ResolvedPkg)) -> Record PackageInfo -> HashSet (Name, SemVer) -> Int -> HashSet Name -> Bool -> NpmFetcherState
+ NixFromNpm: NpmFetcherState :: [URI] -> Maybe Text -> Record (HashMap SemVer (Either NExpr ResolvedPkg)) -> Record PackageInfo -> HashSet (Name, SemVer) -> Int -> HashSet Name -> Bool -> NpmFetcherState
- NixFromNpm: [resolved] :: NpmFetcherState -> Record (HashMap SemVer (Either NixExpr ResolvedPkg))
+ NixFromNpm: [resolved] :: NpmFetcherState -> Record (HashMap SemVer (Either NExpr ResolvedPkg))
- NixFromNpm: _startingExpr :: NixExpr
+ NixFromNpm: _startingExpr :: NExpr
- NixFromNpm: _startingSrc :: Text
+ NixFromNpm: _startingSrc :: String
- NixFromNpm: callPackage :: NixExpr -> NixExpr
+ NixFromNpm: callPackage :: NExpr -> NExpr
- NixFromNpm: distInfoToNix :: DistInfo -> NixExpr
+ NixFromNpm: distInfoToNix :: DistInfo -> NExpr
- NixFromNpm: dumpPkgs :: MonadIO m => String -> Record (HashMap SemVer (Either NixExpr ResolvedPkg)) -> m ()
+ NixFromNpm: dumpPkgs :: MonadIO m => String -> Record (HashMap SemVer (Either NExpr ResolvedPkg)) -> m ()
- NixFromNpm: findExisting :: String -> IO (Record (HashMap SemVer NixExpr))
+ NixFromNpm: findExisting :: String -> IO (Record (HashMap SemVer NExpr))
- NixFromNpm: getPkg :: Name -> Record (HashMap SemVer NixExpr) -> IO (Record (HashMap SemVer (Either NixExpr ResolvedPkg)))
+ NixFromNpm: getPkg :: Name -> Record (HashMap SemVer NExpr) -> IO (Record (HashMap SemVer (Either NExpr ResolvedPkg)))
- NixFromNpm: metaToNix :: PackageMeta -> NixExpr
+ NixFromNpm: metaToNix :: PackageMeta -> NExpr
- NixFromNpm: parseVersion :: String -> IO (Maybe (SemVer, NixExpr))
+ NixFromNpm: parseVersion :: String -> IO (Maybe (SemVer, NExpr))
- NixFromNpm: resolvedPkgToNix :: ResolvedPkg -> NixExpr
+ NixFromNpm: resolvedPkgToNix :: ResolvedPkg -> NExpr
- NixFromNpm: startState :: Record (HashMap SemVer NixExpr) -> [Text] -> Maybe Text -> NpmFetcherState
+ NixFromNpm: startState :: Record (HashMap SemVer NExpr) -> [Text] -> Maybe Text -> NpmFetcherState

Files

nixfromnpm.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                nixfromnpm-version:             0.1.0.6+version:             0.1.0.7 synopsis: Generate nix expressions from npm packages. -- description: license:             MIT@@ -31,6 +31,7 @@                      , mtl                      , bytestring                      , unordered-containers+                     , containers                      , parsec                      , aeson                      , data-default@@ -42,7 +43,7 @@                      , filepath                      , network-uri                      , directory-                     , simple-nix >=0.1.0.4+                     , hnix   hs-source-dirs:      src   default-language:    Haskell2010 @@ -50,14 +51,23 @@  executable nixfromnpm   main-is:             Main.hs---  other-modules:       NixFromNpm+  other-modules:       NixFromNpm.Common+                     , NixFromNpm.ConvertToNix+                     , NixFromNpm.NpmLookup+                     , NixFromNpm.NpmTypes+                     , NixFromNpm.NpmVersion+                     , NixFromNpm.SemVer+                     , NixFromNpm.Parsers.Common+                     , NixFromNpm.Parsers.NpmVersion+                     , NixFromNpm.Parsers.SemVer   other-extensions:    NoImplicitPrelude, OverloadedStrings-  build-depends:         base >=4.8 && <4.9+  build-depends:       base >=4.8 && <4.9                      , classy-prelude                      , text                      , mtl                      , bytestring                      , unordered-containers+                     , containers                      , parsec                      , aeson                      , data-default@@ -69,7 +79,7 @@                      , filepath                      , network-uri                      , directory-                     , simple-nix >=0.1.0.4+                     , hnix                      , docopt   hs-source-dirs:      src   default-language:    Haskell2010@@ -86,6 +96,7 @@                      , text                      , bytestring                      , unordered-containers+                     , containers                      , parsec                      , io-streams                      , http-client-streams@@ -102,4 +113,4 @@                      , filepath                      , network-uri                      , directory-                     , simple-nix+                     , hnix
src/Main.hs view
@@ -23,15 +23,14 @@   \                                    package\n\   \  --node-version VERSION            Use this version of node\n" -getFlag args f = isPresent args (longOption f)- main :: IO () main = do   patterns <- parseUsageOrExit usageString   args <- parseArgsOrExit patterns =<< getArgs-  let args ?? arg = getArgOrExitWith patterns args (argument arg)-  pkgName <- map pack $ args ?? "packagename"-  path <- map pack $ args ?? "outputpath"+  let getText = map pack . getArgOrExitWith patterns args+      getFlag = isPresent args . longOption+  pkgName <- getText (argument "packagename")+  path <- getText (longOption "output")   dumpPkgFromOptions $ (defaultOptions pkgName path) {-        nfnoNoCache = args `getFlag` "no-cache"+        nfnoNoCache = getFlag "no-cache"       }
src/NixFromNpm/ConvertToNix.hs view
@@ -6,123 +6,158 @@  import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as H+import Data.Map (Map)+import qualified Data.Map as M import Data.Text (Text) import qualified Data.Text as T  import NixFromNpm.Common-import Nix.Expr+import Nix.Types import Nix.Parser+import Nix.Pretty (prettyNix) import NixFromNpm.NpmTypes import NixFromNpm.SemVer import NixFromNpm.Parsers.SemVer import NixFromNpm.NpmLookup  -_startingSrc :: Text-_startingSrc = unlines [-  "{nixpkgs ? import <nixpkgs> {}}:",-  "let",-  "  allPkgs = nixpkgs // nodePkgs // {inherit (nixpkgs.nodePackages)",-  "      buildNodePackage;};",-  "  callPackage = pth: overrides: let",-  "    f = import pth;",-  "  in",-  "    f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs)",-  "       // overrides);",-  "  nodePkgs = byVersion // defaults;",-  "in",-  "nodePkgs"-  ]+_startingSrc :: String+_startingSrc = "\+  \{nixpkgs ? import <nixpkgs> {}}:\n\+  \let\n\+  \  allPkgs = nixpkgs // nodePkgs // {inherit (nixpkgs.nodePackages)\n\+  \      buildNodePackage;};\n\+  \  callPackage = pth: overrides: let\n\+  \    f = import pth;\n\+  \  in\n\+  \    f ((builtins.intersectAttrs (builtins.functionArgs f) allPkgs)\n\+  \       // overrides);\n\+  \  nodePkgs = byVersion // defaults;\n\+  \in\n\+  \nodePkgs" -_startingExpr :: NixExpr-_startingExpr = fromRight $ parseNix _startingSrc+_startingExpr :: NExpr+_startingExpr = case parseNixString _startingSrc of+  Success e -> e+  Failure e -> error $ unlines ["Starting source failed to parse:", show e] -callPackage :: NixExpr -> NixExpr-callPackage e = Apply (Apply (Var "callPackage") e) (Set False [])+callPackage :: NExpr -> NExpr+callPackage = callPackageWith [] +callPackageWith :: [Binding NExpr] -> NExpr -> NExpr+callPackageWith args e = mkApp (mkApp (mkSym "callPackage") e)+                               (mkNonRecSet args)++callPackageWithRec :: [Binding NExpr] -> NExpr -> NExpr+callPackageWithRec args e = mkApp (mkApp (mkSym "callPackage") e)+                                  (mkRecSet args)++-- | Turns a string into one that can be used as an identifier. fixName :: Name -> Name fixName = T.replace "." "-" +-- | Converts a package name and semver into an identifier. toDepName :: Name -> SemVer -> Name toDepName name (a, b, c) = concat [fixName name, "_", pack $                                    intercalate "-" $ map show [a, b, c]] +-- | Gets the .nix filename of a semver. E.g. (0, 1, 2) -> 0.1.2.nix toDotNix :: SemVer -> Text toDotNix (a,b,c) = pack $ intercalate "." (map show [a,b,c]) <> ".nix" -distInfoToNix :: DistInfo -> NixExpr-distInfoToNix DistInfo{..} = Apply (Var "fetchurl") $ Set False-  [ "url" =$= str diUrl,-    "sha1" =$=  str diShasum ]+-- | Creates a doublequoted string from some text.+str :: Text -> NExpr+str = mkStr DoubleQuoted +-- | Converts distinfo into a nix fetchurl call.+distInfoToNix :: DistInfo -> NExpr+distInfoToNix DistInfo{..} = mkApp (mkSym "fetchurl") $ mkNonRecSet+  [ "url" `bindTo` str diUrl,+    "sha1" `bindTo`  str diShasum ]++-- | Tests if there is information in the package meta. metaNotEmpty :: PackageMeta -> Bool metaNotEmpty PackageMeta{..} = isJust pmDescription -metaToNix :: PackageMeta -> NixExpr+-- | Converts package meta to a nix expression.+metaToNix :: PackageMeta -> NExpr metaToNix PackageMeta{..} = case pmDescription of-  Nothing -> Set False []-  Just d -> Set False ["description" =$= str d]+  Nothing -> mkNonRecSet []+  Just d -> mkNonRecSet ["description" `bindTo` str d] -resolvedPkgToNix :: ResolvedPkg -> NixExpr+-- | Converts a resolved package object into a nix expression. The expresion+-- will be a function where the arguments are its dependencies, and its result+-- is a call to `buildNodePackage`.+resolvedPkgToNix :: ResolvedPkg -> NExpr resolvedPkgToNix ResolvedPkg{..} = do-  let deps = map (Var . uncurry toDepName) $ H.toList rpDependencies+  let -- Get a string representation of each dependency in name-version format.+      deps = map (mkSym . uncurry toDepName) $ H.toList rpDependencies+      -- Get the parameters of the package function (deps + utility functions).       _funcParams = map (uncurry toDepName) (H.toList rpDependencies)                     <> ["buildNodePackage", "fetchurl"]-      funcParams = toKwargs $ map (\x -> (x, Nothing)) _funcParams-  let args = Set False $ catMaybes [-        Just $ "name" =$= str rpName,-        Just $ "version" =$= (str $ renderSV rpVersion),-        Just $ "src" =$= distInfoToNix rpDistInfo,-        maybeIf (length deps > 0) $ "deps" =$= List deps,-        maybeIf (metaNotEmpty rpMeta) $ "meta" =$= metaToNix rpMeta+      -- None of these have defaults, so put them into pairs with Nothing.+      funcParams = mkFormalSet $ map (\x -> (x, Nothing)) _funcParams+  let args = mkNonRecSet $ catMaybes [+        Just $ "name" `bindTo` str rpName,+        Just $ "version" `bindTo` (str $ renderSV rpVersion),+        Just $ "src" `bindTo` distInfoToNix rpDistInfo,+        maybeIf (length deps > 0) $ "deps" `bindTo` mkList deps,+        maybeIf (metaNotEmpty rpMeta) $ "meta" `bindTo` metaToNix rpMeta         ]-  Function funcParams $ Apply (Var "buildNodePackage") args+  mkFunction funcParams $ mkApp (mkSym "buildNodePackage") args -mkDefault :: Record (HashMap SemVer a) -> NixExpr-mkDefault rec = do-  let mkPath name ver = fromText $ concat ["./", name, "/", toDotNix ver]-      mkAssign name ver = Assign [Plain $ toDepName name ver]-                                 (callPackage $ Path $ mkPath name ver)-      mkAssigns name vers = map (mkAssign name) vers+-- | Creates the `default.nix` file that is the top-level expression we are+-- generating.+mkDefaultNix :: Record (HashMap SemVer a) -> NExpr+mkDefaultNix rec = do+  let mkPath' = mkPath False . unpack+      toPath name ver = mkPath' $ concat ["./", name, "/", toDotNix ver]+      mkBinding name ver = toDepName name ver +                            `bindTo` callPackage (toPath name ver)+      mkBindings name vers = map (mkBinding name) vers       mkDefVer name vers = do-        Assign [Plain $ fixName name] (Var $ toDepName name $ maximum vers)+        fixName name `bindTo` mkSym (toDepName name $ maximum vers)       -- This bit of map gymnastics will create a list of pairs of names       -- with all of the versions of that name that we have.       versOnly = map (map (map fst)) $ H.toList $ map H.toList rec-      byVersion = Set False $ concatMap (uncurry mkAssigns) versOnly-      defaults = With (Var "byVersion") $-        Set False $ map (uncurry mkDefVer) versOnly-      newAssigns = ["byVersion" =$= byVersion, "defaults" =$= defaults]-      Function params (Let assigns e) = _startingExpr-  Function params (Let (assigns <> newAssigns) e)+      byVersion = mkNonRecSet $ concatMap (uncurry mkBindings) versOnly+      defaults = mkWith (mkSym "byVersion") $+        mkNonRecSet $ map (uncurry mkDefVer) versOnly+      newBindings = ["byVersion" `bindTo` byVersion, +                     "defaults" `bindTo` defaults]+  modifyFunctionBody (appendBindings newBindings) _startingExpr  dumpPkgs :: MonadIO m          => String-         -> Record (HashMap SemVer (Either NixExpr ResolvedPkg))+         -> Record (HashMap SemVer (Either NExpr ResolvedPkg))          -> m () dumpPkgs path rPkgs = liftIO $ do   createDirectoryIfMissing True path   withDir path $ forM_ (H.toList rPkgs) $ \(pkgName, pkgVers) -> do-    writeFile "default.nix" $ renderIndented 2 $ mkDefault rPkgs+    writeFile "default.nix" $ show $ prettyNix $ mkDefaultNix rPkgs     let subdir = path </> unpack pkgName     createDirectoryIfMissing False subdir     withDir subdir $ forM_ (H.toList pkgVers) $ \(ver, rpkg) -> do       let nixexpr = case rpkg of+            -- A left value means it had already existed; we can simply+            -- dump out the package we had before.             Left e -> e+            -- A right value means it's a ResolvedPkg object; in this case+            -- we convert it to a nix expression.             Right r -> resolvedPkgToNix r-      writeFile (unpack $ toDotNix ver) $ renderIndented 2 nixexpr+      writeFile (unpack $ toDotNix ver) $ show $ prettyNix nixexpr -parseVersion :: String -> IO (Maybe (SemVer, NixExpr))+parseVersion :: String -> IO (Maybe (SemVer, NExpr)) parseVersion pth = do   case parseSemVer . pack $ dropSuffix ".nix" $ takeBaseName pth of     Left _ -> return Nothing -- not a version file-    Right version -> parseNix . pack <$> readFile pth >>= \case-      Left err -> do+    Right version -> parseNixString . pack <$> readFile pth >>= \case+      Failure err -> do         putStrsLn [pack pth, " failed to parse: ", pack $ show err]         return Nothing -- invalid nix, should overwrite-      Right expr -> return $ Just (version, expr)+      Success expr -> return $ Just (version, expr) -findExisting :: String -> IO (Record (HashMap SemVer NixExpr))+findExisting :: String -> IO (Record (HashMap SemVer NExpr)) findExisting path = do   putStrLn "Searching for existing expressions..."   doesDirectoryExist path >>= \case
src/NixFromNpm/NpmLookup.hs view
@@ -29,13 +29,13 @@ import NixFromNpm.Parsers.SemVer import NixFromNpm.NpmVersion import NixFromNpm.Parsers.NpmVersion-import Nix.Expr+import Nix.Types --------------------------------------------------------------------------  data NpmFetcherState = NpmFetcherState {   registries :: [URI],   githubAuthToken :: Maybe Text,-  resolved :: Record (HashMap SemVer (Either NixExpr ResolvedPkg)),+  resolved :: Record (HashMap SemVer (Either NExpr ResolvedPkg)),   pkgInfos :: Record PackageInfo,   -- For cycle detection.   currentlyResolving :: HashSet (Name, SemVer),@@ -379,7 +379,7 @@             Nothing -> errorC ["Invalid URI: ", txt]             Just uri -> uri -startState :: Record (HashMap SemVer NixExpr)+startState :: Record (HashMap SemVer NExpr)            -> [Text]            -> Maybe Text            -> NpmFetcherState@@ -421,8 +421,8 @@     (Right x, state) -> return (x, state)  getPkg :: Name-       -> Record (HashMap SemVer NixExpr)-       -> IO (Record (HashMap SemVer (Either NixExpr ResolvedPkg)))+       -> Record (HashMap SemVer NExpr)+       -> IO (Record (HashMap SemVer (Either NExpr ResolvedPkg))) getPkg name existing = do   let range = Gt (0, 0, 0)   state <- startState existing <$> getRegistries <*> getToken