Compare commits

..

4 Commits

5 changed files with 27 additions and 42 deletions

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import secrets import secrets
import sys
from functools import wraps from functools import wraps
from hashlib import sha256 from hashlib import sha256
from pathlib import Path, PurePath from pathlib import Path, PurePath
@ -90,6 +91,8 @@ def config_update(modify):
return "read" return "read"
f.write(new) f.write(new)
f.close() f.close()
if sys.platform == "win32":
conffile.unlink() # Windows doesn't support atomic replace
tmpname.rename(conffile) # Atomic replace tmpname.rename(conffile) # Atomic replace
except: except:
f.close() f.close()

View File

@ -149,15 +149,3 @@ class Space(msgspec.Struct):
free: int free: int
usage: int usage: int
storage: int storage: int
def make_dir_data(root):
if len(root) == 3:
return FileEntry(*root)
id_, size, mtime, listing = root
converted = {}
for name, data in listing.items():
converted[name] = make_dir_data(data)
sz = sum(x.size for x in converted.values())
mt = max(x.mtime for x in converted.values())
return DirEntry(id_, sz, max(mt, mtime), converted)

View File

@ -110,26 +110,6 @@ class State:
with self.lock: with self.lock:
del self._listing[self._slice(relpath)] del self._listing[self._slice(relpath)]
def _index(self, rel: PurePosixPath):
idx = 0
ret = []
def _dir(self, idx: int):
level = self._listing[idx].level + 1
end = len(self._listing)
idx += 1
ret = []
while idx < end and (r := self._listing[idx]).level >= level:
if r.level == level:
ret.append(idx)
return ret, idx
def update(self, rel: PurePosixPath, value: FileEntry):
begin = 0
parents = []
while self._listing[begin].level < len(rel.parts):
parents.append(begin)
state = State() state = State()
rootpath: Path = None # type: ignore rootpath: Path = None # type: ignore
@ -149,7 +129,7 @@ def watcher_thread(loop):
global rootpath global rootpath
import inotify.adapters import inotify.adapters
while True: while not quit:
rootpath = config.config.path rootpath = config.config.path
i = inotify.adapters.InotifyTree(rootpath.as_posix()) i = inotify.adapters.InotifyTree(rootpath.as_posix())
# Initialize the tree from filesystem # Initialize the tree from filesystem
@ -160,8 +140,8 @@ def watcher_thread(loop):
state.root = new state.root = new
broadcast(format_update(old, new), loop) broadcast(format_update(old, new), loop)
# The watching is not entirely reliable, so do a full refresh every minute # The watching is not entirely reliable, so do a full refresh every 30 seconds
refreshdl = time.monotonic() + 60.0 refreshdl = time.monotonic() + 30.0
for event in i.event_gen(): for event in i.event_gen():
if quit: if quit:
@ -238,11 +218,15 @@ def _walk(rel: PurePosixPath, isfile: int, st: stat_result) -> list[FileEntry]:
try: try:
li = [] li = []
for f in path.iterdir(): for f in path.iterdir():
if quit:
raise SystemExit("quit")
if f.name.startswith("."): if f.name.startswith("."):
continue # No dotfiles continue # No dotfiles
s = f.stat() s = f.stat()
li.append((int(not stat.S_ISDIR(s.st_mode)), f.name, s)) li.append((int(not stat.S_ISDIR(s.st_mode)), f.name, s))
for [isfile, name, s] in humansorted(li): for [isfile, name, s] in humansorted(li):
if quit:
raise SystemExit("quit")
subtree = _walk(rel / name, isfile, s) subtree = _walk(rel / name, isfile, s)
child = subtree[0] child = subtree[0]
entry.mtime = max(entry.mtime, child.mtime) entry.mtime = max(entry.mtime, child.mtime)
@ -337,7 +321,7 @@ async def abroadcast(msg):
async def start(app, loop): async def start(app, loop):
config.load_config() config.load_config()
use_inotify = False and sys.platform == "linux" use_inotify = sys.platform == "linux"
app.ctx.watcher = threading.Thread( app.ctx.watcher = threading.Thread(
target=watcher_thread if use_inotify else watcher_thread_poll, target=watcher_thread if use_inotify else watcher_thread_poll,
args=[loop], args=[loop],

View File

@ -29,7 +29,7 @@ dependencies = [
] ]
[project.urls] [project.urls]
Homepage = "" Homepage = "https://git.zi.fi/Vasanko/cista-storage"
[project.scripts] [project.scripts]
cista = "cista.__main__:main" cista = "cista.__main__:main"
@ -40,20 +40,18 @@ dev = [
"ruff", "ruff",
] ]
[tool.hatchling]
# Build frontend
pre_build = "npm run build --prefix cista-front"
[tool.hatch.version] [tool.hatch.version]
source = "vcs" source = "vcs"
[tool.hatch.build] [tool.hatch.build]
artifacts = ["cista/wwwroot"]
hooks.custom.path = "scripts/build-frontend.py"
hooks.vcs.version-file = "cista/_version.py" hooks.vcs.version-file = "cista/_version.py"
hooks.vcs.template = """ hooks.vcs.template = """
# This file is automatically generated by hatch build. # This file is automatically generated by hatch build.
__version__ = {version!r} __version__ = {version!r}
""" """
only-packages = true
targets.sdist.include = [ targets.sdist.include = [
"/cista", "/cista",
] ]

12
scripts/build-frontend.py Normal file
View File

@ -0,0 +1,12 @@
# noqa: INP001
import subprocess
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
class CustomBuildHook(BuildHookInterface):
def initialize(self, version, build_data):
super().initialize(version, build_data)
print("Building Cista frontend...")
subprocess.run("npm install --prefix frontend".split(" "), check=True) # noqa: S603
subprocess.run("npm run build --prefix frontend".split(" "), check=True) # noqa: S603