aboutsummaryrefslogtreecommitdiff
path: root/src/cli_ffi.erl
blob: 3cc77aa569c8c60e0786b62352a66f4ba8a115f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
-module(cli_ffi).
-export([
    get_cpu/0,
    get_esbuild/1,
    get_os/0,
    unzip_esbuild/1,
    exec/3
]).

get_os() ->
    case os:type() of
        {win32, _} -> <<"win32">>;
        {unix, darwin} -> <<"darwin">>;
        {unix, linux} -> <<"linux">>;
        {_, Unknown} -> atom_to_binary(Unknown, utf8)
    end.

get_cpu() ->
    case erlang:system_info(os_type) of
        {unix, _} ->
            [Arch, _] = string:split(erlang:system_info(system_architecture), "-"),
            list_to_binary(Arch);
        {win32, _} ->
            case erlang:system_info(wordsize) of
                4 -> {ok, <<"ia32">>};
                8 -> {ok, <<"x64">>}
            end
    end.

get_esbuild(Url) ->
    inets:start(),
    ssl:start(),

    case httpc:request(get, {Url, []}, [], [{body_format, binary}]) of
        {ok, {{_, 200, _}, _, Zip}} -> {ok, Zip};
        {ok, Res} -> {error, Res};
        {error, Err} -> {error, Err}
    end.

unzip_esbuild(Zip) ->
    Result =
        erl_tar:extract({binary, Zip}, [
            memory, compressed, {files, ["package/bin/esbuild"]}
        ]),

    case Result of
        {ok, [{_, Esbuild}]} -> {ok, Esbuild};
        {ok, Res} -> {error, Res};
        {error, Err} -> {error, Err}
    end.

exec(Command, Args, Cwd) ->
    Command_ = binary_to_list(Command),
    Args_ = lists:map(fun(Arg) -> binary_to_list(Arg) end, Args),
    Cwd_ = binary_to_list(Cwd),

    Name = case Command_ of
      "./" ++ _ -> {spawn_executable, Command_};
      "/" ++ _ -> {spawn_executable, Command_};
      _ -> {spawn_executable, os:find_executable(Command_)}
    end,

    Port = open_port(Name, [exit_status, binary, hide, stream, eof,
        {args, Args_},
        {cd, Cwd_}
    ]),

    do_exec(Port, []).

do_exec(Port, Acc) ->
    receive
        {Port, {data, Data}} -> do_exec(Port, [Data | Acc]);
        {Port, {exit_status, 0}} -> {ok, list_to_binary(lists:reverse(Acc))};
        {Port, {exit_status, Code}} -> {error, {Code, list_to_binary(lists:reverse(Acc))}}
    end.