Skip to content
go-libfossil Check-in [8de2ae751d]
Login

Check-in [8de2ae751d]

Overview
Comment:fix(cli): match PATH as fossil does; run pragmas in a fixed order (#457)

* fix(cli): match PATH as fossil does; run pragmas in a fixed order

log --path, cat --at and diff drop a leading ./, a trailing / and doubled or /./ separators, and compare names with the repository's case-sensitive setting, fossil's platform default when unset. Not found stays exit 2, where fossil exits 1; the docs now say so. SettingBoolean moves to internal/repo, shared by sync and checkout.

Opening a repository runs every pragma in a fixed order, not only busy_timeout first.

Tracked in #451

* feat(cli): document and pin repo new for embedding apps

repo new takes the path from -R as the other embedding commands do, refuses a missing parent directory with a message naming it, and is documented in the embedding contract with its output and exit statuses. Tests pin each behaviour and that stock fossil opens the result.

Tracked in #451

* docs(cli): say how ../x, absolute paths and the global case-sensitive setting behave

Tracked in #451

Timelines: family | ancestors | descendants | both | main | trunk
Files: files | file ages | folders
SHA3-256: 8de2ae751d8b3a026c7d038d06f30e4da19a0499f3d71a0e8aa5cd00ced248ff
User & Date: [email protected] on 2026-10-20 02:58:39.000
Other Links: branch diff | manifest | tags
Context
2026-10-20
03:15
fix(manifest): honor fossil's optional ticket columns (#456)

* test(manifest): cover ticket schemas without fossil's optional columns

Fossil treats the ticket table, ticket.tkt_ctime, the ticketchng table, ticketchng.tkt_rid and ticketchng.tkt_user as optional. Each schema here must derive the rows fossil rebuild derives; all fail today.

* fix(manifest): honor fossil's optional ticket columns

Port ticket_insert and ticket_rebuild_entry's schema probes from src/tkt.c: the ticket table, tkt_ctime, the ticketchng table, tkt_rid and tkt_user are optional, a change row is written only when it has a field or bookkeeping column to fill, fields stored in both tables are copied from the ticket row, and baseline columns record the assigning rid. Rebuilding fossil's own repository failed on its missing tkt_user.

* docs(changelog): note optional ticket columns fix

* test(manifest): pin ticket append to an unset field, baselines and shared columns

The corpus now appends to a field no artifact set, to a field with a baseline column, and to a field stored in both tables, so the comparison against fossil rebuild covers each branch of the append path. check-in: 1f46e25556 user: [email protected] tags: main, trunk

03:11
Merge branch 'main' into fix/verify-leaf-rule check-in: 0762218b66 user: [email protected] tags: fix/verify-leaf-rule, main, trunk
03:01
Merge remote-tracking branch 'origin/main' into feat/submanifest-reader

# Conflicts: # internal/checkout/vfile.go check-in: 741864259c user: [email protected] tags: feat/submanifest-reader, main, trunk

02:58
fix(cli): match PATH as fossil does; run pragmas in a fixed order (#457)

* fix(cli): match PATH as fossil does; run pragmas in a fixed order

log --path, cat --at and diff drop a leading ./, a trailing / and doubled or /./ separators, and compare names with the repository's case-sensitive setting, fossil's platform default when unset. Not found stays exit 2, where fossil exits 1; the docs now say so. SettingBoolean moves to internal/repo, shared by sync and checkout.

Opening a repository runs every pragma in a fixed order, not only busy_timeout first.

Tracked in #451

* feat(cli): document and pin repo new for embedding apps

repo new takes the path from -R as the other embedding commands do, refuses a missing parent directory with a message naming it, and is documented in the embedding contract with its output and exit statuses. Tests pin each behaviour and that stock fossil opens the result.

Tracked in #451

* docs(cli): say how ../x, absolute paths and the global case-sensitive setting behave

Tracked in #451 check-in: 8de2ae751d user: [email protected] tags: main, trunk

01:30
feat(cli): checkout-free snapshot, per-path log, cat --at and diff --json (#453)

* feat(cli): checkout-free snapshot, per-path log, cat --at and diff --json

repo snapshot commits one file's bytes onto trunk with no checkout, a no-op when they equal the tip. repo log --path lists the check-ins that changed a path, repo cat --at reads a file as a version holds it, and repo diff --json A B [PATH] diffs two versions. Exit 2 means not found. A snapshot re-checks the check-in stamp inside its write transaction and retries, so concurrent processes build one linear trunk.

Tracked in #451

* test(cli): cover log across a rename; order exit statuses in the docs

Tracked in #451

* fix(db): convert Julian days to the millisecond SQLite gives

log --json printed most check-in times 1ms before their D card: db.julianToTime truncated where SQLite's date.c rounds with (sqlite3_int64)(r*86400000.0+0.5). fsltype.MillisFromJulianDay now does exactly that, JulianToTime and ScanTime use it, and ScanTime rounds the time.Time ncruces hands back to the millisecond as well.

* fix(cli): print usage errors on stderr and pin their exit status 80

The documented status was right for the binary; go run turns it into 1. Usage text went to stdout, so an embedder reading stdout saw it on a failure. The doc now says which status a measurement under go run shows, and a test pins 80 for an unknown flag, a missing flag or argument and an unknown subcommand.

* fix(cli): refuse a snapshot path holding a control byte or a reserved name

validateRepoPath now applies fossil's own rules for a new file name: file_is_simple_pathname in strict form (deck.StrictPathname), no byte below 0x20, and file_is_reserved_name, whose existing port in deck is exported as IsReservedName. Each refusal exits 1 and names the reason.

* fix(cli): diff A B PATH matches fossil's PATH rules

A PATH in neither version printed [] and exited 0; fossil diff --from A --to B fails with "not found". It now exits 2 (not found), and PATH also matches a directory, as fossil's file_dir_match does. The test runs fossil on the same repository as the oracle.

* fix(cli): refuse a snapshot into a repository with no main-branch check-in

When the main branch resolved to nothing, snapshot took the repository for empty and committed a second root beside the existing history. It now treats only a repository with no check-ins as empty, and otherwise fails at exit 1 naming the branch.

* test(cli): compare log across a rename with fossil finfo

The rename test built its history through manifest.Checkin and checked our own idea of the result. It now builds the history with the fossil binary and compares repo log with fossil finfo on the same repository: both stop a name's history at the rename. The doc tells an embedder how to follow a file across renames, and where log differs from finfo.

* fix(db): set busy_timeout before any other pragma on open

The drivers build the DSN's _pragma parameters from a map and run them in that order, so journal_mode or foreign_keys often ran before busy_timeout. An open while another process held a lock then failed at once with "database is locked" instead of waiting: one cause of TestSnapshotConcurrentProcesses failing under -tags test_ncruces.

* fix(cli): hold the write lock from snapshot's read of the tip to its commit

Under -tags test_ncruces, TestSnapshotConcurrentProcesses failed 8 of 20 runs. Besides the open-time lock error fixed in db, a snapshot read the tip's manifest outside any transaction while another process's check-in re-deltaed it, and failed with a hash mismatch. A snapshot now runs in one bound write transaction from the read of the tip to its commit, so no other check-in can land in between; the optimistic retry loop it replaces is gone. check-in: 90345545d3 user: [email protected] tags: main, trunk

Changes