Skip to content

Commit

Permalink
Merge branch 'main' into emmercm/pr-943-again
Browse files Browse the repository at this point in the history
  • Loading branch information
emmercm authored Feb 24, 2024
2 parents 75a4170 + 6d077c3 commit ce338ec
Show file tree
Hide file tree
Showing 26 changed files with 803 additions and 230 deletions.
4 changes: 2 additions & 2 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
// Renovate's defaults for these options
schedule: 'at any time',
prCreation: 'immediate',
platformAutomerge: true,
automerge: true,
minimumReleaseAge: '0 days'
},

Expand All @@ -82,7 +82,7 @@
// Renovate's defaults for these options
schedule: 'at any time',
prCreation: 'immediate',
platformAutomerge: true,
automerge: true,
},

// Disable automatic merging of GitHub Actions major version updates
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Information about the inner workings of `igir`.
- Patch files are matched to ROMs found
- ROM preferences are applied (`--single`, see [filtering & preference docs](../roms/filtering-preferences.md#preferences-for-1g1r))
- ROMs are combined (`--zip-dat-name`)
- ROMs are written to the output directory, if specified (`copy`, `move`, `symlink`)
- ROMs are written to the output directory, if specified (`copy`, `move`, `link`)
- Written ROMs are tested for accuracy, if specified (`test`)
- A "dir2dat" DAT is created, if specified (`dir2dat`) (see [dir2dat docs](../dats/dir2dat.md))
- A "fixdat" is created, if specified (`fixdat`) (see [fixdats docs](../dats/fixdats.md))
Expand Down
8 changes: 4 additions & 4 deletions docs/advanced/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ There are additional levels of verbosity that can be enabled with the `-v` flag:

This includes:

- Files being copied, zipped, and symlinked
- Files being copied, zipped, and linked
- [dir2dat](../dats/dir2dat.md) files being created
- [Fixdat](../dats/fixdats.md) files being created
- Input files deleted after being moved
Expand All @@ -31,13 +31,13 @@ There are additional levels of verbosity that can be enabled with the `-v` flag:
This includes:

- Everything from the `INFO` level above
- Files skipped from being copied, zipped, or symlinked because the output file exists and an `--overwrite` option wasn't provided
- Files skipped from being copied, zipped, or linked because the output file exists and an `--overwrite` option wasn't provided
- [Fixdat](../dats/fixdats.md) files skipped from being created because all games were found
Usage:
```shell
igir [commands..] [options] -v
igir [commands..] [options] -vv
```
This level is helpful to turn on if you want debug why an action didn't take place.
Expand All @@ -47,7 +47,7 @@ There are additional levels of verbosity that can be enabled with the `-v` flag:
Usage:

```shell
igir [commands..] [options] -v
igir [commands..] [options] -vvv
```

!!! note
Expand Down
3 changes: 2 additions & 1 deletion docs/alternatives.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ There are a few different popular ROM managers that have similar features:
| DATs: built-in download manager ||| ⚠️ via [DatVault](https://www.datvault.com/) ||
| DATs: supports DAT URLs |||||
| DATs: create from files (dir2dat) |[dir2dat docs](dats/dir2dat.md) ||||
| DATs: fixdat creation |[Fixdat docs](dats/fixdats.md) ||||
| DATs: combine multiple |||||
| Archives: extraction formats | ✅ many formats ([reading archives docs](input/reading-archives.md)) |`.zip`, `.7z`, `.rar` | ⚠️ `.zip`, `.7z` | ⚠️ `.zip`, `.7z` |
| Archives: creation formats |`.zip` only by design ([writing archives docs](output/writing-archives.md)) |`.zip`, `.7z`, `.rar` | ⚠️ `.zip`, `.7z` | ⚠️ `.zip`, `.7z` |
Expand All @@ -29,10 +30,10 @@ There are a few different popular ROM managers that have similar features:
| Filtering: 1G1R support | ✅ many options | ⚠️ region & language only || ⚠️ only at DB setup |
| Reports: report-only mode |||||
| Reports: easily parseable | ✅ CSV | ⚠️ newline-separated "have" & "miss" lists | ⚠️ newline-separated "full" & "fix" reports | ⚠️ newline-separated "have" & "miss" lists |
| Output: file link support | ✅ hard & symbolic links ||||
| Output: separate input & output dirs ||| ⚠️ yes but files are always moved ||
| Output: subdirectory customization ||| ⚠️ depends on DAT organization ||
| Output: create single archive for DAT |||||
| Output: fixdat creation |[Fixdat docs](dats/fixdats.md) ||||

!!! note

Expand Down
6 changes: 3 additions & 3 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ Move ROMs from an input directory to the output directory. The same directory ca

ROMs will be deleted from their input directory after _all_ ROMs for _every_ [DAT](dats/introduction.md) have been written.

### `symlink`
### `link`

Create a symbolic link in the output directory to a ROM in the input directory.
Create a link in the output directory to a ROM in the input directory.

By default, absolute file paths will be used. You can specify the `--symlink-relative` option to use relative file paths.
By default, hard links are created, similar to [ln(1)](https://linux.die.net/man/1/ln). Use the `--symlink` option to create symbolic links.

## ROM archiving

Expand Down
2 changes: 1 addition & 1 deletion docs/dats/fixdats.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Fixdats help you find files missing from your collection, and they can be used to generate a collection of those files once you've found them. This sub-collection of files can then be merged back into your main collection.

The `fixdat` command creates a [Logiqx XML](http://www.logiqx.com/DatFAQs/) DAT for every input DAT (the [`--dat <path>` option](./processing.md#scanning-for-dats)) that is missing ROMs. When writing (`copy`, `move`, and `symlink` [commands](../commands.md)), the fixdat will be written to the output directory, otherwise it will be written to the working directory.
The `fixdat` command creates a [Logiqx XML](http://www.logiqx.com/DatFAQs/) DAT for every input DAT (the [`--dat <path>` option](./processing.md#scanning-for-dats)) that is missing ROMs. When writing (`copy`, `move`, and `link` [commands](../commands.md)), the fixdat will be written to the output directory, otherwise it will be written to the working directory.

For example:

Expand Down
2 changes: 1 addition & 1 deletion docs/output/cleaning.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Output Cleaning

The `igir clean` [command](../commands.md) can be used when writing (`igir copy`, `igir move`, and `igir symlink`) to delete files from the `--output <path>` directory that are either:
The `igir clean` [command](../commands.md) can be used when writing (`igir copy`, `igir move`, and `igir link`) to delete files from the `--output <path>` directory that are either:

- Not contained in any provided [DAT](../dats/introduction.md) (the [`--dat <path>` option](../dats/processing.md#scanning-for-dats)).
- Contained in a [DAT](../dats/introduction.md) (the [`--dat <path>` option](../dats/processing.md#scanning-for-dats)), but the file is in the incorrect location.
Expand Down
6 changes: 5 additions & 1 deletion src/igir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ export default class Igir {
async main(): Promise<void> {
// Windows 10 may require admin privileges to symlink at all
// @see https://github.com/nodejs/node/issues/18518
if (this.options.shouldSymlink() && process.platform === 'win32' && !await FsPoly.canSymlink(Constants.GLOBAL_TEMP_DIR)) {
if (this.options.shouldLink()
&& this.options.getSymlink()
&& process.platform === 'win32'
&& !await FsPoly.canSymlink(Constants.GLOBAL_TEMP_DIR)
) {
if (!await isAdmin()) {
throw new Error(`${Constants.COMMAND_NAME} does not have permissions to create symlinks, please try running as administrator`);
}
Expand Down
68 changes: 46 additions & 22 deletions src/modules/argumentsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class ArgumentsParser {
const groupDatInput = 'DAT input options:';
const groupRomOutput = 'ROM output options (processed in order):';
const groupRomZip = 'ROM zip command options:';
const groupRomSymlink = 'ROM symlink command options:';
const groupRomLink = 'ROM link command options:';
const groupRomHeader = 'ROM header options:';
const groupRomSet = 'ROM set options:';
const groupRomFiltering = 'ROM filtering options:';
Expand All @@ -78,10 +78,11 @@ export default class ArgumentsParser {

// Add every command to a yargs object, recursively, resulting in the ability to specify
// multiple commands
const commands = [
const commands: [string, string | boolean][] = [
['copy', 'Copy ROM files from the input to output directory'],
['move', 'Move ROM files from the input to output directory'],
['symlink', 'Create symlinks in the output directory to ROM files in the input directory'],
['link', 'Create links in the output directory to ROM files in the input directory'],
['symlink', false],
['extract', 'Extract ROM files in archives when copying or moving'],
['zip', 'Create zip archives of ROMs when copying or moving'],
['test', 'Test ROMs for accuracy after writing them to the output directory'],
Expand All @@ -99,10 +100,18 @@ export default class ArgumentsParser {
// specifying `igir copy --help`.
.filter(([command]) => commandsToAdd.includes(command))
.forEach(([command, description]) => {
yargsObj.command(command, description, (yargsSubObj) => addCommands(
yargsSubObj,
commandsToAdd.filter((c) => c !== command),
));
if (typeof description === 'string') {
yargsObj.command(command, description, (yargsSubObj) => addCommands(
yargsSubObj,
commandsToAdd.filter((c) => c !== command),
));
} else {
// A deprecation message should be printed elsewhere
yargsObj.command(command, false, (yargsSubObj) => addCommands(
yargsSubObj,
commandsToAdd.filter((c) => c !== command),
));
}
});

if (commandsToAdd.length === 0) {
Expand All @@ -111,21 +120,21 @@ export default class ArgumentsParser {
}
return yargsObj
.middleware((middlewareArgv) => {
/* eslint-disable no-param-reassign */
// Ignore duplicate commands
// eslint-disable-next-line no-param-reassign
middlewareArgv._ = middlewareArgv._.reduce(ArrayPoly.reduceUnique(), []);
}, true)
.check((checkArgv) => {
if (checkArgv.help) {
return true;
}

const writeCommands = ['copy', 'move', 'symlink'].filter((command) => checkArgv._.includes(command));
const writeCommands = ['copy', 'move', 'link', 'symlink'].filter((command) => checkArgv._.includes(command));
if (writeCommands.length > 1) {
throw new Error(`Incompatible commands: ${writeCommands.join(', ')}`);
}

const archiveCommands = ['symlink', 'extract', 'zip'].filter((command) => checkArgv._.includes(command));
const archiveCommands = ['link', 'symlink', 'extract', 'zip'].filter((command) => checkArgv._.includes(command));
if (archiveCommands.length > 1) {
throw new Error(`Incompatible commands: ${archiveCommands.join(', ')}`);
}
Expand All @@ -142,8 +151,8 @@ export default class ArgumentsParser {
});

['test', 'clean'].forEach((command) => {
if (checkArgv._.includes(command) && ['copy', 'move', 'symlink'].every((write) => !checkArgv._.includes(write))) {
throw new Error(`Command "${command}" requires one of the commands: copy, move, or symlink`);
if (checkArgv._.includes(command) && ['copy', 'move', 'link', 'symlink'].every((write) => !checkArgv._.includes(write))) {
throw new Error(`Command "${command}" requires one of the commands: copy, move, or link`);
}
});

Expand Down Expand Up @@ -219,7 +228,7 @@ export default class ArgumentsParser {
.option('dat-regex', {
type: 'string',
coerce: (val) => {
this.logger.warn('--dat-regex is deprecated, use --dat-name-regex instead');
this.logger.warn('the \'--dat-regex\' option is deprecated, use \'--dat-name-regex\' instead');
return ArgumentsParser.readRegexFile(val);
},
requiresArg: true,
Expand All @@ -235,7 +244,7 @@ export default class ArgumentsParser {
.option('dat-regex-exclude', {
type: 'string',
coerce: (val) => {
this.logger.warn('--dat-regex-exclude is deprecated, use --dat-name-regex-exclude instead');
this.logger.warn('the \'--dat-regex-exclude\' option is deprecated, use \'--dat-name-regex-exclude\' instead');
return ArgumentsParser.readRegexFile(val);
},
requiresArg: true,
Expand Down Expand Up @@ -280,7 +289,7 @@ export default class ArgumentsParser {
.option('fixdat', {
type: 'boolean',
coerce: (val: boolean) => {
this.logger.warn('--fixdat is deprecated, use the fixdat command instead');
this.logger.warn('the \'--fixdat\' option is deprecated, use the \'fixdat\' command instead');
return val;
},
implies: 'dat',
Expand Down Expand Up @@ -420,18 +429,33 @@ export default class ArgumentsParser {
return true;
})

.option('symlink', {
group: groupRomLink,
description: 'Creates symbolic links instead of hard links',
type: 'boolean',
})
.middleware((middlewareArgv) => {
if (middlewareArgv._.includes('symlink')) {
this.logger.warn('the \'symlink\' command is deprecated, use \'link --symlink\' instead');
if (middlewareArgv.symlink === undefined) {
// eslint-disable-next-line no-param-reassign
middlewareArgv.symlink = true;
}
}
}, true)
.option('symlink-relative', {
group: groupRomSymlink,
group: groupRomLink,
description: 'Create symlinks as relative to the target path, as opposed to absolute',
type: 'boolean',
implies: 'symlink',
})
.check((checkArgv) => {
if (checkArgv.help) {
return true;
}
const needSymlink = ['symlink-relative'].filter((option) => checkArgv[option]);
if (!checkArgv._.includes('symlink') && needSymlink.length > 0) {
throw new Error(`Missing required command for option${needSymlink.length !== 1 ? 's' : ''} ${needSymlink.join(', ')}: symlink`);
const needLinkCommand = ['symlink'].filter((option) => checkArgv[option]);
if (!checkArgv._.includes('link') && !checkArgv._.includes('symlink') && needLinkCommand.length > 0) {
throw new Error(`Missing required command for option${needLinkCommand.length !== 1 ? 's' : ''} ${needLinkCommand.join(', ')}: link`);
}
return true;
})
Expand Down Expand Up @@ -502,7 +526,7 @@ export default class ArgumentsParser {
.option('language-filter', {
type: 'string',
coerce: (val: string) => {
this.logger.warn('--language-filter is deprecated, use --filter-language instead');
this.logger.warn('the \'--language-filter\' option is deprecated, use \'--filter-language\' instead');
return val.split(',');
},
requiresArg: true,
Expand All @@ -520,7 +544,7 @@ export default class ArgumentsParser {
.option('region-filter', {
type: 'string',
coerce: (val: string) => {
this.logger.warn('--region-filter is deprecated, use --filter-region instead');
this.logger.warn('the \'--region-filter\' option is deprecated, use \'--filter-region\' instead');
return val.split(',');
},
requiresArg: true,
Expand Down Expand Up @@ -704,8 +728,8 @@ export default class ArgumentsParser {
default: Constants.ROM_WRITER_DEFAULT_THREADS,
})
.middleware((middlewareArgv) => {
/* eslint-disable no-param-reassign */
if (middlewareArgv.zipDatName) {
// eslint-disable-next-line no-param-reassign
middlewareArgv.datThreads = 1;
}
}, true)
Expand Down
Loading

0 comments on commit ce338ec

Please sign in to comment.