Vendor fetch.

This commit is contained in:
Christoffer Lerno
2023-01-06 14:00:51 +01:00
committed by Christoffer Lerno
parent ad48770977
commit 38be3d57dd
12 changed files with 210 additions and 5 deletions

View File

@@ -76,6 +76,7 @@ static void usage(void)
OUTPUT(" static-lib <file1> [<file2> ...] Compile files without a project into a static library.");
OUTPUT(" dynamic-lib <file1> [<file2> ...] Compile files without a project into a dynamic library.");
OUTPUT(" headers <file1> [<file2> ...] Analyse files and generate C headers for public methods.");
OUTPUT(" vendor-fetch <library> ... Fetches one or more libraries from the vendor collection.");
OUTPUT("");
OUTPUT("Options:");
OUTPUT(" --tinybackend - Use the TinyBackend for compilation.");
@@ -274,6 +275,17 @@ static void parse_command(BuildOptions *options)
options->command = COMMAND_STATIC_LIB;
return;
}
if (arg_match("vendor-fetch"))
{
options->command = COMMAND_VENDOR_FETCH;
if (at_end() || next_is_opt()) error_exit("error: vendor-fetch needs at least one library.");
while (!at_end() && !next_is_opt())
{
const char *lib = next_arg();
vec_add(options->libraries_to_fetch, lib);
}
return;
}
if (arg_match("dynamic-lib"))
{
options->command = COMMAND_DYNAMIC_LIB;

View File

@@ -33,6 +33,7 @@ typedef enum
COMMAND_RUN,
COMMAND_CLEAN_RUN,
COMMAND_CLEAN,
COMMAND_VENDOR_FETCH,
COMMAND_DIST,
COMMAND_DOCS,
COMMAND_BENCH,
@@ -248,6 +249,7 @@ typedef struct BuildOptions_
const char *sdk_version;
} macos;
int build_threads;
const char** libraries_to_fetch;
const char** files;
const char* output_name;
const char* project_name;

View File

@@ -84,6 +84,7 @@ bool command_is_projectless(CompilerCommand command)
case COMMAND_BENCH:
case COMMAND_PRINT_SYNTAX:
case COMMAND_TEST:
case COMMAND_VENDOR_FETCH:
return false;
}
UNREACHABLE

View File

