@mjcctech/meteor-desktop
Version:
Build a Meteor's desktop client with hot code push.
251 lines (222 loc) • 8.24 kB
JavaScript
"use strict";var module1=module;module1.export({default:()=>Desktop});var regeneratorRuntime;module1.link('regenerator-runtime/runtime',{default(v){regeneratorRuntime=v}},0);var shell;module1.link('shelljs',{default(v){shell=v}},1);var fs;module1.link('fs',{default(v){fs=v}},2);var path;module1.link('path',{default(v){path=v}},3);var Log;module1.link('./log',{default(v){Log=v}},4);// eslint-disable-next-line no-unused-vars
shell.config.fatal = true;
/**
* Checks if the path is empty.
* @param {string} searchPath
* @returns {boolean}
*/
function isEmptySync(searchPath) {
let stat;
try {
stat = fs.statSync(searchPath);
} catch (e) {
return true;
}
if (stat.isDirectory()) {
const items = fs.readdirSync(searchPath);
return !items || !items.length;
}
return false;
}
/**
* Represents the .desktop directory.
* @class
* @property {desktopSettings} settings
*/
class Desktop {
/**
* @param {MeteorDesktop} $ - context
*
* @constructor
*/
constructor($) {
this.$ = $;
this.log = new Log('desktop');
this.settings = null;
this.dependencies = null;
}
/**
* Tries to read and returns settings.json contents from .desktop dir.
*
* @returns {desktopSettings|null}
*/
getSettings() {
if (!this.settings) {
try {
this.settings = JSON.parse(
fs.readFileSync(this.$.env.paths.desktop.settings, 'UTF-8')
);
} catch (e) {
this.log.error('error while trying to read \'.desktop/settings.json\': ', e);
process.exit(1);
}
}
return this.settings;
}
/**
* Returns a version hash representing current .desktop contents.
* @returns {string}
*/
async getHashVersion() {
this.log.info('calculating hash version from .desktop contents');
const version = await this.$.utils.readFilesAndComputeHash(this.$.env.paths.desktop.root);
this.log.verbose(`calculated .desktop hash version is ${version.hash}`);
return version.hash;
}
/**
* Tries to read a module.json file from a module at provided path.
*
* @param {string} modulePath - path to the module dir
* @returns {Object}
*/
getModuleConfig(modulePath) {
let moduleConfig = {};
try {
moduleConfig = JSON.parse(
fs.readFileSync(path.join(modulePath, 'module.json'), 'UTF-8')
);
} catch (e) {
this.log.error(
`error while trying to read 'module.json' from '${modulePath}' module: `,
e
);
process.exit(1);
}
if (!('name' in moduleConfig)) {
this.log.error(`no 'name' field defined in 'module.json' in '${modulePath}' module.`);
process.exit(1);
}
return moduleConfig;
}
/**
* Scans all modules for module.json and gathers this configuration altogether.
*
* @returns {[]}
*/
gatherModuleConfigs() {
const configs = [];
if (!isEmptySync(this.$.env.paths.desktop.modules)) {
shell.ls('-d', path.join(this.$.env.paths.desktop.modules, '*')).forEach(
(module) => {
if (fs.lstatSync(module).isDirectory()) {
const moduleConfig = this.getModuleConfig(module);
moduleConfig.dirName = path.parse(module).name;
configs.push(moduleConfig);
}
}
);
}
return configs;
}
/**
* Summarizes all dependencies defined in .desktop.
*
* @params {Object} settings - settings.json
* @params {boolean} checkModules - whether to gather modules dependencies
* @params {boolean} refresh - recompute
* @returns {{fromSettings: {}, plugins: {}, modules: {}}}
*/
getDependencies(settings = null, checkModules = true, refresh = false) {
if (!refresh && this.dependencies) {
return this.dependencies;
}
const dependencies = {
fromSettings: {},
plugins: {},
modules: {}
};
/** @type {desktopSettings} * */
const settingsJson = settings || this.getSettings();
// Settings can have a 'dependencies' field.
if ('dependencies' in settingsJson) {
dependencies.fromSettings = settingsJson.dependencies;
}
// Plugins are also a npm packages.
if ('plugins' in settingsJson) {
dependencies.plugins = Object.keys(settingsJson.plugins).reduce((plugins, plugin) => {
/* eslint-disable no-param-reassign */
if (typeof settingsJson.plugins[plugin] === 'object') {
plugins[plugin] = settingsJson.plugins[plugin].version;
} else {
plugins[plugin] = settingsJson.plugins[plugin];
}
return plugins;
}, {});
}
// Each module can have its own dependencies defined.
const moduleDependencies = {};
if (checkModules) {
const configs = this.gatherModuleConfigs();
configs.forEach(
(moduleConfig) => {
if (!('dependencies' in moduleConfig)) {
moduleConfig.dependencies = {};
}
if (moduleConfig.name in moduleDependencies) {
this.log.error(`duplicate name '${moduleConfig.name}' in 'module.json' in ` +
`'${moduleConfig.dirName}' - another module already registered the same name.`);
process.exit(1);
}
moduleDependencies[moduleConfig.name] = moduleConfig.dependencies;
}
);
}
dependencies.modules = moduleDependencies;
this.dependencies = dependencies;
return dependencies;
}
/**
* Copies the .desktop scaffold into the meteor app dir.
* Adds entry to .meteor/.gitignore.
*/
scaffold() {
this.log.info('creating .desktop scaffold in your project');
if (this.$.utils.exists(this.$.env.paths.desktop.root)) {
this.log.warn('.desktop already exists - delete it if you want a new one to be ' +
'created');
return;
}
shell.cp('-r', this.$.env.paths.scaffold, this.$.env.paths.desktop.root);
shell.mkdir(this.$.env.paths.desktop.import);
this.log.info('.desktop directory prepared');
}
/**
* Verifies if all mandatory files are present in the .desktop.
*
* @returns {boolean}
*/
check() {
this.log.verbose('checking .desktop existence');
return !!(this.$.utils.exists(this.$.env.paths.desktop.root) &&
this.$.utils.exists(this.$.env.paths.desktop.settings) &&
this.$.utils.exists(this.$.env.paths.desktop.desktop));
}
}
/**
* @typedef {Object} desktopSettings
* @property {string} name
* @property {string} projectName
* @property {boolean} devTools
* @property {boolean} devtron
* @property {boolean} desktopHCP
* @property {Object} squirrel
* @property {string} squirrel.autoUpdateFeedUrl
* @property {Object} squirrel.autoUpdateFeedHeaders
* @property {Object} squirrel.autoUpdateCheckOnStart
* @property {Object} desktopHCPSettings
* @property {boolean} desktopHCPSettings.ignoreCompatibilityVersion
* @property {boolean} desktopHCPSettings.blockAppUpdateOnDesktopIncompatibility
* @property {number} webAppStartupTimeout
* @property {Array} linkPackages
* @property {Array} exposedModules
* @property {Object} window
* @property {Object} windowDev
* @property {Object} packageJsonFields
* @property {Object} builderOptions
* @property {Object} builderCliOptions
* @property {Object} packagerOptions
* @property {Object} plugins
* @property {Object} dependencies
* @property {boolean} uglify
* @property {string} version
* */