Skip to content

Commit d8256e9

Browse files
committed
Fundamentum
0 parents  commit d8256e9

9 files changed

Lines changed: 1771 additions & 0 deletions

File tree

.github/workflows/shelltests.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Shell CI
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
unit-tests:
11+
strategy:
12+
matrix:
13+
os: [macos-14, macos-latest]
14+
15+
runs-on: ${{ matrix.os }}
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Run scan_test
21+
run: ./scan_test.sh
22+
23+
- name: Run apply_test
24+
run: ./apply_test.sh

LICENSE

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## replix — Plan 9 replica tools for Unix in AWK
2+
3+
**replix** is a small AWK‑ and Shell‑based re‑implementation of a
4+
few Plan 9 replica(8)[^1] commands. It’s meant for simple synchronization
5+
and change‑tracking tasks on Unix‑like systems.
6+
7+
The code is intentionally minimal. It runs best on **macOS** and
8+
the **BSDs**; **Linux** users may need to adjust a few commands or
9+
AWK behaviors. The included **test suite** shows the expected
10+
behavior and helps anyone adapting the code to other systems.
11+
12+
See **example.mk** and **example.proto** for basic usage patterns.
13+
14+
---
15+
[^1]: *[replica](http://9p.io/magic/man2html/8/replica)*(8)

apply.sh

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/bin/sh
2+
# Watch ./apply_test.sh
3+
usage(){
4+
echo >&2 'apply.sh old new [timefile] <log'
5+
echo >&2 'see also replica/applylog in https://9p.io/magic/man2html/8/replica'
6+
exit 64
7+
}
8+
9+
case $# in
10+
[23]) old=${1?} new=${2?} timefile=$3;;
11+
*) usage
12+
esac
13+
14+
exec awk -v 'old='"$old" -v 'new='"$new" -v 'timefile='"$timefile" '
15+
BEGIN {
16+
Time=1; Gen=2; Verb=3; Path=4; Spath=5; Mode=6; Uid=7; Gid=8; Mtime=9; Len=10
17+
loadtime()
18+
} $Time < time {
19+
next
20+
} $Time == time && $Gen <= gen {
21+
next
22+
} $Verb~/[acdm]/ {
23+
print $Verb, $Path, $Spath, $Mode, $Uid, $Gid, $Mtime, $Len
24+
} $Spath == "-" {
25+
$Spath = $Path
26+
} $Verb~/a/ && $Mode~/d/ {
27+
mkdir(new "/" $Path)
28+
} $Verb~/[ac]/ && $Mode!~/d/ {
29+
cp(old "/" $Spath, new "/" $Path)
30+
} $Verb~/[acm]/ {
31+
chmod(new "/" $Path, $Mode)
32+
} $Verb~/d/ && $Mode~/d/ {
33+
rmdir(new "/" $Path)
34+
} $Verb~/d/ && $Mode!~/d/ {
35+
rm(new "/" $Path)
36+
} !errors {
37+
time = $Time; gen = $Gen
38+
} END {
39+
savetime()
40+
}
41+
42+
function mkdir(path) {
43+
x("mkdir -p " path)
44+
}
45+
46+
function rm(path) {
47+
x("rm -f " path)
48+
}
49+
50+
function rmdir(path) {
51+
x("rmdir " path)
52+
}
53+
54+
function cp(old, new) {
55+
x("test ! -e " old " || cp " old " " new " || test ! -e " old)
56+
}
57+
58+
function chmod(path, mode) {
59+
sub("d", "", mode)
60+
x("test ! -e " path " || chmod " mode " " path)
61+
}
62+
63+
function loadtime() {
64+
if(timefile != "" && getline <timefile > 0){
65+
time = int($1)
66+
gen = int($2)
67+
}
68+
}
69+
70+
function savetime() {
71+
if(timefile != "")
72+
x("echo " time " " gen " >" timefile)
73+
}
74+
75+
function x(s) {
76+
# DBG: system("echo + \"" s "\" >&2")
77+
if(system(s) != 0) {
78+
errors++
79+
exit(1)
80+
}
81+
}
82+
' # <log

apply_test.sh

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/bin/sh
2+
# {Watch ./apply_test.sh}
3+
4+
tests=`sed -n '/^test.*[(][)].*{/ s/[^A-Za-z0-9_]*//gp' $0`
5+
6+
testapplyafresh() {
7+
r=/tmp/replica.${testname?} o=$r/old n=$r/new
8+
rm -rf $r
9+
mkdir $r $o $o/dir1 $n
10+
echo t > $o/file1 || exit
11+
rm -f $r/time
12+
{
13+
echo '1648215000 0 a dir0 - d755 user staff 1648208130 0'
14+
echo '1648215000 1 a dir1 - d755 user staff 1648208130 0'
15+
echo '1648215000 2 a file1 - 644 user staff 1648208130 2'
16+
echo '1648215000 3 a cp1 file1 644 user staff 1648208130 2'
17+
} >$r/log
18+
sh ./apply.sh $o $n $r/time <$r/log >$r/out || exit
19+
(
20+
set -x
21+
test -e $n/dir0 || exit
22+
test -d $n/dir1 || exit
23+
test -f $n/file1 || exit
24+
test -w $n/file1 || exit
25+
cmp $n/cp1 $o/file1 || exit
26+
nr=`wc -l <$r/out` && test "$nr" -eq 4 || exit
27+
time=`cat $r/time` && test "$time" = '1648215000 3' || exit
28+
) 2>$r/err || { cat $r/err; exit 1; }
29+
rm -r "$r"
30+
}
31+
32+
testapplyresumed() {
33+
r=/tmp/replica.${testname?} o=$r/old n=$r/new
34+
rm -rf $r
35+
mkdir $r $o $o/dir1 $n
36+
touch $o/file1 $o/dir1/file2 || exit
37+
echo 1648215015 0 > $r/time
38+
{
39+
echo '1648215015 0 a shadowed - d755 user staff 1648208130 0'
40+
echo '1648215015 1 a dir1 - d755 user staff 1648208130 0'
41+
echo '1648215015 2 a file1 - 644 user staff 1648208130 0'
42+
echo '1648215015 3 a dir1/file2 - 444 user staff 1648208130 0'
43+
echo '1648215015 4 a dir2 - d755 user staff 1648208130 0'
44+
} >$r/log
45+
sh ./apply.sh $o $n $r/time <$r/log >$r/out || exit
46+
(
47+
set -x
48+
test ! -e $n/shadowed || exit
49+
test -d $n/dir1 || exit
50+
test -f $n/file1 || exit
51+
test -w $n/file1 || exit
52+
test -f $n/dir1/file2 || exit
53+
test ! -w $n/dir1/file2 || exit
54+
test -d $n/dir2 || exit
55+
time=`cat $r/time` && test "$time" = '1648215015 4' || exit
56+
) 2>$r/err || { cat $r/err; exit 1; }
57+
58+
{
59+
echo '1648216000 0 m dir1/file2 - d644 user staff 1648208130 0'
60+
echo '1648216000 1 d file1 - 744 user staff 1648208130 0'
61+
echo '1648216000 2 d dir2 - d744 user staff 1648208130 0'
62+
} >>$r/log
63+
sh ./apply.sh $o $n $r/time <$r/log >$r/out || exit
64+
(
65+
set -x
66+
test -w $n/dir1/file2 || exit
67+
test '!' -e $n/file1 || exit
68+
test '!' -e $n/dir2 || exit
69+
nr=`wc -l < $r/out` && test "$nr" -eq 3 || exit
70+
time=`cat $r/time` && test "$time" = '1648216000 2' || exit
71+
) 2>$r/err || { cat $r/err; exit 1; }
72+
}
73+
74+
testapplydeleted() {
75+
r=/tmp/replica.${testname?} o=$r/old n=$r/new
76+
rm -rf $r
77+
mkdir $r $o $n
78+
rm -f $r/time
79+
{
80+
echo '1648217000 0 a file1 - 644 user staff 1648208130 2'
81+
echo '1648217001 0 d file1 - 644 user staff 1648208130 2'
82+
} >$r/log
83+
sh ./apply.sh $o $n $r/time <$r/log >$r/out || exit
84+
(
85+
set -x
86+
test ! -e $n/file1 || exit
87+
time=`cat $r/time` && test "$time" = '1648217001 0' || exit
88+
) 2>$r/err || { cat $r/err; exit 1; }
89+
rm -r "$r"
90+
}
91+
92+
93+
p=''
94+
for t in $tests
95+
do testname=$t $t &
96+
p=$p' '$!
97+
done
98+
99+
err=''
100+
for i in $p
101+
do wait $i || err=$?
102+
done
103+
test -z $err && echo ok

example.mk

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fs=mycloudcpu
2+
mnt=/n/${fs}
3+
4+
s=${HOME}
5+
proto=${s}/src/replix/example.proto
6+
db=${s}/replica/home.db
7+
log=${s}/replica/home.log
8+
c=${mnt}/home/${USER}/term
9+
time=${c}/sync.time
10+
11+
put:: ${c}
12+
${HOME}/src/replix/scan.sh ${s} ${db} <${proto} >> ${log} && \
13+
${HOME}/src/replix/apply.sh ${s} ${c} ${time} <${log}

example.proto

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.bash_profile
2+
.gitconfig
3+
.profile
4+
.zprofile
5+
.zshrc
6+
acme.dump
7+
guide
8+
mkfile
9+
.ssh
10+
config
11+
bin d755
12+
+
13+
go d755
14+
src d755
15+
guide
16+
github.com
17+
anacrolix
18+
torrent
19+
guide
20+
dht
21+
guide
22+
lib d755
23+
font d755
24+
+
25+
harvey d755
26+
guide
27+
talk d755
28+
+
29+
demo.regis
30+
demo.sixel
31+
ding
32+
gitignore
33+
plumbing
34+
syntetic.conf 644 - - ../../etc/synthetic.d/synthetic.conf
35+
Library d755
36+
LaunchAgents d755
37+
plumber.plist
38+
replica d755
39+
term.proto
40+
lib
41+
*
42+
src d755
43+
serial.go
44+
docker d755
45+
+
46+
learn d755
47+
+
48+
tmp d755

0 commit comments

Comments
 (0)