Compare commits
	
		
			4 Commits
		
	
	
		
			e0aef07783
			...
			v0.4.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 61f9026e23 | ||
|   | 3e50149d4d | ||
|   | 7077b21159 | ||
|   | 938c5ca657 | 
| @@ -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() | ||||||
|   | |||||||
| @@ -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) |  | ||||||
|   | |||||||
| @@ -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], | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										12
									
								
								scripts/build-frontend.py
									
									
									
									
									
										Normal 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 | ||||||
		Reference in New Issue
	
	Block a user