feat: read config, read history, hash files
most of the functionality exists now
This commit is contained in:
17
package.json
17
package.json
@@ -2,7 +2,10 @@
|
|||||||
"name": "pkgcomp",
|
"name": "pkgcomp",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"description": "Node package compare and change runner",
|
"description": "Node package compare and change runner",
|
||||||
"main": "index.js",
|
"bin": {
|
||||||
|
"pkgcomp": "src/cli.js"
|
||||||
|
},
|
||||||
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint '*.{js,mjs}' 'src/**/*.{js,mjs}'",
|
"lint": "eslint '*.{js,mjs}' 'src/**/*.{js,mjs}'",
|
||||||
"version": "npm-auto-version",
|
"version": "npm-auto-version",
|
||||||
@@ -50,18 +53,22 @@
|
|||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "es5"
|
"trailingComma": "es5"
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"joycon": "^2.2.4",
|
||||||
|
"md5-file": "^4.0.0",
|
||||||
|
"mkdirp": "^0.5.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@w33ble/npm-auto-tools": "*",
|
"@w33ble/npm-auto-tools": "*",
|
||||||
"eslint": "^5.15.3",
|
"eslint": "^5.15.3",
|
||||||
|
"eslint-config-airbnb": "^17.1.0",
|
||||||
"eslint-config-prettier": "^4.1.0",
|
"eslint-config-prettier": "^4.1.0",
|
||||||
"eslint-plugin-import": "^2.14.0",
|
"eslint-plugin-import": "^2.14.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.1.1",
|
||||||
"eslint-plugin-prettier": "^3.0.1",
|
"eslint-plugin-prettier": "^3.0.1",
|
||||||
|
"eslint-plugin-react": "^7.11.0",
|
||||||
"husky": "^1.3.1",
|
"husky": "^1.3.1",
|
||||||
"lint-staged": "^8.1.4",
|
"lint-staged": "^8.1.4",
|
||||||
"eslint-config-airbnb": "^17.1.0",
|
|
||||||
"eslint-plugin-jsx-a11y": "^6.1.1",
|
|
||||||
"eslint-plugin-react": "^7.11.0",
|
|
||||||
"prettier": "^1.16.4"
|
"prettier": "^1.16.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/args.js
Normal file
13
src/args.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module.exports = () => {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
return args.reduce(
|
||||||
|
(acc, arg) => {
|
||||||
|
if (arg === '--verbose') acc.verbose = true;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verbose: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
32
src/cli.js
Executable file
32
src/cli.js
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const utils = require('./utils');
|
||||||
|
const pkgcomp = require('./');
|
||||||
|
|
||||||
|
function parseArgs() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
return args.reduce(
|
||||||
|
(acc, arg) => {
|
||||||
|
if (arg === '--verbose') acc.verbose = true;
|
||||||
|
if (arg === '--use-yarn') acc.useYarn = true;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verbose: false,
|
||||||
|
useYarn: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConfig(args) {
|
||||||
|
// build config object, mixing in CLI overrides
|
||||||
|
const configOverrides = {};
|
||||||
|
if (args.useYarn) configOverrides.cmd = 'yarn';
|
||||||
|
return Object.assign({}, utils.getConfig(), configOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse args from CLI
|
||||||
|
const args = parseArgs();
|
||||||
|
|
||||||
|
pkgcomp(buildConfig(args), utils.getIdent(), args);
|
||||||
34
src/data.js
Normal file
34
src/data.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const mkdirp = require('mkdirp');
|
||||||
|
|
||||||
|
const CONFIG_FILENAME = 'pkgcomp.json';
|
||||||
|
|
||||||
|
exports.read = (fileRoot, ident) => {
|
||||||
|
const stats = fs.statSync(fileRoot);
|
||||||
|
const filePath = path.join(fileRoot, CONFIG_FILENAME);
|
||||||
|
|
||||||
|
// throw if pointing to a file
|
||||||
|
if (stats.isFile()) throw new Error(`getData expects a directory, got a file; ${fileRoot}`);
|
||||||
|
|
||||||
|
// create file if it's missing
|
||||||
|
if (!stats.isDirectory()) {
|
||||||
|
mkdirp.sync(fileRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(fs.readFileSync(filePath));
|
||||||
|
return data[ident] || {};
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
fs.writeFileSync(filePath, JSON.stringify({}));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.write = (fileRoot, ident, payload) => {
|
||||||
|
console.log('WRITE', { fileRoot, ident, payload });
|
||||||
|
throw new Error('Data write not implemented');
|
||||||
|
};
|
||||||
31
src/index.js
31
src/index.js
@@ -1,3 +1,30 @@
|
|||||||
module.exports = function mod() {
|
const md5File = require('md5-file');
|
||||||
// module code goes here
|
const data = require('./data');
|
||||||
|
// const utils = require('./utils');
|
||||||
|
|
||||||
|
function getFileHash(file, verbose = false) {
|
||||||
|
try {
|
||||||
|
return md5File.sync(file);
|
||||||
|
} catch (e) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
if (verbose) console.warn(`File not found: ${file}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function mod(config, ident, opts = {}) {
|
||||||
|
const packageData = data.read(config.dataDir, ident);
|
||||||
|
const firstRun = Object.keys(packageData).length === 0;
|
||||||
|
|
||||||
|
// create file hash object
|
||||||
|
const hashes = config.checkFiles.reduce((acc, file) => {
|
||||||
|
acc[file] = getFileHash(file, opts.verbose);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
console.log('First run?', firstRun);
|
||||||
|
|
||||||
|
data.write(config.dataDir, ident, {
|
||||||
|
hashes,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
64
src/utils.js
Normal file
64
src/utils.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const JoyCon = require('joycon');
|
||||||
|
|
||||||
|
exports.getRootPath = () => process.cwd();
|
||||||
|
|
||||||
|
exports.getHomeDir = () => os.homedir();
|
||||||
|
|
||||||
|
exports.getDataDir = () => path.join(exports.getHomeDir(), '.local/share');
|
||||||
|
|
||||||
|
exports.canAccessFile = (p, flag) => {
|
||||||
|
try {
|
||||||
|
fs.accessSync(p, flag || fs.constants.R_OK);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getFileContents = (filePath, opts = {}) => {
|
||||||
|
if (!exports.canAccessFile(filePath)) throw new Error(`File not found: ${filePath}`);
|
||||||
|
|
||||||
|
const content = fs.readFileSync(filePath);
|
||||||
|
if (opts.format === 'json') return JSON.parse(content);
|
||||||
|
if (opts.format === 'text') return content.toString();
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getRootFileContents = (filename, opts = {}) => {
|
||||||
|
return exports.getFileContents(path.join(exports.getRootPath(), filename), opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getIdent = () => {
|
||||||
|
const { name } = exports.getRootFileContents('package.json', { format: 'json' });
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getBranch = () => {
|
||||||
|
const headPath = path.join(exports.getRootPath(), '.git/HEAD');
|
||||||
|
if (!exports.canAccessFile(headPath)) throw new Error(`Git HEAD not found: ${headPath}`);
|
||||||
|
|
||||||
|
const head = fs.readFileSync(headPath);
|
||||||
|
const match = /ref: refs\/heads\/([^\n]+)/.exec(head);
|
||||||
|
if (!match) throw new Error(`Unable to read branch from ${headPath}`);
|
||||||
|
return match[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getConfig = (overrides = {}) => {
|
||||||
|
const joycon = new JoyCon();
|
||||||
|
const defaults = {
|
||||||
|
checkFiles: ['package-lock.json', 'yarn.lock'],
|
||||||
|
rootDir: process.cwd(),
|
||||||
|
dataDir: exports.getDataDir(),
|
||||||
|
cmd: 'npm',
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = joycon.loadSync({
|
||||||
|
packageKey: 'pkgcomp',
|
||||||
|
files: ['.config/pkgcomp.json', 'pkgcomp.json', 'package.json'],
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.assign(defaults, result.data, overrides);
|
||||||
|
};
|
||||||
10
yarn.lock
10
yarn.lock
@@ -1432,6 +1432,11 @@ isobject@^3.0.0, isobject@^3.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||||
|
|
||||||
|
joycon@^2.2.4:
|
||||||
|
version "2.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/joycon/-/joycon-2.2.4.tgz#ac4119d2673dfaa89b41efe5d6d670208e348bc6"
|
||||||
|
integrity sha512-Z4G7ZPovoSfAHCSEKznWV4IjyyUxzTY78Sgtr8inbnRxaZMAQGwqNJ46BDwcH3WgIwk0Xt1kpCsC/DFAioRtBA==
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
@@ -1659,6 +1664,11 @@ matcher@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
escape-string-regexp "^1.0.4"
|
escape-string-regexp "^1.0.4"
|
||||||
|
|
||||||
|
md5-file@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-4.0.0.tgz#f3f7ba1e2dd1144d5bf1de698d0e5f44a4409584"
|
||||||
|
integrity sha512-UC0qFwyAjn4YdPpKaDNw6gNxRf7Mcx7jC1UGCY4boCzgvU2Aoc1mOGzTtrjjLKhM5ivsnhoKpQVxKPp+1j1qwg==
|
||||||
|
|
||||||
micromatch@^3.1.8:
|
micromatch@^3.1.8:
|
||||||
version "3.1.10"
|
version "3.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
|
||||||
|
|||||||
Reference in New Issue
Block a user