gitoriaLog in with ident

components

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Main branchmain3bc905c5components #15 (mission 003) 2/2: docs (README Look, STATUS, LOG), reportmremain/plugins/fs/server.hl

4.5 KB

  1. file(String path) {
  2. return __native("fs.file", path)
  3. }
  4. readFile(String path) {
  5. return __native("fs.read_file", path)
  6. }
  7. \* Read a whole file as Bytes (ticket #88): every byte as it is on disk,
  8. nothing decoded — the way back for what writeFile stored from a Bytes. *\
  9. readBytes(String path) {
  10. return toBytes(__native("fs.read_file", path))
  11. }
  12. listDir(String path) {
  13. return __native("fs.list_dir", path)
  14. }
  15. \* Does this path exist? (mission 077) The one call in hl:fs that cannot fail:
  16. it answers true/false, never an Error event — probing a path is a question,
  17. not an operation. Relative paths resolve against the SCRIPT's directory like
  18. every other hl:fs path. *\
  19. exists(String path) {
  20. return __native("fs.exists", path)
  21. }
  22. \* Watch a directory tree for changes (the dev-reload bell): an ordinary
  23. event-loop source — register it and every save arrives as an event.
  24. __native("eventloop.register", watch("."), "changed")
  25. on changed(ev) { … ev.name … }
  26. `exclude` (2026-08-30) names directories the descent must NOT enter — a
  27. path string, or a list of them. Omit it and the whole tree is watched, as
  28. it always was. The paths are compared RESOLVED (relative ones against the
  29. script's directory, like every hl:fs path) and normalised, so `./sessions`,
  30. `sessions` and `var/../sessions` are the same directory, and a sibling
  31. named `sessions-old` is NOT inside `sessions`.
  32. watch(".", "./sessions")
  33. watch(".", ["./sessions", "/var/cache/app"])
  34. A program that writes to a directory it also watches needs this: without
  35. it the only escape was that the walker skips dot-directories (which it
  36. still does — `.git` is the reason), i.e. renaming the directory. *\
  37. watch(String path, exclude) {
  38. return __native("fs.watch", path, exclude)
  39. }
  40. \* Write a whole file, ATOMICALLY (2026-08-28). Everything above this line
  41. reads; hl:fs could report a file's `chmod` and never set one, which is why
  42. nothing in this language could persist anything until now.
  43. The write goes to a sibling temp file, is fsynced, and is then renamed over
  44. the target — so a concurrent reader sees the whole OLD file or the whole NEW
  45. one, never a half of either. That matters more than it sounds: the first
  46. caller is the session store, and a truncated session file does not read as
  47. an error, it reads as a logged-out user.
  48. `mode` defaults to 0600 — a file this program wrote, for this program. Pass
  49. one to loosen it; nothing here consults the umask on your behalf.
  50. `contents` is a String or a Bytes (ticket #88): a Bytes is written raw,
  51. byte for byte — an uploaded image stays an image. *\
  52. writeFile(
  53. String path
  54. contents \\ a String or a Bytes
  55. Number mode
  56. ) {
  57. if (hlTypeName(contents) == 'Bytes') {
  58. return __native("fs.write_file_hex", path, contents.hex(), mode)
  59. }
  60. return __native("fs.write_file", path, contents, mode)
  61. }
  62. \* Append to a file — the log's shape, not the session store's (2026-09-27, a
  63. creator ask after routger's two). Opened O_APPEND, never truncated: the file
  64. is created (at `mode`, default 0600, same as writeFile) if it is not there
  65. yet, and every call after that lands its bytes after whatever is already on
  66. disk. `writeFile`'s atomicity is a RENAME over a temp file — there is no
  67. "old" or "new" whole file to swap here, since an append MUTATES the one
  68. that is already there — but O_APPEND carries its own, narrower guarantee:
  69. the kernel positions a single write() at the CURRENT end of file and
  70. performs it as one operation, so two processes each appending one line
  71. never interleave their bytes mid-line, and a reader never sees a torn
  72. append. That is what "a single write of a line lands whole" buys — call it
  73. once per line (or per record) you want that guarantee for.
  74. `contents` is a String or a Bytes (ticket #88), same as writeFile: a Bytes
  75. is appended raw, byte for byte. *\
  76. appendFile(
  77. String path
  78. contents \\ a String or a Bytes
  79. Number mode
  80. ) {
  81. if (hlTypeName(contents) == 'Bytes') {
  82. return __native("fs.append_file_hex", path, contents.hex(), mode)
  83. }
  84. return __native("fs.append_file", path, contents, mode)
  85. }
  86. \* Make a directory and every missing parent. Already-there is SUCCESS: the
  87. caller wants the directory to exist, not to be the one who created it.
  88. `mode` defaults to 0700. *\
  89. mkDir(String path, Number mode) {
  90. return __native("fs.mk_dir", path, mode)
  91. }
  92. \* Delete a path. IDEMPOTENT: true when the path is gone on return, and a path
  93. that was already gone counts. A sweep must not fail because something else
  94. deleted the file first. *\
  95. remove(String path) {
  96. return __native("fs.remove", path)
  97. }

Branches

Latest commits

  • 3bc905c5components #15 (mission 003) 2/2: docs (README Look, STATUS, LOG), reportmre
  • 5a98d77ecomponents #15 (mission 003) 1/2: black/white base look — greys for nuances, no WorldAPI fallbacks, no decorative frames; site + icon black/white; gate 230/0mre
  • 3f93d716components code order (mission 002) 4/4: docs, tests/letcount.py, tests/same-output*, reportmre
  • e747cfa0components code order (mission 002) 3/4: let only where reassigned (257 dropped, 0 never-reassigned left); gate 220/0, layouts gate 73/0, same outputmre
  • 172914a3components code order (mission 002) 2/4: lib/uploads.hl (demo upload storage), thin demo handlers, project.hl map; gate 220/0, same outputmre
  • d29f35b1components code order (mission 002) 1/4: styles.hl -> components/styles.hl; gate 220/0, same outputmre
  • 09945750components: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, http1 773de63e); gate 220/0mre
  • ede4d19acomponents: Hybriel master 190aa11d (fc838894 GC correctness, #126 closure scopes, #127); gate 220/0mre
  • 2bb9a935components: Hybriel master 8efba065 (re-vendor round 069: #126 memory, #48 lambda copy)mre
  • e4f01768antcolony#40: mission references point to the moved missionsmre
  • d32b44e2antcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 0fb80b57components: Hybriel master ff51cf46 (re-vendor round)mre
  • 57408b6ecomponents#14: installable app (manifest, service worker, offline index), own iconmre
  • 317bd09fdeploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • becbd59bcomponents#13: modal dialog (<dialog> based, focus wrap, backdrop/Esc/x close with reason, scroll lock, footer buttons)mre
  • 367dd19adeploy.sh: never send .git or .gitignore to Byrodinmre
  • 4b4dabe5State of 2026-09-27, before the move to gitoriamre