Lustre's CLI and development tooling: zero-config dev server, bundling, and scaffolding.
at main 153 lines 4.3 kB view raw
1-module(lustre_dev_tools_ffi). 2-export([ 3 check_live_reloading/0, 4 fs_start_link/2, 5 get_cwd/0, 6 get_cpu/0, 7 get_esbuild/1, 8 get_tailwind/1, 9 get_os/0, 10 otp_version/0, 11 unzip_esbuild/1, 12 exec/3 13]). 14 15otp_version() -> 16 Version = erlang:system_info(otp_release), 17 list_to_binary(Version). 18 19get_cwd() -> 20 case file:get_cwd() of 21 {ok, Cwd} -> {ok, list_to_binary(Cwd)}; 22 {error, Reason} -> {error, Reason} 23 end. 24 25get_os() -> 26 case os:type() of 27 {win32, _} -> <<"win32">>; 28 {unix, darwin} -> <<"darwin">>; 29 {unix, linux} -> <<"linux">>; 30 {_, Unknown} -> atom_to_binary(Unknown, utf8) 31 end. 32 33get_cpu() -> 34 case erlang:system_info(os_type) of 35 {unix, _} -> 36 [Arch, _] = string:split(erlang:system_info(system_architecture), "-"), 37 list_to_binary(Arch); 38 {win32, _} -> 39 case erlang:system_info(wordsize) of 40 4 -> <<"ia32">>; 41 8 -> <<"x64">> 42 end 43 end. 44 45get_esbuild(Url) -> 46 inets:start(), 47 ssl:start(), 48 49 case httpc:request(get, {Url, []}, [], [{body_format, binary}]) of 50 {ok, {{_, 200, _}, _, Zip}} -> {ok, Zip}; 51 {ok, Res} -> {error, Res}; 52 {error, Err} -> {error, Err} 53 end. 54 55get_tailwind(Url) -> 56 inets:start(), 57 ssl:start(), 58 59 case httpc:request(get, {Url, []}, [], [{body_format, binary}]) of 60 {ok, {{_, 200, _}, _, Bin}} -> {ok, Bin}; 61 {ok, Res} -> {error, Res}; 62 {error, Err} -> {error, Err} 63 end. 64 65unzip_esbuild(Zip) -> 66 Filepath = 67 case os:type() of 68 {win32, _} -> "package/esbuild.exe"; 69 _ -> "package/bin/esbuild" 70 end, 71 72 Result = 73 erl_tar:extract({binary, Zip}, [ 74 memory, compressed, {files, [Filepath]} 75 ]), 76 77 case Result of 78 {ok, [{_, Esbuild}]} -> {ok, Esbuild}; 79 {ok, Res} -> {error, Res}; 80 {error, Err} -> {error, Err} 81 end. 82 83exec(Command, Args, Cwd) -> 84 Command_ = binary_to_list(Command), 85 Args_ = lists:map(fun(Arg) -> binary_to_list(Arg) end, Args), 86 Cwd_ = binary_to_list(Cwd), 87 88 Name = case Command_ of 89 "./" ++ _ -> {spawn_executable, Command_}; 90 "/" ++ _ -> {spawn_executable, Command_}; 91 _ -> {spawn_executable, os:find_executable(Command_)} 92 end, 93 94 Port = open_port(Name, [ 95 exit_status, 96 binary, 97 hide, 98 stream, 99 eof, 100 stderr_to_stdout, % We need this to hide the process' stdout 101 {args, Args_}, 102 {cd, Cwd_} 103 ]), 104 105 do_exec(Port, []). 106 107do_exec(Port, Acc) -> 108 receive 109 {Port, {data, Data}} -> do_exec(Port, [Data | Acc]); 110 {Port, {exit_status, 0}} -> 111 port_close(Port), 112 {ok, list_to_binary(lists:reverse(Acc))}; 113 {Port, {exit_status, Code}} -> 114 port_close(Port), 115 {error, {Code, list_to_binary(lists:reverse(Acc))}} 116 end. 117 118fs_start_link(Id, Path) -> 119 % We temporarily disable all logs when we call `start_link` because we want 120 % to be displaying a nicer custom error message and not the logged error 121 % coming from `fs`. 122 logger:add_primary_filter(discard_all, {fun(_, _) -> stop end, no_extra}), 123 Result = fs:start_link(Id, Path), 124 logger:remove_primary_filter(discard_all), 125 Result. 126 127% This is what the underlying `fs` library does to check if it has support for 128% a given os: 129% 130% https://github.com/5HT/fs/blob/23a5b46b033437a3d69504811ae6c72f7704a78a/src/fs_sup.erl#L18-L46 131% 132% Sadly the library doesn't expose such a function and just logs any error 133% instead of surfacing it as a value, so we have to implement a slightly 134% modified version of it to have proper error messages. 135check_live_reloading() -> 136 Watcher = 137 case os:type() of 138 {unix, darwin} -> fsevents; 139 {unix, linux} -> inotifywait; 140 {unix, sunos} -> undefined; 141 {unix, _} -> kqueue; 142 {win32, nt} -> inotifywait_win32; 143 _ -> undefined 144 end, 145 146 case Watcher of 147 undefined -> {error, no_file_watcher_supported_for_os}; 148 _ -> 149 case Watcher:find_executable() of 150 false -> {error, {no_file_watcher_installed, Watcher}}; 151 _ -> {ok, nil} 152 end 153 end.