cleanup comments, update translations, bump to 0.4.1
This commit is contained in:
parent
9edcc9841b
commit
7d8ab87eee
28 changed files with 412 additions and 1114 deletions
|
|
@ -1,23 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
// Sender-side hashing: walking sync units into a manifest of dirs, links and
|
||||
// files, with the digest of every file. Exported as a factory over the path
|
||||
// guards and the hash store, so every launcher state (and every test device)
|
||||
// builds manifests for its own files.
|
||||
// Sender-side hashing: walk sync units into a manifest of dirs, links, files.
|
||||
// Factory over the path guards and hash store, one per launcher state.
|
||||
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const fsp = fs.promises
|
||||
|
||||
function createManifestBuilder({ filesPath, filesRoot, hash, mapLimit, concurrency }) {
|
||||
// Symlink targets travel RELATIVE whenever they point inside the launcher
|
||||
// data (a prefix linking into its wine build, an app linking to its own
|
||||
// assets): the mirrored trees have the same internal layout on both
|
||||
// machines, so a relative target is correct over there while an absolute one
|
||||
// would point at the sender's own folders - which is exactly how a synced
|
||||
// prefix ends up with hundreds of dangling links. Targets outside files/
|
||||
// (a system font, a mounted drive, /) are machine-specific and stay as they
|
||||
// are.
|
||||
// Targets inside the launcher data travel relative (the mirrored layout is
|
||||
// the same on both machines); outside targets stay as they are.
|
||||
function portableLinkTarget(linkAbs, target) {
|
||||
if (typeof target !== 'string' || !target || !path.isAbsolute(target)) return target
|
||||
const rel = path.relative(path.dirname(linkAbs), target)
|
||||
|
|
@ -28,16 +20,8 @@ function createManifestBuilder({ filesPath, filesRoot, hash, mapLimit, concurren
|
|||
return rel
|
||||
}
|
||||
|
||||
// Walk without following symlinks: builds and prefixes contain links that
|
||||
// are part of what is being synced (dosdevices, build internals), and
|
||||
// following them would both loop and copy the wrong thing.
|
||||
//
|
||||
// Iterative (a queue instead of an await-per-directory recursion) and with
|
||||
// the stat/readlink calls of one directory in flight together: walking a
|
||||
// prefix is dominated by those two syscalls, and serializing them costs more
|
||||
// than the readdir itself. Regular files are re-verified with one stat
|
||||
// (size, mode, mtime feed both the manifest and the hash cache), everything
|
||||
// else is skipped.
|
||||
// Walk without following symlinks (dosdevices etc. are part of the sync).
|
||||
// Iterative, with one directory's stat/readlink calls in flight together.
|
||||
async function scanTree(abs, rel, out, mtimes) {
|
||||
const queue = [[abs, rel]]
|
||||
while (queue.length) {
|
||||
|
|
@ -77,18 +61,16 @@ function createManifestBuilder({ filesPath, filesRoot, hash, mapLimit, concurren
|
|||
return
|
||||
}
|
||||
if (!st.isFile()) return
|
||||
// mode travels with the file: a wine build's `proton`/`wine` binary is
|
||||
// useless on the other side without its executable bit
|
||||
// mode travels with the file
|
||||
out.push({ path: relChild, type: 'file', size: st.size, mode: st.mode & 0o777, hash: null })
|
||||
// kept out of the manifest: only this machine can use its own mtimes
|
||||
// mtimes are machine-local: kept out of the manifest
|
||||
if (mtimes) mtimes.set(relChild, st.mtimeMs || 0)
|
||||
})
|
||||
queue.push(...dirs)
|
||||
}
|
||||
}
|
||||
|
||||
// Manifest of one sync unit. `force` skips hashing entirely - the receiver
|
||||
// then treats every file as different ("force sync all files").
|
||||
// Manifest of one unit; `force` skips hashing (receiver replaces everything).
|
||||
async function buildManifest(roots, force, onProgress) {
|
||||
const entries = []
|
||||
const mtimes = new Map()
|
||||
|
|
@ -116,8 +98,7 @@ function createManifestBuilder({ filesPath, filesRoot, hash, mapLimit, concurren
|
|||
}
|
||||
}
|
||||
const files = entries.filter(e => e.type === 'file')
|
||||
// the unit's total size is known before a byte is hashed, so the bar can
|
||||
// start empty and fill with the bytes actually read
|
||||
// total size is known before hashing, so the bar starts empty
|
||||
const totalBytes = files.reduce((sum, entry) => sum + (entry.size || 0), 0)
|
||||
if (!force && files.length) {
|
||||
let done = 0
|
||||
|
|
@ -125,8 +106,7 @@ function createManifestBuilder({ filesPath, filesRoot, hash, mapLimit, concurren
|
|||
await mapLimit(files, concurrency, async entry => {
|
||||
const abs = filesPath(entry.path)
|
||||
try {
|
||||
// identical size and mtime means identical bytes, so the digest from
|
||||
// an earlier sync still describes this file
|
||||
// unchanged size + mtime: the cached digest still holds
|
||||
const mtimeMs = mtimes.get(entry.path) || 0
|
||||
entry.hash = abs
|
||||
? await hash.cachedHash(entry.path, abs, entry.size, mtimeMs, bytes => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue