Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

```
Usage: jenkinsPlugins2nix [-r|--dependency-resolution [as-given|latest|jenkins[:VERSION]]]
[--no-deps]
[--skip-optional]
(-p|--plugin PLUGIN_NAME{:PLUGIN_VERSION})
Generate nix expressions for requested Jenkins plugins.
Expand All @@ -12,8 +13,11 @@ Available options:
`jenkins:<VERSION>` to resolve against a specific
Jenkins version (for example: `-r jenkins:2.401`).
-p,--plugin PLUGIN_NAME{:PLUGIN_VERSION}
Plugins we should generate nix for. Latest version is
used if not specified.
Plugins we should generate nix for. Latest version is
used if not specified.
--no-deps Do not download or include transitive dependencies;
only generate nix for explicitly requested --plugin
entries.
--skip-optional Skip optional dependencies when downloading plugins
-h,--help Show this help text

Expand Down Expand Up @@ -63,3 +67,10 @@ By default the tool downloads all dependencies (including optional ones) to
avoid backward-compatibility problems. Use `--skip-optional` to exclude
optional dependencies from downloads when you prefer a minimal set of
dependencies.

### No dependency downloads

If you already have a fully resolved/pinned plugins list (for example produced by
`jenkins-plugin-cli --list`) and only want the nix conversion, use `--no-deps`.
This prevents `jenkinsPlugins2nix` from downloading any transitive dependencies
and will only produce output for the plugins explicitly provided via `--plugin`.
42 changes: 29 additions & 13 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ parseConfig = Config
<> Opt.showDefaultWith (resolutions Bimap.!)
<> Opt.metavar (printf "[%s]" . concat . intersperse "|" $ Bimap.keysR resolutions)
<> Opt.value Latest )
<*> Opt.switch
( Opt.long "no-deps"
<> Opt.help "Do not download or include transitive dependencies; only generate nix for explicitly requested --plugin entries." )
<*> 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." )
)
( 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." )
)
<*> Opt.flag Optional Mandatory
( Opt.long "skip-optional"
<> Opt.help "skip optional dependencies" )
Expand All @@ -58,14 +61,27 @@ parseConfig = Config
resolutions = Bimap.fromList [(AsGiven, "as-given"), (Latest, "latest"), (JenkinsVersion(""), "jenkins")]

resolutionReader :: Opt.ReadM ResolutionStrategy
resolutionReader = let
strat = \s -> (Text.unpack (head (Text.splitOn ":" (Text.pack s))))
version = \s -> (Text.unpack(last (Text.splitOn ":" (Text.pack s))))
in Opt.eitherReader $ \s -> case Bimap.lookupR (strat s) resolutions of
Nothing -> Left $ "Invalid dependency resolution, needs to be one of "
<> show (Bimap.keysR resolutions)
Just (JenkinsVersion("")) -> Right (JenkinsVersion(version s))
Just v -> Right v
resolutionReader =
let
splitOnce :: String -> (String, Maybe String)
splitOnce s =
let (k, rest) = Text.breakOn ":" (Text.pack s)
in if Text.null rest
then (Text.unpack k, Nothing)
else (Text.unpack k, Just (Text.unpack (Text.drop 1 rest)))

in Opt.eitherReader $ \s ->
let (k, mv) = splitOnce s
in case Bimap.lookupR k resolutions of
Nothing -> Left $
"Invalid dependency resolution, needs to be one of "
<> show (Bimap.keysR resolutions)
Just (JenkinsVersion "") ->
case mv of
Nothing -> Left "Invalid dependency resolution: jenkins strategy needs a version (jenkins:<VERSION>)"
Just "" -> Left "Invalid dependency resolution: jenkins strategy needs a version (jenkins:<VERSION>)"
Just v -> Right (JenkinsVersion v)
Just v -> Right v

requestedPluginReader :: Opt.ReadM RequestedPlugin
requestedPluginReader = Opt.maybeReader $ \p -> Just $! case break (== ':') p of
Expand Down
39 changes: 28 additions & 11 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
description = "jenkinsPlugins2nix";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/23.05";
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-compat.url = "github:edolstra/flake-compat";
};

outputs = { self, flake-compat, flake-utils, nixpkgs }: flake-utils.lib.eachDefaultSystem (system:
Expand Down
30 changes: 15 additions & 15 deletions jenkinsPlugins2nix.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ library
Nix.JenkinsPlugins2Nix.Parser
Nix.JenkinsPlugins2Nix.Types
build-depends: base >=4.7 && < 5
, attoparsec >=0.13 && <0.15
, bytestring >=0.10 && <0.12
, containers >=0.6 && <0.7
, cryptonite >=0.24 && <0.31
, hnix >=0.6 && <0.18
, http-conduit >=2.3 && <2.4
, mtl >=2.2 && <2.4
, prettyprinter >=1.2 && <1.8
, text
, zip-archive >=0.4 && <0.5
, attoparsec >=0.13 && <0.15
, bytestring >=0.10 && <0.13
, containers >=0.6 && <0.8
, cryptonite >=0.24 && <0.31
, hnix >=0.6 && <0.18
, http-conduit >=2.3 && <2.4
, mtl >=2.2 && <2.4
, prettyprinter >=1.2 && <1.8
, text
, zip-archive >=0.4 && <0.5
default-language: Haskell2010
ghc-options: -Wall

Expand All @@ -38,11 +38,11 @@ executable jenkinsPlugins2nix
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-depends: base
, bimap >=0.3 && <0.6
, jenkinsPlugins2nix
, optparse-applicative >=0.14 && <0.18
, prettyprinter-ansi-terminal >=1.1 && <1.2
, text
, bimap >=0.3 && <0.6
, jenkinsPlugins2nix
, optparse-applicative >=0.14 && <0.19
, prettyprinter-ansi-terminal >=1.1 && <1.2
, text
default-language: Haskell2010

test-suite jenkinsPlugins2nix-test
Expand Down
27 changes: 16 additions & 11 deletions src/Nix/JenkinsPlugins2Nix.hs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,14 @@ downloadPlugin p = do

-- | Download the given plugin as well as recursively download its dependencies.
downloadPluginsRecursive
:: ResolutionStrategy -- ^ Decide what version of dependencies to pick.
:: Bool -- ^ If 'True', do not recurse into dependencies.
-> ResolutionStrategy -- ^ Decide what version of dependencies to pick.
-> PluginResolution -- ^ Wheter to include or skip optional dependencies
-> 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 presolution uPs m p = if Map.member (requested_name p) m
downloadPluginsRecursive noDeps strategy presolution uPs m p = if Map.member (requested_name p) m
then return m
else do
-- Adjust the requested plugin based on whether it was
Expand All @@ -98,22 +99,26 @@ downloadPluginsRecursive strategy presolution uPs m p = if Map.member (requested
-- based on versions listed in manifest dependencies.
Just userPlugin -> userPlugin
plugin <- MTL.ExceptT $ downloadPlugin adjustedPlugin
foldM (\m' p' -> downloadPluginsRecursive strategy presolution uPs m' $
RequestedPlugin { requested_name = plugin_dependency_name p'
, requested_version = Just $! plugin_dependency_version p'
})
(Map.insert (requested_name p) plugin m)
(Set.filter (\dep -> plugin_dependency_resolution dep <= presolution)
(plugin_dependencies $ manifest plugin))
let m' = Map.insert (requested_name p) plugin m
if noDeps
then return m'
else
foldM (\m'' p' -> downloadPluginsRecursive noDeps strategy presolution uPs m'' $
RequestedPlugin { requested_name = plugin_dependency_name p'
, requested_version = Just $! plugin_dependency_version p'
})
m'
(Set.filter (\dep -> plugin_dependency_resolution dep <= presolution)
(plugin_dependencies $ manifest plugin))

-- | Pretty-print nix expression for all the given plugins and their
-- dependencies that the user asked for.
mkExprsFor :: Config
-> IO (Either String (Doc ann))
mkExprsFor (Config { resolution_strategy = st, requested_plugins = ps, plugin_resolution = pr }) = do
mkExprsFor (Config { resolution_strategy = st, no_deps = noDeps, requested_plugins = ps, plugin_resolution = pr }) = do
eplugins <- MTL.runExceptT $ do
let userPlugins = Map.fromList $ map (requested_name &&& id) ps
plugins <- foldM (downloadPluginsRecursive st pr userPlugins) Map.empty ps
plugins <- foldM (downloadPluginsRecursive noDeps st pr userPlugins) Map.empty ps
return $ Map.elems plugins
return $! case eplugins of
Left err -> Left err
Expand Down
29 changes: 16 additions & 13 deletions src/Nix/JenkinsPlugins2Nix/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Nix.JenkinsPlugins2Nix.Types
runParseManifest :: Text -> Either String Manifest
runParseManifest = A.parseOnly parseManifest

-- | 'Manifest' parser.
-- | Manifest parser.
parseManifest :: A.Parser Manifest
parseManifest = do
kvs <- kvMap
Expand All @@ -35,27 +35,30 @@ parseManifest = do
Nothing -> Left $ "Could not find " <> Text.unpack k <> " in " <> show kvs
Just v -> Right v

getOptionalKey :: Text -> Either String (Maybe Text)
getOptionalKey k = Right (Map.lookup k kvs)

getKeyParsing :: Text -> A.Parser a -> Either String a
getKeyParsing k p = getKey k >>= A.parseOnly p

eManifest :: Either String Manifest
eManifest = do
manifest_version' <- getKey "Manifest-Version"
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"
archiver_version' <- getOptionalKey "Archiver-Version"
created_by' <- getOptionalKey "Created-By"
built_by' <- getOptionalKey "Built-By"
build_jdk' <- getOptionalKey "Build-Jdk"
extension_name' <- getOptionalKey "Extension-Name"
specification_title' <- getOptionalKey "Specification-Title"
implementation_title' <- getOptionalKey "Implementation-Title"
implementation_version' <- getOptionalKey "Implementation-Version"
group_id' <- getOptionalKey "Group-Id"
short_name' <- getKey "Short-Name"
long_name' <- getKey "Long-Name"
url' <- optional $ getKey "Url"
url' <- getOptionalKey "Url"
plugin_version' <- getKey "Plugin-Version"
hudson_version' <- optional $ getKey "Hudson-Version"
jenkins_version' <- optional $ getKey "Jenkins-Version"
hudson_version' <- getOptionalKey "Hudson-Version"
jenkins_version' <- getOptionalKey "Jenkins-Version"
plugin_dependencies' <- either (\_ -> Right Set.empty) return $
getKeyParsing "Plugin-Dependencies" parsePluginDependencies
plugin_developers' <- either (\_ -> Right Set.empty) return $
Expand Down
3 changes: 3 additions & 0 deletions src/Nix/JenkinsPlugins2Nix/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ data ResolutionStrategy =
data Config = Config
{ -- | Dependency resolution strategy
resolution_strategy :: !ResolutionStrategy
-- | If 'True', do not download or include transitive dependencies.
-- Only generate nix for explicitly requested plugins.
, no_deps :: !Bool
-- | User-required plugins.
, requested_plugins :: ![RequestedPlugin]
-- | Plugin resolution
Expand Down