Merge pull request #280322 from h7x4/add-hocon-format-generator
pkgs.formats: Add HOCON format generator
This commit is contained in:
commit
11cd405226
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -52,6 +52,7 @@
|
||||||
/pkgs/pkgs-lib @infinisil
|
/pkgs/pkgs-lib @infinisil
|
||||||
## Format generators/serializers
|
## Format generators/serializers
|
||||||
/pkgs/pkgs-lib/formats/libconfig @ckiee @h7x4
|
/pkgs/pkgs-lib/formats/libconfig @ckiee @h7x4
|
||||||
|
/pkgs/pkgs-lib/formats/hocon @h7x4
|
||||||
|
|
||||||
# pkgs/by-name
|
# pkgs/by-name
|
||||||
/pkgs/test/nixpkgs-check-by-name @infinisil
|
/pkgs/test/nixpkgs-check-by-name @infinisil
|
||||||
|
|
|
@ -5,12 +5,7 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.jibri;
|
cfg = config.services.jibri;
|
||||||
|
|
||||||
# Copied from the jitsi-videobridge.nix file.
|
format = pkgs.formats.hocon { };
|
||||||
toHOCON = x:
|
|
||||||
if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
|
|
||||||
else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
|
|
||||||
else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
|
|
||||||
else builtins.toJSON x;
|
|
||||||
|
|
||||||
# We're passing passwords in environment variables that have names generated
|
# We're passing passwords in environment variables that have names generated
|
||||||
# from an attribute name, which may not be a valid bash identifier.
|
# from an attribute name, which may not be a valid bash identifier.
|
||||||
|
@ -38,13 +33,13 @@ let
|
||||||
control-login = {
|
control-login = {
|
||||||
domain = env.control.login.domain;
|
domain = env.control.login.domain;
|
||||||
username = env.control.login.username;
|
username = env.control.login.username;
|
||||||
password.__hocon_envvar = toVarName "${name}_control";
|
password = format.lib.mkSubstitution (toVarName "${name}_control");
|
||||||
};
|
};
|
||||||
|
|
||||||
call-login = {
|
call-login = {
|
||||||
domain = env.call.login.domain;
|
domain = env.call.login.domain;
|
||||||
username = env.call.login.username;
|
username = env.call.login.username;
|
||||||
password.__hocon_envvar = toVarName "${name}_call";
|
password = format.lib.mkSubstitution (toVarName "${name}_call");
|
||||||
};
|
};
|
||||||
|
|
||||||
strip-from-room-domain = env.stripFromRoomDomain;
|
strip-from-room-domain = env.stripFromRoomDomain;
|
||||||
|
@ -85,13 +80,13 @@ let
|
||||||
};
|
};
|
||||||
# Allow overriding leaves of the default config despite types.attrs not doing any merging.
|
# Allow overriding leaves of the default config despite types.attrs not doing any merging.
|
||||||
jibriConfig = recursiveUpdate defaultJibriConfig cfg.config;
|
jibriConfig = recursiveUpdate defaultJibriConfig cfg.config;
|
||||||
configFile = pkgs.writeText "jibri.conf" (toHOCON { jibri = jibriConfig; });
|
configFile = format.generate "jibri.conf" { jibri = jibriConfig; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.jibri = with types; {
|
options.services.jibri = with types; {
|
||||||
enable = mkEnableOption (lib.mdDoc "Jitsi BRoadcasting Infrastructure. Currently Jibri must be run on a host that is also running {option}`services.jitsi-meet.enable`, so for most use cases it will be simpler to run {option}`services.jitsi-meet.jibri.enable`");
|
enable = mkEnableOption (lib.mdDoc "Jitsi BRoadcasting Infrastructure. Currently Jibri must be run on a host that is also running {option}`services.jitsi-meet.enable`, so for most use cases it will be simpler to run {option}`services.jitsi-meet.jibri.enable`");
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = attrs;
|
type = format.type;
|
||||||
default = { };
|
default = { };
|
||||||
description = lib.mdDoc ''
|
description = lib.mdDoc ''
|
||||||
Jibri configuration.
|
Jibri configuration.
|
||||||
|
|
|
@ -5,14 +5,9 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.jicofo;
|
cfg = config.services.jicofo;
|
||||||
|
|
||||||
# HOCON is a JSON superset that some jitsi-meet components use for configuration
|
format = pkgs.formats.hocon { };
|
||||||
toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
|
|
||||||
else if isAttrs x && x ? __hocon_unquoted_string then x.__hocon_unquoted_string
|
|
||||||
else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
|
|
||||||
else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
|
|
||||||
else builtins.toJSON x;
|
|
||||||
|
|
||||||
configFile = pkgs.writeText "jicofo.conf" (toHOCON cfg.config);
|
configFile = format.generate "jicofo.conf" cfg.config;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.jicofo = with types; {
|
options.services.jicofo = with types; {
|
||||||
|
@ -77,7 +72,7 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = (pkgs.formats.json {}).type;
|
type = format.type;
|
||||||
default = { };
|
default = { };
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
{
|
{
|
||||||
|
@ -99,7 +94,7 @@ in
|
||||||
hostname = cfg.xmppHost;
|
hostname = cfg.xmppHost;
|
||||||
username = cfg.userName;
|
username = cfg.userName;
|
||||||
domain = cfg.userDomain;
|
domain = cfg.userDomain;
|
||||||
password = { __hocon_envvar = "JICOFO_AUTH_PASS"; };
|
password = format.lib.mkSubstitution "JICOFO_AUTH_PASS";
|
||||||
xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain;
|
xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain;
|
||||||
};
|
};
|
||||||
service = client;
|
service = client;
|
||||||
|
|
|
@ -6,16 +6,7 @@ let
|
||||||
cfg = config.services.jitsi-videobridge;
|
cfg = config.services.jitsi-videobridge;
|
||||||
attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a);
|
attrsToArgs = a: concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") a);
|
||||||
|
|
||||||
# HOCON is a JSON superset that videobridge2 uses for configuration.
|
format = pkgs.formats.hocon { };
|
||||||
# It can substitute environment variables which we use for passwords here.
|
|
||||||
# https://github.com/lightbend/config/blob/master/README.md
|
|
||||||
#
|
|
||||||
# Substitution for environment variable FOO is represented as attribute set
|
|
||||||
# { __hocon_envvar = "FOO"; }
|
|
||||||
toHOCON = x: if isAttrs x && x ? __hocon_envvar then ("\${" + x.__hocon_envvar + "}")
|
|
||||||
else if isAttrs x then "{${ concatStringsSep "," (mapAttrsToList (k: v: ''"${k}":${toHOCON v}'') x) }}"
|
|
||||||
else if isList x then "[${ concatMapStringsSep "," toHOCON x }]"
|
|
||||||
else builtins.toJSON x;
|
|
||||||
|
|
||||||
# We're passing passwords in environment variables that have names generated
|
# We're passing passwords in environment variables that have names generated
|
||||||
# from an attribute name, which may not be a valid bash identifier.
|
# from an attribute name, which may not be a valid bash identifier.
|
||||||
|
@ -38,7 +29,7 @@ let
|
||||||
hostname = xmppConfig.hostName;
|
hostname = xmppConfig.hostName;
|
||||||
domain = xmppConfig.domain;
|
domain = xmppConfig.domain;
|
||||||
username = xmppConfig.userName;
|
username = xmppConfig.userName;
|
||||||
password = { __hocon_envvar = toVarName name; };
|
password = format.lib.mkSubstitution (toVarName name);
|
||||||
muc_jids = xmppConfig.mucJids;
|
muc_jids = xmppConfig.mucJids;
|
||||||
muc_nickname = xmppConfig.mucNickname;
|
muc_nickname = xmppConfig.mucNickname;
|
||||||
disable_certificate_verification = xmppConfig.disableCertificateVerification;
|
disable_certificate_verification = xmppConfig.disableCertificateVerification;
|
||||||
|
@ -221,7 +212,7 @@ in
|
||||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
|
"-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
|
||||||
"-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
|
"-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
|
||||||
"-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
|
"-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
|
||||||
"-Dconfig.file" = pkgs.writeText "jvb.conf" (toHOCON jvbConfig);
|
"-Dconfig.file" = format.generate "jvb.conf" jvbConfig;
|
||||||
# Mitigate CVE-2021-44228
|
# Mitigate CVE-2021-44228
|
||||||
"-Dlog4j2.formatMsgNoLookups" = true;
|
"-Dlog4j2.formatMsgNoLookups" = true;
|
||||||
} // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
|
} // (mapAttrs' (k: v: nameValuePair "-D${k}" v) cfg.extraProperties);
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
let
|
let
|
||||||
cfg = config.services.suwayomi-server;
|
cfg = config.services.suwayomi-server;
|
||||||
inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
|
inherit (lib) mkOption mdDoc mkEnableOption mkIf types;
|
||||||
|
|
||||||
|
format = pkgs.formats.hocon { };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
|
@ -48,19 +50,7 @@ in
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = types.submodule {
|
type = types.submodule {
|
||||||
freeformType =
|
freeformType = format.type;
|
||||||
let
|
|
||||||
recursiveAttrsType = with types; attrsOf (nullOr (oneOf [
|
|
||||||
str
|
|
||||||
path
|
|
||||||
int
|
|
||||||
float
|
|
||||||
bool
|
|
||||||
(listOf str)
|
|
||||||
(recursiveAttrsType // { description = "instances of this type recursively"; })
|
|
||||||
]));
|
|
||||||
in
|
|
||||||
recursiveAttrsType;
|
|
||||||
options = {
|
options = {
|
||||||
server = {
|
server = {
|
||||||
ip = mkOption {
|
ip = mkOption {
|
||||||
|
@ -180,38 +170,7 @@ in
|
||||||
|
|
||||||
systemd.services.suwayomi-server =
|
systemd.services.suwayomi-server =
|
||||||
let
|
let
|
||||||
flattenConfig = prefix: config:
|
configFile = format.generate "server.conf" (lib.pipe cfg.settings [
|
||||||
lib.foldl'
|
|
||||||
lib.mergeAttrs
|
|
||||||
{ }
|
|
||||||
(lib.attrValues
|
|
||||||
(lib.mapAttrs
|
|
||||||
(k: v:
|
|
||||||
if !(lib.isAttrs v)
|
|
||||||
then { "${prefix}${k}" = v; }
|
|
||||||
else flattenConfig "${prefix}${k}." v
|
|
||||||
)
|
|
||||||
config
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
# HOCON is a JSON superset that suwayomi-server use for configuration
|
|
||||||
toHOCON = attr:
|
|
||||||
let
|
|
||||||
attrType = builtins.typeOf attr;
|
|
||||||
in
|
|
||||||
if builtins.elem attrType [ "string" "path" "int" "float" ]
|
|
||||||
then ''"${toString attr}"''
|
|
||||||
else if attrType == "bool"
|
|
||||||
then lib.boolToString attr
|
|
||||||
else if attrType == "list"
|
|
||||||
then "[\n${lib.concatMapStringsSep ",\n" toHOCON attr}\n]"
|
|
||||||
else # attrs, lambda, null
|
|
||||||
throw ''
|
|
||||||
[suwayomi-server]: invalid config value type '${attrType}'.
|
|
||||||
'';
|
|
||||||
|
|
||||||
configFile = pkgs.writeText "server.conf" (lib.pipe cfg.settings [
|
|
||||||
(settings: lib.recursiveUpdate settings {
|
(settings: lib.recursiveUpdate settings {
|
||||||
server.basicAuthPasswordFile = null;
|
server.basicAuthPasswordFile = null;
|
||||||
server.basicAuthPassword =
|
server.basicAuthPassword =
|
||||||
|
@ -219,12 +178,8 @@ in
|
||||||
then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
|
then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD"
|
||||||
else null;
|
else null;
|
||||||
})
|
})
|
||||||
(flattenConfig "")
|
(lib.filterAttrsRecursive (_: x: x != null))
|
||||||
(lib.filterAttrs (_: x: x != null))
|
|
||||||
(lib.mapAttrsToList (name: value: ''${name} = ${toHOCON value}''))
|
|
||||||
lib.concatLines
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";
|
description = "A free and open source manga reader server that runs extensions built for Tachiyomi.";
|
||||||
|
|
|
@ -41,6 +41,8 @@ rec {
|
||||||
|
|
||||||
libconfig = (import ./formats/libconfig/default.nix { inherit lib pkgs; }).format;
|
libconfig = (import ./formats/libconfig/default.nix { inherit lib pkgs; }).format;
|
||||||
|
|
||||||
|
hocon = (import ./formats/hocon/default.nix { inherit lib pkgs; }).format;
|
||||||
|
|
||||||
json = {}: {
|
json = {}: {
|
||||||
|
|
||||||
type = with lib.types; let
|
type = with lib.types; let
|
||||||
|
|
189
pkgs/pkgs-lib/formats/hocon/default.nix
Normal file
189
pkgs/pkgs-lib/formats/hocon/default.nix
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
{ lib
|
||||||
|
, pkgs
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (pkgs) buildPackages callPackage;
|
||||||
|
|
||||||
|
hocon-generator = buildPackages.rustPlatform.buildRustPackage {
|
||||||
|
name = "hocon-generator";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./src;
|
||||||
|
|
||||||
|
passthru.updateScript = ./update.sh;
|
||||||
|
|
||||||
|
cargoLock.lockFile = ./src/Cargo.lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
hocon-validator = pkgs.writers.writePython3Bin "hocon-validator" {
|
||||||
|
libraries = [ pkgs.python3Packages.pyhocon ];
|
||||||
|
} ''
|
||||||
|
from sys import argv
|
||||||
|
from pyhocon import ConfigFactory
|
||||||
|
|
||||||
|
if not len(argv) == 2:
|
||||||
|
print("USAGE: hocon-validator <file>")
|
||||||
|
|
||||||
|
ConfigFactory.parse_file(argv[1])
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# https://github.com/lightbend/config/blob/main/HOCON.md
|
||||||
|
format = {
|
||||||
|
generator ? hocon-generator
|
||||||
|
, validator ? hocon-validator
|
||||||
|
# `include classpath("")` is not implemented in pyhocon.
|
||||||
|
# In the case that you need this functionality,
|
||||||
|
# you will have to disable pyhocon validation.
|
||||||
|
, doCheck ? true
|
||||||
|
}: let
|
||||||
|
hoconLib = {
|
||||||
|
mkInclude = value: let
|
||||||
|
includeStatement = if lib.isAttrs value && !(lib.isDerivation value) then {
|
||||||
|
required = false;
|
||||||
|
type = null;
|
||||||
|
_type = "include";
|
||||||
|
} // value else {
|
||||||
|
value = toString value;
|
||||||
|
required = false;
|
||||||
|
type = null;
|
||||||
|
_type = "include";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
assert lib.assertMsg (lib.elem includeStatement.type [ "file" "url" "classpath" null ]) ''
|
||||||
|
Type of HOCON mkInclude is not of type 'file', 'url' or 'classpath':
|
||||||
|
${(lib.generators.toPretty {}) includeStatement}
|
||||||
|
'';
|
||||||
|
includeStatement;
|
||||||
|
|
||||||
|
mkAppend = value: {
|
||||||
|
inherit value;
|
||||||
|
_type = "append";
|
||||||
|
};
|
||||||
|
|
||||||
|
mkSubstitution = value:
|
||||||
|
if lib.isString value
|
||||||
|
then
|
||||||
|
{
|
||||||
|
inherit value;
|
||||||
|
optional = false;
|
||||||
|
_type = "substitution";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
assert lib.assertMsg (lib.isAttrs value) ''
|
||||||
|
Value of invalid type provided to `hocon.lib.mkSubstition`: ${lib.typeOf value}
|
||||||
|
'';
|
||||||
|
assert lib.assertMsg (value ? "value") ''
|
||||||
|
Argument to `hocon.lib.mkSubstition` is missing a `value`:
|
||||||
|
${builtins.toJSON value}
|
||||||
|
'';
|
||||||
|
{
|
||||||
|
value = value.value;
|
||||||
|
optional = value.optional or false;
|
||||||
|
_type = "substitution";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
type = let
|
||||||
|
type' = with lib.types; let
|
||||||
|
atomType = nullOr (oneOf [
|
||||||
|
bool
|
||||||
|
float
|
||||||
|
int
|
||||||
|
path
|
||||||
|
str
|
||||||
|
]);
|
||||||
|
in (oneOf [
|
||||||
|
atomType
|
||||||
|
(listOf atomType)
|
||||||
|
(attrsOf type')
|
||||||
|
]) // {
|
||||||
|
description = "HOCON value";
|
||||||
|
};
|
||||||
|
in type';
|
||||||
|
|
||||||
|
lib = hoconLib;
|
||||||
|
|
||||||
|
generate = name: value:
|
||||||
|
let
|
||||||
|
# TODO: remove in 24.11
|
||||||
|
# Backwards compatability for generators in the following locations:
|
||||||
|
# - nixos/modules/services/networking/jibri/default.nix (__hocon_envvar)
|
||||||
|
# - nixos/modules/services/networking/jicofo.nix (__hocon_envvar, __hocon_unquoted_string)
|
||||||
|
# - nixos/modules/services/networking/jitsi-videobridge.nix (__hocon_envvar)
|
||||||
|
replaceOldIndicators = value:
|
||||||
|
if lib.isAttrs value then
|
||||||
|
(if value ? "__hocon_envvar"
|
||||||
|
then
|
||||||
|
lib.warn ''
|
||||||
|
Use of `__hocon_envvar` has been deprecated, and will
|
||||||
|
be removed in the future.
|
||||||
|
|
||||||
|
Please use `(pkgs.formats.hocon {}).lib.mkSubstitution` instead.
|
||||||
|
''
|
||||||
|
(hoconLib.mkSubstitution value.__hocon_envvar)
|
||||||
|
else if value ? "__hocon_unquoted_string"
|
||||||
|
then
|
||||||
|
lib.warn ''
|
||||||
|
Use of `__hocon_unquoted_string` has been deprecated, and will
|
||||||
|
be removed in the future.
|
||||||
|
|
||||||
|
Please make use of the freeform options of
|
||||||
|
`(pkgs.formats.hocon {}).format` instead.
|
||||||
|
''
|
||||||
|
{
|
||||||
|
value = value.__hocon_unquoted_string;
|
||||||
|
_type = "unquoted_string";
|
||||||
|
}
|
||||||
|
else lib.mapAttrs (_: replaceOldIndicators) value)
|
||||||
|
else if lib.isList value
|
||||||
|
then map replaceOldIndicators value
|
||||||
|
else value;
|
||||||
|
|
||||||
|
finalValue = replaceOldIndicators value;
|
||||||
|
in
|
||||||
|
callPackage
|
||||||
|
({
|
||||||
|
stdenvNoCC
|
||||||
|
, hocon-generator
|
||||||
|
, hocon-validator
|
||||||
|
, writeText
|
||||||
|
}:
|
||||||
|
stdenvNoCC.mkDerivation rec {
|
||||||
|
inherit name;
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
json = builtins.toJSON finalValue;
|
||||||
|
passAsFile = [ "json" ];
|
||||||
|
|
||||||
|
strictDeps = true;
|
||||||
|
nativeBuildInputs = [ hocon-generator ];
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
hocon-generator < $jsonPath > output.conf
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
inherit doCheck;
|
||||||
|
nativeCheckInputs = [ hocon-validator ];
|
||||||
|
checkPhase = ''
|
||||||
|
runHook preCheck
|
||||||
|
hocon-validator output.conf
|
||||||
|
runHook postCheck
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
mv output.conf $out
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
passthru.json = writeText "${name}.json" json;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
hocon-generator = generator;
|
||||||
|
hocon-validator = validator;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
1
pkgs/pkgs-lib/formats/hocon/src/.gitignore
vendored
Normal file
1
pkgs/pkgs-lib/formats/hocon/src/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
target
|
89
pkgs/pkgs-lib/formats/hocon/src/Cargo.lock
generated
Normal file
89
pkgs/pkgs-lib/formats/hocon/src/Cargo.lock
generated
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hocon-generator"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.190"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.190"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.107"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
10
pkgs/pkgs-lib/formats/hocon/src/Cargo.toml
Normal file
10
pkgs/pkgs-lib/formats/hocon/src/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "hocon-generator"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "1.0.178"
|
||||||
|
serde_json = "1.0.104"
|
237
pkgs/pkgs-lib/formats/hocon/src/src/main.rs
Normal file
237
pkgs/pkgs-lib/formats/hocon/src/src/main.rs
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
use serde_json::{value, Map, Value};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum HOCONValue {
|
||||||
|
Null,
|
||||||
|
Append(Box<HOCONValue>),
|
||||||
|
Bool(bool),
|
||||||
|
Number(value::Number),
|
||||||
|
String(String),
|
||||||
|
List(Vec<HOCONValue>),
|
||||||
|
Substitution(String, bool),
|
||||||
|
Object(Vec<HOCONInclude>, Vec<(String, HOCONValue)>),
|
||||||
|
Literal(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum HOCONInclude {
|
||||||
|
Heuristic(String, bool),
|
||||||
|
Url(String, bool),
|
||||||
|
File(String, bool),
|
||||||
|
ClassPath(String, bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HOCONInclude {
|
||||||
|
fn map_fst(&self, f: &dyn Fn(&String) -> String) -> HOCONInclude {
|
||||||
|
match self {
|
||||||
|
HOCONInclude::Heuristic(s, r) => HOCONInclude::Heuristic(f(s), *r),
|
||||||
|
HOCONInclude::Url(s, r) => HOCONInclude::Url(f(s), *r),
|
||||||
|
HOCONInclude::File(s, r) => HOCONInclude::File(f(s), *r),
|
||||||
|
HOCONInclude::ClassPath(s, r) => HOCONInclude::ClassPath(f(s), *r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_include(o: &Map<String, Value>) -> HOCONInclude {
|
||||||
|
let value = o
|
||||||
|
.get("value")
|
||||||
|
.expect("Missing field 'value' for include statement")
|
||||||
|
.as_str()
|
||||||
|
.expect("Field 'value' is not a string in include statement")
|
||||||
|
.to_string();
|
||||||
|
let required = o
|
||||||
|
.get("required")
|
||||||
|
.expect("Missing field 'required' for include statement")
|
||||||
|
.as_bool()
|
||||||
|
.expect("Field 'required'is not a bool in include statement");
|
||||||
|
let include_type = match o
|
||||||
|
.get("type")
|
||||||
|
.expect("Missing field 'type' for include statement")
|
||||||
|
{
|
||||||
|
Value::Null => None,
|
||||||
|
Value::String(s) => Some(s.as_str()),
|
||||||
|
t => panic!("Field 'type' is not a string in include statement: {:?}", t),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assert that this was an intentional include
|
||||||
|
debug_assert!(o.get("_type").and_then(|t| t.as_str()) == Some("include"));
|
||||||
|
|
||||||
|
match include_type {
|
||||||
|
None => HOCONInclude::Heuristic(value, required),
|
||||||
|
Some("url") => HOCONInclude::Url(value, required),
|
||||||
|
Some("file") => HOCONInclude::File(value, required),
|
||||||
|
Some("classpath") => HOCONInclude::ClassPath(value, required),
|
||||||
|
_ => panic!(
|
||||||
|
"Could not recognize type for include statement: {}",
|
||||||
|
include_type.unwrap()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_special_types(o: &Map<String, Value>) -> Option<HOCONValue> {
|
||||||
|
o.get("_type")
|
||||||
|
.and_then(|r#type| r#type.as_str())
|
||||||
|
.map(|r#type| match r#type {
|
||||||
|
"substitution" => {
|
||||||
|
let value = o
|
||||||
|
.get("value")
|
||||||
|
.expect("Missing value for substitution")
|
||||||
|
.as_str()
|
||||||
|
.unwrap_or_else(|| panic!("Substition value is not a string: {:?}", o));
|
||||||
|
let required = o
|
||||||
|
.get("required")
|
||||||
|
.unwrap_or(&Value::Bool(false))
|
||||||
|
.as_bool()
|
||||||
|
.unwrap_or_else(|| panic!("Substition value is not a string: {:?}", o));
|
||||||
|
|
||||||
|
debug_assert!(!value.contains('}'));
|
||||||
|
|
||||||
|
HOCONValue::Substitution(value.to_string(), required)
|
||||||
|
}
|
||||||
|
"append" => {
|
||||||
|
let value = o.get("value").expect("Missing value for append");
|
||||||
|
|
||||||
|
HOCONValue::Append(Box::new(json_to_hocon(value)))
|
||||||
|
}
|
||||||
|
"unquoted_string" => {
|
||||||
|
let value = o
|
||||||
|
.get("value")
|
||||||
|
.expect("Missing value for unquoted_string")
|
||||||
|
.as_str()
|
||||||
|
.unwrap_or_else(|| panic!("Unquoted string value is not a string: {:?}", o));
|
||||||
|
|
||||||
|
HOCONValue::Literal(value.to_string())
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"\
|
||||||
|
Attribute set contained special element '_type',\
|
||||||
|
but its value is not recognized:\n{}",
|
||||||
|
r#type
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_to_hocon(v: &Value) -> HOCONValue {
|
||||||
|
match v {
|
||||||
|
Value::Null => HOCONValue::Null,
|
||||||
|
Value::Bool(b) => HOCONValue::Bool(*b),
|
||||||
|
Value::Number(n) => HOCONValue::Number(n.clone()),
|
||||||
|
Value::String(s) => HOCONValue::String(s.clone()),
|
||||||
|
Value::Array(a) => {
|
||||||
|
let items = a.iter().map(json_to_hocon).collect::<Vec<HOCONValue>>();
|
||||||
|
HOCONValue::List(items)
|
||||||
|
}
|
||||||
|
Value::Object(o) => {
|
||||||
|
if let Some(result) = parse_special_types(o) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut items = o
|
||||||
|
.iter()
|
||||||
|
.filter(|(key, _)| key.as_str() != "_includes")
|
||||||
|
.map(|(key, value)| (key.clone(), json_to_hocon(value)))
|
||||||
|
.collect::<Vec<(String, HOCONValue)>>();
|
||||||
|
|
||||||
|
items.sort_by(|(a, _), (b, _)| a.partial_cmp(b).unwrap());
|
||||||
|
|
||||||
|
let includes = o
|
||||||
|
.get("_includes")
|
||||||
|
.map(|x| {
|
||||||
|
x.as_array()
|
||||||
|
.expect("_includes is not an array")
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
x.as_object()
|
||||||
|
.unwrap_or_else(|| panic!("Include is not an object: {}", x))
|
||||||
|
})
|
||||||
|
.map(parse_include)
|
||||||
|
.collect::<Vec<HOCONInclude>>()
|
||||||
|
})
|
||||||
|
.unwrap_or(vec![]);
|
||||||
|
|
||||||
|
HOCONValue::Object(includes, items)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for HOCONValue {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
HOCONValue::Null => "null".to_string(),
|
||||||
|
HOCONValue::Bool(b) => b.to_string(),
|
||||||
|
HOCONValue::Number(n) => n.to_string(),
|
||||||
|
HOCONValue::String(s) => serde_json::to_string(&Value::String(s.clone())).unwrap(),
|
||||||
|
HOCONValue::Substitution(v, required) => {
|
||||||
|
format!("${{{}{}}}", if *required { "" } else { "?" }, v)
|
||||||
|
}
|
||||||
|
HOCONValue::List(l) => {
|
||||||
|
let items = l
|
||||||
|
.iter()
|
||||||
|
.map(|item| item.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",\n")
|
||||||
|
.split('\n')
|
||||||
|
.map(|s| " ".to_owned() + s)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
format!("[\n{}\n]", items)
|
||||||
|
}
|
||||||
|
HOCONValue::Object(i, o) => {
|
||||||
|
let includes = i
|
||||||
|
.iter()
|
||||||
|
.map(|x| {
|
||||||
|
x.map_fst(&|s| serde_json::to_string(&Value::String(s.clone())).unwrap())
|
||||||
|
})
|
||||||
|
.map(|x| match x {
|
||||||
|
HOCONInclude::Heuristic(s, r) => (s.to_string(), r),
|
||||||
|
HOCONInclude::Url(s, r) => (format!("url({})", s), r),
|
||||||
|
HOCONInclude::File(s, r) => (format!("file({})", s), r),
|
||||||
|
HOCONInclude::ClassPath(s, r) => (format!("classpath({})", s), r),
|
||||||
|
})
|
||||||
|
.map(|(i, r)| if r { format!("required({})", i) } else { i })
|
||||||
|
.map(|s| format!("include {}", s))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
let items = o
|
||||||
|
.iter()
|
||||||
|
.map(|(key, value)| {
|
||||||
|
(
|
||||||
|
serde_json::to_string(&Value::String(key.clone())).unwrap(),
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(key, value)| match value {
|
||||||
|
HOCONValue::Append(v) => format!("{} += {}", key, v.to_string()),
|
||||||
|
v => format!("{} = {}", key, v.to_string()),
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
let content = (if includes.is_empty() {
|
||||||
|
items
|
||||||
|
} else {
|
||||||
|
format!("{}{}", includes, items)
|
||||||
|
})
|
||||||
|
.split('\n')
|
||||||
|
.map(|s| format!(" {}", s))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
format!("{{\n{}\n}}", content)
|
||||||
|
}
|
||||||
|
HOCONValue::Append(_) => panic!("Append should not be present at this point"),
|
||||||
|
Self::Literal(s) => s.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let stdin = std::io::stdin().lock();
|
||||||
|
let json = serde_json::Deserializer::from_reader(stdin)
|
||||||
|
.into_iter::<Value>()
|
||||||
|
.next()
|
||||||
|
.expect("Could not read content from stdin")
|
||||||
|
.expect("Could not parse JSON from stdin");
|
||||||
|
|
||||||
|
print!("{}\n\n", json_to_hocon(&json).to_string());
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
{ lib, formats, stdenvNoCC, writeText, ... }:
|
||||||
|
let
|
||||||
|
hocon = formats.hocon { };
|
||||||
|
|
||||||
|
expression = {
|
||||||
|
substitution = { __hocon_envvar = "PATH"; };
|
||||||
|
literal = {
|
||||||
|
__hocon_unquoted_string = ''
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]'';
|
||||||
|
};
|
||||||
|
|
||||||
|
nested = {
|
||||||
|
substitution = { __hocon_envvar = "PATH"; };
|
||||||
|
literal = {
|
||||||
|
__hocon_unquoted_string = ''
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nested_in_array = [
|
||||||
|
{ __hocon_envvar = "PATH"; }
|
||||||
|
{
|
||||||
|
__hocon_unquoted_string = ''
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
hocon-test-conf = hocon.generate "hocon-test.conf" expression;
|
||||||
|
in
|
||||||
|
stdenvNoCC.mkDerivation {
|
||||||
|
name = "pkgs.formats.hocon-test-backwards-compatibility";
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
|
checkPhase = ''
|
||||||
|
runHook preCheck
|
||||||
|
|
||||||
|
diff -U3 ${./expected.txt} ${hocon-test-conf}
|
||||||
|
|
||||||
|
runHook postCheck
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
mkdir $out
|
||||||
|
cp ${./expected.txt} $out/expected.txt
|
||||||
|
cp ${hocon-test-conf} $out/hocon-test.conf
|
||||||
|
cp ${hocon-test-conf.passthru.json} $out/hocon-test.json
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"literal" = [
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]
|
||||||
|
"nested" = {
|
||||||
|
"literal" = [
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]
|
||||||
|
"substitution" = ${?PATH}
|
||||||
|
}
|
||||||
|
"nested_in_array" = [
|
||||||
|
${?PATH},
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
"a",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
"substitution" = ${?PATH}
|
||||||
|
}
|
||||||
|
|
83
pkgs/pkgs-lib/formats/hocon/test/comprehensive/default.nix
Normal file
83
pkgs/pkgs-lib/formats/hocon/test/comprehensive/default.nix
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{ lib, formats, stdenvNoCC, writeText, ... }:
|
||||||
|
let
|
||||||
|
hocon = formats.hocon { };
|
||||||
|
|
||||||
|
include_file = (writeText "hocon-test-include.conf" ''
|
||||||
|
"val" = 1
|
||||||
|
'').overrideAttrs (_: _: {
|
||||||
|
outputHashAlgo = "sha256";
|
||||||
|
outputHashMode = "flat";
|
||||||
|
outputHash = "sha256-UhkJLhT3bD6znq+IdDjs/ahP19mLzrLCy/R14pVrfew=";
|
||||||
|
});
|
||||||
|
|
||||||
|
expression = {
|
||||||
|
simple_top_level_attr = "1.0";
|
||||||
|
nested.attrset.has.a.integer.value = 100;
|
||||||
|
some_floaty = 29.95;
|
||||||
|
|
||||||
|
array2d = [
|
||||||
|
[ 1 2 "a" ]
|
||||||
|
[ 2 1 "b" ]
|
||||||
|
];
|
||||||
|
nasty_string = "\"@\n\\\t^*\b\f\n\0\";'''$";
|
||||||
|
|
||||||
|
"misc attrs" = {
|
||||||
|
x = 1;
|
||||||
|
y = hocon.lib.mkAppend { a = 1; };
|
||||||
|
};
|
||||||
|
|
||||||
|
"cursed \" .attrs \" " = {
|
||||||
|
"a" = 1;
|
||||||
|
"a b" = hocon.lib.mkSubstitution "a";
|
||||||
|
"a b c" = hocon.lib.mkSubstitution {
|
||||||
|
value = "a b";
|
||||||
|
required = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
to_include = {
|
||||||
|
_includes = [
|
||||||
|
(hocon.lib.mkInclude include_file)
|
||||||
|
(hocon.lib.mkInclude "https://example.com")
|
||||||
|
(hocon.lib.mkInclude {
|
||||||
|
required = true;
|
||||||
|
type = "file";
|
||||||
|
value = include_file;
|
||||||
|
})
|
||||||
|
(hocon.lib.mkInclude { value = include_file; })
|
||||||
|
(hocon.lib.mkInclude {
|
||||||
|
value = "https://example.com";
|
||||||
|
type = "url";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
hocon-test-conf = hocon.generate "hocon-test.conf" expression;
|
||||||
|
in
|
||||||
|
stdenvNoCC.mkDerivation {
|
||||||
|
name = "pkgs.formats.hocon-test-comprehensive";
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
|
checkPhase = ''
|
||||||
|
runHook preCheck
|
||||||
|
|
||||||
|
diff -U3 ${./expected.txt} ${hocon-test-conf}
|
||||||
|
|
||||||
|
runHook postCheck
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
mkdir $out
|
||||||
|
cp ${./expected.txt} $out/expected.txt
|
||||||
|
cp ${hocon-test-conf} $out/hocon-test.conf
|
||||||
|
cp ${hocon-test-conf.passthru.json} $out/hocon-test.json
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
}
|
47
pkgs/pkgs-lib/formats/hocon/test/comprehensive/expected.txt
Normal file
47
pkgs/pkgs-lib/formats/hocon/test/comprehensive/expected.txt
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"array2d" = [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
"a"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
"b"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
"cursed \" .attrs \" " = {
|
||||||
|
"a" = 1
|
||||||
|
"a b" = ${?a}
|
||||||
|
"a b c" = ${?a b}
|
||||||
|
}
|
||||||
|
"misc attrs" = {
|
||||||
|
"x" = 1
|
||||||
|
"y" += {
|
||||||
|
"a" = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"nasty_string" = "\"@\n\\\t^*bf\n0\";'''$"
|
||||||
|
"nested" = {
|
||||||
|
"attrset" = {
|
||||||
|
"has" = {
|
||||||
|
"a" = {
|
||||||
|
"integer" = {
|
||||||
|
"value" = 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"simple_top_level_attr" = "1.0"
|
||||||
|
"some_floaty" = 29.95
|
||||||
|
"to_include" = {
|
||||||
|
include "/nix/store/ccnzr53dpipdacxgci3ii3bqacvb5hxm-hocon-test-include.conf"
|
||||||
|
include "https://example.com"
|
||||||
|
include required(file("/nix/store/ccnzr53dpipdacxgci3ii3bqacvb5hxm-hocon-test-include.conf"))
|
||||||
|
include "/nix/store/ccnzr53dpipdacxgci3ii3bqacvb5hxm-hocon-test-include.conf"
|
||||||
|
include url("https://example.com")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
pkgs/pkgs-lib/formats/hocon/test/default.nix
Normal file
15
pkgs/pkgs-lib/formats/hocon/test/default.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
comprehensive = pkgs.callPackage ./comprehensive { };
|
||||||
|
backwards-compatibility =
|
||||||
|
let
|
||||||
|
pkgsNoWarn = pkgs.extend (final: prev: {
|
||||||
|
lib = prev.lib.extend (libFinal: libPrev: {
|
||||||
|
warn = msg: v: v;
|
||||||
|
trivial = libPrev.trivial // {
|
||||||
|
warn = msg: v: v;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
in pkgsNoWarn.callPackage ./backwards-compatibility { };
|
||||||
|
}
|
4
pkgs/pkgs-lib/formats/hocon/update.sh
Executable file
4
pkgs/pkgs-lib/formats/hocon/update.sh
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -p cargo -i bash
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
cargo update
|
|
@ -17,7 +17,10 @@ let
|
||||||
jdk11 = pkgs.callPackage ../formats/java-properties/test { jdk = pkgs.jdk11_headless; };
|
jdk11 = pkgs.callPackage ../formats/java-properties/test { jdk = pkgs.jdk11_headless; };
|
||||||
jdk17 = pkgs.callPackage ../formats/java-properties/test { jdk = pkgs.jdk17_headless; };
|
jdk17 = pkgs.callPackage ../formats/java-properties/test { jdk = pkgs.jdk17_headless; };
|
||||||
};
|
};
|
||||||
|
|
||||||
libconfig = recurseIntoAttrs (import ../formats/libconfig/test { inherit pkgs; });
|
libconfig = recurseIntoAttrs (import ../formats/libconfig/test { inherit pkgs; });
|
||||||
|
|
||||||
|
hocon = recurseIntoAttrs (import ../formats/hocon/test { inherit pkgs; });
|
||||||
};
|
};
|
||||||
|
|
||||||
flatten = prefix: as:
|
flatten = prefix: as:
|
||||||
|
|
|
@ -1471,7 +1471,12 @@ with pkgs;
|
||||||
writers = callPackage ../build-support/writers { };
|
writers = callPackage ../build-support/writers { };
|
||||||
|
|
||||||
# lib functions depending on pkgs
|
# lib functions depending on pkgs
|
||||||
inherit (import ../pkgs-lib { inherit lib pkgs; }) formats;
|
inherit (import ../pkgs-lib {
|
||||||
|
# The `lib` variable in this scope doesn't include any applied lib overlays,
|
||||||
|
# `pkgs.lib` does.
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
inherit pkgs;
|
||||||
|
}) formats;
|
||||||
|
|
||||||
testers = callPackage ../build-support/testers { };
|
testers = callPackage ../build-support/testers { };
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user