feat: read config, read history, hash files

most of the functionality exists now
This commit is contained in:
2019-04-04 15:28:24 -07:00
parent 655c27a89d
commit ca2fc85135
8 changed files with 194 additions and 10 deletions

View File

@@ -1,3 +0,0 @@
const mod = require('./src/index.js');
module.exports = mod;

View File

@@ -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
View 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
View 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
View 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');
};

View File

@@ -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
View 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);
};

View File

@@ -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"