Skip to main content

src/kludge.erl

-module(kludge).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/kludge.gleam").
-export([main/0]).
-export_type([apply_patch_error/0]).

-type apply_patch_error() :: invalid_file_name |
    dependency_does_not_exist |
    {git_apply_error, snag:snag(), gleam@option:option(binary())} |
    patch_already_applied.

-file("src/kludge.gleam", 28).
-spec patch_plural(integer()) -> binary().
patch_plural(Count) ->
    case Count of
        1 ->
            <<"patch"/utf8>>;

        _ ->
            <<"patches"/utf8>>
    end.

-file("src/kludge.gleam", 35).
-spec print_help() -> nil.
print_help() ->
    gleam_stdlib:println(
        <<"Kludge - patch a package in a pinch 🩹

gleam run -m kludge # Patches everything in ./patches
gleam run -m kludge [package] # Writes your changes in ./patches for that package"/utf8>>
    ).

-file("src/kludge.gleam", 277).
-spec git(list(binary()), binary()) -> {ok, child_process:output()} |
    {error, snag:snag()}.
git(Args, Cwd) ->
    gleam@result:'try'(
        begin
            _pipe = child_process:new_with_path(<<"git"/utf8>>),
            _pipe@1 = child_process:cwd(_pipe, Cwd),
            _pipe@2 = child_process:args(_pipe@1, Args),
            _pipe@3 = child_process:run(_pipe@2),
            snag:map_error(_pipe@3, fun gleam@string:inspect/1)
        end,
        fun(_use0) ->
            {output, Code, Text} = Out = _use0,
            case Code of
                0 ->
                    {ok, Out};

                _ ->
                    snag:error(
                        <<<<<<"Git returned an unexpected error with code "/utf8,
                                    (erlang:integer_to_binary(Code))/binary>>/binary,
                                " and body "/utf8>>/binary,
                            Text/binary>>
                    )
            end
        end
    ).

-file("src/kludge.gleam", 559).
-spec get_gleam_cache() -> {ok, binary()} | {error, snag:snag()}.
get_gleam_cache() ->
    case platform:os() of
        darwin ->
            case directories:home_dir() of
                {ok, Home} ->
                    {ok, filepath:join(Home, <<"Library/Caches/gleam"/utf8>>)};

                {error, nil} ->
                    snag:error(<<"Cannot find home directory"/utf8>>)
            end;

        win32 ->
            case directories:data_local_dir() of
                {ok, Dir} ->
                    {ok, filepath:join(Dir, <<"gleam"/utf8>>)};

                {error, nil} ->
                    snag:error(<<"Cannot find local app data"/utf8>>)
            end;

        linux ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end;

        free_bsd ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end;

        open_bsd ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end;

        sun_os ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end;

        aix ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end;

        {other_os, _} ->
            case directories:cache_dir() of
                {ok, Cache} ->
                    _pipe = filepath:join(Cache, <<"gleam"/utf8>>),
                    {ok, _pipe};

                {error, nil} ->
                    snag:error(<<"Cannot find cache directory"/utf8>>)
            end
    end.

-file("src/kludge.gleam", 430).
-spec clone_original_into(kludge@internal@manifest:manifest_package(), binary()) -> {ok,
        nil} |
    {error, snag:snag()}.
