From 56cee61ad4270021ac86bbf902b7eb013890d686 Mon Sep 17 00:00:00 2001 From: Renaud Lenne Date: Fri, 6 Dec 2024 16:50:15 +0100 Subject: [PATCH 1/9] Add the possibility to fetch the input directly from the AoC website (#16) * feat: added a new --fetch flag to the 'new' command, to directly fetch the input from the AoC website * feat: extract the AoC cookie env name to a constant + use envoy instead of the soon-to-be-deprecated os.getenv * feat: do the input fetching in the create_input_file step * feat: use a guard instead to avoid having another argument to the case * style: code formatting * feat: handle non-200 http response while fetching input * feat: use request builder to build the request to fetch the input * feat: add a user-agent when sending request to AoC to be in line with official AoC recommendations * feat: check if the input file already exists when trying to fetch it and return an error without trying to downloading it again if that's the case * chore: better output FailedToWriteToFile error message * chore: call simplifile.file_info to ensure the pre-existence of the input file before fetching it, instead of calling both is_file and is_directory --- gleam.toml | 3 + manifest.toml | 6 ++ src/gladvent/internal/cmd/new.gleam | 91 +++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/gleam.toml b/gleam.toml index 076047d..fac81ef 100644 --- a/gleam.toml +++ b/gleam.toml @@ -22,6 +22,9 @@ filepath = ">= 1.0.0 and < 2.0.0" tom = ">= 1.0.0 and < 2.0.0" decode = ">= 0.2.0 and < 1.0.0" gleam_json = ">= 1.0.0 and < 3.0.0" +gleam_httpc = ">= 4.0.0 and < 5.0.0" +gleam_http = ">= 3.7.1 and < 4.0.0" +envoy = ">= 1.0.2 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.2.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index d124eed..64aee65 100644 --- a/manifest.toml +++ b/manifest.toml @@ -4,10 +4,13 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, { name = "decode", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "05E14DC95A550BA51B8774485B04894B87A898C588B9B1C920104B110AED218B" }, + { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" }, { name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" }, { name = "gleam_community_colour", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "386CB9B01B33371538672EEA8A6375A0A0ADEF41F17C86DDCB81C92AD00DA610" }, { name = "gleam_erlang", version = "0.30.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "760618870AE4A497B10C73548E6E44F43B76292A54F0207B3771CBB599C675B4" }, + { name = "gleam_http", version = "3.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "A9EE0722106FCCAB8AD3BF9D0A3EFF92BFE8561D59B83BAE96EB0BE1938D4E0F" }, + { name = "gleam_httpc", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "76FEEC99473E568EBA34336A37CF3D54629ACE77712950DC9BB097B5FD664664" }, { name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" }, { name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" }, { name = "gleam_package_interface", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "CF3BFC5D0997750D9550D8D73A90F4B8D71C6C081B20ED4E70FFBE1E99AFC3C2" }, @@ -27,8 +30,11 @@ packages = [ [requirements] argv = { version = "~> 1.0" } decode = { version = ">= 0.2.0 and < 1.0.0" } +envoy = { version = ">= 1.0.2 and < 2.0.0" } filepath = { version = ">= 1.0.0 and < 2.0.0" } gleam_erlang = { version = "~> 0.7 or ~> 1.0" } +gleam_http = { version = ">= 3.7.1 and < 4.0.0" } +gleam_httpc = { version = ">= 4.0.0 and < 5.0.0" } gleam_json = { version = ">= 1.0.0 and < 3.0.0" } gleam_otp = { version = "~> 0.4 or ~> 1.0" } gleam_package_interface = { version = "~> 1.0" } diff --git a/src/gladvent/internal/cmd/new.gleam b/src/gladvent/internal/cmd/new.gleam index 6ccc362..c4eb99a 100644 --- a/src/gladvent/internal/cmd/new.gleam +++ b/src/gladvent/internal/cmd/new.gleam @@ -1,8 +1,13 @@ +import envoy import filepath import gladvent/internal/cmd import gladvent/internal/input import gladvent/internal/parse.{type Day, pad} import gladvent/internal/util +import gleam/http +import gleam/http/request +import gleam/http/response +import gleam/httpc import gleam/int import gleam/list import gleam/pair @@ -11,8 +16,16 @@ import gleam/string import glint import simplifile +const aoc_cookie_name = "AOC_COOKIE" + type Context { - Context(year: Int, day: Day, add_parse: Bool, create_example_file: Bool) + Context( + year: Int, + day: Day, + add_parse: Bool, + create_example_file: Bool, + fetch_input: Bool, + ) } fn create_src_file(ctx: Context) -> fn() -> Result(String, Err) { @@ -41,23 +54,52 @@ fn create_input_file( ) -> fn() -> Result(String, Err) { fn() { let input_path = input.get_file_path(ctx.year, ctx.day, kind) - simplifile.create_file(input_path) - |> result.map_error(handle_file_open_failure(_, input_path)) + case kind { + input.Puzzle if ctx.fetch_input -> { + case simplifile.file_info(input_path) { + Error(_) -> { + use content <- result.try(download_input(ctx)) + simplifile.write(input_path, content) + |> result.map_error(FailedToWriteToFile(_)) + } + _ -> Error(FileAlreadyExists(input_path)) + } + } + _ -> { + simplifile.create_file(input_path) + |> result.map_error(handle_file_open_failure(_, input_path)) + } + } |> result.replace(input_path) } } type Err { + CookieNotDefined FailedToCreateDir(String) FailedToCreateFile(String) + FailedToWriteToFile(simplifile.FileError) FileAlreadyExists(String) + HttpError(httpc.HttpError) + UnexpectedHttpResponse(response.Response(String)) } fn err_to_string(e: Err) -> String { case e { + CookieNotDefined -> + "'" <> aoc_cookie_name <> "' environment variable not defined" FailedToCreateDir(d) -> "failed to create dir: " <> d FailedToCreateFile(f) -> "failed to create file: " <> f + FailedToWriteToFile(e) -> + "failed to write to file:" <> simplifile.describe_error(e) FileAlreadyExists(f) -> "file already exists: " <> f + HttpError(e) -> + "HTTP error while fetching input file: " <> string.inspect(e) + UnexpectedHttpResponse(r) -> + "unexpected HTTP response (" + <> int.to_string(r.status) + <> ") while fetching input file: " + <> r.body } } @@ -96,6 +138,37 @@ fn handle_file_open_failure( } } +fn get_cookie_value() -> Result(String, Err) { + case envoy.get(aoc_cookie_name) { + Ok(cookie) -> Ok(cookie) + _ -> Error(CookieNotDefined) + } +} + +fn download_input(ctx: Context) -> Result(String, Err) { + use cookie <- result.try(get_cookie_value()) + use resp <- result.try( + request.new() + |> request.set_host("adventofcode.com") + |> request.set_path( + "/" + <> int.to_string(ctx.year) + <> "/day/" + <> int.to_string(ctx.day) + <> "/input", + ) + |> request.set_scheme(http.Https) + |> request.set_cookie("session", cookie) + |> request.set_header("user-agent", "github.com/TanklesXL/gladvent") + |> httpc.send() + |> result.map_error(HttpError(_)), + ) + case resp.status { + 200 -> Ok(resp.body) + _ -> Error(UnexpectedHttpResponse(resp)) + } +} + fn do(ctx: Context) -> String { let seq = [ create_dir(input.dir(ctx.year)), @@ -188,17 +261,27 @@ pub fn new_command() { "Generate example input files to run your solution against", ), ) + use fetch_flag <- glint.flag( + glint.bool_flag("fetch") + |> glint.flag_default(False) + |> glint.flag_help("Fetch your own input from the AoC website. + + Needs to have your AoC cookie stored in the '" <> aoc_cookie_name <> "' environment variable"), + ) use _, args, flags <- glint.command() use days <- result.map(parse.days(args)) let days = util.deduplicate_sort(days) let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) let assert Ok(add_parse) = parse_flag(flags) let assert Ok(create_example_file) = example_flag(flags) + let assert Ok(fetch_input) = fetch_flag(flags) cmd.exec( days, cmd.Endless, - fn(day) { do(Context(year:, day:, add_parse:, create_example_file:)) }, + fn(day) { + do(Context(year:, day:, add_parse:, create_example_file:, fetch_input:)) + }, collect_async(year, _), ) } From 061b548556d807f2fa02cec5124f217acd6c07da Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Fri, 6 Dec 2024 17:37:20 +0100 Subject: [PATCH 2/9] get ready for v2.1.0 --- .mise.toml | 2 - README.md | 41 ++++++++++------ gleam.toml | 2 +- manifest.toml | 6 +-- src/gladvent/internal/cmd/new.gleam | 74 +++++++++++------------------ 5 files changed, 59 insertions(+), 66 deletions(-) delete mode 100644 .mise.toml diff --git a/.mise.toml b/.mise.toml deleted file mode 100644 index 06a18f7..0000000 --- a/.mise.toml +++ /dev/null @@ -1,2 +0,0 @@ -[tools] -gleam = "latest" diff --git a/README.md b/README.md index 413f77f..c31b466 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,13 @@ _Note:_ Part 1: error: todo - unimplemented in module aoc_2024/day_1 in function pt_1 at line 2 ``` +## Fetching problem inputs + +When stubbing out a new day's solution with the `new` command, you can use the `--fetch` flag to tell gladvent to fetch your problem input from the advent of code website. + +Some things to note: +- The `AOC_COOKIE` environment variable must be set with your advent of code session cookie. +- Gladvent will only attempt to fetch your input if the input file for the day being requested does not exist. This is to prevent accidental and redundant calls to the advent of code website, there should be no reason to fetch input data for the same day more than once. ## Reusable parse funtions @@ -110,17 +117,18 @@ Gladvent makes it easy for you to define expected outputs in your `gleam.toml` f Defining expectations is as simple as adding sections to your `gleam.toml` in the following format: ```toml -[gladvent..] -pt_1 = -pt_2 = +[gladvent.] +1 = { pt_1 = , pt_2 = } +2 = { pt_1 = , pt_2 = } +3 = { pt_1 = , pt_2 = } +... ``` For example, to set the expectations for Dec 1st 2024 (2024 day 1) you would add something like: ```toml -[gladvent.2024.1] -pt_1 = 1 -pt_2 = 2 +[gladvent.2024] +1 = { pt_1 = 1, pt_2 = 2 } ``` When running, gladvent will detect whether a specific day has it's expectations set and if so will print out the result for you. @@ -145,16 +153,21 @@ _Note_: gladvent will not compare your solution output against the expectations ### Why did you make this? -It seemed fun, I like small command line utilities and I wanted a way to get advent of code done in gleam without having the additional overhead of lots of copy-pasting and connecting things to get it to run - -### Why does this not download the input from the advent of code website? - -A few reasons: - -1. I wanted to keep this utility as simple as possible to start with -2. I like the advent of code website and I felt like it was a shame to circumvent visiting it, especially since you should access it to read the daily challenge. On top of that, I would like to avoid spamming the `advent of code` api if possible. +It seemed fun, I like small command line utilities and I wanted a way to get advent of code done in gleam without having the overhead of lots of copy-pasting and connecting things to get it to run. ### Why run as a command line utility and not just use unit tests? I thought a lot about that and I just prefer the overall interactivity of a CLI better, as well as allowing for endless runs or runs with configurable timeouts. Having it run as part of `eunit` doesnt provide as much flexibility as I would like. Other testing frameworks have been popping up but I leave the decision to use them up to you! + +### Why did you change your mind on fetching inputs? + +I started to reflect a bit after gladvent's users kept asking for the feature... + +While my initial rationale was twofold: +1. To encourage people to use the advent of code website, and I felt like fetching inputs somehow took away from that. +2. To minimise the risk that people would use a tool I made to spam the advent of code website with requests. + +Fetching inputs in a smart way (only ever if your input file does not already exist, so you should only need to do it once per day) still requires users to visit the advent of code website for the following (things gladvent will never do): +- fetching the description of the daily problems +- submitting solutions diff --git a/gleam.toml b/gleam.toml index fac81ef..9c91ea9 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "gladvent" -version = "2.0.2" +version = "2.1.0" repository = { type = "github", user = "TanklesXL", repo = "gladvent" } description = "An Advent Of Code runner for gleam" licences = ["Apache-2.0"] diff --git a/manifest.toml b/manifest.toml index 64aee65..b33f683 100644 --- a/manifest.toml +++ b/manifest.toml @@ -8,13 +8,13 @@ packages = [ { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" }, { name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" }, { name = "gleam_community_colour", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "386CB9B01B33371538672EEA8A6375A0A0ADEF41F17C86DDCB81C92AD00DA610" }, - { name = "gleam_erlang", version = "0.30.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "760618870AE4A497B10C73548E6E44F43B76292A54F0207B3771CBB599C675B4" }, + { name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" }, { name = "gleam_http", version = "3.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "A9EE0722106FCCAB8AD3BF9D0A3EFF92BFE8561D59B83BAE96EB0BE1938D4E0F" }, { name = "gleam_httpc", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "76FEEC99473E568EBA34336A37CF3D54629ACE77712950DC9BB097B5FD664664" }, { name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" }, { name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" }, { name = "gleam_package_interface", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "CF3BFC5D0997750D9550D8D73A90F4B8D71C6C081B20ED4E70FFBE1E99AFC3C2" }, - { name = "gleam_stdlib", version = "0.43.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "69EF22E78FDCA9097CBE7DF91C05B2A8B5436826D9F66680D879182C0860A747" }, + { name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" }, { name = "glearray", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "B99767A9BC63EF9CC8809F66C7276042E5EFEACAA5B25188B552D3691B91AC6D" }, { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, { name = "glint", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "5F6720081150AED8023131B0F3A35F9B0D6426A96CE02BEC52AD7018DF70566A" }, @@ -23,7 +23,7 @@ packages = [ { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, { name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" }, { name = "snag", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "08E9EB87C413457DB1DD66CD704C6878DACC9C93B418600F63873D0CD224E756" }, - { name = "spinner", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "9EE43AA33BE2DA5731B8F3F170AAB59AF1A815AFA5BF615F12C1B91F3B03F157" }, + { name = "spinner", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "B824C4CFDA6AC912D14365BF365F2A52C4DA63EF2D768D2A1C46D9BF7AF669E7" }, { name = "tom", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "228E667239504B57AD05EC3C332C930391592F6C974D0EFECF32FFD0F3629A27" }, ] diff --git a/src/gladvent/internal/cmd/new.gleam b/src/gladvent/internal/cmd/new.gleam index c4eb99a..c839b75 100644 --- a/src/gladvent/internal/cmd/new.gleam +++ b/src/gladvent/internal/cmd/new.gleam @@ -4,6 +4,7 @@ import gladvent/internal/cmd import gladvent/internal/input import gladvent/internal/parse.{type Day, pad} import gladvent/internal/util +import gleam/bool import gleam/http import gleam/http/request import gleam/http/response @@ -34,7 +35,7 @@ fn create_src_file(ctx: Context) -> fn() -> Result(String, Err) { use _ <- result.try( simplifile.create_file(gleam_src_path) - |> result.map_error(handle_file_open_failure(_, gleam_src_path)), + |> result.map_error(FailedToCreateFile(gleam_src_path, _)), ) let file_data = case ctx.add_parse { @@ -43,7 +44,7 @@ fn create_src_file(ctx: Context) -> fn() -> Result(String, Err) { } simplifile.write(gleam_src_path, file_data) - |> result.map_error(handle_file_open_failure(_, gleam_src_path)) + |> result.map_error(FailedToWriteToFile(gleam_src_path, _)) |> result.replace(gleam_src_path) } } @@ -54,32 +55,26 @@ fn create_input_file( ) -> fn() -> Result(String, Err) { fn() { let input_path = input.get_file_path(ctx.year, ctx.day, kind) - case kind { - input.Puzzle if ctx.fetch_input -> { - case simplifile.file_info(input_path) { - Error(_) -> { - use content <- result.try(download_input(ctx)) - simplifile.write(input_path, content) - |> result.map_error(FailedToWriteToFile(_)) - } - _ -> Error(FileAlreadyExists(input_path)) - } - } - _ -> { - simplifile.create_file(input_path) - |> result.map_error(handle_file_open_failure(_, input_path)) - } - } + use Nil <- result.try( + simplifile.create_file(input_path) + |> result.map_error(FailedToCreateFile(input_path, _)), + ) + use <- bool.guard( + when: kind == input.Example || !ctx.fetch_input, + return: Ok(input_path), + ) + use content <- result.try(download_input(ctx)) + simplifile.write(input_path, content) + |> result.map_error(FailedToWriteToFile(input_path, _)) |> result.replace(input_path) } } type Err { CookieNotDefined - FailedToCreateDir(String) - FailedToCreateFile(String) - FailedToWriteToFile(simplifile.FileError) - FileAlreadyExists(String) + FailedToCreateDir(String, simplifile.FileError) + FailedToCreateFile(String, simplifile.FileError) + FailedToWriteToFile(String, simplifile.FileError) HttpError(httpc.HttpError) UnexpectedHttpResponse(response.Response(String)) } @@ -88,11 +83,12 @@ fn err_to_string(e: Err) -> String { case e { CookieNotDefined -> "'" <> aoc_cookie_name <> "' environment variable not defined" - FailedToCreateDir(d) -> "failed to create dir: " <> d - FailedToCreateFile(f) -> "failed to create file: " <> f - FailedToWriteToFile(e) -> - "failed to write to file:" <> simplifile.describe_error(e) - FileAlreadyExists(f) -> "file already exists: " <> f + FailedToCreateDir(d, e) -> + "failed to create dir '" <> d <> "': " <> simplifile.describe_error(e) + FailedToCreateFile(f, e) -> + "failed to create file '" <> f <> "': " <> simplifile.describe_error(e) + FailedToWriteToFile(f, e) -> + "failed to write to file '" <> f <> "': " <> simplifile.describe_error(e) HttpError(e) -> "HTTP error while fetching input file: " <> string.inspect(e) UnexpectedHttpResponse(r) -> @@ -121,28 +117,14 @@ fn handle_dir_open_res( case res { Ok(_) -> Ok(filename) Error(simplifile.Eexist) -> Ok("") - _ -> - filename - |> FailedToCreateDir - |> Error - } -} - -fn handle_file_open_failure( - reason: simplifile.FileError, - filename: String, -) -> Err { - case reason { - simplifile.Eexist -> FileAlreadyExists(filename) - _ -> FailedToCreateFile(filename) + Error(e) -> Error(FailedToCreateDir(filename, e)) } } fn get_cookie_value() -> Result(String, Err) { - case envoy.get(aoc_cookie_name) { - Ok(cookie) -> Ok(cookie) - _ -> Error(CookieNotDefined) - } + aoc_cookie_name + |> envoy.get() + |> result.replace_error(CookieNotDefined) } fn download_input(ctx: Context) -> Result(String, Err) { @@ -161,7 +143,7 @@ fn download_input(ctx: Context) -> Result(String, Err) { |> request.set_cookie("session", cookie) |> request.set_header("user-agent", "github.com/TanklesXL/gladvent") |> httpc.send() - |> result.map_error(HttpError(_)), + |> result.map_error(HttpError), ) case resp.status { 200 -> Ok(resp.body) From 333f4ce2fb66fdda51cdefcac3f4e9f391a9b2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andris=20Horv=C3=A1th?= <59876688+horvathandris@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:14:44 +0000 Subject: [PATCH 3/9] Measure solution execution time with `--timed` flag (#23) * feat: add timed flag to measure solution time * rename time to execution_time * feat: always measure exec time and only print when flag enabled * feat: show time measurement in different units * refactor: use /. operator * test: format_float unit test --- src/gladvent.gleam | 1 + src/gladvent/internal/cmd/run.gleam | 73 +++++++++++++++++++++++------ src/gladvent/internal/util.gleam | 17 +++++++ test/util_test.gleam | 17 +++++++ 4 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 test/util_test.gleam diff --git a/src/gladvent.gleam b/src/gladvent.gleam index e3101da..565b78f 100644 --- a/src/gladvent.gleam +++ b/src/gladvent.gleam @@ -27,6 +27,7 @@ pub fn run() { |> glint.add(at: ["new"], do: new.new_command()) |> glint.group_flag(at: ["run"], of: run.timeout_flag()) |> glint.group_flag(at: ["run"], of: run.allow_crash_flag()) + |> glint.group_flag(at: ["run"], of: run.timed_flag()) |> glint.add(at: ["run"], do: run.run_command()) |> glint.add(at: ["run", "all"], do: run.run_all_command()) diff --git a/src/gladvent/internal/cmd/run.gleam b/src/gladvent/internal/cmd/run.gleam index 8a5d806..2b68114 100644 --- a/src/gladvent/internal/cmd/run.gleam +++ b/src/gladvent/internal/cmd/run.gleam @@ -43,7 +43,11 @@ type SolveErr { } type SolveResult = - gleam.Result(Dynamic, SolveErr) + gleam.Result(Solution, SolveErr) + +type Solution { + Solution(value: Dynamic, execution_time: Int) +} fn run_err_to_snag(err: RunErr) -> Snag { case err { @@ -104,7 +108,7 @@ fn do( case allow_crash { True -> { let input = parse(input) - Ok(#(Ok(pt_1(input)), Ok(pt_2(input)))) + Ok(#(Ok(solve(pt_1, input)), Ok(solve(pt_2, input)))) } False -> { use input <- result.try( @@ -114,11 +118,11 @@ fn do( |> result.map_error(FailedToParseInput), ) let pt_1 = - fn() { pt_1(input) } + fn() { solve(pt_1, input) } |> erlang.rescue |> result.map_error(crash_to_solve_err) let pt_2 = - fn() { pt_2(input) } + fn() { solve(pt_2, input) } |> erlang.rescue |> result.map_error(crash_to_solve_err) Ok(#(pt_1, pt_2)) @@ -126,6 +130,11 @@ fn do( } } +fn solve(solver: fn(a) -> Dynamic, input: a) -> Solution { + let #(execution_time, value) = util.timed(fn() { solver(input) }) + Solution(value, execution_time) +} + fn crash_to_dyn(err: erlang.Crash) -> dynamic.Dynamic { case err { erlang.Errored(dyn) | erlang.Exited(dyn) | erlang.Thrown(dyn) -> dyn @@ -218,17 +227,20 @@ fn solve_err_to_string(solve_err: SolveErr) -> String { fn solve_res_to_string( res: SolveResult, expectation: option.Option(Expectation), + timed: Bool, ) -> String { result.unwrap_both({ - use res <- result.map(res |> result.map_error(solve_err_to_string)) + use solution <- result.map(res |> result.map_error(solve_err_to_string)) option.lazy_unwrap( { use expect <- option.map(expectation) case expect { ExpectInt(expect) -> { - case dynamic.int(res) { + case dynamic.int(solution.value) { Ok(i) if expect == i -> - "✅ met expected value: " <> int.to_string(i) + "✅ met expected value: " + <> int.to_string(i) + <> exec_time_suffix(solution, timed) Ok(i) -> "❌ unmet expectation: expected " <> int.to_string(expect) @@ -242,8 +254,11 @@ fn solve_res_to_string( } } ExpectString(expect) -> { - case dynamic.string(res) { - Ok(s) if expect == s -> "✅ met expected value: " <> s + case dynamic.string(solution.value) { + Ok(s) if expect == s -> + "✅ met expected value: " + <> s + <> exec_time_suffix(solution, timed) Ok(s) -> "❌ unmet expectation: expected " <> expect <> ", got " <> s Error(_) -> @@ -255,17 +270,36 @@ fn solve_res_to_string( } } }, - or: fn() { string.inspect(res) }, + or: fn() { + string.inspect(solution.value) <> exec_time_suffix(solution, timed) + }, ) }) } +fn exec_time_suffix(solution: Solution, timed: Bool) -> String { + case timed { + True -> " (in " <> format_execution_time(solution.execution_time) <> ")" + False -> "" + } +} + +fn format_execution_time(execution_time: Int) -> String { + let #(divisor, precision, unit) = case execution_time { + t if t > 1_000_000 -> #(1_000_000.0, 3, " s") + t if t > 1000 -> #(1000.0, 3, " ms") + _ -> #(1.0, 0, " µs") + } + util.format_float(int.to_float(execution_time) /. divisor, precision) <> unit +} + import gleam/pair fn collect_async( year: Int, x: #(Day, AsyncResult), expectations: Option(dict.Dict(String, tom.Toml)), + timed: Bool, ) -> String { let expect = fn(key) { use ex <- option.then(expectations) @@ -276,7 +310,7 @@ fn collect_async( x |> pair.map_second(result.map_error(_, Other)) |> pair.map_second(result.flatten) - |> collect(year, _, expect("pt_1"), expect("pt_2")) + |> collect(year, _, expect("pt_1"), expect("pt_2"), timed) } fn collect( @@ -284,6 +318,7 @@ fn collect( x: #(Day, RunResult), expect_pt_1: Option(Expectation), expect_pt_2: Option(Expectation), + timed: Bool, ) -> String { let day = int.to_string(x.0) case x.1 { @@ -294,10 +329,10 @@ fn collect( <> day <> ":\n" <> " Part 1: " - <> solve_res_to_string(res_1, expect_pt_1) + <> solve_res_to_string(res_1, expect_pt_1, timed) <> "\n" <> " Part 2: " - <> solve_res_to_string(res_2, expect_pt_2) + <> solve_res_to_string(res_2, expect_pt_2, timed) Error(err) -> err @@ -327,6 +362,12 @@ pub fn allow_crash_flag() { |> glint.flag_help("Don't catch exceptions thrown by runners") } +pub fn timed_flag() { + glint.bool_flag("timed") + |> glint.flag_default(False) + |> glint.flag_help("Display solution execution time") +} + pub fn run_command() -> glint.Command(Result(List(String))) { use <- glint.command_help("Run the specified days") use <- glint.unnamed_args(glint.MinArgs(1)) @@ -342,6 +383,7 @@ pub fn run_command() -> glint.Command(Result(List(String))) { let days = util.deduplicate_sort(days) let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) let assert Ok(allow_crash) = glint.get_flag(flags, allow_crash_flag()) + let assert Ok(timed) = glint.get_flag(flags, timed_flag()) let assert Ok(input_kind) = case example_flag(flags) { Error(a) -> Error(a) Ok(True) -> Ok(input.Example) @@ -383,7 +425,7 @@ pub fn run_command() -> glint.Command(Result(List(String))) { |> cmd.exec( timing, do(year, _, package, allow_crash, input_kind), - collect_async(year, _, expectations), + collect_async(year, _, expectations, timed), ) } @@ -394,6 +436,7 @@ pub fn run_all_command() -> glint.Command(Result(List(String))) { let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) let assert Ok(allow_crash) = glint.get_flag(flags, allow_crash_flag()) + let assert Ok(timed) = glint.get_flag(flags, timed_flag()) let spinner = spinner.new("running all days in " <> int.to_string(year)) @@ -433,7 +476,7 @@ pub fn run_all_command() -> glint.Command(Result(List(String))) { |> cmd.exec( timing, do(year, _, package, allow_crash, input.Puzzle), - collect_async(year, _, expectations), + collect_async(year, _, expectations, timed), ) } diff --git a/src/gladvent/internal/util.gleam b/src/gladvent/internal/util.gleam index 463c5b2..5a6c9b1 100644 --- a/src/gladvent/internal/util.gleam +++ b/src/gladvent/internal/util.gleam @@ -1,3 +1,5 @@ +import gleam/erlang/charlist.{type Charlist} +import gleam/float import gleam/int import gleam/list import gleam/set @@ -11,3 +13,18 @@ pub fn defer(do later: fn() -> _, after now: fn() -> a) -> a { pub fn deduplicate_sort(l: List(Int)) -> List(Int) { l |> set.from_list |> set.to_list |> list.sort(int.compare) } + +@external(erlang, "timer", "tc") +pub fn timed(fun: fn() -> a) -> #(Int, a) + +pub fn format_float(input: Float, precision: Int) -> String { + case precision { + p if p >= 1 -> + do_format("~." <> int.to_string(precision) <> "f", [input]) + |> charlist.to_string + _ -> float.truncate(input) |> int.to_string + } +} + +@external(erlang, "io_lib", "format") +fn do_format(format: String, data: List(a)) -> Charlist diff --git a/test/util_test.gleam b/test/util_test.gleam new file mode 100644 index 0000000..f088c05 --- /dev/null +++ b/test/util_test.gleam @@ -0,0 +1,17 @@ +import gladvent/internal/util +import gleam/list +import gleeunit/should + +pub fn format_float_test() { + use #(float, precision, expected) <- list.each([ + #(123.123, 4, "123.1230"), + #(123.123, 2, "123.12"), + #(123.123, 0, "123"), + #(123.123, -3, "123"), + #(-123.123, 2, "-123.12"), + #(0.0, 0, "0"), + ]) + + util.format_float(float, precision) + |> should.equal(expected) +} From b0483ff338c96085235f0f717fa454b1dd1d0e40 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Wed, 18 Dec 2024 18:32:10 +0100 Subject: [PATCH 4/9] don't print the names of created directories --- gleam.toml | 2 +- src/gladvent/internal/cmd/new.gleam | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/gleam.toml b/gleam.toml index 9c91ea9..d1fb108 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "gladvent" -version = "2.1.0" +version = "2.2.0" repository = { type = "github", user = "TanklesXL", repo = "gladvent" } description = "An Advent Of Code runner for gleam" licences = ["Apache-2.0"] diff --git a/src/gladvent/internal/cmd/new.gleam b/src/gladvent/internal/cmd/new.gleam index c839b75..8e2a53c 100644 --- a/src/gladvent/internal/cmd/new.gleam +++ b/src/gladvent/internal/cmd/new.gleam @@ -29,7 +29,7 @@ type Context { ) } -fn create_src_file(ctx: Context) -> fn() -> Result(String, Err) { +fn create_src_file(ctx: Context) -> fn() -> Result(Success, Err) { fn() { let gleam_src_path = gleam_src_path(ctx.year, ctx.day) @@ -45,14 +45,14 @@ fn create_src_file(ctx: Context) -> fn() -> Result(String, Err) { simplifile.write(gleam_src_path, file_data) |> result.map_error(FailedToWriteToFile(gleam_src_path, _)) - |> result.replace(gleam_src_path) + |> result.replace(File(gleam_src_path)) } } fn create_input_file( ctx: Context, kind: input.Kind, -) -> fn() -> Result(String, Err) { +) -> fn() -> Result(Success, Err) { fn() { let input_path = input.get_file_path(ctx.year, ctx.day, kind) use Nil <- result.try( @@ -61,15 +61,20 @@ fn create_input_file( ) use <- bool.guard( when: kind == input.Example || !ctx.fetch_input, - return: Ok(input_path), + return: Ok(File(input_path)), ) use content <- result.try(download_input(ctx)) simplifile.write(input_path, content) |> result.map_error(FailedToWriteToFile(input_path, _)) - |> result.replace(input_path) + |> result.replace(File(input_path)) } } +type Success { + Dir(String) + File(String) +} + type Err { CookieNotDefined FailedToCreateDir(String, simplifile.FileError) @@ -103,10 +108,11 @@ fn gleam_src_path(year: Int, day: Day) -> String { filepath.join(cmd.src_dir(year), "day_" <> pad(day) <> ".gleam") } -fn create_dir(dir: String) -> fn() -> Result(String, Err) { +fn create_dir(dir: String) -> fn() -> Result(Success, Err) { fn() { simplifile.create_directory_all(dir) |> handle_dir_open_res(dir) + |> result.map(Dir) } } @@ -183,8 +189,8 @@ fn do(ctx: Context) -> String { { use acc, f <- list.fold(seq, #("", "")) case f() { - Ok("") -> acc - Ok(o) -> pair.map_first(acc, newline_tab(_, o)) + Ok(Dir(_)) -> acc + Ok(File(o)) -> pair.map_first(acc, newline_tab(_, o)) Error(err) -> pair.map_second(acc, newline_tab(_, err_to_string(err))) } } From 7db6ecbca14ddeabd3b5c23434c69a6896997268 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Wed, 18 Dec 2024 18:34:20 +0100 Subject: [PATCH 5/9] add more desc to timed flag --- README.md | 15 +++++++++++++++ src/gladvent/internal/cmd/run.gleam | 8 ++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c31b466..38dca81 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,21 @@ Example input files will be generated at and run from `input//.exampl _Note_: gladvent will not compare your solution output against the expectations defined in `gleam.toml` when running in example mode. + +## Display execution time + +Use the `--timed` flag when running your solutions to display how long each part took to solve. + +For example: + +``` +Ran 2024 day 1: + Part 1: ✅ met expected value: 1579939 (in 885 µs) + Part 2: ✅ met expected value: 20351745 (in 605 µs) +``` + +Note: as the output of the `parse` function is reused for both parts, its execution time is not included in the displayed time. + ## FAQ ### Why did you make this? diff --git a/src/gladvent/internal/cmd/run.gleam b/src/gladvent/internal/cmd/run.gleam index 2b68114..73197b3 100644 --- a/src/gladvent/internal/cmd/run.gleam +++ b/src/gladvent/internal/cmd/run.gleam @@ -359,13 +359,17 @@ pub fn timeout_flag() { pub fn allow_crash_flag() { glint.bool_flag("allow-crash") |> glint.flag_default(False) - |> glint.flag_help("Don't catch exceptions thrown by runners") + |> glint.flag_help("Don't catch exceptions thrown by runners.") } pub fn timed_flag() { glint.bool_flag("timed") |> glint.flag_default(False) - |> glint.flag_help("Display solution execution time") + |> glint.flag_help( + "Display solution execution time. + +The time displayed does not include any work done in a 'parse' function.", + ) } pub fn run_command() -> glint.Command(Result(List(String))) { From c3c9a5d07e3186788c2c04f3fab21fa12f7796c0 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Thu, 13 Mar 2025 02:20:19 +0100 Subject: [PATCH 6/9] remove package-interface bug workaround, require gleam >=1.9 (#26) * remove package-interface bug workaround, require gleam >=1.9 * move ffi file * bump parallel_map dep --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- gleam.toml | 4 +- manifest.toml | 36 ++++++------ src/gladvent/internal/runners.gleam | 55 +------------------ .../internal/runners_ffi.erl} | 2 +- 6 files changed, 26 insertions(+), 75 deletions(-) rename src/{gladvent_ffi.erl => gladvent/internal/runners_ffi.erl} (89%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d0de3f6..eeab7ab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: uses: TanklesXL/gleam_actions/.github/workflows/release.yaml@main secrets: inherit with: - gleam_version: 1.6.1 + gleam_version: 1.9.1 erlang_version: 26 test_erlang: true test_node: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87f9966..47b7747 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,6 @@ jobs: test: uses: TanklesXL/gleam_actions/.github/workflows/test.yaml@main with: - gleam_version: 1.6.1 + gleam_version: 1.9.1 test_node: false test_erlang: true diff --git a/gleam.toml b/gleam.toml index d1fb108..02b0e87 100644 --- a/gleam.toml +++ b/gleam.toml @@ -4,7 +4,7 @@ repository = { type = "github", user = "TanklesXL", repo = "gladvent" } description = "An Advent Of Code runner for gleam" licences = ["Apache-2.0"] internal_modules = ["gladvent/internal/*"] -gleam = ">=1.4.0 and < 2.0.0" +gleam = ">=1.9.0 and < 2.0.0" [dependencies] glint = ">=1.0.0 and < 2.0.0" @@ -17,7 +17,7 @@ gleam_stdlib = "~> 0.39 or ~> 1.0" gleam_otp = "~> 0.4 or ~> 1.0" gleam_erlang = "~> 0.7 or ~> 1.0" snag = "~> 1.0" -parallel_map = ">= 2.0.0 and < 3.0.0" +parallel_map = ">= 3.0.0 and < 4.0.0" filepath = ">= 1.0.0 and < 2.0.0" tom = ">= 1.0.0 and < 2.0.0" decode = ">= 0.2.0 and < 1.0.0" diff --git a/manifest.toml b/manifest.toml index b33f683..7aadb38 100644 --- a/manifest.toml +++ b/manifest.toml @@ -6,25 +6,27 @@ packages = [ { name = "decode", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "05E14DC95A550BA51B8774485B04894B87A898C588B9B1C920104B110AED218B" }, { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" }, - { name = "gleam_community_ansi", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "4CD513FC62523053E62ED7BAC2F36136EC17D6A8942728250A9A00A15E340E4B" }, - { name = "gleam_community_colour", version = "1.4.1", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "386CB9B01B33371538672EEA8A6375A0A0ADEF41F17C86DDCB81C92AD00DA610" }, - { name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" }, - { name = "gleam_http", version = "3.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "A9EE0722106FCCAB8AD3BF9D0A3EFF92BFE8561D59B83BAE96EB0BE1938D4E0F" }, - { name = "gleam_httpc", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "76FEEC99473E568EBA34336A37CF3D54629ACE77712950DC9BB097B5FD664664" }, - { name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" }, - { name = "gleam_otp", version = "0.14.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "5A8CE8DBD01C29403390A7BD5C0A63D26F865C83173CF9708E6E827E53159C65" }, - { name = "gleam_package_interface", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "CF3BFC5D0997750D9550D8D73A90F4B8D71C6C081B20ED4E70FFBE1E99AFC3C2" }, - { name = "gleam_stdlib", version = "0.45.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "206FCE1A76974AECFC55AEBCD0217D59EDE4E408C016E2CFCCC8FF51278F186E" }, - { name = "glearray", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "B99767A9BC63EF9CC8809F66C7276042E5EFEACAA5B25188B552D3691B91AC6D" }, - { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, - { name = "glint", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "5F6720081150AED8023131B0F3A35F9B0D6426A96CE02BEC52AD7018DF70566A" }, - { name = "parallel_map", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "parallel_map", source = "hex", outer_checksum = "DE2BA9878728EF9EE34BE83FEDC7A18A1ABE4B2AC1E79C710E3E5D95F5E73404" }, + { name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" }, + { name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" }, + { name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" }, + { name = "gleam_http", version = "3.7.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8A70D2F70BB7CFEB5DF048A2183FFBA91AF6D4CF5798504841744A16999E33D2" }, + { name = "gleam_httpc", version = "4.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "1A38507AF26CACA145248733688703EADCB734EA971D4E34FB97B7613DECF132" }, + { name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" }, + { name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" }, + { name = "gleam_package_interface", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "80D8B1842ACC6CF50E53FF1B220FF57E2B3A60FAF19DD885EC683CDED64C2C52" }, + { name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" }, + { name = "gleam_stdlib", version = "0.57.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86EFACDF6460B8681E82752C5490F9630EC0F138F88A037DDCB241799AA8811F" }, + { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, + { name = "glearray", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "2CDF973B9ECE4A1AB8FBFB719AA37D9F3F1FF947B260C1B21ED5B608B52BC111" }, + { name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" }, + { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" }, + { name = "parallel_map", version = "3.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "gleam_yielder"], otp_app = "parallel_map", source = "hex", outer_checksum = "6E8A2E098AF56B9D429E77F2C35A494D8C4DDC659D581C01A51477D96BD9AE06" }, { name = "repeatedly", version = "2.1.2", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "93AE1938DDE0DC0F7034F32C1BF0D4E89ACEBA82198A1FE21F604E849DA5F589" }, { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, { name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" }, - { name = "snag", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "08E9EB87C413457DB1DD66CD704C6878DACC9C93B418600F63873D0CD224E756" }, - { name = "spinner", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "B824C4CFDA6AC912D14365BF365F2A52C4DA63EF2D768D2A1C46D9BF7AF669E7" }, - { name = "tom", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "228E667239504B57AD05EC3C332C930391592F6C974D0EFECF32FFD0F3629A27" }, + { name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" }, + { name = "spinner", version = "1.3.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "21BDE7FF9D7D9ACBB4086C0D5C86F0A90CE6B0F3CB593B41D03384AE7724B5B4" }, + { name = "tom", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0910EE688A713994515ACAF1F486A4F05752E585B9E3209D8F35A85B234C2719" }, ] [requirements] @@ -41,7 +43,7 @@ gleam_package_interface = { version = "~> 1.0" } gleam_stdlib = { version = "~> 0.39 or ~> 1.0" } gleeunit = { version = ">= 1.2.0 and < 2.0.0" } glint = { version = ">=1.0.0 and < 2.0.0" } -parallel_map = { version = ">= 2.0.0 and < 3.0.0" } +parallel_map = { version = ">= 3.0.0 and < 4.0.0" } shellout = { version = "~> 1.6" } simplifile = { version = "~> 2.0" } snag = { version = "~> 1.0" } diff --git a/src/gladvent/internal/runners.gleam b/src/gladvent/internal/runners.gleam index 8354a81..285e0c9 100644 --- a/src/gladvent/internal/runners.gleam +++ b/src/gladvent/internal/runners.gleam @@ -18,7 +18,6 @@ import shellout import simplifile import snag.{type Result} import spinner -import tom pub type PartRunner = fn(Dynamic) -> Dynamic @@ -30,12 +29,8 @@ const package_interface_path = "build/.gladvent/pkg.json" type PkgInterfaceErr { FailedToGleamBuild(String) - FailedToReadGleamToml(simplifile.FileError) - FailedToDecodeGleamToml(tom.ParseError) - FailedToGetPackageName(tom.GetError) FailedToGeneratePackageInterface(String) FailedToReadPackageInterface(simplifile.FileError) - FailedToClearBuildCache(simplifile.FileError) FailedToDecodePackageInterface(json.DecodeError) } @@ -44,18 +39,6 @@ fn package_interface_error_to_snag(e: PkgInterfaceErr) -> snag.Snag { FailedToGleamBuild(s) -> snag.new(s) |> snag.layer("failed to build gleam project") - FailedToDecodeGleamToml(e) -> - snag.new(string.inspect(e)) - |> snag.layer("failed to decode gleam.toml") - FailedToGetPackageName(e) -> - snag.new(string.inspect(e)) - |> snag.layer("failed to get package name") - FailedToReadGleamToml(e) -> - snag.new(string.inspect(e)) - |> snag.layer("failed to read gleam.toml") - FailedToClearBuildCache(e) -> - snag.new(string.inspect(e)) - |> snag.layer("failed to clear build cache") FailedToGeneratePackageInterface(s) -> snag.new(s) |> snag.layer("failed to generate " <> package_interface_path) @@ -78,40 +61,6 @@ pub fn pkg_interface() -> Result(package_interface.Package) { let root = cmd.root() - spinner.set_text(spinner, "reading gleam.toml") - use gleam_toml <- result.try( - simplifile.read(filepath.join(root, "gleam.toml")) - |> result.map_error(FailedToReadGleamToml), - ) - - spinner.set_text(spinner, "decoding gleam.toml") - use toml <- result.try( - tom.parse(gleam_toml) - |> result.map_error(FailedToDecodeGleamToml), - ) - - spinner.set_text(spinner, "fetching project name") - use name <- result.try( - tom.get_string(toml, ["name"]) - |> result.map_error(FailedToGetPackageName), - ) - - spinner.set_text(spinner, "clearing build cache") - use _ <- result.try( - ["build/prod/erlang", "build/dev/erlang"] - |> list.try_map(fn(cache) { - filepath.join(root, cache) - |> filepath.join(name) - |> simplifile.delete - }) - |> result.try_recover(fn(e) { - case e { - simplifile.Enoent -> Ok([]) - _ -> Error(FailedToClearBuildCache(e)) - } - }), - ) - spinner.set_text(spinner, "rebuilding project") use _ <- result.try( shellout.command("gleam", ["build"], root, []) @@ -274,7 +223,7 @@ fn to_erlang_module_name(name) { string.replace(name, "/", "@") } -@external(erlang, "gladvent_ffi", "function_arity_one") +@external(erlang, "runners_ffi", "function_arity_one") fn function_arity_one( module: atom.Atom, function: atom.Atom, @@ -284,7 +233,7 @@ fn parse_function(module: String) -> fn(String) -> Dynamic { do_parse_function(atom.create_from_string(to_erlang_module_name(module))) } -@external(erlang, "gladvent_ffi", "parse_function") +@external(erlang, "runners_ffi", "parse_function") fn do_parse_function(module: atom.Atom) -> fn(String) -> Dynamic const string = package_interface.Named( diff --git a/src/gladvent_ffi.erl b/src/gladvent/internal/runners_ffi.erl similarity index 89% rename from src/gladvent_ffi.erl rename to src/gladvent/internal/runners_ffi.erl index 90053f9..09d2fed 100644 --- a/src/gladvent_ffi.erl +++ b/src/gladvent/internal/runners_ffi.erl @@ -1,4 +1,4 @@ --module(gladvent_ffi). +-module(runners_ffi). -export([ function_arity_one/2, From 03326000af9d1a14e661e2e66d04a93cf9e636e6 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Thu, 12 Jun 2025 15:30:35 -0400 Subject: [PATCH 7/9] wip: upgrade to glint v2 --- gleam.toml | 37 +++--- manifest.toml | 72 ++++++----- mise.toml | 2 + src/gladvent.gleam | 54 +++------ src/gladvent/internal/cmd.gleam | 6 +- src/gladvent/internal/cmd/new.gleam | 48 ++++---- src/gladvent/internal/cmd/run.gleam | 180 +++++++++++----------------- src/gladvent/internal/runners.gleam | 2 +- test/parse_test.gleam | 13 +- test/util_test.gleam | 4 +- 10 files changed, 187 insertions(+), 231 deletions(-) create mode 100644 mise.toml diff --git a/gleam.toml b/gleam.toml index 02b0e87..d2771e7 100644 --- a/gleam.toml +++ b/gleam.toml @@ -4,27 +4,28 @@ repository = { type = "github", user = "TanklesXL", repo = "gladvent" } description = "An Advent Of Code runner for gleam" licences = ["Apache-2.0"] internal_modules = ["gladvent/internal/*"] -gleam = ">=1.9.0 and < 2.0.0" +gleam = ">=1.11.0 and < 2.0.0" [dependencies] -glint = ">=1.0.0 and < 2.0.0" -simplifile = "~> 2.0" -argv = "~> 1.0" -shellout = "~> 1.6" -gleam_package_interface = "~> 1.0" -spinner = "~> 1.1" -gleam_stdlib = "~> 0.39 or ~> 1.0" -gleam_otp = "~> 0.4 or ~> 1.0" -gleam_erlang = "~> 0.7 or ~> 1.0" -snag = "~> 1.0" -parallel_map = ">= 3.0.0 and < 4.0.0" -filepath = ">= 1.0.0 and < 2.0.0" -tom = ">= 1.0.0 and < 2.0.0" -decode = ">= 0.2.0 and < 1.0.0" -gleam_json = ">= 1.0.0 and < 3.0.0" -gleam_httpc = ">= 4.0.0 and < 5.0.0" -gleam_http = ">= 3.7.1 and < 4.0.0" +glint = {path="../glint"} envoy = ">= 1.0.2 and < 2.0.0" +simplifile = ">= 2.2.1 and < 3.0.0" +gleam_json = ">= 3.0.1 and < 4.0.0" +parallel_map = ">= 3.0.1 and < 4.0.0" +gleam_stdlib = ">= 0.60.0 and < 1.0.0" +gleam_otp = ">= 0.16.1 and < 1.0.0" +gleam_erlang = ">= 0.34.0 and < 1.0.0" +gleam_http = ">= 4.0.0 and < 5.0.0" +gleam_httpc = ">= 4.1.1 and < 5.0.0" +filepath = ">= 1.1.2 and < 2.0.0" +gleam_package_interface = ">= 3.0.1 and < 4.0.0" +shellout = ">= 1.7.0 and < 2.0.0" +spinner = ">= 1.3.1 and < 2.0.0" +tom = ">= 2.0.0 and < 3.0.0" +argv = ">= 1.0.2 and < 2.0.0" +snag = ">= 1.1.0 and < 2.0.0" +asset = ">= 1.2.0 and < 2.0.0" + [dev-dependencies] gleeunit = ">= 1.2.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index 7aadb38..b35f239 100644 --- a/manifest.toml +++ b/manifest.toml @@ -3,49 +3,55 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, - { name = "decode", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "05E14DC95A550BA51B8774485B04894B87A898C588B9B1C920104B110AED218B" }, + { name = "asset", version = "1.2.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "glance", "gleam_stdlib", "glexer", "simplifile"], otp_app = "asset", source = "hex", outer_checksum = "71B572581CE75CEA23F444EB56CD845DB64766FB5D52573DAE5F465D752526A5" }, + { name = "bigi", version = "3.2.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "bigi", source = "hex", outer_checksum = "5BE723D3F5C9BCD7C20C432FEDD9EF55AC8B357BD0592433E275483F3F14CB98" }, { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, - { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" }, + { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, + { name = "glance", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "FAA3DAC74AF71D47C67D88EB32CE629075169F878D148BB1FF225439BE30070A" }, { name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" }, - { name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" }, + { name = "gleam_community_colour", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "F0ACE69E3A47E913B03D3D0BB23A5563A91A4A7D20956916286068F4A9F817FE" }, + { name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" }, { name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" }, - { name = "gleam_http", version = "3.7.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8A70D2F70BB7CFEB5DF048A2183FFBA91AF6D4CF5798504841744A16999E33D2" }, - { name = "gleam_httpc", version = "4.1.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "1A38507AF26CACA145248733688703EADCB734EA971D4E34FB97B7613DECF132" }, - { name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" }, + { name = "gleam_http", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "0A62451FC85B98062E0907659D92E6A89F5F3C0FBE4AB8046C99936BF6F91DBC" }, + { name = "gleam_httpc", version = "4.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C670EBD46FC1472AD5F1F74F1D3938D1D0AC1C7531895ED1D4DDCB6F07279F43" }, + { name = "gleam_json", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "5BA154440B22D9800955B1AB854282FA37B97F30F409D76B0824D0A60C934188" }, { name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" }, - { name = "gleam_package_interface", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "80D8B1842ACC6CF50E53FF1B220FF57E2B3A60FAF19DD885EC683CDED64C2C52" }, - { name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" }, - { name = "gleam_stdlib", version = "0.57.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86EFACDF6460B8681E82752C5490F9630EC0F138F88A037DDCB241799AA8811F" }, + { name = "gleam_package_interface", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "8F2D19DE9876D9401BB0626260958A6B1580BB233489C32831FE74CE0ACAE8B4" }, + { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, + { name = "gleam_stdlib", version = "0.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" }, + { name = "gleam_time", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D71F1AFF7FEB534FF55E5DC58E534E9201BA75A444619788A2E4DEA4EBD87D16" }, { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" }, - { name = "glearray", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "2CDF973B9ECE4A1AB8FBFB719AA37D9F3F1FF947B260C1B21ED5B608B52BC111" }, - { name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" }, - { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" }, - { name = "parallel_map", version = "3.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "gleam_yielder"], otp_app = "parallel_map", source = "hex", outer_checksum = "6E8A2E098AF56B9D429E77F2C35A494D8C4DDC659D581C01A51477D96BD9AE06" }, + { name = "glearray", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "5E272F7CB278CC05A929C58DEB58F5D5AC6DB5B879A681E71138658D0061C38A" }, + { name = "gleeunit", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D33B7736CF0766ED3065F64A1EBB351E72B2E8DE39BAFC8ADA0E35E92A6A934F" }, + { name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" }, + { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_deque", "gleam_stdlib", "lenient_parse", "snag"], source = "local", path = "../glint" }, + { name = "lenient_parse", version = "3.0.0", build_tools = ["gleam"], requirements = ["bigi", "gleam_deque", "gleam_stdlib"], otp_app = "lenient_parse", source = "hex", outer_checksum = "E6C654A75E6EB17B559418C5216583D0B9E7D82018E0608A7FF1AFF328D9F474" }, + { name = "parallel_map", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib", "gleam_yielder"], otp_app = "parallel_map", source = "hex", outer_checksum = "E5A38C9294831F67DF8EAC17870FEA97FF0D8F891049E0CA634B30A1AFE37A8F" }, { name = "repeatedly", version = "2.1.2", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "93AE1938DDE0DC0F7034F32C1BF0D4E89ACEBA82198A1FE21F604E849DA5F589" }, - { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, - { name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" }, + { name = "shellout", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "1BDC03438FEB97A6AF3E396F4ABEB32BECF20DF2452EC9A8C0ACEB7BDDF70B14" }, + { name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" }, { name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" }, { name = "spinner", version = "1.3.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "21BDE7FF9D7D9ACBB4086C0D5C86F0A90CE6B0F3CB593B41D03384AE7724B5B4" }, - { name = "tom", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0910EE688A713994515ACAF1F486A4F05752E585B9E3209D8F35A85B234C2719" }, + { name = "tom", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "74D0C5A3761F7A7D06994755D4D5AD854122EF8E9F9F76A3E7547606D8C77091" }, ] [requirements] -argv = { version = "~> 1.0" } -decode = { version = ">= 0.2.0 and < 1.0.0" } +argv = { version = ">= 1.0.2 and < 2.0.0" } +asset = { version = ">= 1.2.0 and < 2.0.0" } envoy = { version = ">= 1.0.2 and < 2.0.0" } -filepath = { version = ">= 1.0.0 and < 2.0.0" } -gleam_erlang = { version = "~> 0.7 or ~> 1.0" } -gleam_http = { version = ">= 3.7.1 and < 4.0.0" } -gleam_httpc = { version = ">= 4.0.0 and < 5.0.0" } -gleam_json = { version = ">= 1.0.0 and < 3.0.0" } -gleam_otp = { version = "~> 0.4 or ~> 1.0" } -gleam_package_interface = { version = "~> 1.0" } -gleam_stdlib = { version = "~> 0.39 or ~> 1.0" } +filepath = { version = ">= 1.1.2 and < 2.0.0" } +gleam_erlang = { version = ">= 0.34.0 and < 1.0.0" } +gleam_http = { version = ">= 4.0.0 and < 5.0.0" } +gleam_httpc = { version = ">= 4.1.1 and < 5.0.0" } +gleam_json = { version = ">= 3.0.1 and < 4.0.0" } +gleam_otp = { version = ">= 0.16.1 and < 1.0.0" } +gleam_package_interface = { version = ">= 3.0.1 and < 4.0.0" } +gleam_stdlib = { version = ">= 0.60.0 and < 1.0.0" } gleeunit = { version = ">= 1.2.0 and < 2.0.0" } -glint = { version = ">=1.0.0 and < 2.0.0" } -parallel_map = { version = ">= 3.0.0 and < 4.0.0" } -shellout = { version = "~> 1.6" } -simplifile = { version = "~> 2.0" } -snag = { version = "~> 1.0" } -spinner = { version = "~> 1.1" } -tom = { version = ">= 1.0.0 and < 2.0.0" } +glint = { path = "../glint" } +parallel_map = { version = ">= 3.0.1 and < 4.0.0" } +shellout = { version = ">= 1.7.0 and < 2.0.0" } +simplifile = { version = ">= 2.2.1 and < 3.0.0" } +snag = { version = ">= 1.1.0 and < 2.0.0" } +spinner = { version = ">= 1.3.1 and < 2.0.0" } +tom = { version = ">= 2.0.0 and < 3.0.0" } diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..06a18f7 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +gleam = "latest" diff --git a/src/gladvent.gleam b/src/gladvent.gleam index 565b78f..799fe11 100644 --- a/src/gladvent.gleam +++ b/src/gladvent.gleam @@ -2,51 +2,35 @@ import argv import gladvent/internal/cmd import gladvent/internal/cmd/new import gladvent/internal/cmd/run -import gleam/io import gleam/string import glint -import snag +import glintio /// Add this function to your project's `main` function in order to run the gladvent CLI. /// /// This function gets its input from the command line arguments by using the `argv` library. /// pub fn run() { - let commands = - glint.new() - |> glint.path_help( - [], - "gladvent is an advent of code runner and generator for gleam. + glint.new() + |> glint.with_name("gladvent") + |> glint.with_version("2.3.0") + |> glint.path_help( + [], + "gladvent is an advent of code runner and generator for gleam. Please use either the 'run' or 'new' commands. ", - ) - |> glint.pretty_help(glint.default_pretty_help()) - |> glint.group_flag(at: [], of: cmd.year_flag()) - |> glint.add(at: ["new"], do: new.new_command()) - |> glint.group_flag(at: ["run"], of: run.timeout_flag()) - |> glint.group_flag(at: ["run"], of: run.allow_crash_flag()) - |> glint.group_flag(at: ["run"], of: run.timed_flag()) - |> glint.add(at: ["run"], do: run.run_command()) - |> glint.add(at: ["run", "all"], do: run.run_all_command()) - - use out <- glint.run_and_handle(commands, argv.load().arguments) - case out { - Ok(out) -> - out - |> string.join("\n\n") - |> io.println - Error(err) -> print_snag_and_halt(err) - } -} - -@external(erlang, "erlang", "halt") -fn exit(a: Int) -> Nil - -fn print_snag_and_halt(err: snag.Snag) -> Nil { - err - |> snag.pretty_print() - |> io.println() - exit(1) + ) + |> glint.with_default_header_style + |> glint.group_flag(at: [], of: cmd.year_flag()) + |> glint.add(at: ["new"], do: new.new_command()) + |> glint.group_flag(at: ["run"], of: run.timeout_flag()) + |> glint.group_flag(at: ["run"], of: run.allow_crash_flag()) + |> glint.group_flag(at: ["run"], of: run.timed_flag()) + |> glint.add(at: ["run"], do: run.run_command()) + |> glint.add(at: ["run", "all"], do: run.run_all_command()) + |> glint.run(argv.load().arguments) + |> glintio.print(string.join(_, "\n\n")) + |> glintio.exit } diff --git a/src/gladvent/internal/cmd.gleam b/src/gladvent/internal/cmd.gleam index f985e9a..3ef38ed 100644 --- a/src/gladvent/internal/cmd.gleam +++ b/src/gladvent/internal/cmd.gleam @@ -82,9 +82,9 @@ fn current_year() -> Int { } pub fn year_flag() { - use year <- glint.flag_constraint( - glint.int_flag("year") - |> glint.flag_default(current_year()), + use year <- glint.constraint( + glint.int("year") + |> glint.default(current_year()), ) case year < 2015 { True -> diff --git a/src/gladvent/internal/cmd/new.gleam b/src/gladvent/internal/cmd/new.gleam index 8e2a53c..f415aed 100644 --- a/src/gladvent/internal/cmd/new.gleam +++ b/src/gladvent/internal/cmd/new.gleam @@ -234,42 +234,44 @@ fn collect(year: Int, x: #(Day, String)) -> String { "initialized " <> year <> " day " <> day <> "\n" <> x.1 } -pub fn new_command() { +pub fn new_command() -> glint.Command(List(String), glint.ArgsSet) { use <- glint.command_help("Create .gleam and input files") - use <- glint.unnamed_args(glint.MinArgs(1)) + use <- glint.min_args("days", 1, "The days to create files for.") use parse_flag <- glint.flag( - glint.bool_flag("parse") - |> glint.flag_default(False) - |> glint.flag_help("Generate day runners with a parse function"), + glint.bool("parse") + |> glint.default(False) + |> glint.param_help("Generate day runners with a parse function"), ) use example_flag <- glint.flag( - glint.bool_flag("example") - |> glint.flag_default(False) - |> glint.flag_help( + glint.bool("example") + |> glint.default(False) + |> glint.param_help( "Generate example input files to run your solution against", ), ) use fetch_flag <- glint.flag( - glint.bool_flag("fetch") - |> glint.flag_default(False) - |> glint.flag_help("Fetch your own input from the AoC website. + glint.bool("fetch") + |> glint.default(False) + |> glint.param_help("Fetch your own input from the AoC website. Needs to have your AoC cookie stored in the '" <> aoc_cookie_name <> "' environment variable"), ) use _, args, flags <- glint.command() - use days <- result.map(parse.days(args)) + use days <- glint.try(parse.days(args)) let days = util.deduplicate_sort(days) - let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) - let assert Ok(add_parse) = parse_flag(flags) - let assert Ok(create_example_file) = example_flag(flags) - let assert Ok(fetch_input) = fetch_flag(flags) + use year <- glint.with_flag(flags, cmd.year_flag()) + use add_parse <- parse_flag(flags) + use create_example_file <- example_flag(flags) + use fetch_input <- fetch_flag(flags) - cmd.exec( - days, - cmd.Endless, - fn(day) { - do(Context(year:, day:, add_parse:, create_example_file:, fetch_input:)) - }, - collect_async(year, _), + glint.Success( + cmd.exec( + days, + cmd.Endless, + fn(day) { + do(Context(year:, day:, add_parse:, create_example_file:, fetch_input:)) + }, + collect_async(year, _), + ), ) } diff --git a/src/gladvent/internal/cmd/run.gleam b/src/gladvent/internal/cmd/run.gleam index 73197b3..3d8784a 100644 --- a/src/gladvent/internal/cmd/run.gleam +++ b/src/gladvent/internal/cmd/run.gleam @@ -1,4 +1,3 @@ -import decode import filepath import gladvent/internal/cmd.{Ending, Endless} import gladvent/internal/input @@ -8,8 +7,8 @@ import gladvent/internal/util import gleam import gleam/dict import gleam/dynamic.{type Dynamic} +import gleam/dynamic/decode import gleam/erlang -import gleam/erlang/atom import gleam/erlang/charlist.{type Charlist} import gleam/int import gleam/list @@ -19,7 +18,7 @@ import gleam/result import gleam/string import glint import simplifile -import snag.{type Result, type Snag} +import snag.{type Snag} import spinner import tom @@ -103,7 +102,7 @@ fn do( |> result.replace_error(FailedToReadInput(input_path)), ) - let parse = option.unwrap(parse, dynamic.from) + let parse = option.unwrap(parse, dynamic.string) case allow_crash { True -> { @@ -141,51 +140,17 @@ fn crash_to_dyn(err: erlang.Crash) -> dynamic.Dynamic { } } -type GleamErr { - GleamErr( - gleam_error: atom.Atom, - module: String, - function: String, - line: Int, - message: String, - value: Option(Dynamic), - ) -} +import gleeunit/internal/gleam_panic fn decode_gleam_err(dyn: dynamic.Dynamic) { - decode.into({ - use gleam_error <- decode.parameter - use module <- decode.parameter - use function <- decode.parameter - use line <- decode.parameter - use message <- decode.parameter - use value <- decode.parameter - GleamErr(gleam_error, module, function, line, message, value) - }) - |> decode.field(atom.create_from_string("gleam_error"), { - use dyn <- decode.then(decode.dynamic) - case atom.from_dynamic(dyn) { - Ok(a) -> decode.into(a) - Error(e) -> - decode.fail("failed to decode gleam error: " <> string.inspect(e)) - } - }) - |> decode.field(atom.create_from_string("module"), decode.string) - |> decode.field(atom.create_from_string("function"), decode.string) - |> decode.field(atom.create_from_string("line"), decode.int) - |> decode.field(atom.create_from_string("message"), decode.string) - |> decode.field( - atom.create_from_string("value"), - decode.optional(decode.dynamic), - ) - |> decode.from(dyn) + gleam_panic.from_dynamic(dyn) } -fn gleam_err_to_string(g: GleamErr) -> String { +fn gleam_err_to_string(g: gleam_panic.GleamPanic) -> String { string.join( [ "error:", - atom.to_string(g.gleam_error), + string.inspect(g.kind), "-", g.message, "in module", @@ -194,9 +159,6 @@ fn gleam_err_to_string(g: GleamErr) -> String { g.function, "at line", int.to_string(g.line), - g.value - |> option.map(fn(val) { "with value " <> string.inspect(val) }) - |> option.unwrap(""), ], " ", ) @@ -236,7 +198,7 @@ fn solve_res_to_string( use expect <- option.map(expectation) case expect { ExpectInt(expect) -> { - case dynamic.int(solution.value) { + case decode.run(solution.value, decode.int) { Ok(i) if expect == i -> "✅ met expected value: " <> int.to_string(i) @@ -254,7 +216,7 @@ fn solve_res_to_string( } } ExpectString(expect) -> { - case dynamic.string(solution.value) { + case decode.run(solution.value, decode.string) { Ok(s) if expect == s -> "✅ met expected value: " <> s @@ -345,9 +307,9 @@ fn collect( // ----- CLI ----- pub fn timeout_flag() { - use i <- glint.flag_constraint( - glint.int_flag("timeout") - |> glint.flag_help("Run with specified timeout"), + use i <- glint.constraint( + glint.int("timeout") + |> glint.param_help("Run with specified timeout"), ) case i > 0 { @@ -357,41 +319,41 @@ pub fn timeout_flag() { } pub fn allow_crash_flag() { - glint.bool_flag("allow-crash") - |> glint.flag_default(False) - |> glint.flag_help("Don't catch exceptions thrown by runners.") + glint.bool("allow-crash") + |> glint.default(False) + |> glint.param_help("Don't catch exceptions thrown by runners.") } pub fn timed_flag() { - glint.bool_flag("timed") - |> glint.flag_default(False) - |> glint.flag_help( + glint.bool("timed") + |> glint.default(False) + |> glint.param_help( "Display solution execution time. The time displayed does not include any work done in a 'parse' function.", ) } -pub fn run_command() -> glint.Command(Result(List(String))) { +pub fn run_command() -> glint.Command(List(String), glint.ArgsSet) { use <- glint.command_help("Run the specified days") - use <- glint.unnamed_args(glint.MinArgs(1)) + use <- glint.min_args("days", 1, "The days to run solutions for.") use example_flag <- glint.flag( - glint.bool_flag("example") - |> glint.flag_default(False) - |> glint.flag_help( + glint.bool("example") + |> glint.default(False) + |> glint.param_help( "Run solutions against example inputs (found at input//.example.txt)", ), ) use _, args, flags <- glint.command() - use days <- result.then(parse.days(args)) + use days <- glint.try(parse.days(args)) let days = util.deduplicate_sort(days) - let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) - let assert Ok(allow_crash) = glint.get_flag(flags, allow_crash_flag()) - let assert Ok(timed) = glint.get_flag(flags, timed_flag()) - let assert Ok(input_kind) = case example_flag(flags) { - Error(a) -> Error(a) - Ok(True) -> Ok(input.Example) - _ -> Ok(input.Puzzle) + use year <- glint.with_flag(flags, cmd.year_flag()) + use allow_crash <- glint.with_flag(flags, allow_crash_flag()) + use timed <- glint.with_flag(flags, timed_flag()) + use input_kind <- example_flag(flags) + let input_kind = case input_kind { + True -> input.Example + False -> input.Puzzle } let spinner = @@ -405,12 +367,12 @@ pub fn run_command() -> glint.Command(Result(List(String))) { use <- util.defer(do: fn() { spinner.stop(spinner) }) - let timing = - glint.get_flag(flags, timeout_flag()) - |> result.map(Ending) - |> result.unwrap(Endless) + let timing = case glint.get_flag(flags, timeout_flag()) { + Ok(timeout) -> Ending(timeout) + Error(_) -> Endless + } - use gleam_toml <- result.try(read_gleam_toml()) + use gleam_toml <- glint.try(read_gleam_toml()) let expectations = case input_kind { input.Puzzle -> @@ -420,27 +382,29 @@ pub fn run_command() -> glint.Command(Result(List(String))) { input.Example -> option.None } - use package <- result.map( + use package <- glint.try( runners.pkg_interface() |> snag.context("failed to generate package interface"), ) - days - |> cmd.exec( - timing, - do(year, _, package, allow_crash, input_kind), - collect_async(year, _, expectations, timed), + glint.Success( + days + |> cmd.exec( + timing, + do(year, _, package, allow_crash, input_kind), + collect_async(year, _, expectations, timed), + ), ) } -pub fn run_all_command() -> glint.Command(Result(List(String))) { +pub fn run_all_command() -> glint.Command(List(String), glint.ArgsSet) { use <- glint.command_help("Run all registered days") - use <- glint.unnamed_args(glint.EqArgs(0)) + use <- glint.no_args() use _, _, flags <- glint.command() - let assert Ok(year) = glint.get_flag(flags, cmd.year_flag()) - let assert Ok(allow_crash) = glint.get_flag(flags, allow_crash_flag()) - let assert Ok(timed) = glint.get_flag(flags, timed_flag()) + use year <- glint.with_flag(flags, cmd.year_flag()) + use allow_crash <- glint.with_flag(flags, allow_crash_flag()) + use timed <- glint.with_flag(flags, timed_flag()) let spinner = spinner.new("running all days in " <> int.to_string(year)) @@ -448,39 +412,41 @@ pub fn run_all_command() -> glint.Command(Result(List(String))) { use <- util.defer(do: fn() { spinner.stop(spinner) }) - let timing = - glint.get_flag(flags, timeout_flag()) - |> result.map(Ending) - |> result.unwrap(Endless) + let timing = case glint.get_flag(flags, timeout_flag()) { + Ok(timeout) -> Ending(timeout) + Error(_) -> Endless + } - use gleam_toml <- result.try(read_gleam_toml()) + use gleam_toml <- glint.try(read_gleam_toml()) let expectations = option.from_result( tom.get_table(gleam_toml, ["gladvent", int.to_string(year)]), ) - use package <- result.map( + use package <- glint.try( runners.pkg_interface() |> snag.context("failed to generate package interface"), ) - package.modules - |> dict.keys - |> list.filter_map(fn(k) { - use day <- result.try(string.split_once( - k, - "aoc_" <> int.to_string(year) <> "/day_", - )) - day.1 - |> parse.day - |> result.replace_error(Nil) - }) - |> list.sort(int.compare) - |> cmd.exec( - timing, - do(year, _, package, allow_crash, input.Puzzle), - collect_async(year, _, expectations, timed), + glint.Success( + package.modules + |> dict.keys + |> list.filter_map(fn(k) { + use day <- result.try(string.split_once( + k, + "aoc_" <> int.to_string(year) <> "/day_", + )) + day.1 + |> parse.day + |> result.replace_error(Nil) + }) + |> list.sort(int.compare) + |> cmd.exec( + timing, + do(year, _, package, allow_crash, input.Puzzle), + collect_async(year, _, expectations, timed), + ), ) } diff --git a/src/gladvent/internal/runners.gleam b/src/gladvent/internal/runners.gleam index 285e0c9..c0a8886 100644 --- a/src/gladvent/internal/runners.gleam +++ b/src/gladvent/internal/runners.gleam @@ -86,7 +86,7 @@ pub fn pkg_interface() -> Result(package_interface.Package) { spinner.set_text(spinner, "decoding package interface JSON") use pkg_interface_details <- result.try( - json.decode(from: pkg_interface_contents, using: package_interface.decoder) + json.parse(from: pkg_interface_contents, using: package_interface.decoder()) |> result.map_error(FailedToDecodePackageInterface), ) diff --git a/test/parse_test.gleam b/test/parse_test.gleam index 528213f..999084d 100644 --- a/test/parse_test.gleam +++ b/test/parse_test.gleam @@ -1,22 +1,19 @@ import gladvent/internal/parse.{day, pad} import gleam/int import gleam/list -import gleeunit/should pub fn day_success_test() { use x <- list.each(list.range(1, 25)) - x - |> int.to_string() - |> day - |> should.equal(Ok(x)) + assert x + |> int.to_string() + |> day + == Ok(x) } pub fn day_error_test() { list.each(["", "0", "-1", "26"], fn(x) { - x - |> day - |> should.be_error + let assert Error(_) = day(x) }) } diff --git a/test/util_test.gleam b/test/util_test.gleam index f088c05..8cf80e4 100644 --- a/test/util_test.gleam +++ b/test/util_test.gleam @@ -1,6 +1,5 @@ import gladvent/internal/util import gleam/list -import gleeunit/should pub fn format_float_test() { use #(float, precision, expected) <- list.each([ @@ -12,6 +11,5 @@ pub fn format_float_test() { #(0.0, 0, "0"), ]) - util.format_float(float, precision) - |> should.equal(expected) + assert util.format_float(float, precision) == expected } From a7194f4baeaf57ee27718da1487491581a7721e1 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Thu, 12 Jun 2025 16:09:50 -0400 Subject: [PATCH 8/9] bump for glint v2 testing --- gleam.toml | 2 +- manifest.toml | 4 ++-- test/parse_test.gleam | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gleam.toml b/gleam.toml index d2771e7..40d6be7 100644 --- a/gleam.toml +++ b/gleam.toml @@ -7,7 +7,7 @@ internal_modules = ["gladvent/internal/*"] gleam = ">=1.11.0 and < 2.0.0" [dependencies] -glint = {path="../glint"} +glint = { git = "https://github.com/tanklesxl/glint.git", ref = "next" } envoy = ">= 1.0.2 and < 2.0.0" simplifile = ">= 2.2.1 and < 3.0.0" gleam_json = ">= 3.0.1 and < 4.0.0" diff --git a/manifest.toml b/manifest.toml index b35f239..2f4e15b 100644 --- a/manifest.toml +++ b/manifest.toml @@ -24,7 +24,7 @@ packages = [ { name = "glearray", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "5E272F7CB278CC05A929C58DEB58F5D5AC6DB5B879A681E71138658D0061C38A" }, { name = "gleeunit", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D33B7736CF0766ED3065F64A1EBB351E72B2E8DE39BAFC8ADA0E35E92A6A934F" }, { name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" }, - { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_deque", "gleam_stdlib", "lenient_parse", "snag"], source = "local", path = "../glint" }, + { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_deque", "gleam_stdlib", "lenient_parse", "snag"], source = "git", repo = "https://github.com/tanklesxl/glint.git", commit = "33829b9aaf2db6a9f53b16c4d108f81af7adb32f" }, { name = "lenient_parse", version = "3.0.0", build_tools = ["gleam"], requirements = ["bigi", "gleam_deque", "gleam_stdlib"], otp_app = "lenient_parse", source = "hex", outer_checksum = "E6C654A75E6EB17B559418C5216583D0B9E7D82018E0608A7FF1AFF328D9F474" }, { name = "parallel_map", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib", "gleam_yielder"], otp_app = "parallel_map", source = "hex", outer_checksum = "E5A38C9294831F67DF8EAC17870FEA97FF0D8F891049E0CA634B30A1AFE37A8F" }, { name = "repeatedly", version = "2.1.2", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "93AE1938DDE0DC0F7034F32C1BF0D4E89ACEBA82198A1FE21F604E849DA5F589" }, @@ -48,7 +48,7 @@ gleam_otp = { version = ">= 0.16.1 and < 1.0.0" } gleam_package_interface = { version = ">= 3.0.1 and < 4.0.0" } gleam_stdlib = { version = ">= 0.60.0 and < 1.0.0" } gleeunit = { version = ">= 1.2.0 and < 2.0.0" } -glint = { path = "../glint" } +glint = { git = "https://github.com/tanklesxl/glint.git", ref = "next" } parallel_map = { version = ">= 3.0.1 and < 4.0.0" } shellout = { version = ">= 1.7.0 and < 2.0.0" } simplifile = { version = ">= 2.2.1 and < 3.0.0" } diff --git a/test/parse_test.gleam b/test/parse_test.gleam index 999084d..1cb9b2e 100644 --- a/test/parse_test.gleam +++ b/test/parse_test.gleam @@ -18,9 +18,9 @@ pub fn day_error_test() { } pub fn pad_test() { - pad(1) |> should.equal("01") + assert pad(1) == "01" } pub fn padded_day_to_int_test() { - "01" |> int.parse() |> should.be_ok() |> should.equal(1) + assert "01" |> int.parse() == Ok(1) } From 59858124d8d322d9505b8013980d65956e7f25a8 Mon Sep 17 00:00:00 2001 From: Robert Attard Date: Thu, 12 Jun 2025 16:15:57 -0400 Subject: [PATCH 9/9] bump gleam in ci --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eeab7ab..7efbe07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: uses: TanklesXL/gleam_actions/.github/workflows/release.yaml@main secrets: inherit with: - gleam_version: 1.9.1 + gleam_version: 1.11.1 erlang_version: 26 test_erlang: true test_node: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47b7747..39660ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,6 @@ jobs: test: uses: TanklesXL/gleam_actions/.github/workflows/test.yaml@main with: - gleam_version: 1.9.1 + gleam_version: 1.11.1 test_node: false test_erlang: true