Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: prefer input files not from the output path #767

Merged
merged 3 commits into from
Oct 29, 2023
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
25 changes: 21 additions & 4 deletions src/modules/fileIndexer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'node:path';

import ProgressBar, { ProgressBarSymbol } from '../console/progressBar.js';
import FsPoly from '../polyfill/fsPoly.js';
import ArchiveEntry from '../types/files/archives/archiveEntry.js';
import Rar from '../types/files/archives/rar.js';
import SevenZip from '../types/files/archives/sevenZip.js';
Expand Down Expand Up @@ -48,6 +49,9 @@ export default class FileIndexer extends Module {
}
});

const outputDir = path.resolve(this.options.getOutputDirRoot());
const outputDirDisk = (await FsPoly.disks()).find((mount) => outputDir.startsWith(mount));

// Sort the file arrays
[...results.entries()]
.forEach(([hashCode, filesForHash]) => filesForHash.sort((fileOne, fileTwo) => {
Expand All @@ -67,14 +71,27 @@ export default class FileIndexer extends Module {
return fileOneArchived - fileTwoArchived;
}

// Then, prefer files that are already in the output directory
const outputDir = path.resolve(this.options.getOutputDirRoot());
const fileOneInOutput = path.resolve(fileOne.getFilePath()).startsWith(outputDir) ? 0 : 1;
const fileTwoInOutput = path.resolve(fileTwo.getFilePath()).startsWith(outputDir) ? 0 : 1;
// Then, prefer files that are NOT already in the output directory
// This is in case the output file is invalid and we're trying to overwrite it with
// something else. Otherwise, we'll just attempt to overwrite the invalid output file with
// itself, still resulting in an invalid output file.
const fileOneInOutput = path.resolve(fileOne.getFilePath()).startsWith(outputDir) ? 1 : 0;
const fileTwoInOutput = path.resolve(fileTwo.getFilePath()).startsWith(outputDir) ? 1 : 0;
if (fileOneInOutput !== fileTwoInOutput) {
return fileOneInOutput - fileTwoInOutput;
}

// Then, prefer files that are on the same disk for fs efficiency see {@link FsPoly#mv}
if (outputDirDisk) {
const fileOneInOutputDisk = path.resolve(fileOne.getFilePath())
.startsWith(outputDirDisk) ? 0 : 1;
const fileTwoInOutputDisk = path.resolve(fileTwo.getFilePath())
.startsWith(outputDirDisk) ? 0 : 1;
if (fileOneInOutputDisk !== fileTwoInOutputDisk) {
return fileOneInOutputDisk - fileTwoInOutputDisk;
}
}

// Otherwise, be deterministic
return fileOne.getFilePath().localeCompare(fileTwo.getFilePath());
}));
Expand Down
12 changes: 9 additions & 3 deletions src/polyfill/fsPoly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ export default class FsPoly {
static readonly FILE_READING_CHUNK_SIZE = 1024 * 1024; // 1MiB

// Assume that all drives we're reading from or writing to were already mounted at startup
private static readonly DRIVE_MOUNTS = nodeDiskInfo.getDiskInfoSync()
.map((info) => info.mounted)
.sort((a, b) => b.split(/[\\/]/).length - a.split(/[\\/]/).length);
public static readonly DRIVE_MOUNTS = FsPoly.disksSync();

static async canSymlink(tempDir: string): Promise<boolean> {
const source = await this.mktemp(path.join(tempDir, 'source'));
Expand Down Expand Up @@ -67,6 +65,14 @@ export default class FsPoly {
.sort((a, b) => b.split(/[\\/]/).length - a.split(/[\\/]/).length);
}

static disksSync(): string[] {
return nodeDiskInfo.getDiskInfoSync()
.filter((drive) => drive.available > 0)
.map((drive) => drive.mounted)
// Sort by mount points with the deepest number of subdirectories first
.sort((a, b) => b.split(/[\\/]/).length - a.split(/[\\/]/).length);
}

/**
* There is no promise version of existsSync()
*/
Expand Down
Loading