packages feed

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 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