jenkinsPlugins2nix 0.1.0.0 → 0.2.0.0
raw patch · 6 files changed
+145/−63 lines, 6 filesdep +bimapdep +optparse-applicativePVP ok
version bump matches the API change (PVP)
Dependencies added: bimap, optparse-applicative
API changes (from Hackage documentation)
+ Nix.JenkinsPlugins2Nix.Types: AsGiven :: ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: Config :: !ResolutionStrategy -> ![RequestedPlugin] -> Config
+ Nix.JenkinsPlugins2Nix.Types: Latest :: ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: [requested_plugins] :: Config -> ![RequestedPlugin]
+ Nix.JenkinsPlugins2Nix.Types: [resolution_strategy] :: Config -> !ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: data Config
+ Nix.JenkinsPlugins2Nix.Types: data ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Classes.Eq Nix.JenkinsPlugins2Nix.Types.Config
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Classes.Eq Nix.JenkinsPlugins2Nix.Types.ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Classes.Ord Nix.JenkinsPlugins2Nix.Types.Config
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Classes.Ord Nix.JenkinsPlugins2Nix.Types.ResolutionStrategy
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Show.Show Nix.JenkinsPlugins2Nix.Types.Config
+ Nix.JenkinsPlugins2Nix.Types: instance GHC.Show.Show Nix.JenkinsPlugins2Nix.Types.ResolutionStrategy
- Nix.JenkinsPlugins2Nix: downloadPluginsRecursive :: Map Text Plugin -> RequestedPlugin -> ExceptT String IO (Map Text Plugin)
+ Nix.JenkinsPlugins2Nix: downloadPluginsRecursive :: ResolutionStrategy -> Map Text RequestedPlugin -> Map Text Plugin -> RequestedPlugin -> ExceptT String IO (Map Text Plugin)
- Nix.JenkinsPlugins2Nix: mkExprsFor :: [RequestedPlugin] -> IO (Either String Doc)
+ Nix.JenkinsPlugins2Nix: mkExprsFor :: Config -> IO (Either String Doc)
Files
- README.md +32/−3
- app/Main.hs +44/−24
- jenkinsPlugins2nix.cabal +3/−1
- src/Nix/JenkinsPlugins2Nix.hs +33/−11
- src/Nix/JenkinsPlugins2Nix/Parser.hs +12/−23
- src/Nix/JenkinsPlugins2Nix/Types.hs +21/−1
README.md view
@@ -1,18 +1,47 @@ # jenkinsPlugins2nix ```-jenkinsPlugins2nix: PLUGIN_NAME{:PLUGIN_VERSION} [PLUGIN_NAME{:PLUGIN_VERSION} ...]+Usage: jenkinsPlugins2nix [-r|--dependency-resolution [as-given|latest]]+ (-p|--plugin PLUGIN_NAME{:PLUGIN_VERSION})+ Generate nix expressions for requested Jenkins plugins.++Available options:+ -r,--dependency-resolution [as-given|latest]+ Dependency resolution (default: latest)+ -p,--plugin PLUGIN_NAME{:PLUGIN_VERSION}+ Plugins we should generate nix for. Latest version is+ used if not specified.+ -h,--help Show this help text+ ``` Along with recent nixpkgs, you can then do the following. ```-jenkinsPlugins2nix github-api > plugins.nix+jenkinsPlugins2nix -p github-api > plugins.nix ``` and in your `configuration.nix`: ```-services.jenkins.plugins = pkgs.callPackage plugins.nix {};+services.jenkins.plugins = import plugins.nix { inherit (pkgs) fetchurl stdenv; }; ```++## Version specification++Care is taken to preserve versions of plugins explicitly specified by+the user, even with the `as-given` resolution strategy. For example,+if plugin `A` has a dependency `B:0.2` in its manifest file and we+specify:++```+jenkins2nix -r latest -p A:0.7 -p B:0.1+```++We will end up with `A:0.7` and `B:0.2`. This also applies when no+explicit version is provided which is equivalent to asking for the+latest one.++In case we only ask for `A`, the version of `B` will depend on+`--resolution-strategy`.
app/Main.hs view
@@ -1,48 +1,68 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -- |--- Module : Nix.JenkinsPlugins2Nix.Types+-- Module : Main -- Copyright : (c) 2017 Mateusz Kowalczyk -- License : BSD3 -- -- @jenkinsPlugins2nix@ entry point. module Main (main) where -import Data.Monoid ((<>))+import qualified Data.Bimap as Bimap+import Data.List (intersperse)+import Data.Monoid ((<>), mconcat) import qualified Data.Text as Text import Nix.JenkinsPlugins2Nix import Nix.JenkinsPlugins2Nix.Types-import System.Environment+import qualified Options.Applicative as Opt import System.Exit import System.IO import qualified Text.PrettyPrint.ANSI.Leijen as Pretty--usage :: Handle -> IO ()-usage h = do- pName <- getProgName- hPutStrLn h $- pName <> ": PLUGIN_NAME{:PLUGIN_VERSION} [PLUGIN_NAME{:PLUGIN_VERSION} ...]"+import Text.Printf (printf) main :: IO () main = do- getArgs >>= \case- [] -> do- usage stderr+ config <- Opt.execParser opts+ mkExprsFor config >>= \case+ Left err -> do+ hPutStrLn stderr err exitFailure- [v] | v == "-h" || v == "--help" -> do- usage stdout+ Right p -> do+ Pretty.putDoc p exitSuccess- plugins -> do- mkExprsFor (map parseRequestedPlugin plugins) >>= \case- Left err -> do- hPutStrLn stderr err- exitFailure- Right p -> do- Pretty.putDoc p- exitSuccess where- parseRequestedPlugin :: String -> RequestedPlugin- parseRequestedPlugin p = case break (== ':') p of+ opts = Opt.info (parseConfig Opt.<**> Opt.helper)+ ( Opt.fullDesc+ <> Opt.progDesc "Generate nix expressions for requested Jenkins plugins." )+++parseConfig :: Opt.Parser Config+parseConfig = Config+ <$> Opt.option resolutionReader+ ( Opt.long "dependency-resolution"+ <> Opt.short 'r'+ <> Opt.help "Dependency resolution"+ <> Opt.showDefaultWith (resolutions Bimap.!)+ <> Opt.metavar (printf "[%s]" . mconcat . intersperse "|" $ Bimap.keysR resolutions)+ <> Opt.value Latest )+ <*> Opt.some (Opt.option requestedPluginReader+ ( Opt.metavar "PLUGIN_NAME{:PLUGIN_VERSION}"+ <> Opt.long "plugin"+ <> Opt.short 'p'+ <> Opt.help "Plugins we should generate nix for. Latest version is used if not specified." )+ )+ where+ resolutions :: Bimap.Bimap ResolutionStrategy String+ resolutions = Bimap.fromList [(AsGiven, "as-given"), (Latest, "latest")]++ resolutionReader :: Opt.ReadM ResolutionStrategy+ resolutionReader = Opt.eitherReader $ \s -> case Bimap.lookupR s resolutions of+ Nothing -> Left $ "Invalid dependency resolution, needs to be one of "+ <> show (Bimap.keysR resolutions)+ Just v -> Right v++ requestedPluginReader :: Opt.ReadM RequestedPlugin+ requestedPluginReader = Opt.maybeReader $ \p -> Just $! case break (== ':') p of (n, ':' : ver) -> RequestedPlugin { requested_name = Text.pack n , requested_version = Just (Text.pack ver)
jenkinsPlugins2nix.cabal view
@@ -1,5 +1,5 @@ name: jenkinsPlugins2nix-version: 0.1.0.0+version: 0.2.0.0 synopsis: Generate nix for Jenkins plugins. description: Generate nix for Jenkins plugins. homepage: https://github.com/Fuuzetsu/jenkinsPlugins2nix#readme@@ -39,7 +39,9 @@ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall build-depends: base , ansi-wl-pprint+ , bimap , jenkinsPlugins2nix+ , optparse-applicative , text default-language: Haskell2010
src/Nix/JenkinsPlugins2Nix.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} -- |--- Module : Nix.JenkinsPlugins2Nix.Types+-- Module : Nix.JenkinsPlugins2Nix -- Copyright : (c) 2017 Mateusz Kowalczyk -- License : BSD3 --@@ -8,6 +8,7 @@ module Nix.JenkinsPlugins2Nix where import qualified Codec.Archive.Zip as Zip+import Control.Arrow ((&&&)) import Control.Monad (foldM) import qualified Control.Monad.Except as MTL import qualified Crypto.Hash as Hash@@ -66,27 +67,48 @@ } -- | Download the given plugin as well as recursively download its dependencies.-downloadPluginsRecursive :: Map Text Plugin -- ^ Already downloaded plugins.- -> RequestedPlugin -- ^ Plugins we're asked to download.- -> MTL.ExceptT String IO (Map Text Plugin)-downloadPluginsRecursive m p = if Map.member (requested_name p) m+downloadPluginsRecursive+ :: ResolutionStrategy -- ^ Decide what version of dependencies to pick.+ -> Map Text RequestedPlugin -- ^ Plugins user requested.+ -> Map Text Plugin -- ^ Already downloaded plugins.+ -> RequestedPlugin -- ^ Plugin we're going to download.+ -> MTL.ExceptT String IO (Map Text Plugin)+downloadPluginsRecursive strategy uPs m p = if Map.member (requested_name p) m then return m else do- plugin <- MTL.ExceptT $ downloadPlugin p- foldM (\m' p' -> downloadPluginsRecursive m' $+ -- Adjust the requested plugin based on whether it was+ -- specifically requested by the user and on resolution+ -- strategy.+ let adjustedPlugin = case Map.lookup (requested_name p) uPs of+ -- This is not a user-requested plugin which means we have+ -- to decide what version we're going to grab.+ Nothing -> case strategy of+ -- We're just going with whatever was in the manifest+ -- file, i.e. the thing we passed in in the first place.+ AsGiven -> p+ -- It's not a user-specified plugin and we want the latest+ -- version per strategy so download the latest one.+ Latest -> p { requested_version = Nothing }+ -- The user has asked for this plugin explicitly so use+ -- their possibly-versioned request rather than picking+ -- based on versions listed in manifest dependencies.+ Just userPlugin -> userPlugin+ plugin <- MTL.ExceptT $ downloadPlugin adjustedPlugin+ foldM (\m' p' -> downloadPluginsRecursive strategy uPs m' $ RequestedPlugin { requested_name = plugin_dependency_name p'- , requested_version = Just $ plugin_dependency_version p'+ , requested_version = Just $! plugin_dependency_version p' }) (Map.insert (requested_name p) plugin m) (plugin_dependencies $ manifest plugin) -- | Pretty-print nix expression for all the given plugins and their -- dependencies that the user asked for.-mkExprsFor :: [RequestedPlugin]+mkExprsFor :: Config -> IO (Either String Pretty.Doc)-mkExprsFor ps = do+mkExprsFor (Config { resolution_strategy = st, requested_plugins = ps }) = do eplugins <- MTL.runExceptT $ do- plugins <- foldM downloadPluginsRecursive Map.empty ps+ let userPlugins = Map.fromList $ map (requested_name &&& id) ps+ plugins <- foldM (downloadPluginsRecursive st userPlugins) Map.empty ps return $ Map.elems plugins return $! case eplugins of Left err -> Left err
src/Nix/JenkinsPlugins2Nix/Parser.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -- |--- Module : Nix.JenkinsPlugins2Nix.Types+-- Module : Nix.JenkinsPlugins2Nix.Parser -- Copyright : (c) 2017 Mateusz Kowalczyk -- License : BSD3 --@@ -43,32 +43,21 @@ eManifest :: Either String Manifest eManifest = do manifest_version' <- getKey "Manifest-Version"- archiver_version' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Archiver-Version"- created_by' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Created-By"- built_by' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Built-By"- build_jdk' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Build-Jdk"- extension_name' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Extension-Name"- specification_title' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Specification-Title"- implementation_title' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Implementation-Title"- implementation_version' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Implementation-Version"- group_id' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Group-Id"+ archiver_version' <- optional $ getKey "Archiver-Version"+ created_by' <- optional $ getKey "Created-By"+ built_by' <- optional $ getKey "Built-By"+ build_jdk' <- optional $ getKey "Build-Jdk"+ extension_name' <- optional $ getKey "Extension-Name"+ specification_title' <- optional $ getKey "Specification-Title"+ implementation_title' <- optional $ getKey "Implementation-Title"+ implementation_version' <- optional $ getKey "Implementation-Version"+ group_id' <- optional $ getKey "Group-Id" short_name' <- getKey "Short-Name" long_name' <- getKey "Long-Name" url' <- getKey "Url" plugin_version' <- getKey "Plugin-Version"- hudson_version' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Hudson-Version"- jenkins_version' <- either (\_ -> Right Nothing) (return . Just) $- getKey "Jenkins-Version"+ hudson_version' <- optional $ getKey "Hudson-Version"+ jenkins_version' <- optional $ getKey "Jenkins-Version" plugin_dependencies' <- either (\_ -> Right Set.empty) return $ getKeyParsing "Plugin-Dependencies" parsePluginDependencies plugin_developers' <- either (\_ -> Right Set.empty) return $
src/Nix/JenkinsPlugins2Nix/Types.hs view
@@ -6,16 +6,36 @@ -- -- Types used through-out jenkinsPlugins2nix module Nix.JenkinsPlugins2Nix.Types- ( Manifest(..)+ ( Config(..)+ , Manifest(..) , Plugin(..) , PluginDependency(..) , PluginResolution(..) , RequestedPlugin(..)+ , ResolutionStrategy(..) ) where import qualified Crypto.Hash as Hash import Data.Set (Set) import Data.Text (Text)++-- | The way in which version of dependencies will be picked.+data ResolutionStrategy =+ -- | Pick the version of the dependency that the package tells us+ -- about in its manifest file. If none, latest version available is+ -- used.+ AsGiven+ -- | Always pick latest version of the dependency we're told about.+ | Latest+ deriving (Show, Eq, Ord)++-- | Program configuration+data Config = Config+ { -- | Dependency resolution strategy+ resolution_strategy :: !ResolutionStrategy+ -- | User-required plugins.+ , requested_plugins :: ![RequestedPlugin]+ } deriving (Show, Eq, Ord) -- | Plugin that user requested on the command line. data RequestedPlugin = RequestedPlugin