diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f4eba15f3..6558bf773 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -133,6 +133,9 @@ /modules/programs/rtorrent.nix @marsam +/modules/programs/sbt.nix @kubukoz +/tests/modules/programs/sbt @kubukoz + /modules/programs/ssh.nix @rycee /modules/programs/starship.nix @marsam diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index 3282df9f9..220dccf7f 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -31,6 +31,12 @@ github = "olmokramer"; githubId = 3612514; }; + kubukoz = { + name = "Jakub Kozłowski"; + email = "kubukoz@users.noreply.github.com"; + github = "kubukoz"; + githubId = 894884; + }; matrss = { name = "Matthias Riße"; email = "matrss@users.noreply.github.com"; diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 09b89345d..0791c0fd9 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1845,6 +1845,13 @@ in macOS. ''; } + + { + time = "2021-02-04T22:28:26+00:00"; + message = '' + A new module is available: 'programs.sbt'. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index 221fcd778..11367e72f 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -119,6 +119,7 @@ let (loadModule ./programs/rtorrent.nix { }) (loadModule ./programs/skim.nix { }) (loadModule ./programs/starship.nix { }) + (loadModule ./programs/sbt.nix { }) (loadModule ./programs/ssh.nix { }) (loadModule ./programs/taskwarrior.nix { }) (loadModule ./programs/termite.nix { }) diff --git a/modules/programs/sbt.nix b/modules/programs/sbt.nix new file mode 100644 index 000000000..d3ba31e19 --- /dev/null +++ b/modules/programs/sbt.nix @@ -0,0 +1,141 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + renderPlugin = plugin: '' + addSbtPlugin("${plugin.org}" % "${plugin.artifact}" % "${plugin.version}") + ''; + + renderCredential = cred: '' + credentials += Credentials("${cred.realm}", "${cred.host}", "${cred.user}", "${cred.passwordCommand}".!!) + ''; + + renderCredentials = creds: '' + import scala.sys.process._ + ${concatStrings (map renderCredential creds)}''; + + sbtTypes = { + plugin = types.submodule { + options = { + org = mkOption { + type = types.str; + description = "The organization the artifact is published under."; + }; + + artifact = mkOption { + type = types.str; + description = "The name of the artifact."; + }; + + version = mkOption { + type = types.str; + description = "The version of the plugin."; + }; + }; + }; + + credential = types.submodule { + options = { + realm = mkOption { + type = types.str; + description = "The realm of the repository you're authenticating to."; + }; + + host = mkOption { + type = types.str; + description = + "The hostname of the repository you're authenticating to."; + }; + + user = mkOption { + type = types.str; + description = "The user you're using to authenticate."; + }; + + passwordCommand = mkOption { + type = types.str; + description = '' + The command that provides the password or authentication token for + the repository. + ''; + }; + }; + }; + }; + + cfg = config.programs.sbt; + +in { + meta.maintainers = [ maintainers.kubukoz ]; + + options.programs.sbt = { + enable = mkEnableOption "sbt"; + + package = mkOption { + type = types.package; + default = pkgs.sbt; + defaultText = literalExample "pkgs.sbt"; + description = "The package with sbt to be installed."; + }; + + baseConfigPath = mkOption { + type = types.str; + default = ".sbt/1.0"; + description = "Where the plugins and credentials should be located."; + }; + + plugins = mkOption { + type = types.listOf (sbtTypes.plugin); + default = [ ]; + example = literalExample '' + [ + { + org = "net.virtual-void"; + artifact = "sbt-dependency-graph"; + version = "0.10.0-RC1"; + } + { + org = "com.dwijnand"; + artifact = "sbt-project-graph"; + version = "0.4.0"; + } + ] + ''; + description = '' + A list of plugins to place in the sbt configuration directory. + ''; + }; + + credentials = mkOption { + type = types.listOf (sbtTypes.credential); + default = [ ]; + example = literalExample '' + [{ + realm = "Sonatype Nexus Repository Manager"; + host = "example.com"; + user = "user"; + passwordCommand = "pass show sbt/user@example.com"; + }] + ''; + description = '' + A list of credentials to define in the sbt configuration directory. + ''; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { home.packages = [ cfg.package ]; } + + (mkIf (cfg.plugins != [ ]) { + home.file."${cfg.baseConfigPath}/plugins/plugins.sbt".text = + concatStrings (map renderPlugin cfg.plugins); + }) + + (mkIf (cfg.credentials != [ ]) { + home.file."${cfg.baseConfigPath}/credentials.sbt".text = + renderCredentials cfg.credentials; + }) + ]); +} diff --git a/tests/default.nix b/tests/default.nix index 9437f0820..ba5de77f2 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -68,6 +68,7 @@ import nmt { ./modules/programs/powerline-go ./modules/programs/qutebrowser ./modules/programs/readline + ./modules/programs/sbt ./modules/programs/ssh ./modules/programs/starship ./modules/programs/texlive diff --git a/tests/modules/programs/sbt/credentials.nix b/tests/modules/programs/sbt/credentials.nix new file mode 100644 index 000000000..5aa4c2f77 --- /dev/null +++ b/tests/modules/programs/sbt/credentials.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + credentials = [ + { + realm = "Sonatype Nexus Repository Manager"; + host = "example.com"; + user = "user"; + passwordCommand = "echo password"; + } + { + realm = "Sonatype Nexus Repository Manager X"; + host = "v2.example.com"; + user = "user1"; + passwordCommand = "echo password1"; + } + ]; + expectedCredentialsSbt = pkgs.writeText "credentials.sbt" '' + import scala.sys.process._ + credentials += Credentials("Sonatype Nexus Repository Manager", "example.com", "user", "echo password".!!) + credentials += Credentials("Sonatype Nexus Repository Manager X", "v2.example.com", "user1", "echo password1".!!) + ''; + credentialsSbtPath = ".sbt/1.0/credentials.sbt"; +in { + config = { + programs.sbt = { + enable = true; + credentials = credentials; + package = pkgs.writeScriptBin "sbt" ""; + }; + + nmt.script = '' + assertFileExists "home-files/${credentialsSbtPath}" + assertFileContent "home-files/${credentialsSbtPath}" "${expectedCredentialsSbt}" + ''; + }; +} diff --git a/tests/modules/programs/sbt/default.nix b/tests/modules/programs/sbt/default.nix new file mode 100644 index 000000000..59ad89dae --- /dev/null +++ b/tests/modules/programs/sbt/default.nix @@ -0,0 +1,4 @@ +{ + sbt-plugins = ./plugins.nix; + sbt-credentials = ./credentials.nix; +} diff --git a/tests/modules/programs/sbt/plugins.nix b/tests/modules/programs/sbt/plugins.nix new file mode 100644 index 000000000..b413de80e --- /dev/null +++ b/tests/modules/programs/sbt/plugins.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + dependencyGraph = { + org = "net.virtual-void"; + artifact = "sbt-dependency-graph"; + version = "0.10.0-RC1"; + }; + projectGraph = { + org = "com.dwijnand"; + artifact = "sbt-project-graph"; + version = "0.4.0"; + }; + + plugins = [ dependencyGraph projectGraph ]; + + pluginsSbtPath = ".sbt/1.0/plugins/plugins.sbt"; + + expectedPluginsSbt = pkgs.writeText "plugins.sbt" '' + addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1") + addSbtPlugin("com.dwijnand" % "sbt-project-graph" % "0.4.0") + ''; + +in { + config = { + programs.sbt = { + enable = true; + plugins = plugins; + package = pkgs.writeScriptBin "sbt" ""; + }; + + nmt.script = '' + assertFileExists "home-files/${pluginsSbtPath}" + assertFileContent "home-files/${pluginsSbtPath}" "${expectedPluginsSbt}" + ''; + }; +}