PAX

 view release on metacpan or  search on metacpan

lib/PAX/AppImage.pm  view on Meta::CPAN

        ? { status => 'built' }
        : { status => 'not_built', reason => 'C launcher compile failed' };
}

# _launcher_source($image)
# Renders the C source for the app-image launcher, including embedded asset
# extraction and Unix-socket request forwarding.
# Input: image metadata hash reference.
# Output: C source string.
sub _launcher_source {
    my ($image) = @_;
    my $socket = _c_string($image->{socket_path});
    my $entrypoint = _c_string($image->{entrypoint});
    my $perl5lib = _c_string(join ':', @{ $image->{lib_dirs} // [] });
    my $asset_root = _c_string($image->{asset_root});
    my $asset_table = _asset_table_c($image->{assets} // []);
    return <<"C";
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>

struct pax_asset {
    const char *path;
    const unsigned char *data;
    unsigned long len;
};

$asset_table

static void ensure_parent_dirs(const char *path) {
    char tmp[4096];
    size_t len = strlen(path);
    if (len >= sizeof(tmp)) return;
    memcpy(tmp, path, len + 1);
    for (char *p = tmp + 1; *p; p++) {
        if (*p == '/') {
            *p = 0;
            mkdir(tmp, 0700);
            *p = '/';
        }
    }
}

static void extract_embedded_assets(void) {
    if (pax_asset_count == 0) return;
    mkdir($asset_root, 0700);
    for (unsigned long i = 0; i < pax_asset_count; i++) {
        char path[4096];
        snprintf(path, sizeof(path), "%s/%s", $asset_root, pax_assets[i].path);
        ensure_parent_dirs(path);
        FILE *out = fopen(path, "wb");
        if (!out) continue;
        fwrite(pax_assets[i].data, 1, pax_assets[i].len, out);
        fclose(out);
    }
    setenv("PAX_EMBEDDED_ASSET_ROOT", $asset_root, 1);
}

static void json_string(FILE *out, const char *s) {
    fputc('"', out);
    for (; *s; s++) {
        if (*s == '"' || *s == '\\\\') { fputc('\\\\', out); fputc(*s, out); }
        else if (*s == '\\n') fputs("\\\\n", out);
        else fputc(*s, out);
    }
    fputc('"', out);
}

static int fallback_exec(int argc, char **argv) {
    extract_embedded_assets();
    if (strlen($perl5lib) > 0) {
        const char *old = getenv("PERL5LIB");
        char merged[8192];
        if (old && strlen(old) > 0) snprintf(merged, sizeof(merged), "%s:%s", $perl5lib, old);
        else snprintf(merged, sizeof(merged), "%s", $perl5lib);
        setenv("PERL5LIB", merged, 1);
    }
    char **next = calloc((size_t)argc + 2, sizeof(char *));
    if (!next) return 111;
    next[0] = "perl";
    next[1] = $entrypoint;
    for (int i = 1; i < argc; i++) next[i + 1] = argv[i];
    execvp("perl", next);
    perror("execvp perl");
    return 111;
}

int main(int argc, char **argv) {
    extract_embedded_assets();
    int fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) return fallback_exec(argc, argv);
    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, $socket, sizeof(addr.sun_path) - 1);
    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) return fallback_exec(argc, argv);

    FILE *stream = fdopen(fd, "r+");
    if (!stream) return fallback_exec(argc, argv);
    fputs("{\\"argv\\":[", stream);
    for (int i = 1; i < argc; i++) {
        if (i > 1) fputc(',', stream);
        json_string(stream, argv[i]);
    }
    fputs("],\\"cwd\\":", stream);
    char cwd[4096];
    if (getcwd(cwd, sizeof(cwd))) json_string(stream, cwd); else json_string(stream, ".");
    fputs("}\\n", stream);
    fflush(stream);

    char buf[8192];
    while (fgets(buf, sizeof(buf), stream)) {
        if (strncmp(buf, "__PAX_EXIT__:", 13) == 0) return atoi(buf + 13);
        fputs(buf, stdout);
    }
    return 0;



( run in 0.785 second using v1.01-cache-2.11-cpan-71847e10f99 )