clone_original_into(Package, Destination) ->
    case Package of
        {hex_package, _, _, _, _, _, _} ->
            gleam@result:'try'(
                begin
                    _pipe = get_gleam_cache(),
                    snag:context(
                        _pipe,
                        <<"Cannot find gleam hexpm cache directory"/utf8>>
                    )
                end,
                fun(Cache) ->
                    Hexpkgs = filepath:join(
                        Cache,
                        <<"hex/hexpm/packages/"/utf8>>
                    ),
                    Cached_package_path = filepath:join(
                        Hexpkgs,
                        <<(erlang:element(7, Package))/binary, ".tar"/utf8>>
                    ),
                    Can_use_cached = gleam@result:unwrap(
                        simplifile_erl:is_file(Cached_package_path),
                        false
                    ),
                    Outer_archive_find_result = case Can_use_cached of
                        true ->
                            gleam@result:'try'(
                                begin
                                    _pipe@1 = simplifile_erl:read_bits(
                                        Cached_package_path
                                    ),
                                    snag:map_error(
                                        _pipe@1,
                                        fun simplifile:describe_error/1
                                    )
                                end,
                                fun(Bits) ->
                                    Checksum = gleam_stdlib:base16_encode(
                                        gleam@crypto:hash(sha256, Bits)
                                    ),
                                    gleam@bool:guard(
                                        Checksum /= erlang:element(7, Package),
                                        snag:error(
                                            <<<<<<"Hash validation error! Expected (manifest): "/utf8,
                                                        (erlang:element(
                                                            7,
                                                            Package
                                                        ))/binary>>/binary,
                                                    " Got (in cache): "/utf8>>/binary,
                                                Checksum/binary>>
                                        ),
                                        fun() -> {ok, {from_data, Bits}} end
                                    )
                                end
                            );

                        false ->
                            gleam@result:'try'(
                                begin
                                    _pipe@2 = gleam@http@request:new(),
                                    _pipe@3 = gleam@http@request:set_method(
                                        _pipe@2,
                                        get
                                    ),
                                    _pipe@4 = gleam@http@request:set_scheme(
                                        _pipe@3,
                                        https
                                    ),
                                    _pipe@5 = gleam@http@request:set_host(
                                        _pipe@4,
                                        <<"repo.hex.pm"/utf8>>
                                    ),
                                    _pipe@6 = gleam@http@request:set_path(
                                        _pipe@5,
                                        <<<<<<<<"tarballs/"/utf8,
                                                        (erlang:element(
                                                            2,
                                                            Package
                                                        ))/binary>>/binary,
                                                    "-"/utf8>>/binary,
                                                (erlang:element(3, Package))/binary>>/binary,
                                            ".tar"/utf8>>
                                    ),
                                    _pipe@7 = gleam@http@request:set_body(
                                        _pipe@6,
                                        <<>>
                                    ),
                                    _pipe@8 = gleam@httpc:send_bits(_pipe@7),
                                    _pipe@9 = snag:map_error(
                                        _pipe@8,
                                        fun gleam@string:inspect/1
                                    ),
                                    snag:context(
                                        _pipe@9,
                                        <<"Cannot fetch package "/utf8,
                                            (erlang:element(2, Package))/binary>>
                                    )
                                end,
                                fun(Response) ->
                                    gleam@bool:guard(
                                        erlang:element(2, Response) /= 200,
                                        snag:error(
                                            <<<<"Non 200 response ("/utf8,
                                                    (erlang:integer_to_binary(
                                                        erlang:element(
                                                            2,
                                                            Response
                                                        )
                                                    ))/binary>>/binary,
                                                ") was sent by hexpm"/utf8>>
                                        ),
                                        fun() ->
                                            Checksum@1 = gleam_stdlib:base16_encode(
                                                gleam@crypto:hash(
                                                    sha256,
                                                    erlang:element(4, Response)
                                                )
                                            ),
                                            gleam@bool:guard(
                                                Checksum@1 /= erlang:element(
                                                    7,
                                                    Package
                                                ),
                                                snag:error(
                                                    <<<<<<"Hash validation error! Expected (manifest): "/utf8,
                                                                (erlang:element(
                                                                    7,
                                                                    Package
                                                                ))/binary>>/binary,
                                                            " Got (downloaded): "/utf8>>/binary,
                                                        Checksum@1/binary>>
                                                ),
                                                fun() ->
                                                    {ok,
                                                        {from_data,
                                                            erlang:element(
                                                                4,
                                                                Response
                                                            )}}
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                    end,
                    gleam@result:'try'(
                        begin
                            _pipe@10 = Outer_archive_find_result,
                            snag:context(
                                _pipe@10,
                                <<"Cannot find outer archive source"/utf8>>
                            )
                        end,
                        fun(Outer_archive) ->
                            gleam@result:'try'(
                                begin
                                    _pipe@11 = Outer_archive,
                                    _pipe@12 = star:extract_memory(
                                        _pipe@11,
                                        uncompressed,
                                        all_entries
                                    ),
                                    _pipe@13 = snag:map_error(
                                        _pipe@12,
                                        fun gleam@string:inspect/1
                                    ),
                                    snag:context(
                                        _pipe@13,
                                        <<"Error when decompressing decompressing outer"/utf8>>
                                    )
                                end,
                                fun(Outer_files) ->
                                    gleam@result:'try'(
                                        begin
                                            _pipe@14 = gleam@list:find(
                                                Outer_files,
                                                fun(File) ->
                                                    erlang:element(
                                                        2,
                                                        erlang:element(2, File)
                                                    )
                                                    =:= <<"contents.tar.gz"/utf8>>
                                                end
                                            ),
                                            snag:replace_error(
                                                _pipe@14,
                                                <<"Cannot find contents.tar.gz in hex archive"/utf8>>
                                            )
                                        end,
                                        fun(Contents) ->
                                            gleam@result:'try'(
                                                begin
                                                    _pipe@15 = star:extract(
                                                        {from_data,
                                                            erlang:element(
                                                                3,
                                                                Contents
                                                            )},
                                                        Destination,
                                                        gzip,
                                                        all_entries,
                                                        overwrite
                                                    ),
                                                    _pipe@16 = snag:map_error(
                                                        _pipe@15,
                                                        fun gleam@string:inspect/1
                                                    ),
                                                    snag:context(
                                                        _pipe@16,
                                                        <<"Failed to extract hexpm contents.tar.gz"/utf8>>
                                                    )
                                                end,
                                                fun(_use0) ->
                                                    nil = _use0,
                                                    {ok, nil}
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            );

        {git_package, _, _, _, _, _, _} ->
            Git = fun(_capture) -> git(_capture, Destination) end,
            gleam@result:'try'(
                begin
                    _pipe@17 = Git([<<"init"/utf8>>]),
                    snag:context(
                        _pipe@17,
                        <<"Failed to initialize git repository"/utf8>>
                    )
                end,
                fun(_) ->
                    gleam@result:'try'(
                        begin
                            _pipe@18 = Git(
                                [<<"remote"/utf8>>,
                                    <<"add"/utf8>>,
                                    <<"origin"/utf8>>,
                                    erlang:element(6, Package)]
                            ),
                            snag:context(
                                _pipe@18,
                                <<"Cannot add repo origin of "/utf8,
                                    (erlang:element(6, Package))/binary>>
                            )
                        end,
                        fun(_) ->
                            gleam@result:'try'(
                                begin
                                    _pipe@19 = Git(
                                        [<<"fetch"/utf8>>,
                                            <<"--depth=1"/utf8>>,
                                            <<"origin"/utf8>>,
                                            erlang:element(7, Package)]
                                    ),
                                    snag:context(
                                        _pipe@19,
                                        <<<<"Error fetching git commit hash"/utf8,
                                                (erlang:element(7, Package))/binary>>/binary,
                                            ". Warning: server may not support shallow SHA fetches (uploadpack.allowReachableSHA1InWant)"/utf8>>
                                    )
                                end,
                                fun(_) ->
                                    gleam@result:'try'(
                                        begin
                                            _pipe@20 = Git(
                                                [<<"checkout"/utf8>>,
                                                    <<"FETCH_HEAD"/utf8>>]
                                            ),
                                            snag:context(
                                                _pipe@20,
                                                <<"Cannot check out FETCH_HEAD"/utf8>>
                                            )
                                        end,
                                        fun(_) -> {ok, nil} end
                                    )
                                end
                            )
                        end
                    )
                end
            );

        {path_package, _, _, _, _, _} ->
            {error,
                snag:new(<<"Path packages are not supported in kludge."/utf8>>)}
    end.

-file("src/kludge.gleam", 116).
-spec get_manifest() -> {ok, kludge@internal@manifest:manifest()} |
    {error, snag:snag()}.
get_manifest() ->
    gleam@result:'try'(
        begin
            _pipe = simplifile:read(<<"manifest.toml"/utf8>>),
            _pipe@1 = snag:map_error(_pipe, fun simplifile:describe_error/1),
            snag:context(_pipe@1, <<"Unable to read manifest file"/utf8>>)
        end,
        fun(Toml_text) ->
            gleam@result:'try'(
                begin
                    _pipe@2 = tom:parse_to_dynamic(Toml_text),
                    _pipe@3 = snag:map_error(
                        _pipe@2,
                        fun gleam@string:inspect/1
                    ),
                    snag:context(
                        _pipe@3,
                        <<"Cannot parse manifest file's toml"/utf8>>
                    )
                end,
                fun(Toml) ->
                    gleam@result:'try'(
                        begin
                            _pipe@4 = gleam@dynamic@decode:run(
                                Toml,
                                kludge@internal@manifest:manifest_decoder()
                            ),
                            _pipe@5 = snag:map_error(
                                _pipe@4,
                                fun gleam@string:inspect/1
                            ),
                            snag:context(
                                _pipe@5,
                                <<"Cannot decode manfiest file structure"/utf8>>
                            )
                        end,
                        fun(Manifest) -> {ok, Manifest} end
                    )
                end
            )
        end
    ).

-file("src/kludge.gleam", 297).
-spec find_patches(binary()) -> {ok, binary()} | {error, snag:snag()}.
find_patches(Package_name) ->
    gleam@result:'try'(
        get_manifest(),
        fun(Manifest) ->
            gleam@result:'try'(
                begin
                    _pipe = gleam@list:find(
                        erlang:element(2, Manifest),
                        fun(It) -> erlang:element(2, It) =:= Package_name end
                    ),
                    snag:replace_error(
                        _pipe,
                        <<"Cannot find package "/utf8, Package_name/binary>>
                    )
                end,
                fun(Package) ->
                    Patch_file_path = <<<<<<<<"./patches/"/utf8,
                                    (erlang:element(2, Package))/binary>>/binary,
                                "+"/utf8>>/binary,
                            (erlang:element(3, Package))/binary>>/binary,
                        ".patch"/utf8>>,
                    gleam@bool:guard(
                        begin
                            _pipe@1 = simplifile_erl:is_file(Patch_file_path),
                            gleam@result:unwrap(_pipe@1, false)
                        end,
                        snag:error(
                            <<<<"Patch "/utf8, Patch_file_path/binary>>/binary,
                                " already exists, move or remove to make a new patch"/utf8>>
                        ),
                        fun() ->
                            Diff = begin
                                _pipe@22 = begin
                                    temporary:create(
                                        temporary:directory(),
                                        fun(Temp_dir) ->
                                            Git = fun(_capture) ->
                                                git(_capture, Temp_dir)
                                            end,
                                            gleam@result:'try'(
                                                begin
                                                    _pipe@2 = Git(
                                                        [<<"--version"/utf8>>]
                                                    ),
                                                    snag:context(
                                                        _pipe@2,
                                                        <<"Cannot check version"/utf8>>
                                                    )
                                                end,
                                                fun(Version) ->
                                                    gleam@bool:guard(
                                                        not gleam_stdlib:string_starts_with(
                                                            erlang:element(
                                                                3,
                                                                Version
                                                            ),
                                                            <<"git version "/utf8>>
                                                        ),
                                                        begin
                                                            _pipe@3 = snag:error(
                                                                <<"git does not appear to be git, the version control software"/utf8>>
                                                            ),
                                                            snag:context(
                                                                _pipe@3,
                                                                <<"Cannot check version"/utf8>>
                                                            )
                                                        end,
                                                        fun() ->
                                                            gleam@result:'try'(
                                                                begin
                                                                    _pipe@4 = clone_original_into(
                                                                        Package,
                                                                        Temp_dir
                                                                    ),
                                                                    snag:context(
                                                                        _pipe@4,
                                                                        <<"Cannot getting original version of the package"/utf8>>
                                                                    )
                                                                end,
                                                                fun(_use0) ->
                                                                    nil = _use0,
                                                                    gleam@result:'try'(
                                                                        begin
                                                                            _pipe@5 = child_process:new_with_path(
                                                                                <<"git"/utf8>>
                                                                            ),
                                                                            _pipe@6 = child_process:cwd(
                                                                                _pipe@5,
                                                                                Temp_dir
                                                                            ),
                                                                            _pipe@7 = child_process:args(
                                                                                _pipe@6,
                                                                                [<<"init"/utf8>>]
                                                                            ),
                                                                            _pipe@8 = child_process:run(
                                                                                _pipe@7
                                                                            ),
                                                                            _pipe@9 = snag:map_error(
                                                                                _pipe@8,
                                                                                fun gleam@string:inspect/1
                                                                            ),
                                                                            snag:context(
                                                                                _pipe@9,
                                                                                <<"Error initializing repository"/utf8>>
                                                                            )
                                                                        end,
                                                                        fun(_) ->
                                                                            gleam@result:'try'(
                                                                                begin
                                                                                    _pipe@10 = Git(
                                                                                        [<<"config"/utf8>>,
                                                                                            <<"--local"/utf8>>,
                                                                                            <<"user.name"/utf8>>,
                                                                                            <<"gleam-kludge"/utf8>>]
                                                                                    ),
                                                                                    snag:context(
                                                                                        _pipe@10,
                                                                                        <<"Error setting git username"/utf8>>
                                                                                    )
                                                                                end,
                                                                                fun(
                                                                                    _
                                                                                ) ->
                                                                                    gleam@result:'try'(
                                                                                        begin
                                                                                            _pipe@11 = Git(
                                                                                                [<<"config"/utf8>>,
                                                                                                    <<"--local"/utf8>>,
                                                                                                    <<"user.email"/utf8>>,
                                                                                                    <<"gleam@kludge.run"/utf8>>]
                                                                                            ),
                                                                                            snag:context(
                                                                                                _pipe@11,
                                                                                                <<"Error setting git email"/utf8>>
                                                                                            )
                                                                                        end,
                                                                                        fun(
                                                                                            _
                                                                                        ) ->
                                                                                            gleam@result:'try'(
                                                                                                begin
                                                                                                    _pipe@12 = Git(
                                                                                                        [<<"add"/utf8>>,
                                                                                                            <<"-f"/utf8>>,
                                                                                                            <<"."/utf8>>]
                                                                                                    ),
                                                                                                    snag:context(
                                                                                                        _pipe@12,
                                                                                                        <<"Error adding original files to be tracked"/utf8>>
                                                                                                    )
                                                                                                end,
                                                                                                fun(
                                                                                                    _
                                                                                                ) ->
                                                                                                    gleam@result:'try'(
                                                                                                        begin
                                                                                                            _pipe@13 = Git(
                                                                                                                [<<"commit"/utf8>>,
                                                                                                                    <<"--allow-empty"/utf8>>,
                                                                                                                    <<"-m"/utf8>>,
                                                                                                                    <<"original"/utf8>>]
                                                                                                            ),
                                                                                                            snag:context(
                                                                                                                _pipe@13,
                                                                                                                <<"Error commiting original files"/utf8>>
                                                                                                            )
                                                                                                        end,
                                                                                                        fun(
                                                                                                            _
                                                                                                        ) ->
                                                                                                            gleam@result:'try'(
                                                                                                                begin
                                                                                                                    _pipe@14 = simplifile_erl:read_directory(
                                                                                                                        Temp_dir
                                                                                                                    ),
                                                                                                                    _pipe@15 = snag:map_error(
                                                                                                                        _pipe@14,
                                                                                                                        fun simplifile:describe_error/1
                                                                                                                    ),
                                                                                                                    snag:context(
                                                                                                                        _pipe@15,
                                                                                                                        <<"Cannot list temp dir"/utf8>>
                                                                                                                    )
                                                                                                                end,
                                                                                                                fun(
                                                                                                                    Entries
                                                                                                                ) ->
                                                                                                                    gleam@result:'try'(
                                                                                                                        begin
                                                                                                                            _pipe@17 = gleam@list:try_each(
                                                                                                                                gleam@list:filter(
                                                                                                                                    Entries,
                                                                                                                                    fun(
                                                                                                                                        E
                                                                                                                                    ) ->
                                                                                                                                        E
                                                                                                                                        /= <<".git"/utf8>>
                                                                                                                                    end
                                                                                                                                ),
                                                                                                                                fun(
                                                                                                                                    Entry
                                                                                                                                ) ->
                                                                                                                                    _pipe@16 = simplifile_erl:delete(
                                                                                                                                        filepath:join(
                                                                                                                                            Temp_dir,
                                                                                                                                            Entry
                                                                                                                                        )
                                                                                                                                    ),
                                                                                                                                    snag:map_error(
                                                                                                                                        _pipe@16,
                                                                                                                                        fun simplifile:describe_error/1
                                                                                                                                    )
                                                                                                                                end
                                                                                                                            ),
                                                                                                                            snag:context(
                                                                                                                                _pipe@17,
                                                                                                                                <<"Cannot clear temp dir"/utf8>>
                                                                                                                            )
                                                                                                                        end,
                                                                                                                        fun(
                                                                                                                            _
                                                                                                                        ) ->
                                                                                                                            Original = <<"build/packages/"/utf8,
                                                                                                                                (erlang:element(
                                                                                                                                    2,
                                                                                                                                    Package
                                                                                                                                ))/binary>>,
                                                                                                                            gleam@result:'try'(
                                                                                                                                begin
                                                                                                                                    _pipe@18 = simplifile:copy_directory(
                                                                                                                                        Original,
                                                                                                                                        Temp_dir
                                                                                                                                    ),
                                                                                                                                    _pipe@19 = snag:map_error(
                                                                                                                                        _pipe@18,
                                                                                                                                        fun simplifile:describe_error/1
                                                                                                                                    ),
                                                                                                                                    snag:context(
                                                                                                                                        _pipe@19,
                                                                                                                                        <<<<"Cannot copy modified files to git temp dir ("/utf8,
                                                                                                                                                Temp_dir/binary>>/binary,
                                                                                                                                            ")"/utf8>>
                                                                                                                                    )
                                                                                                                                end,
                                                                                                                                fun(
                                                                                                                                    _use0@1
                                                                                                                                ) ->
                                                                                                                                    nil = _use0@1,
                                                                                                                                    gleam@result:'try'(
                                                                                                                                        begin
                                                                                                                                            _pipe@20 = Git(
                                                                                                                                                [<<"add"/utf8>>,
                                                                                                                                                    <<"-f"/utf8>>,
                                                                                                                                                    <<"."/utf8>>]
                                                                                                                                            ),
                                                                                                                                            snag:context(
                                                                                                                                                _pipe@20,
                                                                                                                                                <<"Cannot stage modified files to repo"/utf8>>
                                                                                                                                            )
                                                                                                                                        end,
                                                                                                                                        fun(
                                                                                                                                            _
                                                                                                                                        ) ->
                                                                                                                                            gleam@result:'try'(
                                                                                                                                                begin
                                                                                                                                                    _pipe@21 = Git(
                                                                                                                                                        [<<"reset"/utf8>>,
                                                                                                                                                            <<"--"/utf8>>,
                                                                                                                                                            <<"build"/utf8>>,
                                                                                                                                                            <<"manifest.toml"/utf8>>]
                                                                                                                                                    ),
                                                                                                                                                    snag:context(
                                                                                                                                                        _pipe@21,
                                                                                                                                                        <<"Cannot reset modified in repo"/utf8>>
                                                                                                                                                    )
                                                                                                                                                end,
                                                                                                                                                fun(
                                                                                                                                                    _
                                                                                                                                                ) ->
                                                                                                                                                    gleam@result:'try'(
                                                                                                                                                        Git(
                                                                                                                                                            [<<"diff"/utf8>>,
                                                                                                                                                                <<"--cached"/utf8>>,
                                                                                                                                                                <<"--no-color"/utf8>>,
                                                                                                                                                                <<"--ignore-space-at-eol"/utf8>>,
                                                                                                                                                                <<"--no-ext-diff"/utf8>>,
                                                                                                                                                                <<"--src-prefix=a/"/utf8>>,
                                                                                                                                                                <<"--dst-prefix=b/"/utf8>>]
                                                                                                                                                        ),
                                                                                                                                                        fun(
                                                                                                                                                            _use0@2
                                                                                                                                                        ) ->
                                                                                                                                                            {output,
                                                                                                                                                                Code,
                                                                                                                                                                Text} = _use0@2,
                                                                                                                                                            case Code of
                                                                                                                                                                0 ->
                                                                                                                                                                    {ok,
                                                                                                                                                                        Text};

                                                                                                                                                                _ ->
                                                                                                                                                                    case gleam_stdlib:contains_string(
                                                                                                                                                                        Text,
                                                                                                                                                                        <<"Unexpected file mode string: 120000"/utf8>>
                                                                                                                                                                    ) of
                                                                                                                                                                        true ->
                                                                                                                                                                            {error,
                                                                                                                                                                                snag:new(
                                                                                                                                                                                    <<"These changes involve creating symlinks, kludge does not support symlinks."/utf8>>
                                                                                                                                                                                )};

                                                                                                                                                                        false ->
                                                                                                                                                                            {error,
                                                                                                                                                                                snag:new(
                                                                                                                                                                                    <<"Cannot create diff"/utf8,
                                                                                                                                                                                        Text/binary>>
                                                                                                                                                                                )}
                                                                                                                                                                    end
                                                                                                                                                            end
                                                                                                                                                        end
                                                                                                                                                    )
                                                                                                                                                end
                                                                                                                                            )
                                                                                                                                        end
                                                                                                                                    )
                                                                                                                                end
                                                                                                                            )
                                                                                                                        end
                                                                                                                    )
                                                                                                                end
                                                                                                            )
                                                                                                        end
                                                                                                    )
                                                                                                end
                                                                                            )
                                                                                        end
                                                                                    )
                                                                                end
                                                                            )
                                                                        end
                                                                    )
                                                                end
                                                            )
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end,
                                _pipe@23 = snag:map_error(
                                    _pipe@22,
                                    fun simplifile:describe_error/1
                                ),
                                _pipe@24 = gleam@result:flatten(_pipe@23),
                                snag:context(
                                    _pipe@24,
                                    <<"Cannot determine diff"/utf8>>
                                )
                            end,
                            gleam@result:'try'(
                                Diff,
                                fun(Diff@1) ->
                                    gleam@bool:guard(
                                        gleam@string:is_empty(Diff@1),
                                        snag:error(
                                            <<"No changes have been made"/utf8>>
                                        ),
                                        fun() ->
                                            gleam@result:'try'(
                                                begin
                                                    _pipe@25 = simplifile:create_directory_all(
                                                        <<"./patches"/utf8>>
                                                    ),
                                                    _pipe@26 = snag:map_error(
                                                        _pipe@25,
                                                        fun simplifile:describe_error/1
                                                    ),
                                                    snag:context(
                                                        _pipe@26,
                                                        <<"Cannot make patches directory"/utf8>>
                                                    )
                                                end,
                                                fun(_use0@3) ->
                                                    nil = _use0@3,
                                                    gleam@result:'try'(
                                                        begin
                                                            _pipe@27 = simplifile:write(
                                                                Patch_file_path,
                                                                Diff@1
                                                            ),
                                                            _pipe@28 = snag:map_error(
                                                                _pipe@27,
                                                                fun simplifile:describe_error/1
                                                            ),
                                                            snag:context(
                                                                _pipe@28,
                                                                <<"Cannot write patch file"/utf8>>
                                                            )
                                                        end,
                                                        fun(_use0@4) ->
                                                            nil = _use0@4,
                                                            {ok,
                                                                Patch_file_path}
                                                        end
                                                    )
                                                end
                                            )
                                        end
                                    )
                                end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/kludge.gleam", 135).
-spec apply_patches() -> {ok,
        {list(binary()), list({binary(), snag:snag()}), list(binary())}} |
    {error, snag:snag()}.
apply_patches() ->
    gleam@result:'try'(
        get_manifest(),
        fun(Manifest) ->
            gleam@result:'try'(
                begin
                    _pipe = simplifile_erl:read_directory(<<"./patches"/utf8>>),
                    _pipe@1 = snag:map_error(
                        _pipe,
                        fun simplifile:describe_error/1
                    ),
                    snag:context(
                        _pipe@1,
                        <<"Cannot read patches directory"/utf8>>
                    )
                end,
                fun(Patches) ->
                    Sorted_patches = begin
                        _pipe@3 = gleam@list:map(
                            Patches,
                            fun(Name) ->
                                _pipe@2 = kludge@internal@patch:parse_patch_name(
                                    <<"./patches/"/utf8, Name/binary>>
                                ),
                                gleam@result:replace_error(_pipe@2, Name)
                            end
                        ),
                        gleam@list:sort(_pipe@3, fun(Lhs, Rhs) -> case Lhs of
                                    {ok, Lhs@1} ->
                                        case Rhs of
                                            {ok, Rhs@1} ->
                                                kludge@internal@patch:compare_patch(
                                                    Lhs@1,
                                                    Rhs@1
                                                );

                                            {error, _} ->
                                                gt
                                        end;

                                    {error, _} ->
                                        lt
                                end end)
                    end,
                    _pipe@21 = gleam@list:fold(
                        Sorted_patches,
                        {[], [], []},
                        fun(Acc, Patch) ->
                            Name@2 = case Patch of
                                {ok, Patch@1} ->
                                    erlang:element(2, Patch@1);

                                {error, Name@1} ->
                                    Name@1
                            end,
                            {Successes, Errors, Ignored} = Acc,
                            Result = begin
                                gleam@result:'try'(
                                    begin
                                        _pipe@4 = Patch,
                                        gleam@result:replace_error(
                                            _pipe@4,
                                            invalid_file_name
                                        )
                                    end,
                                    fun(Patch@2) ->
                                        Version = case gleam@list:find(
                                            erlang:element(2, Manifest),
                                            fun(It) ->
                                                erlang:element(2, It) =:= erlang:element(
                                                    3,
                                                    Patch@2
                                                )
                                            end
                                        ) of
                                            {ok, Manifest_package} ->
                                                case Manifest_package of
                                                    {git_package,
                                                        _,
                                                        _,
                                                        _,
                                                        _,
                                                        _,
                                                        _} ->
                                                        _pipe@5 = erlang:element(
                                                            3,
                                                            Manifest_package
                                                        ),
                                                        {ok, _pipe@5};

                                                    {path_package,
                                                        _,
                                                        _,
                                                        _,
                                                        _,
                                                        _} ->
                                                        _pipe@5 = erlang:element(
                                                            3,
                                                            Manifest_package
                                                        ),
                                                        {ok, _pipe@5};

                                                    {hex_package,
                                                        _,
                                                        _,
                                                        _,
                                                        _,
                                                        _,
                                                        _} ->
                                                        _pipe@5 = erlang:element(
                                                            3,
                                                            Manifest_package
                                                        ),
                                                        {ok, _pipe@5}
                                                end;

                                            {error, nil} ->
                                                {error,
                                                    dependency_does_not_exist}
                                        end,
                                        gleam@result:'try'(
                                            Version,
                                            fun(Version@1) ->
                                                Actual_version = case Version@1
                                                =:= erlang:element(4, Patch@2) of
                                                    true ->
                                                        none;

                                                    false ->
                                                        {some, Version@1}
                                                end,
                                                gleam@result:'try'(
                                                    begin
                                                        _pipe@6 = child_process:new_with_path(
                                                            <<"git"/utf8>>
                                                        ),
                                                        _pipe@7 = child_process:cwd(
                                                            _pipe@6,
                                                            <<"."/utf8>>
                                                        ),
                                                        _pipe@8 = child_process:args(
                                                            _pipe@7,
                                                            [<<"apply"/utf8>>,
                                                                <<"--directory=build/packages/"/utf8,
                                                                    (erlang:element(
                                                                        3,
                                                                        Patch@2
                                                                    ))/binary>>,
                                                                erlang:element(
                                                                    2,
                                                                    Patch@2
                                                                )]
                                                        ),
                                                        _pipe@9 = child_process:run(
                                                            _pipe@8
                                                        ),
                                                        gleam@result:map_error(
                                                            _pipe@9,
                                                            fun(Err) ->
                                                                _pipe@10 = gleam@string:inspect(
                                                                    Err
                                                                ),
                                                                _pipe@11 = snag:new(
                                                                    _pipe@10
                                                                ),
                                                                _pipe@12 = snag:layer(
                                                                    _pipe@11,
                                                                    <<"Cannot start git"/utf8>>
                                                                ),
                                                                {git_apply_error,
                                                                    _pipe@12,
                                                                    Actual_version}
                                                            end
                                                        )
                                                    end,
                                                    fun(_use0) ->
                                                        {output, Code, _} = _use0,
                                                        case Code of
                                                            0 ->
                                                                {ok, nil};

                                                            _ ->
                                                                gleam@result:'try'(
                                                                    begin
                                                                        _pipe@13 = child_process:new_with_path(
                                                                            <<"git"/utf8>>
                                                                        ),
                                                                        _pipe@14 = child_process:cwd(
                                                                            _pipe@13,
                                                                            <<"."/utf8>>
                                                                        ),
                                                                        _pipe@15 = child_process:args(
                                                                            _pipe@14,
                                                                            [<<"apply"/utf8>>,
                                                                                <<"--check"/utf8>>,
                                                                                <<"--reverse"/utf8>>,
                                                                                <<"--directory=build/packages/"/utf8,
                                                                                    (erlang:element(
                                                                                        3,
                                                                                        Patch@2
                                                                                    ))/binary>>,
                                                                                erlang:element(
                                                                                    2,
                                                                                    Patch@2
                                                                                )]
                                                                        ),
                                                                        _pipe@16 = child_process:run(
                                                                            _pipe@15
                                                                        ),
                                                                        gleam@result:map_error(
                                                                            _pipe@16,
                                                                            fun(
                                                                                Err@1
                                                                            ) ->
                                                                                _pipe@17 = gleam@string:inspect(
                                                                                    Err@1
                                                                                ),
                                                                                _pipe@18 = snag:new(
                                                                                    _pipe@17
                                                                                ),
                                                                                _pipe@19 = snag:layer(
                                                                                    _pipe@18,
                                                                                    <<"Cannot start git"/utf8>>
                                                                                ),
                                                                                {git_apply_error,
                                                                                    _pipe@19,
                                                                                    Actual_version}
                                                                            end
                                                                        )
                                                                    end,
                                                                    fun(_use0@1) ->
                                                                        {output,
                                                                            Code@1,
                                                                            Text} = _use0@1,
                                                                        gleam@bool:guard(
                                                                            Code@1
                                                                            /= 0,
                                                                            {error,
                                                                                {git_apply_error,
                                                                                    begin
                                                                                        _pipe@20 = snag:new(
                                                                                            <<"git error: "/utf8,
                                                                                                Text/binary>>
                                                                                        ),
                                                                                        snag:layer(
                                                                                            _pipe@20,
                                                                                            <<"Cannot apply patch"/utf8>>
                                                                                        )
                                                                                    end,
                                                                                    Actual_version}},
                                                                            fun(
                                                                                
                                                                            ) ->
                                                                                {error,
                                                                                    patch_already_applied}
                                                                            end
                                                                        )
                                                                    end
                                                                )
                                                        end
                                                    end
                                                )
                                            end
                                        )
                                    end
                                )
                            end,
                            case Result of
                                {ok, nil} ->
                                    {[Name@2 | Successes], Errors, Ignored};

                                {error, Err@2} ->
                                    case Err@2 of
                                        invalid_file_name ->
                                            {Successes,
                                                [{Name@2,
                                                        snag:new(
                                                            <<"Cannot parse file name"/utf8>>
                                                        )} |
                                                    Errors],
                                                Ignored};

                                        {git_apply_error,
                                            Snag,
                                            Expected_version} ->
                                            Snag@1 = case Expected_version of
                                                {some, Version@2} ->
                                                    snag:layer(
                                                        Snag,
                                                        <<"Package version mismatch, actual version is "/utf8,
                                                            Version@2/binary>>
                                                    );

                                                none ->
                                                    Snag
                                            end,
                                            {Successes,
                                                [{Name@2, Snag@1} | Errors],
                                                Ignored};

                                        dependency_does_not_exist ->
                                            {Successes,
                                                [{Name@2,
                                                        snag:new(
                                                            <<"Dependency does not exist in manifest.toml"/utf8>>
                                                        )} |
                                                    Errors],
                                                Ignored};

                                        patch_already_applied ->
                                            {Successes,
                                                Errors,
                                                [Name@2 | Ignored]}
                                    end
                            end
                        end
                    ),
                    {ok, _pipe@21}
                end
            )
        end
    ).

-file("src/kludge.gleam", 44).
-spec main() -> nil.
main() ->
    case erlang:element(4, argv:load()) of
        [] ->
            case apply_patches() of
                {ok, {[], [], _}} ->
                    gleam_stdlib:println(<<"No patches left to apply"/utf8>>);

                {ok, {Success, Failure, Ignored}} ->
                    Success_count = begin
                        _pipe = Success,
                        erlang:length(_pipe)
                    end,
                    Success_msg = case Success_count of
                        0 ->
                            <<""/utf8>>;

                        _ ->
                            Applied = begin
                                _pipe@1 = Success,
                                _pipe@2 = gleam@list:map(
                                    _pipe@1,
                                    fun(Path) -> <<"* "/utf8, Path/binary>> end
                                ),
                                gleam@string:join(_pipe@2, <<"\n"/utf8>>)
                            end,
                            <<<<<<<<<<"Successfully applied "/utf8,
                                                (begin
                                                    _pipe@3 = Success_count,
                                                    erlang:integer_to_binary(
                                                        _pipe@3
                                                    )
                                                end)/binary>>/binary,
                                            " "/utf8>>/binary,
                                        (patch_plural(Success_count))/binary>>/binary,
                                    "\n"/utf8>>/binary,
                                Applied/binary>>
                    end,
                    Failure_count = begin
                        _pipe@4 = Failure,
                        erlang:length(_pipe@4)
                    end,
                    Failure_msg = case Failure_count of
                        0 ->
                            <<""/utf8>>;

                        _ ->
                            Failures = begin
                                _pipe@5 = Failure,
                                _pipe@6 = gleam@list:map(
                                    _pipe@5,
                                    fun(Path@1) ->
                                        <<<<<<"* "/utf8,
                                                    (erlang:element(1, Path@1))/binary>>/binary,
                                                " - "/utf8>>/binary,
                                            (snag:line_print(
                                                erlang:element(2, Path@1)
                                            ))/binary>>
                                    end
                                ),
                                gleam@string:join(_pipe@6, <<"\n"/utf8>>)
                            end,
                            <<<<<<<<<<"Failed to apply "/utf8,
                                                (begin
                                                    _pipe@7 = Failure_count,
                                                    erlang:integer_to_binary(
                                                        _pipe@7
                                                    )
                                                end)/binary>>/binary,
                                            " "/utf8>>/binary,
                                        (patch_plural(Failure_count))/binary>>/binary,
                                    "\n"/utf8>>/binary,
                                Failures/binary>>
                    end,
                    Ignored_count = begin
                        _pipe@8 = Ignored,
                        erlang:length(_pipe@8)
                    end,
                    Ignored_msg = case Ignored_count of
                        0 ->
                            <<""/utf8>>;

                        1 ->
                            <<"There is 1 patch that was already applied"/utf8>>;

                        _ ->
                            <<<<<<<<"There are "/utf8,
                                            (begin
                                                _pipe@9 = Ignored_count,
                                                erlang:integer_to_binary(
                                                    _pipe@9
                                                )
                                            end)/binary>>/binary,
                                        " "/utf8>>/binary,
                                    (patch_plural(Ignored_count))/binary>>/binary,
                                " that were already applied"/utf8>>
                    end,
                    _pipe@10 = [Success_msg, Failure_msg, Ignored_msg],
                    _pipe@13 = gleam@list:filter(
                        _pipe@10,
                        fun(It) -> _pipe@11 = It,
                            _pipe@12 = gleam@string:is_empty(_pipe@11),
                            gleam@bool:negate(_pipe@12) end
                    ),
                    _pipe@14 = gleam@string:join(_pipe@13, <<"\n"/utf8>>),
                    gleam_stdlib:println(_pipe@14);

                {error, Err} ->
                    gleam_stdlib:println(snag:pretty_print(Err))
            end;

        [<<"--help"/utf8>>] ->
            print_help();

        [<<"-h"/utf8>>] ->
            print_help();

        [<<"help"/utf8>>] ->
            print_help();

        [Package] ->
            case find_patches(Package) of
                {ok, Diff} ->
                    gleam_stdlib:println(
                        <<"Wrote patch to "/utf8, Diff/binary>>
                    );

                {error, Err@1} ->
                    gleam_stdlib:println(snag:pretty_print(Err@1))
            end;

        _ ->
            print_help()
    end,
    nil.