@ig3/srf
Version:
Spaced Repetition Flashcards
174 lines (160 loc) • 4.23 kB
JavaScript
;
const parseArgs = require('node:util').parseArgs;
const path = require('path');
const optionsConfig = {
help: {
type: 'boolean',
short: 'h',
description: 'print usage',
},
port: {
type: 'string',
short: 'p',
default: '8000',
description: 'The port the server will listen on',
},
directory: {
type: 'string',
short: 'd',
default: path.join(process.env.HOME, '.local', 'share', 'srf'),
description: 'The directory containing the srf data',
},
db: {
type: 'string',
description: 'The name of the srf database file',
},
database: {
type: 'string',
short: 'D',
default: 'srf.db',
description: 'The name of the srf database file',
},
config: {
type: 'string',
short: 'c',
default: 'config.json',
description: 'The name of the configuraiton file',
},
scheduler: {
type: 'string',
short: 's',
default: '@ig3/srf-scheduler',
description: 'The scheduler plugin to load',
},
verbose: {
type: 'boolean',
short: 'v',
description: 'Produce verbose output',
},
media: {
type: 'string',
default: 'media',
description: 'The name of the sub-directory containing media files',
},
htdocs: {
type: 'string',
default: 'htdocs',
description: 'The name of the sub-directory containing static content overrides',
},
views: {
type: 'string',
default: 'views',
description: 'The name of the sub-directory containing view overrides',
},
};
function usage (options = optionsConfig) {
const name = path.basename(process.argv[1]);
let usage = 'Usage: ' + name + ' [OPTIONS]\n';
let maxOptionLength = 0;
Object.keys(options)
.forEach(key => {
if (key.length > maxOptionLength) maxOptionLength = key.length;
});
Object.keys(options)
.forEach(key => {
const opt = options[key];
let option = ' --' + key + (opt.type === 'string' ? '=ARG' : '[=BOOL]') +
(opt.multiple ? '*' : '');
if (opt.short) {
option += ',';
option = option.padEnd(maxOptionLength + 12, ' ');
option += '-' + opt.short;
}
if (opt.default) {
option = option.padEnd(maxOptionLength + 16, ' ');
option += '(default: ' +
(opt.multiple ? opt.default.join(',') : opt.default) + ')';
}
if (opt.description) {
option += '\n ' + opt.description;
}
usage += option + '\n\n';
});
return usage;
}
function resolveFullPath (root, p) {
if (p.substr(0, 1) === '/') {
return p;
}
if (p === '~') {
return process.env.HOME;
}
if (p.substr(0, 2) === '~/') {
return path.join(process.env.HOME, p.substr(2));
}
return path.join(root, p);
}
function main () {
const { values: options, positionals } =
parseArgs({
options: optionsConfig,
allowPositionals: true,
});
if (options.verbose) console.log('opts: ', options);
if (options.help) {
return console.log(usage());
}
const [command, subargv] = positionals;
// Make paths absolute
const root = path.join(process.env.HOME, '.local', 'share', 'srf');
options.directory = resolveFullPath(root, options.directory);
['config', 'database', 'media', 'htdocs', 'views']
.forEach(dir => {
options[dir] = resolveFullPath(options.directory, options[dir]);
});
const srf = require('../lib/srf')({
directory: options.directory,
database: options.database,
media: options.media,
config: options.config,
scheduler: options.scheduler,
});
['SIGTERM', 'SIGINT']
.forEach(signal => {
process.on(signal, () => {
srf.shutdown();
});
});
if (command === 'import') {
srf.importFile(subargv);
} else if (command === 'backup') {
srf.backupDatabase();
} else if (command === 'fix') {
srf.backupDatabase();
srf.fixDatabase();
} else if (command === undefined || command === 'run') {
srf.runServer(options, subargv);
} else {
throw new Error('Unsupported command: ' + command);
}
}
try {
main();
} catch (err) {
console.error('failed with error:');
console.error(' ' + err.message);
console.error(' ' + err.stack);
console.error(usage());
process.exitCode = 1;
}