carmel: init a basic software package builder
This commit is contained in:
parent
167b99c4e2
commit
537c0bd446
7 changed files with 369 additions and 0 deletions
3
programs/carmel/.gitignore
vendored
Normal file
3
programs/carmel/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.o
|
||||||
|
*.tar.gz
|
||||||
|
carmel-build
|
20
programs/carmel/Makefile
Normal file
20
programs/carmel/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
CC = cc
|
||||||
|
CFLAGS = -std=c99 -pedantic -Wall -Wextra \
|
||||||
|
$(shell pkg-config --cflags iniparser)
|
||||||
|
LDFLAGS = -liniparser
|
||||||
|
OBJS = carmel-build.o util.o
|
||||||
|
|
||||||
|
all: carmel-build
|
||||||
|
|
||||||
|
carmel-build: ${OBJS}
|
||||||
|
cc ${CFLAGS} -o $@ ${OBJS} ${LDFLAGS}
|
||||||
|
|
||||||
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} ${CFLAGS} -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f carmel-build ${OBJS}
|
||||||
|
|
||||||
|
.PHONY: all clean
|
248
programs/carmel/carmel-build.c
Normal file
248
programs/carmel/carmel-build.c
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
/*
|
||||||
|
* carmel-build
|
||||||
|
* Copyright (c) 2024 Jeremy Baxter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <iniparser.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
char *description;
|
||||||
|
char *version;
|
||||||
|
char *builder;
|
||||||
|
} manifest;
|
||||||
|
|
||||||
|
static const char *buildBase = "/tmp/carmel-";
|
||||||
|
static const char *defaultOutputFile = "auto";
|
||||||
|
static const char *defaultPackageName = "void";
|
||||||
|
static const char *defaultPackageVersion = "0";
|
||||||
|
static const char *defaultPackageBuilder = "builder.sh";
|
||||||
|
static bool oflag, vflag;
|
||||||
|
|
||||||
|
#define WARNV(...) if (vflag) warnx(__VA_ARGS__)
|
||||||
|
|
||||||
|
void
|
||||||
|
builder(const char *script)
|
||||||
|
{
|
||||||
|
FILE *proc;
|
||||||
|
ssize_t ret;
|
||||||
|
int fd;
|
||||||
|
char ch[1];
|
||||||
|
|
||||||
|
proc = popen("sh", "w");
|
||||||
|
fd = open(script, O_RDONLY);
|
||||||
|
|
||||||
|
if (!proc)
|
||||||
|
err(1, "cannot execute shell");
|
||||||
|
if (fd == -1)
|
||||||
|
err(1, "cannot open %s", script);
|
||||||
|
|
||||||
|
while ((ret = read(fd, &ch, 1)) > 0) {
|
||||||
|
fwrite(ch, sizeof(char), 1, proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
err(1, "cannot read from %s", script);
|
||||||
|
|
||||||
|
pclose(proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KEY(name, def) strdup(iniparser_getstring(ini, (":" name), (def)))
|
||||||
|
|
||||||
|
manifest
|
||||||
|
makeManifest(const char *path)
|
||||||
|
{
|
||||||
|
dictionary *ini;
|
||||||
|
manifest m;
|
||||||
|
|
||||||
|
ini = iniparser_load(path);
|
||||||
|
m.name = KEY("name", defaultPackageName);
|
||||||
|
m.description = KEY("description", "");
|
||||||
|
m.version = KEY("version", defaultPackageVersion);
|
||||||
|
m.builder = KEY("builder", defaultPackageBuilder);
|
||||||
|
iniparser_freedict(ini);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef KEY
|
||||||
|
|
||||||
|
void
|
||||||
|
freeManifest(manifest *m)
|
||||||
|
{
|
||||||
|
free(m->name);
|
||||||
|
free(m->description);
|
||||||
|
free(m->version);
|
||||||
|
free(m->builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
makeDirectory(const char *path)
|
||||||
|
{
|
||||||
|
if (mkdir(path, 0710) == -1)
|
||||||
|
err(1, "cannot create directory '%s'", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sh(const char *command)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = system(command);
|
||||||
|
if (ret == -1)
|
||||||
|
err(1, "system");
|
||||||
|
if (WEXITSTATUS(ret) != 0)
|
||||||
|
errx(1, "command failed with exit code %d: %s", ret, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
workingDirectory(void)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = 64;
|
||||||
|
do {
|
||||||
|
buffer = malloc(len * sizeof(char));
|
||||||
|
len *= 2;
|
||||||
|
} while (getcwd(buffer, len) == NULL);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeTo(const char *path, const char *contents)
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
|
||||||
|
fd = open(path, O_WRONLY | O_CREAT, 0644);
|
||||||
|
for (i = 0; contents[i] != 0; i++)
|
||||||
|
write(fd, (char[]){contents[i]}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
manifest m;
|
||||||
|
char *buildDirectory;
|
||||||
|
char *outputFile;
|
||||||
|
char *startDirectory;
|
||||||
|
size_t buildDirectoryLen, outputFileLen;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
outputFileLen = strlen(defaultOutputFile) + 1;
|
||||||
|
outputFile = malloc(outputFileLen * sizeof(char));
|
||||||
|
strbcpy(outputFile, defaultOutputFile, outputFileLen);
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "C:o:v")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'C':
|
||||||
|
changeDirectory(optarg);
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
oflag = 1;
|
||||||
|
outputFileLen = strlen(optarg) + 1;
|
||||||
|
outputFile = malloc(outputFileLen * sizeof(char));
|
||||||
|
strbcpy(outputFile, optarg, outputFileLen);
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
vflag = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - optind != 1) {
|
||||||
|
fputs("usage: carmel-build [-v] [-C directory] [-o output] manifest\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
startDirectory = workingDirectory();
|
||||||
|
|
||||||
|
if (!exists(argv[optind]))
|
||||||
|
errx(1, "cannot open %s", argv[optind]);
|
||||||
|
m = makeManifest(argv[optind]);
|
||||||
|
|
||||||
|
if (strcmp(m.name, defaultPackageName) == 0)
|
||||||
|
warnx("manifest name not provided; using '%s'", m.name);
|
||||||
|
if (strcmp(m.version, defaultPackageVersion) == 0)
|
||||||
|
warnx("manifest version not provided; using '%s'", m.version);
|
||||||
|
if (strlen(m.builder) == 0)
|
||||||
|
errx(1, "manifest builder not provided; using '%s'", m.builder);
|
||||||
|
|
||||||
|
if (strcmp(outputFile, defaultOutputFile) == 0) {
|
||||||
|
char *extension = ".tar.gz";
|
||||||
|
outputFileLen = strlen(m.name) + 1 + strlen(m.version)
|
||||||
|
+ strlen(extension) + 1;
|
||||||
|
outputFile = malloc(outputFileLen * sizeof(char));
|
||||||
|
snprintf(outputFile, outputFileLen, "%s-%s%s",
|
||||||
|
m.name, m.version, extension);
|
||||||
|
}
|
||||||
|
WARNV("building %s", outputFile);
|
||||||
|
|
||||||
|
/* PIDs up to 7 digits */
|
||||||
|
buildDirectoryLen = strlen(buildBase) + 8;
|
||||||
|
buildDirectory = malloc(buildDirectoryLen * sizeof(char));
|
||||||
|
snprintf(buildDirectory, buildDirectoryLen, "%s%d",
|
||||||
|
buildBase, getpid());
|
||||||
|
|
||||||
|
WARNV("entering build origin");
|
||||||
|
makeDirectory(buildDirectory);
|
||||||
|
changeDirectory(buildDirectory);
|
||||||
|
makeDirectory("origin");
|
||||||
|
changeDirectory("origin");
|
||||||
|
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = strlen(startDirectory) + 1 + strlen(m.builder) + 1;
|
||||||
|
buffer = malloc(len * sizeof(char));
|
||||||
|
snprintf(buffer, len, "%s/%s", startDirectory, m.builder);
|
||||||
|
copyFile(buffer, "builder.sh");
|
||||||
|
}
|
||||||
|
|
||||||
|
WARNV("executing builder");
|
||||||
|
setenv("out", buildDirectory, 1);
|
||||||
|
builder("builder.sh");
|
||||||
|
|
||||||
|
changeDirectory("..");
|
||||||
|
sh("rm -fr origin/");
|
||||||
|
|
||||||
|
WARNV("writing to carmel-meta");
|
||||||
|
makeDirectory("carmel-meta");
|
||||||
|
changeDirectory("carmel-meta");
|
||||||
|
writeTo("name", m.name);
|
||||||
|
writeTo("description", m.description);
|
||||||
|
writeTo("version", m.version);
|
||||||
|
|
||||||
|
WARNV("making tarball");
|
||||||
|
setenv("out", outputFile, 1);
|
||||||
|
setenv("start", startDirectory, 1);
|
||||||
|
setenv("build", buildDirectory, 1);
|
||||||
|
changeDirectory(buildDirectory);
|
||||||
|
sh("tar -czf \"$out\" *");
|
||||||
|
sh("mv \"$out\" \"$start\"/");
|
||||||
|
changeDirectory(startDirectory);
|
||||||
|
sh("rm -fr \"$build\"");
|
||||||
|
|
||||||
|
freeManifest(&m);
|
||||||
|
free(outputFile);
|
||||||
|
free(startDirectory);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
programs/carmel/packages/callisto/builder.sh
Normal file
5
programs/carmel/packages/callisto/builder.sh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
curl -L https://git.sr.ht/~jeremy/callisto/archive/master.tar.gz | tar -xz
|
||||||
|
cd callisto-master
|
||||||
|
./configure -wreadline
|
||||||
|
make
|
||||||
|
make install PREFIX=/usr/local DESTDIR=$out
|
3
programs/carmel/packages/callisto/manifest.ini
Normal file
3
programs/carmel/packages/callisto/manifest.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
name = callisto
|
||||||
|
version = 0.1-master
|
||||||
|
description = runtime environment for Lua under POSIX
|
76
programs/carmel/util.c
Normal file
76
programs/carmel/util.c
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
copyFile(const char *source, const char *dest)
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
ssize_t ret;
|
||||||
|
int s, d;
|
||||||
|
|
||||||
|
if ((s = open(source, O_RDONLY)) == -1)
|
||||||
|
err(1, "cannot open %s", source);
|
||||||
|
if ((d = open(dest, O_WRONLY | O_CREAT, 0644)) == -1)
|
||||||
|
err(1, "cannot open %s", dest);
|
||||||
|
|
||||||
|
while ((ret = read(s, &buffer, 1024)) > 0) {
|
||||||
|
write(d, buffer, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
err(1, "cannot read from %s", source);
|
||||||
|
|
||||||
|
close(s);
|
||||||
|
close(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
changeDirectory(const char *path)
|
||||||
|
{
|
||||||
|
if (chdir(path) == -1)
|
||||||
|
err(1, "cd '%s'", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
exists(const char *path)
|
||||||
|
{
|
||||||
|
if (open(path, O_RDONLY) == -1) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy string src to buffer dst of size dsize. At most dsize-1
|
||||||
|
* chars will be copied. Always NUL terminates (unless dsize == 0).
|
||||||
|
* Returns strlen(src); if retval >= dsize, truncation occurred.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
strbcpy(char *dst, const char *src, size_t dsize)
|
||||||
|
{
|
||||||
|
const char *osrc = src;
|
||||||
|
size_t nleft = dsize;
|
||||||
|
|
||||||
|
/* Copy as many bytes as will fit. */
|
||||||
|
if (nleft != 0) {
|
||||||
|
while (--nleft != 0) {
|
||||||
|
if ((*dst++ = *src++) == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not enough room in dst, add NUL and traverse rest of src. */
|
||||||
|
if (nleft == 0) {
|
||||||
|
if (dsize != 0)
|
||||||
|
*dst = '\0'; /* NUL-terminate dst */
|
||||||
|
while (*src++)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (src - osrc - 1); /* count does not include NUL */
|
||||||
|
}
|
14
programs/carmel/util.h
Normal file
14
programs/carmel/util.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef _UTIL_H_
|
||||||
|
#define _UTIL_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef char byte;
|
||||||
|
typedef byte bool;
|
||||||
|
|
||||||
|
void copyFile(const char *, const char *);
|
||||||
|
void changeDirectory(const char *);
|
||||||
|
bool exists(const char *);
|
||||||
|
size_t strbcpy(char *, const char *, size_t);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue