wip support symlinks/recursion dirs + tests

This commit is contained in:
Leon van Kammen 2026-07-24 17:06:31 +02:00
parent 3ea550e2b4
commit 2b287e4a7e
19 changed files with 104 additions and 64 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ experienceB
result
src/v
janusweb*
myverse

2
run.sh
View file

@ -1,4 +1,4 @@
#!/bin/sh
source ./.env
rebuild
result/bin/xrforge.com server
result/bin/xrforge.com "$@"

View file

@ -88,7 +88,7 @@ app --
app.on('init', function()
if assert(unix.fork()) == 0 then
app.plugin.diskscan.scan()
app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir)
print_r(app.cache)
--os.execute("ls ; sleep 5")
print("ok")

View file

@ -6,7 +6,7 @@ return function(app)
name = "XRForge",
baseurl="/",
title="Your XR Forge",
subtitle="Portable XR experiences for Phone, VRheadset & desktop.",
subtitle="Local-first XR experiences for Phone, VRheadset & desktop.",
admin_title = "XRForge Admin",
admin_subtitle = "Manage your XR experiences here",
}

View file

@ -3,11 +3,13 @@ return function(app,argv)
io.write( app.bin .. " " .. k .. "\t\t # " .. v.info .. "\n")
end)
io.write("\nexample: " .. app.bin .. " title='My XRForge experiences'\n\n")
io.write("Flags: (overrides xrforge.lua configfile)\n\n")
io.write("example content: unzip result/bin/xrforge.com myverse/*\n\n")
io.write("Flags:\n\n")
foreach( app.opts, function(k,v)
if not k:match("/") and not k:match("^help") and not k:match("updated") then
io.write( " " .. k .. "='" .. v .. "'\n")
end
end)
io.write("\n> NOTE: flags override flags in xrforge.lua configfile]\n")
os.exit()
end

View file

@ -0,0 +1,6 @@
<title>world 1 title</title>
<fireboxroom>
<room use_local_asset="room-plane">
</room>
</fireboxroom>

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

View file

@ -0,0 +1 @@
../tronverse

View file

@ -0,0 +1 @@
../janusxr

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

View file

