diff --git a/.dockerignore b/.dockerignore index d55305a..643e6db 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ * -!vieter/ +!src/ !Makefile diff --git a/.gitignore b/.gitignore index 8d15c59..8c67f97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,16 @@ *.c data/ -vieter/vieter + +# Build artifacts +vieter +dvieter +pvieter +vieter.c # Ignore testing files *.pkg* vieter.log + +# External lib; gets added by Makefile +libarchive-* diff --git a/.woodpecker/.build.yml b/.woodpecker/.build.yml new file mode 100644 index 0000000..40a50e1 --- /dev/null +++ b/.woodpecker/.build.yml @@ -0,0 +1,18 @@ +pipeline: + vieter: + image: 'chewingbever/vlang:latest' + group: 'build' + commands: + - make vieter + + debug: + image: 'chewingbever/vlang:latest' + group: 'build' + commands: + - make debug + + prod: + image: 'chewingbever/vlang:latest' + group: 'build' + commands: + - make prod diff --git a/.woodpecker/.lint.yml b/.woodpecker/.lint.yml new file mode 100644 index 0000000..72529e7 --- /dev/null +++ b/.woodpecker/.lint.yml @@ -0,0 +1,5 @@ +pipeline: + lint: + image: 'chewingbever/vlang:latest' + commands: + - make fmt diff --git a/.woodpecker/.publish.yml b/.woodpecker/.publish.yml new file mode 100644 index 0000000..490d422 --- /dev/null +++ b/.woodpecker/.publish.yml @@ -0,0 +1,24 @@ +branches: [main, dev] + +pipeline: + dev: + image: plugins/docker + secrets: [ docker_username, docker_password ] + settings: + repo: chewingbever/vieter + tag: dev + when: + event: push + branch: dev + + release: + image: plugins/docker + secrets: [ docker_username, docker_password ] + settings: + repo: chewingbever/vieter + tag: + - latest + - $CI_COMMIT_TAG + when: + event: tag + branch: main diff --git a/Dockerfile b/Dockerfile index e8b2484..556ca58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,21 @@ -FROM archlinux:latest AS builder +FROM chewingbever/vlang:latest AS builder -WORKDIR /src -COPY vieter ./vieter +WORKDIR /app + +# Copy over source code & build production binary +COPY src ./src COPY Makefile ./ - -RUN pacman \ - -Syu --noconfirm --needed \ - gcc git openssl make && \ - make customv && \ - jjr-v/v -prod vieter +RUN make prod -FROM archlinux:latest +FROM alpine:3.15 ENV REPO_DIR=/data -COPY --from=builder /src/vieter/vieter /usr/local/bin/ +RUN apk update && \ + apk add --no-cache \ + libarchive + +COPY --from=builder /app/pvieter /usr/local/bin/vieter ENTRYPOINT [ "/usr/local/bin/vieter" ] diff --git a/Makefile b/Makefile index a48a802..15c52cd 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,60 @@ +# =====CONFIG===== +SRC_DIR := src +SOURCES != find '$(SRC_DIR)' -iname '*.v' + +LARCHIVE_VER := 3.5.2 +LARCHIVE_DIR := libarchive-$(LARCHIVE_VER) +LARCHIVE_LIB := $(LARCHIVE_DIR)/libarchive/libarchive.so + +# Custom V command for linking libarchive +# V := LDFLAGS=$(PWD)/$(LARCHIVE_LIB) v -cflags '-I$(PWD)/$(LARCHIVE_DIR) -I $(PWD)/$(LARCHIVE_DIR)' +V := v + +all: vieter + +# =====COMPILATION===== +# Regular binary +vieter: $(SOURCES) + $(V) -g -o vieter $(SRC_DIR) + +# Debug build using gcc +.PHONY: debug +debug: dvieter +dvieter: $(SOURCES) + $(V) -keepc -cg -cc gcc -o dvieter $(SRC_DIR) + +# Optimised production build +.PHONY: prod +prod: pvieter +pvieter: $(SOURCES) + $(V) -o pvieter -prod $(SRC_DIR) + +.PHONY: c +c: + $(V) -o vieter.c $(SRC_DIR) + + +# =====EXECUTION===== +# Run the server in the default 'data' directory .PHONY: run -run: - API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG v -cg run vieter +run: vieter + API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG ./vieter .PHONY: run-prod -run-prod: - API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG v -prod run vieter +run-prod: prod + API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG ./vieter-prod +# Same as run, but restart when the source code changes .PHONY: watch watch: - API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG v watch run vieter + API_KEY=test REPO_DIR=data LOG_LEVEL=DEBUG $(V) watch run vieter + +# =====OTHER===== +# Format the V codebase .PHONY: fmt fmt: - v fmt -w vieter + v fmt -w $(SRC_DIR) # Pulls & builds my personal build of the v compiler, required for this project to function .PHONY: customv @@ -23,3 +65,15 @@ customv: --single-branch \ https://github.com/ChewingBever/v jjr-v '$(MAKE)' -C jjr-v + + +# =====LIBARCHIVE===== +.PHONY: libarchive +libarchive: $(LARCHIVE_LIB) +$(LARCHIVE_LIB): + curl -o - "https://libarchive.org/downloads/libarchive-${LARCHIVE_VER}.tar.gz" | tar xzf - + cd "libarchive-${LARCHIVE_VER}" && cmake . + '$(MAKE)' -C "libarchive-${LARCHIVE_VER}" + +clean: + rm -rf '$(LARCHIVE_DIR)' 'data' 'vieter' 'dvieter' 'pvieter' 'vieter.c' diff --git a/src/archive/archive.v b/src/archive/archive.v new file mode 100644 index 0000000..ca911c7 --- /dev/null +++ b/src/archive/archive.v @@ -0,0 +1,43 @@ +module archive + +import os + +pub fn get_pkg_info(pkg_path string) ?string { + if !os.is_file(pkg_path) { + return error("'$pkg_path' doesn't exist or isn't a file.") + } + + a := C.archive_read_new() + entry := C.archive_entry_new() + mut r := 0 + + C.archive_read_support_filter_all(a) + C.archive_read_support_format_all(a) + + // TODO find out where does this 10240 come from + r = C.archive_read_open_filename(a, &char(pkg_path.str), 10240) + defer { + C.archive_read_free(a) + } + + if r != C.ARCHIVE_OK { + return error('Failed to open package.') + } + + // We iterate over every header in search of the .PKGINFO one + mut buf := voidptr(0) + for C.archive_read_next_header(a, &entry) == C.ARCHIVE_OK { + if C.strcmp(C.archive_entry_pathname(entry), c'.PKGINFO') == 0 { + size := C.archive_entry_size(entry) + + // TODO can this unsafe block be avoided? + buf = unsafe { malloc(size) } + C.archive_read_data(a, voidptr(buf), size) + break + } else { + C.archive_read_data_skip(a) + } + } + + return unsafe { cstring_to_vstring(&char(buf)) } +} diff --git a/src/archive/bindings.v b/src/archive/bindings.v new file mode 100644 index 0000000..678d715 --- /dev/null +++ b/src/archive/bindings.v @@ -0,0 +1,46 @@ +module archive + +#flag -larchive + +#include "archive.h" + +struct C.archive {} + +// Create a new archive struct +fn C.archive_read_new() &C.archive +fn C.archive_read_support_filter_all(&C.archive) +fn C.archive_read_support_format_all(&C.archive) + +// Open an archive for reading +fn C.archive_read_open_filename(&C.archive, &char, int) int + +// Go to next entry header in archive +fn C.archive_read_next_header(&C.archive, &&C.archive_entry) int + +// Skip reading the current entry +fn C.archive_read_data_skip(&C.archive) + +// Free an archive +fn C.archive_read_free(&C.archive) int + +// Read an archive entry's contents into a pointer +fn C.archive_read_data(&C.archive, voidptr, int) + +#include "archive_entry.h" + +struct C.archive_entry {} + +// Create a new archive_entry struct +fn C.archive_entry_new() &C.archive_entry + +// Get the filename of the given entry +fn C.archive_entry_pathname(&C.archive_entry) &char + +// Get an entry's file size +// Note: this function actually returns an i64, but as this can't be used as an arugment to malloc, we'll just roll with it & assume an entry is never bigger than 4 gigs +fn C.archive_entry_size(&C.archive_entry) int + +#include + +// Compare two C strings; 0 means they're equal +fn C.strcmp(&char, &char) int diff --git a/vieter/auth.v b/src/auth.v similarity index 100% rename from vieter/auth.v rename to src/auth.v diff --git a/vieter/main.v b/src/main.v similarity index 90% rename from vieter/main.v rename to src/main.v index b974864..af6b06c 100644 --- a/vieter/main.v +++ b/src/main.v @@ -5,6 +5,7 @@ import os import log import io import repo +import archive const port = 8000 @@ -100,3 +101,12 @@ fn main() { repo: repo }, port) } + +// fn main() { +// // archive.list_filenames() +// info := archive.get_pkg_info('test/jjr-joplin-desktop-2.6.10-4-x86_64.pkg.tar.zst') or { +// eprintln(err.msg) +// return +// } +// println(info) +// } diff --git a/vieter/repo.v b/src/repo.v similarity index 100% rename from vieter/repo.v rename to src/repo.v diff --git a/vieter/routes.v b/src/routes.v similarity index 100% rename from vieter/routes.v rename to src/routes.v diff --git a/vieter/web/logging.v b/src/web/logging.v similarity index 100% rename from vieter/web/logging.v rename to src/web/logging.v diff --git a/vieter/web/parse.v b/src/web/parse.v similarity index 100% rename from vieter/web/parse.v rename to src/web/parse.v diff --git a/vieter/web/web.v b/src/web/web.v similarity index 100% rename from vieter/web/web.v rename to src/web/web.v