summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2024-05-08 08:20:58 -0300
committerEuAndreh <eu@euandre.org>2024-05-08 09:10:47 -0300
commit5e8e65015a77ed7606c6cfbd2d1cedc79e42a6a5 (patch)
tree7e39359779ca29e512171e14828a5c5fd2f20e7b
parentInitial empty commit (diff)
downloadq-5e8e65015a77ed7606c6cfbd2d1cedc79e42a6a5.tar.gz
q-5e8e65015a77ed7606c6cfbd2d1cedc79e42a6a5.tar.xz
Initial version
-rw-r--r--Makefile86
-rw-r--r--deps.mk3
-rwxr-xr-xmkdeps.sh13
-rwxr-xr-xsrc/q116
4 files changed, 218 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f911417
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,86 @@
+.POSIX:
+DATE = 1970-01-01
+VERSION = 0.1.0
+NAME = q
+NAME_UC = $(NAME)
+LANGUAGES = en
+## Installation prefix. Defaults to "/usr".
+PREFIX = /usr
+BINDIR = $(PREFIX)/bin
+LIBDIR = $(PREFIX)/lib
+INCLUDEDIR = $(PREFIX)/include
+SRCDIR = $(PREFIX)/src/$(NAME)
+SHAREDIR = $(PREFIX)/share
+LOCALEDIR = $(SHAREDIR)/locale
+MANDIR = $(SHAREDIR)/man
+EXEC = ./
+## Where to store the installation. Empty by default.
+DESTDIR =
+LDLIBS =
+
+
+
+.SUFFIXES:
+
+
+
+all:
+include deps.mk
+
+sources = \
+ $(sources.sh) \
+
+
+derived-assets = \
+
+side-assets = \
+
+
+
+## Default target. Builds all artifacts required for testing
+## and installation.
+all: $(derived-assets)
+
+
+
+check-unit:
+
+
+check-integration:
+
+
+## Run all tests. Each test suite is isolated, so that a parallel
+## build can run tests at the same time. The required artifacts
+## are created if missing.
+check: check-unit check-integration
+
+
+
+## Remove *all* derived artifacts produced during the build.
+## A dedicated test asserts that this is always true.
+clean:
+ rm -rf $(derived-assets) $(side-assets)
+
+
+## Installs into $(DESTDIR)$(PREFIX). Its dependency target
+## ensures that all installable artifacts are crafted beforehand.
+install: all
+ mkdir -p \
+ '$(DESTDIR)$(BINDIR)' \
+ '$(DESTDIR)$(SRCDIR)'
+ cp $(sources.sh) '$(DESTDIR)$(BINDIR)'
+ cp $(sources.sh) '$(DESTDIR)$(SRCDIR)'
+
+
+## Uninstalls from $(DESTDIR)$(PREFIX). This is a perfect mirror
+## of the "install" target, and removes *all* that was installed.
+## A dedicated test asserts that this is always true.
+uninstall:
+ rm -rf \
+ '$(DESTDIR)$(SRCDIR)'
+ for f in $(sources.sh); do \
+ rm -f '$(DESTDIR)$(BINDIR)'/"$${f#src/}"; \
+ done
+
+
+ALWAYS:
diff --git a/deps.mk b/deps.mk
new file mode 100644
index 0000000..028851e
--- /dev/null
+++ b/deps.mk
@@ -0,0 +1,3 @@
+sources.sh = \
+ src/q \
+
diff --git a/mkdeps.sh b/mkdeps.sh
new file mode 100755
index 0000000..8204798
--- /dev/null
+++ b/mkdeps.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -eu
+
+export LANG=POSIX.UTF-8
+
+varlist() {
+ printf '%s = \\\n' "$1"
+ sort | sed 's|^\(.*\)$|\t\1 \\|'
+ printf '\n'
+}
+
+
+find src/* -type f -perm -111 | varlist 'sources.sh'
diff --git a/src/q b/src/q
new file mode 100755
index 0000000..17fb37d
--- /dev/null
+++ b/src/q
@@ -0,0 +1,116 @@
+#!/bin/sh
+set -eu
+
+
+usage() {
+ echo 'Usage: q TOPIC ACTION [OPTION]'
+}
+
+CONSUMER='default-consumer'
+while getopts 'C:' flag; do
+ case "$flag" in
+ C)
+ CONSUMER="$OPTARG"
+ ;;
+ *)
+ usage >&2
+ exit 2
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+TOPIC="${1:-}"
+ACTION="${2:-}"
+
+eval "$(assert-arg -- "$TOPIC" 'TOPIC')"
+eval "$(assert-arg -- "$ACTION" 'ACTION')"
+
+
+Q_DIR="${Q_DIR:-$XDG_DATA_HOME/q}/topics/$TOPIC"
+mkdir -p "$Q_DIR"
+cd "$Q_DIR"
+
+mkdir -p tmp cur dead/"$CONSUMER" offset/"$CONSUMER"
+
+for f in n offset/"$CONSUMER"/n; do
+ if [ ! -e "$f" ]; then
+ echo 0 > "$f"
+ fi
+done
+
+
+case "$ACTION" in
+ in)
+ N="$(cat n)"
+ ID="$(uuid)"
+ cat > tmp/"$ID"
+ mv tmp/"$ID" cur/"$N"
+ echo $((N + 1)) > n
+ ;;
+ out)
+ N="$(cat offset/"$CONSUMER"/n)"
+ if [ ! -e cur/"$N" ]; then
+ exit 3
+ fi
+ cat cur/"$N"
+ ;;
+ commit)
+ N="$(cat offset/"$CONSUMER"/n)"
+ if [ ! -e cur/"$N" ]; then
+ exit 3
+ fi
+ echo $((N + 1)) > offset/"$CONSUMER"/n
+ ;;
+ dead)
+ N="$(cat offset/"$CONSUMER"/n)"
+ if [ ! -e cur/"$N" ]; then
+ exit 3
+ fi
+ touch "dead/$CONSUMER/$N"
+ echo $((N + 1)) > offset/"$CONSUMER"/n
+ ;;
+ ls-dead)
+ (
+ cd dead/"$CONSUMER"/
+ find * 2>/dev/null | sort -n
+ )
+ ;;
+ cat)
+ eval "$(assert-arg -- "${3:-}" 'N')"
+ OLD_N="$3"
+ if [ ! -e cur/"$OLD_N" ]; then
+ exit 3
+ fi
+ cat cur/"$OLD_N"
+ ;;
+ revive)
+ eval "$(assert-arg -- "${3:-}" 'N')"
+ OLD_N="$3"
+ if [ ! -e dead/"$CONSUMER"/"$OLD_N" ]; then
+ exit 3
+ fi
+ N="$(cat n)"
+ ln -s "$OLD_N" cur/"$N"
+ echo $((N + 1)) > n
+ rm -f dead/"$CONSUMER"/"$OLD_N"
+ ;;
+ size)
+ cat n
+ ;;
+ offset)
+ cat offset/"$CONSUMER"/n
+ ;;
+ has-data)
+ ! cmp -s n offset/"$CONSUMER"/n
+ ;;
+ reset)
+ eval "$(assert-arg -- "${3:-}" 'N')"
+ N="$3"
+ echo "$N" > offset/"$CONSUMER"/n
+ ;;
+ *)
+ echo "Bad ACTION: $ACTION" >&2
+ exit 2
+ ;;
+esac