Skip to content

Commit

Permalink
Better input handling and patchignore documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Haaxor1689 committed Dec 9, 2023
1 parent 2c5a237 commit f29a3bd
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 31 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,35 @@ haax-mpq <directoryPath> <archivePath?>
- `directoryPath`: Full path to the folder
- `archivePath`: Full path to the output MPQ file. Default: `<directoryPath>.mpq`

## Patchignore

You can add a `.patchignore` file to your archive folder that will list rules about what files shouldn't be included in the built archive. It uses a similar syntax to `.gitignore` files (using [anymatch](https://github.com/micromatch/anymatch) library).

If no `.patchignore` file is found, these defaults will be used:

```
# ignore git related stuff
.git/**
.github/**
.gitignore
# ignore all file formats that have nothing to do in patch
**/*.json
**/*.yml
**/*.yaml
**/*.exe
**/*.dll
**/*.db
**/*.csv
**/*.png
**/*.psd
**/*.txt
**/*.md
**/*.sql
.patchignore
```

## Executable

You can also use this CLI as a standalone executable that can be found in Releases. Download `haax-mpq.exe` for Windows or `haax-mpq` for Linux. You can then drag & drop any folder you want to archive onto the executable.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "haax-mpq",
"version": "1.1.3",
"version": "1.1.4",
"author": "Haaxor1689",
"license": "MIT",
"repository": {
Expand Down
34 changes: 20 additions & 14 deletions src/archiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@ import {
MPQ_CREATE,
MPQ_FILE
} from 'stormlib-node/dist/enums';
import Logger, { getTimeElapsed } from './logger';
import Patchignore from './patchignore';

const pad = (v: number, p = 2) => v.toString().padStart(p, '0');
export const getTimeElapsed = (startDate: Date, endDate = new Date()) => {
let ms = endDate.getTime() - startDate.getTime();
const m = Math.floor(ms / (1000 * 60));
ms %= 1000 * 60;
const s = Math.floor(ms / 1000);
ms %= 1000;
return `${m ? `${pad(m)}:` : ''}${pad(s)}.${pad(ms, 3)}`;
};

type ArchiveBuildOptions = {
archivePath: string;
directoryPath: string;
Expand All @@ -27,12 +36,12 @@ export const build = async (input: ArchiveBuildOptions) => {

const matches = await Patchignore(input.directoryPath);

Logger.log(`Building archive "${path.basename(input.archivePath)}"...`);
console.log(
`Building "${input.directoryPath}" into archive "${input.archivePath}"...`
);

const getAllFiles = async (filePath: string): Promise<string[]> => {
const relativePath = filePath
.slice(input.directoryPath.length + 1)
.replaceAll('\\\\', '/');
const relativePath = filePath.slice(input.directoryPath.length + 1);
if (await matches(relativePath)) return [];

if (!(await fs.lstat(filePath)).isDirectory()) return [filePath];
Expand All @@ -58,36 +67,33 @@ export const build = async (input: ArchiveBuildOptions) => {

try {
for (const file of files) {
const fullPath = file.replaceAll('\\\\', '/');
const relativePath = file
.slice(input.directoryPath.length + 1)
.replaceAll('\\\\', '/');
const relativePath = file.slice(input.directoryPath.length + 1);

if (await matches(relativePath)) {
Logger.log(`Ignored "${relativePath}"`);
console.log(`Ignored "${relativePath}"`);
continue;
}

SFileAddFileEx(
hMpq,
fullPath,
file,
relativePath,
MPQ_FILE.COMPRESS,
MPQ_COMPRESSION.ZLIB,
MPQ_COMPRESSION.NEXT_SAME
);
}

Logger.log('Compressing the archive...');
console.log('Compressing the archive...');
SFileCompactArchive(hMpq);

Logger.log(
console.log(
`Archive "${path.basename(input.archivePath)}" built in ${getTimeElapsed(
startTime
)}s`
);
} catch (e) {
Logger.error(e);
console.error(e);
} finally {
SFileCloseArchive(hMpq);
}
Expand Down
23 changes: 20 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,32 @@

import path from 'node:path';
import { build } from './archiver';
import { existsSync, lstatSync } from 'node:fs';

const args = process.argv.slice(2);
if (args.length === 0 || args.length > 2) {
console.log('Incorrect number of arguments passed');
process.exit(1);
}

const directoryPath = path.normalize(args[0]);
const archivePath =
args.length === 1 ? `${directoryPath}.mpq` : path.normalize(args[1]);
let directoryPath = path.normalize(args[0]);

// Handle trailing slash
if (directoryPath.endsWith('\\') || directoryPath.endsWith('/')) {
directoryPath = directoryPath.slice(0, -1);
}

// Check if directory exists
if (existsSync(directoryPath) && !lstatSync(directoryPath).isDirectory()) {
console.log('First argument must be a directory');
process.exit(1);
}

let archivePath = args.length === 1 ? directoryPath : path.normalize(args[1]);

// Handle extension
if (!archivePath.toLocaleLowerCase().endsWith('.mpq')) {
archivePath = `${directoryPath}.mpq`;
}

build({ directoryPath, archivePath });
12 changes: 0 additions & 12 deletions src/logger.ts

This file was deleted.

9 changes: 8 additions & 1 deletion src/patchignore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,15 @@ const defaultPatchignore = `

const Patchignore = async (directoryPath: string) => {
const patchignorePath = path.join(directoryPath, '.patchignore');
const exists = existsSync(patchignorePath);
console.log(
exists
? 'Loading .patchignore from target directory'
: 'Using default .patchignore'
);

const patchignore = (
existsSync(patchignorePath)
exists
? await fs.readFile(patchignorePath, { encoding: 'utf-8' })
: defaultPatchignore
)
Expand Down

0 comments on commit f29a3bd

Please sign in to comment.