Current section
Files
Jump to
Current section
Files
src/parrot_ffi.erl
-module(parrot_ffi).
-export([get_cpu/0, get_os/0, download_file/1, download_zip/1, extract_sqlc_binary/1, extract_sqlc_from_targz/1]).
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 ->
<<"ia32">>;
8 ->
<<"x64">>
end
end.
%% Generic file download function
download_file(Url) ->
case httpc:request(get, {Url, []}, [{timeout, 30000}], [{body_format, binary}]) of
{ok, {{_, 200, _}, _Headers, Body}} ->
{ok, Body};
{ok, {{_, StatusCode, _}, _Headers, _Body}} ->
{error, {http_error, StatusCode}};
{error, Reason} ->
{error, Reason}
end.
%% Backward compatibility - alias for download_file
download_zip(Url) ->
download_file(Url).
%% Extract sqlc binary from either zip or tar.gz archive
extract_sqlc_binary(ArchiveData) ->
case detect_archive_type(ArchiveData) of
zip ->
extract_from_zip(ArchiveData);
targz ->
extract_from_targz(ArchiveData);
{error, Reason} ->
{error, Reason}
end.
%% Extract sqlc binary from tar.gz archive
extract_sqlc_from_targz(TarGzData) ->
extract_from_targz(TarGzData).
%% Helper function to detect archive type by magic bytes
detect_archive_type(<<16#1F, 16#8B, _/binary>>) ->
% Gzip magic bytes (tar.gz files start with gzip header)
targz;
detect_archive_type(<<16#50, 16#4B, 16#03, 16#04, _/binary>>) ->
% ZIP magic bytes (local file header signature)
zip;
detect_archive_type(<<16#50, 16#4B, 16#05, 16#06, _/binary>>) ->
% ZIP magic bytes (end of central directory signature)
zip;
detect_archive_type(<<16#50, 16#4B, 16#07, 16#08, _/binary>>) ->
% ZIP magic bytes (data descriptor signature)
zip;
detect_archive_type(_) ->
{error, unknown_archive_type}.
%% Extract from ZIP archive
extract_from_zip(ZipData) ->
case zip:unzip(ZipData, [memory]) of
{ok, FileList} ->
find_sqlc_binary(FileList);
{error, Reason} ->
{error, {zip_error, Reason}}
end.
%% Extract from tar.gz archive
extract_from_targz(TarGzData) ->
case extract_tar_gz(TarGzData) of
{ok, TarData} ->
case erl_tar:extract({binary, TarData}, [memory]) of
{ok, FileList} ->
find_sqlc_binary(FileList);
{error, Reason} ->
{error, {tar_extract_error, Reason}}
end;
{error, Reason} ->
{error, Reason}
end.
%% Helper function to decompress gzip data
extract_tar_gz(TarGzData) ->
try
TarData = zlib:gunzip(TarGzData),
{ok, TarData}
catch
error:Reason ->
{error, {gzip_error, Reason}}
end.
%% Helper function to find sqlc binary in file list
find_sqlc_binary(FileList) ->
case find_sqlc_in_files(FileList) of
{ok, Data} ->
{ok, Data};
not_found ->
{error, file_not_found}
end.
%% Recursively search for sqlc binary in file list
find_sqlc_in_files([]) ->
not_found;
find_sqlc_in_files([{Filename, Data} | Rest]) ->
case is_sqlc_binary(Filename) of
true ->
{ok, Data};
false ->
find_sqlc_in_files(Rest)
end.
%% Check if filename indicates it's the sqlc binary
is_sqlc_binary(Filename) ->
% Convert to string for easier manipulation
FilenameStr = binary_to_list(iolist_to_binary(Filename)),
% Check for exact match or sqlc with extension
case filename:basename(FilenameStr) of
"sqlc" -> true;
"sqlc.exe" -> true;
_ -> false
end.