@ -9,45 +9,51 @@ return {
key='app.opts.plugin_diskscan_dir',
title='Directory',
info="Directory to scan for experiences (use '.' for current) ",
default=".",
default="./myverse",
values=''
}
},
shouldHideFile = function(name)
return name == ".."
return name == ".." -- parent
or name == "util" -- repository
or name == ".git" -- files
or name == "src" --
or name == "result" --
or name:match("^%.") -- hidden
or name == "src" -- repository
or name == "result" -- repository
end,
scan = function()
scan = function(scandir,parent,seen)
seen = seen or {}
local me = app.plugin.diskscan
local folder = app.opts.plugin_diskscan_dir
-- scan dirs
local dref, derr= dir.foreach( folder, function(path,stat,state,name,kind,ino,off,attr,fullpath)
if (kind == unix.DT_DIR or kind == unix.DT_LNK) and not me.shouldHideFile(name) then
local experience = {
path = fullpath,
name = name,
title = name,
tag = {},
file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
}
app.pub("scan_experience", nil, experience)
print(" ".. fullpath)
local dref, derr = dir.foreach( scandir, function(path,stat,state,name,kind,ino,off,attr,fullpath)
-- scan files
local fref, ferr = dir.foreach(fullpath, function(path,stat,state,name,kind,ino,off,attr, fullpath)
if kind ~= unix.DT_DIR and not me.shouldHideFile(name) then
experience.file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
app.pub("scan_experience_file", nil, experience)
local size = attr:size()
trace(" ".. fullpath)
end
end)
if not ferr then fref:close() end
local experience = {
path = fullpath,
name = name,
title = name,
tag = {},
file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
}
-- found directory
if not seen[ino] and (kind == unix.DT_DIR or kind == unix.DT_LNK)
and not me.shouldHideFile(name) then
seen[ino] = true -- prevent recursion with symlinks
print("".. fullpath)
app.pub("scan_experience", nil, experience)
table.insert( app.cache.items, experience)
me.scan(fullpath, dir,seen)
end
---- found file
if not seen[ino] and (kind ~= unix.DT_DIR and kind ~= unix.DT_LNK)
and not me.shouldHideFile(name) then
seen[ino] = true -- prevent recursion with symlinks
print(" ".. fullpath)
app.pub("scan_experience_file", nil, experience)
local size = attr:size()
end
end)
if not derr then dref:close() end

View file

@ -4,27 +4,27 @@ local pattern_fireboxroom = "[Ff][Ii][Rr][Ee][Bb][Oo][Xx][Rr][Oo][Oo][Mm][ ]?.*>
local pattern_title = "<[Tt][Ii][Tt][Ll][Ee]>(.*)<"
app.on('scan_experience', function(exp)
print("dir: "..exp.file.fullpath)
--print_r(exp)
end)
app.on('scan_experience_file', function(exp)
local size = exp.file.attr:size()
if exp.file.name:match(".glb") and not util.contains(exp.tag,"xrfragment") then
print("✅ └─ plugin/janusxr: generating janusxr.xml")
table.insert(exp.tag, "janusxr")
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
table.insert( app.cache.items, exp)
elseif size < 1000 then -- skip large binary files
if size < 1000 then -- skip large binary files
local data = util.readfile( exp.file.fullpath)
if data:match(pattern_fireboxroom) then
table.insert(exp.tag, "janusxr")
local title = data:match(pattern_title)
if title then
exp.title = title:gsub("<.*","")
if data then
if data:match(pattern_fireboxroom) then
table.insert(exp.tag, "janusxr")
local title = data:match(pattern_title)
if title then
exp.title = title:gsub("<.*","")
end
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
table.insert( app.cache.items, exp)
print("✅ └─ plugin/janusxr: " .. exp.file.name)
end
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
table.insert( app.cache.items, exp)
print("✅ └─ plugin/janusxr: " .. exp.file.name)
else
-- symlink to directory
end
end
end)

14
src/test/env/demofiles.sh vendored Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
cleanup(){
rm -rf world{1,2,3,4} 2>/dev/null || true
}
create(){
mkdir world1 ;
mkdir world2 ;
ln -s /tmp world3 ;
ln -fs nonexisting world4 ;
}
"$@"

View file

@ -2,22 +2,7 @@ local lust = require 'test/lust'
local describe, it, expect = lust.describe, lust.it, lust.expect
-- usage: https://github.com/bjornbytes/lust
describe('my project', function()
lust.before(function()
-- This gets run before every test.
end)
describe(' app vars', function() -- Can be nested
it('bindir', function()
print(app.bindir)
expect(app.bindir).to.fail('xrforge.com') -- Pass
end)
it('feature2', function()
expect(nil).to.exist() -- Fail
end)
end)
end)
require('test/plugin_diskscan')(lust)
if lust.errors == 0 then
print("✅ all tests passed")

24
src/test/plugin_diskscan.lua Executable file
View file

@ -0,0 +1,24 @@
return function(lust)
local describe, it, expect = lust.describe, lust.it, lust.expect
describe('src/plugin/diskscan.lua', function()
lust.before(function() os.execute('test/env/demofiles.sh create') end)
lust.after(function() os.execute('test/env/demofiles.sh cleanup') end)
describe(' app vars', function() -- Can be nested
it('bindir', function()
print(app.bindir)
expect(app.bindir).to.fail('xrforge.com') -- Pass
end)
it('feature2', function()
expect(nil).to.exist() -- Fail
end)
end)
end)
end

View file

@ -35,12 +35,12 @@ build(){
download redbean
download janusweb
cd src
zip -r ../result/bin/xrforge.com * .lua .init.lua .args
zip -yr ../result/bin/xrforge.com * .lua .init.lua .args
}
rebuild(){
cd src
zip -r ../result/bin/xrforge.com .lua page plugin cmd css .init.lua .args
zip -yr ../result/bin/xrforge.com .lua page plugin cmd css .init.lua .args test myverse
}
"$@"