diff --git a/Shrine/Packages/Pkg/Pkg.HC b/Shrine/Packages/Pkg/Pkg.HC index c2391cce..8f1867b1 100644 --- a/Shrine/Packages/Pkg/Pkg.HC +++ b/Shrine/Packages/Pkg/Pkg.HC @@ -14,9 +14,9 @@ #define PKG_VERSION 10 -static U8* PKG_BASE_URL = "http://shrineupd.ddns.net:8000/packages"; -static U8* PKG_LOCAL_REPO = "::/Misc/Packages"; -static U8* PKG_TMP_DIR = "::/Tmp/PkgTmp"; +static U8* PKG_BASE_URL = "http://shrineupd.ddns.net:8000/packages"; +static U8* PKG_LOCAL_REPO = "::/Misc/Packages"; +static U8* PKG_TMP_DIR = "::/Tmp/PkgTmp"; class CPkgInfo { U8* package_name; @@ -30,6 +30,82 @@ class CPkgInfo { U8* iso_c; }; +// TODO: Is there a built-in for this? +static U8* StripDir(U8* file_path) { + U8* slash = StrLastOcc(file_path, "/"); + + if (slash) + return slash + 1; + else + return file_path; +} + +// If this turns out to be useful, it might be moved into ShrineNet/Url +static I64 UrlGetWithProgress(U8* url, U8** data_out, I64* size_out) { + CUrl curl; + UrlInit(&curl); + + I64 error = 0; + I64 size = 0; + + if (UrlParse(url, &curl)) { + if (!StrCmp(curl.protocol, "http")) { + I64 sock = HttpOpenGet(curl.host, curl.port, curl.path, &size); + + if (sock > 0) { + U8* data = MAlloc(1 + size); + I64 total = 0; + I64 progress = 0; + "[$FG,3$"; + + while (total < size) { + I64 step = size - total; + + if (step > 1024) + step = 1024; + + I64 got = recvall(sock, data + total, step, 0); + + if (got <= 0) { + error = PKG_EEOF; + break; + } + + total += got; + + I64 new_progress = (20 * total + size - 1) / size; + while (progress < new_progress) { + '' 0xfe; + progress++; + } + } + + close(sock); + + if (error) { + "$FG,4$x\n$FG$"; + Free(data); + return error; + } + + "$FG$]\n"; + data[total] = 0; + *data_out = data; + *size_out = total; + } + else + error = sock; + } + else + error = URL_EPROTOCOL; + } + else + error = URL_EPARSE; + + UrlFree(&curl); + return error; +} + U0 PkgInfoInit(CPkgInfo* pinf) { pinf->package_name = 0; @@ -52,6 +128,7 @@ U0 PkgInfoFree(CPkgInfo* pinf) { PkgInfoInit(pinf); } +// Returns 0 or error code I64 PkgParseManifest(CPkgInfo* pinf, U8* manifest) { U8* key = manifest; @@ -95,7 +172,9 @@ I64 PkgParseManifest(CPkgInfo* pinf, U8* manifest) { /*I64 PkgWriteManifest(CPkgInfo* pinf, U8* path) { }*/ -I64 PkgGetPkgInfo(CPkgInfo* pinf, U8* package_name) { +// Downloads a package info from the repository. +// Returns 0 or error code +I64 PkgFetchManifest(CPkgInfo* pinf, U8* package_name) { pinf->package_name = StrNew(package_name); U8* url = MStrPrint("%s/%s", PKG_BASE_URL, package_name); @@ -112,88 +191,27 @@ I64 PkgGetPkgInfo(CPkgInfo* pinf, U8* package_name) { return error; } +// Get the URL of the package's ISO.C download. +// Returns NULL if N/A, otherwise must be Free()d. U8* PkgAllocISOCUrl(CPkgInfo* pinf) { if (!pinf->iso_c) - return 0; + return NULL; + // A bit hacky, but will probably always work if (StrFind("//", pinf->iso_c)) return StrNew(pinf->iso_c); else return MStrPrint("%s/%s", PKG_BASE_URL, pinf->iso_c); } -static I64 UrlGetWithProgress(U8* url, U8** data_out, I64* size_out) { - CUrl curl; - UrlInit(&curl); - - I64 error = 0; - I64 size = 0; - - if (UrlParse(url, &curl)) { - if (!StrCmp(curl.protocol, "http")) { - I64 sock = HttpOpenGet(curl.host, curl.port, curl.path, &size); - - if (sock > 0) { - U8* data = MAlloc(1 + size); - I64 total = 0; - I64 progress = 0; - "[$FG,3$"; - - while (total < size) { - I64 step = size - total; - - if (step > 1024) - step = 1024; - - I64 got = recvall(sock, data + total, step, 0); - - if (got <= 0) { - error = PKG_EEOF; - break; - } - - total += got; - - I64 new_progress = (20 * total + size - 1) / size; - while (progress < new_progress) { - '' 0xfe; - progress++; - } - } - - close(sock); - - if (error) { - "$FG,4$x\n$FG$"; - Free(data); - return error; - } - - "$FG$]\n"; - data[total] = 0; - *data_out = data; - *size_out = total; - } - else - error = sock; - } - else - error = URL_EPROTOCOL; - } - else - error = URL_EPARSE; - - UrlFree(&curl); - return error; -} - -// This only checks if the package is installable IN GENERAL. +// Check if the package is installable IN GENERAL. // You still need to do PkgCheckCompatibility, dependency resolution, // and check for a suitable download format. Bool PkgIsInstallable(CPkgInfo* pinf) { return pinf->version != NULL && pinf->installdir != NULL; } +// Check if the package is compatible with this OS & Pkg version I64 PkgCheckCompatibility(CPkgInfo* pinf) { if (pinf->pkgmin > PKG_VERSION) { "$FG,6$This package requires a more recent version of $FG,5$Pkg\n"; @@ -218,7 +236,12 @@ I64 PkgCheckCompatibility(CPkgInfo* pinf) { return 0; } +// Install a package, using the provided ISO.C file. +// TODO: This will also register the package as installed. I64 PkgInstallISOC(CPkgInfo* pinf, U8* iso_c) { + if (pinf->installdir == NULL) + return PKG_EUNSUITABLE; + I64 error = 0; "Installing %s\n$FG,7$", pinf->package_name; @@ -236,9 +259,9 @@ I64 PkgInstallISOC(CPkgInfo* pinf, U8* iso_c) { return error; } +// Verify, download & install a single package +// All dependencies must have been installed at this point. I64 PkgDownloadAndInstall(CPkgInfo* pinf) { - // Validate Pkg & OS version - I64 error = PkgCheckCompatibility(pinf); if (error) { return error; } @@ -282,7 +305,8 @@ static U8* FormatSize(I64 size) { return buf; } -I64 PkgInstallFromFile(U8* manifest_path) { +// Install a package using a local manifest file +public I64 PkgInstallFromFile(U8* manifest_path) { CPkgInfo pinf; PkgInfoInit(&pinf); @@ -308,14 +332,15 @@ I64 PkgInstallFromFile(U8* manifest_path) { return error; } -I64 PkgInstall(U8* package_name) { +// Install a package from the repository +public I64 PkgInstall(U8* package_name) { SnailInit(); MkDir(PKG_LOCAL_REPO); CPkgInfo pinf; PkgInfoInit(&pinf); - I64 error = PkgGetPkgInfo(&pinf, package_name); + I64 error = PkgFetchManifest(&pinf, package_name); if (error == 0) { if (PkgIsInstallable(&pinf)) { @@ -348,7 +373,7 @@ I64 PkgInstall(U8* package_name) { } } else { - "$FG,4$PkgGetPkgInfo error: %d\n$FG$", error; + "$FG,4$PkgFetchManifest error: %d\n$FG$", error; } PkgInfoFree(&pinf); @@ -356,7 +381,8 @@ I64 PkgInstall(U8* package_name) { return error; } -I64 PkgList() { +// List packages available in the repository +public I64 PkgList() { SnailInit(); U8* url = MStrPrint("%s/packages.list", PKG_BASE_URL); @@ -390,7 +416,8 @@ I64 PkgList() { return error; } -I64 PkgMakeFromDir(U8* manifest_path, U8* src_dir) { +// Build a package from directory contents +public I64 PkgMakeFromDir(U8* manifest_path, U8* src_dir) { CPkgInfo pinf; PkgInfoInit(&pinf); @@ -435,16 +462,7 @@ I64 PkgMakeFromDir(U8* manifest_path, U8* src_dir) { return error; } -// TODO: Is there a built-in for this? -static U8* StripDir(U8* file_path) { - U8* slash = StrLastOcc(file_path, "/"); - - if (slash) - return slash + 1; - else - return file_path; -} - +// Build a package using a single file I64 PkgMakeFromFile(U8* manifest_path, U8* file_path) { DelTree(PKG_TMP_DIR); MkDir(PKG_TMP_DIR);