@@ -574,6 +574,34 @@ static void setup_bool_define(const char *id, bool value)
error_exit("Redefined ident %s", id);
}
}
#if FETCH_AVAILABLE
void vendor_fetch(BuildOptions *options)
{
unsigned count = 0;
FOREACH_BEGIN(const char *lib, options->libraries_to_fetch)
const char *resource = str_printf("/c3lang/vendor/releases/download/latest/%s.c3l", lib);
printf("Fetching library '%s'...", lib);
fflush(stdout);
const char *error = download_file("https://github.com", resource, str_printf("%s.c3l", lib));
if (!error)
{
puts("ok.");
count++;
}
else
{
printf("FAILED: '%s'\n", error);
}
FOREACH_END();
if (count == 0) error_exit("Error: Failed to download any libraries.");
if (count < vec_size(options->libraries_to_fetch)) error_exit("Error: Only some libraries were downloaded.");
}
#else
void vendor_fetch(BuildOptions *options)
{
error_exit("Error: vendor-fetch only available when compiled with cURL.");
}
#endif
void print_syntax(BuildOptions *options)
{

View File

@@ -16,6 +16,7 @@ void init_default_build_target(BuildTarget *target, BuildOptions *options);
void symtab_init(uint32_t max_size);
void symtab_destroy();
void print_syntax(BuildOptions *options);
void vendor_fetch(BuildOptions *options);
extern double compiler_init_time;
extern double compiler_parsing_time;

View File

@@ -69,6 +69,9 @@ int main_real(int argc, const char *argv[])
case COMMAND_CLEAN:
compile_clean(&build_options);
break;
case COMMAND_VENDOR_FETCH:
vendor_fetch(&build_options);
break;
case COMMAND_CLEAN_RUN:
case COMMAND_BUILD:
case COMMAND_RUN:

View File

@@ -38,6 +38,12 @@
#endif
#endif
#if CURL_FOUND || PLATFORM_WINDOWS
#define FETCH_AVAILABLE 1
#else
#define FETCH_AVAILABLE 0
#endif
#define IS_GCC 0
#define IS_CLANG 0
#ifdef __GNUC__

123
src/utils/http.c Normal file
View File

@@ -0,0 +1,123 @@
// Copyright (c) 2023 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "lib.h"
#if PLATFORM_WINDOWS
#include <windows.h>
#include <winhttp.h>
static inline wchar_t *char_to_wchar(const char *str)
{
size_t size = strlen(str) + 1;
wchar_t *wc = malloc(sizeof(wchar_t) * size);
mbstowcs(wc, str, size);
return wc;
}
const char *download_file(const char *url, const char *resource, const char *file_path)
{
LPSTR pszOutBuffer;
bool results = false;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
bool is_https = memcmp("https://", url, 8) == 0;
url = url + (is_https ? 8 : 7);
// Use WinHttpOpen to obtain a session handle.
HINTERNET session = WinHttpOpen(L"C3C/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!session) error_exit("Failed to create http session.");
// Specify an HTTP server.
wchar_t *wurl = char_to_wchar(url);
HINTERNET connect = WinHttpConnect(session, wurl, is_https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
0);
if (!connect) error_exit("Failed to connect to '%s'", url);
free(wurl);
// Create an HTTP request handle.
wchar_t *wresource = char_to_wchar(resource);
HINTERNET request = WinHttpOpenRequest(connect, L"GET", wresource, NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, is_https ? WINHTTP_FLAG_SECURE : 0);
if (!connect) error_exit("Failed to connect to '%s'.", url);
free(wresource);
FILE* file = fopen(file_path, "w+b");
if (!file) return str_printf("Failed to open file '%s' for output", file_path);
// Send a request.
bool result = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
bool success = false;
if (!result || !WinHttpReceiveResponse(request, NULL)) goto END;
char buffer[8192];
while (1)
{
DWORD dw_size = 0;
if (!WinHttpReadData(request, (LPVOID)buffer, sizeof(buffer), &dw_size)) goto END;
fwrite(buffer, (size_t)dw_size, (size_t)1, file);
if (!WinHttpQueryDataAvailable(request, &dw_size)) goto END;
if (!dw_size) break;
}
success = true;
END:
fclose(file);
WinHttpCloseHandle(request);
WinHttpCloseHandle(connect);
WinHttpCloseHandle(session);
if (!success)
{
remove(file_path);
return str_printf("Failed to retrieve '%s%s'.", url, resource);
}
return NULL;
}
#elif CURL_FOUND
#include <curl/curl.h>
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
return fwrite(ptr, size, nmemb, (FILE *)stream);
}
const char *download_file(const char *url, const char *resource, const char *file_path)
{
CURL *curl_handle = curl_easy_init();
if (!curl_handle) error_exit("Could not initialize cURL subsystem.");
FILE* file = fopen(file_path, "w+b");
if (!file) return str_printf("Failed to open file '%s' for output", file_path);
const char *total_url = str_printf("%s%s", url, resource);
curl_easy_setopt(curl_handle, CURLOPT_URL, total_url);
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0L);
// Enable this later
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, file);
CURLcode result = curl_easy_perform(curl_handle);
if (curl_easy_perform(curl_handle) != CURLE_OK)
{
fclose(file);
remove(file_path);
return curl_easy_strerror(result);
}
fclose(file);
return NULL;
}
#endif

View File

@@ -11,6 +11,9 @@
#include "direct.h"
#endif
#if FETCH_AVAILABLE
const char *download_file(const char *url, const char *resource, const char *file_path);
#endif
typedef struct StringSlice_
{

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.4"
#define COMPILER_VERSION "0.4.5"