diff --git a/doc/manual/rl-next/remove-xp-parse-toml-timestamps.md b/doc/manual/rl-next/remove-xp-parse-toml-timestamps.md new file mode 100644 index 000000000..471f40988 --- /dev/null +++ b/doc/manual/rl-next/remove-xp-parse-toml-timestamps.md @@ -0,0 +1,17 @@ +--- +synopsis: Remove the `parse-toml-timestamps` experimental feature +category: "Breaking Changes" +credits: [emilazy] +--- + +The `parse-toml-timestamps` experimental feature has been removed. + +This feature used in‐band signalling to mark timestamps, making it +impossible to unambiguously parse TOML documents. It also exposed +implementation‐defined behaviour in the TOML specification that +changed in the toml11 parser library. + +Any interface for parsing TOML timestamps suitable for future +stabilization would necessarily involve breaking changes, and there +is no evidence this experimental feature is being relied upon in the +wild, so it has been removed. diff --git a/lix/libexpr/primops/fromTOML.cc b/lix/libexpr/primops/fromTOML.cc index a66ccfb4e..9d4b5e6ab 100644 --- a/lix/libexpr/primops/fromTOML.cc +++ b/lix/libexpr/primops/fromTOML.cc @@ -6,80 +6,6 @@ namespace nix { -/** - * This is what toml11 < 4.0 did when choosing the subsecond precision. - * TOML 1.0.0 spec doesn't define how sub-millisecond ranges should be handled and calls it - * implementation defined behavior. For a lack of a better choice we stick with what older versions - * of toml11 did [1]. - * - * [1]: - * https://github.com/ToruNiina/toml11/blob/dcfe39a783a94e8d52c885e5883a6fbb21529019/toml/datetime.hpp#L282 - */ -static size_t normalizeSubsecondPrecision(toml::local_time lt) -{ - auto millis = lt.millisecond; - auto micros = lt.microsecond; - auto nanos = lt.nanosecond; - if (millis != 0 || micros != 0 || nanos != 0) { - if (micros != 0 || nanos != 0) { - if (nanos != 0) { - return 9; - } - return 6; - } - return 3; - } - return 0; -} - -/** - * Normalize date/time formats to serialize to the same strings as versions prior to toml11 4.0. - * - * Several things to consider: - * - * 1. Sub-millisecond range is represented the same way as in toml11 versions prior to 4.0. - * Precision is rounded towards the next multiple of 3 or capped at 9 digits. - * 2. Seconds must be specified. This may become optional in (yet unreleased) TOML 1.1.0, but 1.0.0 - * defined local time in terms of RFC3339 [1]. - * 3. date-time separator (`t`, `T` or space ` `) is canonicalized to an upper T. This is compliant - * with RFC3339 [1] 5.6: > Applications that generate this format SHOULD use upper case letters. - * - * [1]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 - */ -static void normalizeDatetimeFormat(toml::value & t) -{ - if (t.is_local_datetime()) { - auto & ldt = t.as_local_datetime(); - t.as_local_datetime_fmt() = { - .delimiter = toml::datetime_delimiter_kind::upper_T, - // https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 - .has_seconds = true, // Mandated by TOML 1.0.0 - .subsecond_precision = normalizeSubsecondPrecision(ldt.time), - }; - return; - } - - if (t.is_offset_datetime()) { - auto & odt = t.as_offset_datetime(); - t.as_offset_datetime_fmt() = { - .delimiter = toml::datetime_delimiter_kind::upper_T, - // https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 - .has_seconds = true, // Mandated by TOML 1.0.0 - .subsecond_precision = normalizeSubsecondPrecision(odt.time), - }; - return; - } - - if (t.is_local_time()) { - auto & lt = t.as_local_time(); - t.as_local_time_fmt() = { - .has_seconds = true, // Mandated by TOML 1.0.0 - .subsecond_precision = normalizeSubsecondPrecision(lt), - }; - return; - } -} - void prim_fromTOML(EvalState & state, Value ** args, Value & val) { auto toml = state.forceStringNoCtx( @@ -124,20 +50,10 @@ void prim_fromTOML(EvalState & state, Value ** args, Value & val) case toml::value_t::local_datetime: case toml::value_t::offset_datetime: case toml::value_t::local_date: - case toml::value_t::local_time: { - if (experimentalFeatureSettings.isEnabled(Xp::ParseTomlTimestamps)) { - normalizeDatetimeFormat(t); - auto attrs = state.ctx.buildBindings(2); - attrs.alloc("_type").mkString("timestamp"); - std::ostringstream s; - s << t; - attrs.alloc("value").mkString(s.str()); - v.mkAttrs(attrs); - } else { - // NOLINTNEXTLINE(lix-foreign-exceptions) - throw std::runtime_error("Dates and times are not supported"); - } - } break; + case toml::value_t::local_time: + // NOLINTNEXTLINE(lix-foreign-exceptions) + throw std::runtime_error("Dates and times are not supported"); + break; case toml::value_t::empty: v.mkNull(); break; diff --git a/lix/libutil/experimental-features/parse-toml-timestamps.md b/lix/libutil/experimental-features/parse-toml-timestamps.md deleted file mode 100644 index 9dbfb70d0..000000000 --- a/lix/libutil/experimental-features/parse-toml-timestamps.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: parse-toml-timestamps -internalName: ParseTomlTimestamps ---- -Allow parsing of timestamps in builtins.fromTOML. diff --git a/lix/libutil/meson.build b/lix/libutil/meson.build index 9ae86de05..71d55154c 100644 --- a/lix/libutil/meson.build +++ b/lix/libutil/meson.build @@ -158,7 +158,6 @@ experimental_feature_definitions = files( 'experimental-features/lix-custom-sub-commands.md', 'experimental-features/nix-command.md', 'experimental-features/no-url-literals.md', - 'experimental-features/parse-toml-timestamps.md', 'experimental-features/pipe-operator.md', 'experimental-features/read-only-local-store.md', 'experimental-features/repl-automation.md', diff --git a/tests/functional/lang/eval-okay-fromTOML-timestamps.exp b/tests/functional/lang/eval-okay-fromTOML-timestamps.exp deleted file mode 100644 index 56e610533..000000000 --- a/tests/functional/lang/eval-okay-fromTOML-timestamps.exp +++ /dev/null @@ -1 +0,0 @@ -{ "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bin1 = 214; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; dog = { "tater.man" = { type = { name = "pug"; }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; fruit = [ { name = "apple"; physical = { color = "red"; shape = "round"; }; variety = [ { name = "red delicious"; } { name = "granny smith"; } ]; } { name = "banana"; variety = [ { name = "plantain"; } ]; } ]; g = { h = { i = { }; }; }; hex1 = 3735928559; hex2 = 3735928559; hex3 = 3735928559; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { l = { }; }; }; key = "value"; key2 = "value"; ld1 = { _type = "timestamp"; value = "1979-05-27"; }; ldt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00"; }; ldt10 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456789"; }; ldt11 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456789"; }; ldt2 = { _type = "timestamp"; value = "1979-05-27T07:32:00.100"; }; ldt3 = { _type = "timestamp"; value = "1979-05-27T07:32:00.120"; }; ldt4 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123"; }; ldt5 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123400"; }; ldt6 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123450"; }; ldt7 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456"; }; ldt8 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456700"; }; ldt9 = { _type = "timestamp"; value = "1979-05-27T00:32:00.123456780"; }; lt1 = { _type = "timestamp"; value = "07:32:00"; }; lt10 = { _type = "timestamp"; value = "00:32:00.123456789"; }; lt11 = { _type = "timestamp"; value = "00:32:00.123456789"; }; lt2 = { _type = "timestamp"; value = "00:32:00.100"; }; lt3 = { _type = "timestamp"; value = "00:32:00.120"; }; lt4 = { _type = "timestamp"; value = "00:32:00.123"; }; lt5 = { _type = "timestamp"; value = "00:32:00.123400"; }; lt6 = { _type = "timestamp"; value = "00:32:00.123450"; }; lt7 = { _type = "timestamp"; value = "00:32:00.123456"; }; lt8 = { _type = "timestamp"; value = "00:32:00.123456700"; }; lt9 = { _type = "timestamp"; value = "00:32:00.123456780"; }; name = "Orange"; oct1 = 342391; oct2 = 493; odt1 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; odt10 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456Z"; }; odt11 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456700Z"; }; odt12 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456780Z"; }; odt13 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456789Z"; }; odt14 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123456789Z"; }; odt2 = { _type = "timestamp"; value = "1979-05-27T00:32:00-07:00"; }; odt3 = { _type = "timestamp"; value = "1979-05-27T00:32:00.999999-07:00"; }; odt4 = { _type = "timestamp"; value = "1979-05-27T07:32:00Z"; }; odt5 = { _type = "timestamp"; value = "1979-05-27T07:32:00.100Z"; }; odt6 = { _type = "timestamp"; value = "1979-05-27T07:32:00.120Z"; }; odt7 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123Z"; }; odt8 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123400Z"; }; odt9 = { _type = "timestamp"; value = "1979-05-27T07:32:00.123450Z"; }; physical = { color = "orange"; shape = "round"; }; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; "quoted \"value\"" = "value"; site = { "google.com" = true; }; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { animal = { type = { name = "pug"; }; }; name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; } diff --git a/tests/functional/lang/eval-okay-fromTOML-timestamps.flags b/tests/functional/lang/eval-okay-fromTOML-timestamps.flags deleted file mode 100644 index 9ed39dc6b..000000000 --- a/tests/functional/lang/eval-okay-fromTOML-timestamps.flags +++ /dev/null @@ -1 +0,0 @@ ---extra-experimental-features parse-toml-timestamps diff --git a/tests/functional/lang/eval-okay-fromTOML-timestamps.nix b/tests/functional/lang/eval-okay-fromTOML-timestamps.nix deleted file mode 100644 index d8f3a03e9..000000000 --- a/tests/functional/lang/eval-okay-fromTOML-timestamps.nix +++ /dev/null @@ -1,172 +0,0 @@ -builtins.fromTOML '' - key = "value" - bare_key = "value" - bare-key = "value" - 1234 = "value" - - "127.0.0.1" = "value" - "character encoding" = "value" - "ʎǝʞ" = "value" - 'key2' = "value" - 'quoted "value"' = "value" - - name = "Orange" - - physical.color = "orange" - physical.shape = "round" - site."google.com" = true - - # This is legal according to the spec, but cpptoml doesn't handle it. - #a.b.c = 1 - #a.d = 2 - - str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." - - int1 = +99 - int2 = 42 - int3 = 0 - int4 = -17 - int5 = 1_000 - int6 = 5_349_221 - int7 = 1_2_3_4_5 - - hex1 = 0xDEADBEEF - hex2 = 0xdeadbeef - hex3 = 0xdead_beef - - oct1 = 0o01234567 - oct2 = 0o755 - - bin1 = 0b11010110 - - flt1 = +1.0 - flt2 = 3.1415 - flt3 = -0.01 - flt4 = 5e+22 - flt5 = 1e6 - flt6 = -2E-2 - flt7 = 6.626e-34 - flt8 = 9_224_617.445_991_228_313 - - bool1 = true - bool2 = false - - odt1 = 1979-05-27T07:32:00Z - odt2 = 1979-05-27T00:32:00-07:00 - odt3 = 1979-05-27T00:32:00.999999-07:00 - odt4 = 1979-05-27 07:32:00Z - # milliseconds - odt5 = 1979-05-27 07:32:00.1Z - odt6 = 1979-05-27 07:32:00.12Z - odt7 = 1979-05-27 07:32:00.123Z - # microseconds - odt8 = 1979-05-27t07:32:00.1234Z - odt9 = 1979-05-27t07:32:00.12345Z - odt10 = 1979-05-27t07:32:00.123456Z - # nanoseconds - odt11 = 1979-05-27 07:32:00.1234567Z - odt12 = 1979-05-27 07:32:00.12345678Z - odt13 = 1979-05-27 07:32:00.123456789Z - # no more precision after nanoseconds - odt14 = 1979-05-27t07:32:00.1234567891Z - - ldt1 = 1979-05-27T07:32:00 - # milliseconds - ldt2 = 1979-05-27T07:32:00.1 - ldt3 = 1979-05-27T07:32:00.12 - ldt4 = 1979-05-27T07:32:00.123 - # microseconds - ldt5 = 1979-05-27t00:32:00.1234 - ldt6 = 1979-05-27t00:32:00.12345 - ldt7 = 1979-05-27t00:32:00.123456 - # nanoseconds - ldt8 = 1979-05-27 00:32:00.1234567 - ldt9 = 1979-05-27 00:32:00.12345678 - ldt10 = 1979-05-27 00:32:00.123456789 - # no more precision after nanoseconds - ldt11 = 1979-05-27t00:32:00.1234567891 - - ld1 = 1979-05-27 - lt1 = 07:32:00 - # milliseconds - lt2 = 00:32:00.1 - lt3 = 00:32:00.12 - lt4 = 00:32:00.123 - # microseconds - lt5 = 00:32:00.1234 - lt6 = 00:32:00.12345 - lt7 = 00:32:00.123456 - # nanoseconds - lt8 = 00:32:00.1234567 - lt9 = 00:32:00.12345678 - lt10 = 00:32:00.123456789 - # no more precision after nanoseconds - lt11 = 00:32:00.1234567891 - - arr1 = [ 1, 2, 3 ] - arr2 = [ "red", "yellow", "green" ] - arr3 = [ [ 1, 2 ], [3, 4, 5] ] - arr4 = [ "all", 'strings', """are the same""", ''''type''''] - arr5 = [ [ 1, 2 ], ["a", "b", "c"] ] - - arr7 = [ - 1, 2, 3 - ] - - arr8 = [ - 1, - 2, # this is ok - ] - - [table-1] - key1 = "some string" - key2 = 123 - - - [table-2] - key1 = "another string" - key2 = 456 - - [dog."tater.man"] - type.name = "pug" - - [a.b.c] - [ d.e.f ] - [ g . h . i ] - [ j . "ʞ" . 'l' ] - [x.y.z.w] - - name = { first = "Tom", last = "Preston-Werner" } - point = { x = 1, y = 2 } - animal = { type.name = "pug" } - - [[products]] - name = "Hammer" - sku = 738594937 - - [[products]] - - [[products]] - name = "Nail" - sku = 284758393 - color = "gray" - - [[fruit]] - name = "apple" - - [fruit.physical] - color = "red" - shape = "round" - - [[fruit.variety]] - name = "red delicious" - - [[fruit.variety]] - name = "granny smith" - - [[fruit]] - name = "banana" - - [[fruit.variety]] - name = "plantain" -''