An album whose folder cannot be made no longer stops the backup (closes #197)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Each album's folder, links and JSON are written inside one try. A failure prints `FAILED album <name>: <reason>`, lists the album's ID in the new `failedAlbums` of the result and of `--json`, and makes `quak backup` exit 1; the other albums and `failures.json` are still written. An album whose folder would have another album's JSON name, ignoring case, gets its ID. A name over 255 bytes (250 for a folder, which leaves room for `.json`) gets the ID and is cut short between two characters by `shortenToBytes` in `src/filename.ts`. A link's ID goes right before its extension. Apart from its call to `uniqueNames`, the album loop is only indented into the try. Model: opus-5-5
This commit was merged in pull request #204.
This commit is contained in:
+19
-1
@@ -4,7 +4,8 @@
|
||||
// hands us, and quak does not trust the server. Any name taken from them and
|
||||
// used on disk goes through here, so it can only ever name one file inside the
|
||||
// directory the caller chose: never a path, never `..`, never hidden, never a
|
||||
// Windows device name.
|
||||
// Windows device name. Such a name can still be too long for a file name, and
|
||||
// `shortenToBytes` cuts one short.
|
||||
//
|
||||
// A path the user typed (`--out`, `outPath`) is not passed through here: the
|
||||
// caller is trusted, the server is not.
|
||||
@@ -39,3 +40,20 @@ export const safeExtension = (title: string): string => {
|
||||
// `name` with its extension, if it has one, replaced by `ext` (".mov").
|
||||
export const withExtension = (name: string, ext: string): string =>
|
||||
name.slice(0, name.length - extname(name).length) + ext;
|
||||
|
||||
// The longest file name, in bytes, that ext4 and most other file systems allow.
|
||||
export const MAX_NAME_BYTES = 255;
|
||||
|
||||
// `name` cut short to at most `maxBytes` bytes of UTF-8, the encoding a file
|
||||
// name is written to disk in, between two characters, never inside one. A name
|
||||
// that fits comes back unchanged.
|
||||
export const shortenToBytes = (name: string, maxBytes: number): string => {
|
||||
let bytes = 0;
|
||||
let end = 0;
|
||||
for (const character of name) {
|
||||
bytes += Buffer.byteLength(character);
|
||||
if (bytes > maxBytes) break;
|
||||
end += character.length;
|
||||
}
|
||||
return name.slice(0, end);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user