Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ because it turns other people's test suites red.

### Changed

- **`tfg preset eject` writes a `purpose` line for every target, so an
ejected recipe and the `recipe_hash` of every run from a preset differ from
0.3.0.** The recipe carries the purposes so that an ejected preset still
produces exactly what the preset does. The bytes of every generated file
are unchanged. A pipeline comparing `recipe_hash` across tool versions will
see a new value once.

- **A file name longer than 255 bytes is refused before anything is written,
on every system.** Linux stores at most 255 bytes in a name, while Windows
and macOS count characters, so a name of 200 Chinese or Japanese characters
Expand Down Expand Up @@ -307,6 +314,31 @@ because it turns other people's test suites red.

### Added

- **Every preset now says what each of its files is for.** A run from a
preset writes `manifest.instructions.md` beside `manifest.json`: the
question the preset answers, how to read accept, reject, sanitize and
unspecified, and then every file - its name, format and size, what your
system is expected to do with it and one or two sentences on why it is in
the set. Many files of one kind, such as the fifty of a mass upload, are
one entry. The file is named after the manifest, so `run2.json` gets
`run2.instructions.md`, and it is written only when some file has a
purpose - a plain `tfg generate --format png` writes none. `generate`
prints `instructions:` under `manifest:`, `verify` does not count the file
as extra, and `cleanup --with-manifest` removes it with the manifest - only
when it is named after that manifest, so an edited or renamed manifest
never takes instructions that may belong to another run. A
run into a directory that already holds instructions of that name is
refused before anything is written. If the file cannot be written, the run
says so and does not fail over it, because the manifest was saved and
holds the same facts.

- **A `purpose` for every target of a recipe.** One or two sentences on what
the files are and why they are in the set. They reach `files[].purpose` in
the manifest and the instructions beside it, and change no byte of any
file. The batch screen has a `Purpose` box among the manifest notes of each
batch, and the window offers `Open instructions` beside `Open manifest`
after a run that wrote them.

- **A preset for unusual file names: `filename-handling`.** It answers "will
my system store, show and give back a file name it did not expect?" with
fifty names in seven groups: scripts from Polish to Korean, names that look
Expand Down Expand Up @@ -520,6 +552,14 @@ because it turns other people's test suites red.

### Fixed

- **`tfg cleanup --with-manifest` says before it acts that the manifest goes
too.** The list printed without `--yes` named only the files the manifest
lists, and `--yes` then removed the manifest as well. It now ends with the
manifest and the instructions beside it, or says why they would stay, and
the run with `--yes` names them once they are gone. With `--json` both
reports carry them in a new `record` list. `files`, `removed`, `kept` and
`would_remove` still count only what the manifest lists.

- **A report shows a character nobody can see in a file name as an escape.**
`verify`, `cleanup`, the notes of a run, every error message and the
refusals in the window printed such a character as it was, in a file name
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ for entry in manifest["files"]:
assert not response.ok, entry["path"]
```

A run from a preset also writes `manifest.instructions.md` - the same facts for
a person to read: every file, what your system should do with it and why the
file is in the set.

And where the right answer genuinely depends on your own policy, the manifest
says `unspecified` instead of inventing one. A generator that guesses produces
false failures, and a suite that cries wolf gets switched off.
Expand Down Expand Up @@ -315,8 +319,9 @@ tfg cleanup <manifest.json> [--yes] [--force] [--with-manifest] [--against <dir>
Removes what the manifest lists and **nothing else**. Without `--yes` it deletes
nothing and prints what it would remove. A file whose content changed since it
was written is left alone and reported, because it may not be ours - `--force`
removes those too. `--with-manifest` removes the manifest as well, once every
file it lists is gone.
removes those too. `--with-manifest` removes the manifest and the instructions
beside it as well, once every file it lists is gone. The list printed without
`--yes` names them too.

### `tfg recipe fmt`

Expand Down
5 changes: 3 additions & 2 deletions internal/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ func Claimed(m *manifest.Manifest) []manifest.File {
// the manifest usually sits in the directory it describes, and a tool that
// fails on its own output on the most obvious invocation is not usable.
// Matched on the base name rather than the path, because a restored copy
// carries its own copy of the manifest beside the files.
// carries its own copy of the manifest beside the files. The instructions the
// manifest names are its own output in the same way, and skipped the same way.
//
// A run that is cancelled reports what it managed to compare and says so
// through the context error. Reporting "sound" on the strength of half a
Expand Down Expand Up @@ -309,7 +310,7 @@ func Verify(ctx context.Context, dir string, m *manifest.Manifest, skip string)
// decided. walk builds these with filepath.Rel, which returns a clean
// path, so a comparablePath here is a call that cannot be wrong -
// removing it left this guard green. See the comment on comparablePath.
if seen[p] || filepath.Base(p) == skip {
if seen[p] || filepath.Base(p) == skip || (m.Run.Instructions != "" && filepath.Base(p) == m.Run.Instructions) {
continue
}
unclaimed = append(unclaimed, p)
Expand Down
Loading
Loading