gitoriaLog in with ident

ident

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Main branchmain5fdbb6b2ident mission 009: report — scratch folder notemremain/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

  • 5fdbb6b2ident mission 009: report — scratch folder notemre
  • 74235815ident mission 009 (4/4): docs (README files map + same-output test, STATUS, LOG), report, tests/letcount.py + realdata-baseline/comparemre
  • fe183516ident mission 009 (3/4): let only where reassigned — 293 never-reassigned lets are plain declarations; kept: reassigned, loop bodies, names of a file member, a name declared twice in one function; same outputmre
  • d2e7f91bident mission 009 (2/4): one lib file per topic (login, accounts, identities, apps, invites, selector, notify + helpers, util), function routes as thin wrappers in lib/api.hl, project.hl = the map; same outputmre
  • 91017164ident mission 009 (1/4): file moves — the root .hl files into lib/ (api.hl → lib/api-helpers.hl), styles.hl → components/styles.hl; imports adjusted, no other changemre
  • f8bdcbc2ident: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); all gates greenmre
  • ff78726cident: Hybriel master 190aa11d (fc838894 GC correctness, #127, #126 closure scopes); gates all greenmre
  • a3a7d21aident: Hybriel master 8efba065 (#126 GC by bytes, #48 lambda params copy); session-writing lambdas take &sessionmre
  • 98226b41antcolony#40: mission references point to the moved missionsmre
  • ff805b9aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 51a7bcdfident: Hybriel master 73267707 (#122); /code uses the new page() signature; pending address passed as parameter; once-checksmre
  • 836f644fident#24: installable app (manifest, service worker, data-free offline /start), own iconmre
  • 8bebbbf2deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • cc063ea2deploy.sh: never send .git or .gitignore to Byrodinmre
  • 81b15b7bState of 2026-09-27, before the move to gitoriamre