Skip to content

Commit

Permalink
Merge branch 'strict'
Browse files Browse the repository at this point in the history
  • Loading branch information
JimiC committed Jun 21, 2019
2 parents 47ecf4e + 46eaabe commit d0a023a
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 125 deletions.
3 changes: 1 addition & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
"create",
"-s",
".",
"-v",
"-x",
"*",
"*/",
"!test"
"!test/fixtures"
],
"preLaunchTask": "npm: build - dev",
"stopOnEntry": false,
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,12 @@ Contents: The file names (and their data contents) and subdirectories names (wit

**Hashes are the same when:**

- Directory names and contents are the same
- Directory names and contents are the same `(strict: true)`
- Only root directory names are different and subdirectory names and all contents are the same `(strict: false)`

**Hashes are different when:**

- Directory names are different and contents are the same
- Directory names are different and contents are the same `(strict: true)`
- Directory contents are different and names are the same

## Usage
Expand Down
3 changes: 2 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ All `API` calls are `static` members of the `Integrity` class.
|Name|Type|Attribute|Default|Description|
|:---:|:---:|:---:|:---:|:---:|
|cryptoOptions|ICryptoOptions|optional|see `ICryptoOptions` |the `crypto` options to use|
|verbose|boolean|optional|true|whether the computed hashes are returned in a verbosely or non-verbosely structure|
|strict|boolean|optional|false|whether the computed hashes are strictly using the directory name|
|verbose|boolean|optional|false|whether the computed hashes are returned in a verbosely or non-verbosely structure|
|exclude|string[]|optional|[]|the paths to be excluded, supports also `glob` expressions (positive & negative)|

### ICryptoOptions
Expand Down
30 changes: 22 additions & 8 deletions src/app/integrity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ export class Integrity {
}
const exclude = options ? options.exclude : undefined;
const verbose = options ? options.verbose : undefined;
const strict = options ? options.strict : undefined;
if (!options || !options.cryptoOptions ||
!options.cryptoOptions.fileAlgorithm ||
!options.cryptoOptions.dirAlgorithm ||
!options.cryptoOptions.encoding
) {
options = await this._detectOptions(fileOrDirPath, integrity);
options = await this._detectOptions(fileOrDirPath, integrity, strict);
options.exclude = exclude;
options.strict = strict || options.strict;
options.verbose = verbose || options.verbose;
}
const _intObj = await Integrity.create(fileOrDirPath, options);
Expand All @@ -55,7 +57,7 @@ export class Integrity {
// 'integrity' is a hash
if (!_integrityObj) {
const _ls = await pfs.lstatAsync(fileOrDirPath);
const _basename = _ls.isFile() ? path.basename(fileOrDirPath) : '.';
const _basename = _ls.isFile() || options.strict ? path.basename(fileOrDirPath) : '.';
_integrityObj = {
hashes: {
[_basename]: integrity,
Expand Down Expand Up @@ -93,7 +95,8 @@ export class Integrity {
? await this._computeHashVerbosely(_options, dirPath)
: await this._computeHash(_options, dirPath);
const _hasHashes = typeof _hashes === 'string' ? !!_hashes : !!_hashes.hash;
return _hasHashes ? { ['.']: _hashes } : {};
const _dirName = options && options.strict ? path.basename(dirPath) : '.';
return _hasHashes ? { [_dirName]: _hashes } : {};
}

public static async createFileHash(filePath: string, options?: ICryptoOptions): Promise<IHashObject> {
Expand Down Expand Up @@ -193,11 +196,15 @@ export class Integrity {
}

/** @internal */
private static async _detectOptions(inPath: string, integrity: string): Promise<IntegrityOptions> {
private static async _detectOptions(
inPath: string,
integrity: string,
strict: boolean | undefined,
): Promise<IntegrityOptions> {
const _ls = await pfs.lstatAsync(inPath);
const _basename = _ls.isFile() ? path.basename(inPath) : '.';
// get the integrity object
let _integrityObj: IntegrityObject;
const _basename = _ls.isFile() || strict ? path.basename(inPath) : '.';
// 'integrity' is a file or directory path
if (await pfs.existsAsync(integrity)) {
integrity = await this._pathCheck(integrity);
Expand Down Expand Up @@ -225,6 +232,8 @@ export class Integrity {
if (!_first) {
return _options;
}
// detect strict
_options.strict = _basename !== '.';
// detect verbosity
_options.verbose = typeof _first !== 'string';
// detect options
Expand Down Expand Up @@ -348,10 +357,14 @@ export class Integrity {
const _verbose = options && options.verbose !== undefined
? options.verbose
: false;
const _strict = options && options.strict !== undefined
? options.strict
: false;
return {
cryptoOptions: _cryptoOptions,
exclude,
include,
strict: _strict,
verbose: _verbose,
};
}
Expand Down Expand Up @@ -391,8 +404,8 @@ export class Integrity {
if (!sourceDirPath || !integrityDirPath) {
return false;
}
const _getNodeOrDefault = (_obj: IHashObject, l: string): string | IVerboseHashObject =>
_obj[l] || _obj[Object.keys(_obj)[0]] || '';
const _getNodeOrDefault = (_obj: IHashObject, el: string): string | IVerboseHashObject =>
_obj[el] || _obj[Object.keys(_obj)[0]] || '';
const _findHash = (_array: string[], _hashObj: IHashObject): boolean => {
if (_array.length === 1) {
const _integrityHash: string | IVerboseHashObject = _getNodeOrDefault(_hashObj, _array[0]);
Expand Down Expand Up @@ -494,7 +507,8 @@ export class Integrity {
return;
}
_hash = _hash || createHash(dirAlgorithm);
_hash.update(path.basename(_dirPath));
const _dirName = options.strict || this._rootDirPath !== _dirPath ? path.basename(_dirPath) : '.';
_hash.update(_dirName);
const _files = await pfs.readdirAsync(_dirPath);
for (const file of _files) {
await _callback(file);
Expand Down
1 change: 1 addition & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export = (async (): Promise<void> => {
fileAlgorithm: pargs.fileAlgorithm,
},
exclude: exclusions,
strict: pargs.strict,
verbose: pargs.verbose,
};
command = pargs.command;
Expand Down
7 changes: 7 additions & 0 deletions src/common/yargsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export class YargsParser {
description: 'The path to the file or directory to hash',
type: 'string',
},
strict: {
alias: 'st',
default: false,
description: 'Use directory name in root hash',
type: 'boolean',
},
verbose: {
alias: 'v',
default: false,
Expand Down Expand Up @@ -124,6 +130,7 @@ export class YargsParser {
manifest: _pargs.manifest as boolean,
outPath: _pargs.output as string,
pretty: _pargs.pretty as boolean,
strict: _pargs.strict as boolean,
verbose: _pargs.verbose as boolean,
};
}
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/integrityOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { ICryptoOptions } from './cryptoOptions';
export interface IntegrityOptions {
cryptoOptions?: ICryptoOptions;
verbose?: boolean;
strict?: boolean;
exclude?: string[];
}
1 change: 1 addition & 0 deletions src/interfaces/normalizedIntegrityOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ICryptoOptions } from './cryptoOptions';
export interface INormalizedIntegrityOptions {
cryptoOptions: ICryptoOptions;
verbose: boolean;
strict: boolean;
exclude: string[];
include: string[];
}
1 change: 1 addition & 0 deletions src/interfaces/parsedArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export interface IParsedArgs {
manifest: boolean;
outPath: string;
pretty: boolean;
strict: boolean;
verbose: boolean;
}
15 changes: 12 additions & 3 deletions test/api/behavior.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ describe('Integrity: behavior tests', function (): void {
expect(sut).to.be.a('boolean').and.to.be.true;
});

it('directories have the same content but different names',
async function (): Promise<void> {
const sutDirPath = path.resolve(fixturesDirPath, './directory.1');
const hash = await Integrity.create(sutDirPath, { strict: false });
const sut = await Integrity.check(directoryDirPath, JSON.stringify(hash));
expect(hash.hashes).to.haveOwnProperty('.');
expect(sut).to.be.a('boolean').and.to.be.true;
});

});

context('to fail integrity check when', function (): void {
Expand Down Expand Up @@ -80,12 +89,12 @@ describe('Integrity: behavior tests', function (): void {
expect(sut).to.be.a('boolean').and.to.be.false;
});

it('directories have the same content but different names',
it(`directories have the same content but different names in 'strict' mode`,
async function (): Promise<void> {
const sutDirPath = path.resolve(fixturesDirPath, './directory.1');
const hash = await Integrity.create(sutDirPath);
const hash = await Integrity.create(sutDirPath, { strict: true });
const sut = await Integrity.check(directoryDirPath, JSON.stringify(hash));
expect(hash.hashes).to.haveOwnProperty('.');
expect(hash.hashes).to.haveOwnProperty('directory.1');
expect(sut).to.be.a('boolean').and.to.be.false;
});

Expand Down
Loading

0 comments on commit d0a023a

Please sign in to comment.