schwabrak -- simple flat file based issue tracker
-Note: this is the second version/iteration/suggestion. Look for previous
-one in older commits.
+Note: this is the second version/iteration/suggestion.
+Look for previous one in older commits.
I want a relatively simple issue/ticket tracker. Something like Trac,
Redmine or Fossil. But they require heavy dependencies (Python, Ruby),
The "about" file contains the description of the issue. The "result"
(initially empty) contains the resolved issue information. The "meta"
-file contains metainformation in recfile format, having at least "id"
-and "created" fields. The issue.rec file contains the schema of the
-records in current issues database. https://www.gnu.org/software/recutils/
+file contains metainformation in recfile format, having at least
+"created" fields. https://www.gnu.org/software/recutils/
+
+Root directory should contain *.rec files with the schema of the
+records. For example:
+
+ person.rec:
+ %rec: person
+ %key: id
+ %unique: name
+ %mandatory: name email
+ %type: id line
+ %type: name line
+ %type: email email
+
+ id: stargrave
+ name: Сергей Матвеев
+ email: stargrave@stargrave.org
+
+ task.rec:
+ %rec: task
+ %key: id
+ %mandatory: name created
+ %unique: name created about result
+ %allowed: about result ass proj status
+ %sort: created
+ %type: id line
+ %type: name line
+ %type: created date
+ %type: ass rec person
+ %type: proj enum
+ + c (C99)
+ + go (Go)
+ + py (Python3)
+ + tcl (Tcl)
+ %type: status enum
+ + done (task is finished)
+ + reject
+ + wip (work in progress)
+
+Schema of the issues/tasks must be trailing *.rec file after the sort.
Want to search among the issues? Just use git grep, or ordinary grep!
Want to search through attached PDFs or other kind of documents? You are
and press "gf" in your Vi editor to go to "foo-bar" directory of the
dependant issue.
-"full" script exports the whole issues database with the prepended
-issue.rec to stdout, including "about" and "result" fields. It is
-expected to be filtered with recsel/recdel utilities.
+"metas" script exports the whole issues database without about/result
+fields. "show" includes them. "full" also prepends *.rec files to the
+output. They are expected to be filtered with recsel/recdel utilities.
+"cd" lists all issues piped to "fzf" utility, that previews each one
+with "show" script.
The "comment" issue's file is intended to keep the last comment related to
the issue. By committing it you automatically accompany it with your
"add" command as seen above. And yes, it is intended that "issue" and
"name", "to", "create" can be passed as separate arguments, but
issue-name-to-create will be created as expected.
-
-"brief" lists all issues same way as "full", but without about/result
-fields. It does not require recutils installed.
-
-"cd" lists all issues piped to "fzf" utility, that previews each one
-with "full" script.
#!/bin/sh -e
+endash() {
+ ${PERL:-perl} -npe 's/(-+)/$1-/g ; s/ /-/g'
+}
+
SROOT="$(dirname "$(realpath -- "$0")")"
-. "$SROOT/rc.sh"
fn="$@"
fn="$(dirname "$fn")/$(basename "$fn" | endash)"
mkdir "$fn"
-cat >"$fn"/meta <<EOF
-id: $($SROOT/uuidv7)
-created: $(date -u +"%Y-%m-%d %H:%M:%S")
-EOF
+echo created: $(date -u +"%Y-%m-%d %H:%M:%S") >"$fn"/meta
touch "$fn"/about "$fn"/result
$EDITOR "$fn"/about
git add "$fn"
+++ /dev/null
-#!/bin/sh -e
-
-SROOT="$(dirname "$(realpath -- "$0")")"
-. $SROOT/rc.sh
-
-cat issue.rec
-echo
-for i in $(_list $1) ; do
- echo name: $i
- cat $i/meta
- echo
-done
#!/bin/sh -e
SROOT="$(dirname "$(realpath -- "$0")")"
-. $SROOT/rc.sh
-_list . | fzf --ansi --tac \
+$SROOT/metas | recfix --sort | recsel -C -P id | fzf --ansi \
--bind=ctrl-e:preview-page-down \
--bind=ctrl-y:preview-page-up \
- --preview="$SROOT/full {1} | recsel"
+ --preview="$SROOT/show {1}"
#!/bin/sh -e
SROOT="$(dirname "$(realpath -- "$0")")"
-. $SROOT/rc.sh
-
-cat issue.rec
-echo
-for i in $(_list $1) ; do
- echo name: $i
- cat $i/meta
- echo | recins \
- -f about -v "$(echo ; cat $i/about)" \
- -f result -v "$(echo ; cat $i/result)"
- echo
-done
+$SROOT/schemas
+$SROOT/show $@
--- /dev/null
+#!/bin/sh -e
+
+for i in $(find ${1:-.} -type d) ; do
+ i=${i#./}
+ [ -s $i/meta ] || continue
+ echo id: $i
+ echo name: $i | ${PERL:-perl} -npe 's/([^-])-([^-])/$1 $2/g ; s/-(-+)/$1/g'
+ cat $i/meta
+ echo
+done
+++ /dev/null
-endash() {
- ${PERL:-perl} -npe 's/(-+)/$1-/g ; s/ /-/g'
-}
-
-_list() {
- what=${1:-.}
- for i in $(find $what -type d) ; do
- i=${i#./}
- [ -s $i/meta ] || continue
- echo $i
- done
-}
--- /dev/null
+#!/bin/sh -e
+
+for i in $(find . -name "*.rec" -maxdepth 1 | sort -n) ; do
+ cat $i
+ echo
+done
--- /dev/null
+#!/bin/sh -e
+
+SROOT="$(dirname "$(realpath -- "$0")")"
+{ $SROOT/schemas ; $SROOT/metas $1 ; } |
+recfix --sort | recsel -t task -C -P id |
+while read i ; do
+ $SROOT/metas $i |
+ recset -f about -S "$(echo ; cat $i/about)" |
+ recset -f result -S "$(echo ; cat $i/result)"
+ echo
+done
+++ /dev/null
-#!/usr/bin/env perl
-
-use strict;
-use warnings;
-
-my $len = 10;
-my $v;
-open(my $rnd, "/dev/urandom") or die "open(urandom): $!";
-die "read(urandom) != $len" if (read($rnd, $v, $len) != $len);
-close $rnd;
-my @a = unpack "C*", ("000000" . $v);
-
-use Time::HiRes qw(gettimeofday);
-my ($sec, $ms) = gettimeofday();
-my $ts = int($sec * 1000 + $ms / 1000);
-
-$a[0] = ($ts >> 40) & 0xFF;
-$a[1] = ($ts >> 32) & 0xFF;
-$a[2] = ($ts >> 24) & 0xFF;
-$a[3] = ($ts >> 16) & 0xFF;
-$a[4] = ($ts >> 8) & 0xFF;
-$a[5] = $ts & 0xFF;
-
-$a[6] = ($a[6] | 0x0F) | 0x70;
-$a[8] = ($a[8] | 0x3F) | 0x80;
-
-print join("-", map { unpack("H*", pack("C*", @$_)) } (
- [@a[0..3]], [@a[4..5]], [@a[6..7]], [@a[8..9]], [@a[10..15]],
-)) . "\n";