Skip to content

Instantly share code, notes, and snippets.

@monkbroc
Last active October 24, 2016 17:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkbroc/589dd2c721480df90fd62aff1c8c02b4 to your computer and use it in GitHub Desktop.
Save monkbroc/589dd2c721480df90fd62aff1c8c02b4 to your computer and use it in GitHub Desktop.
CLI settings with additional logging
/**
******************************************************************************
* @file settings.js
* @author David Middlecamp (david@particle.io)
* @company Particle ( https://www.particle.io/ )
* @source https://github.com/spark/particle-cli
* @version V1.0.0
* @date 14-February-2014
* @brief Setting module
******************************************************************************
Copyright (c) 2016 Particle Industries, Inc. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
*/
'use strict';
var fs = require('fs');
var path = require('path');
var extend = require('xtend');
var chalk = require('chalk');
var specs = require('./lib/deviceSpecs');
var settings = {
commandPath: './commands/',
apiUrl: 'https://api.particle.io',
clientId: 'CLI2',
access_token: null,
minimumApiDelay: 500,
//useOpenSSL: true,
useSudoForDfu: false,
// TODO set to false once we give flags to control this
verboseOutput: true,
disableUpdateCheck: false,
updateCheckInterval: 24 * 60 * 60 * 1000, // 24 hours
updateCheckTimeout: 3000,
//2 megs -- this constant here is arbitrary
MAX_FILE_SIZE: 1024 * 1024 * 2,
overridesFile: null,
wirelessSetupFilter: /^Photon-.*$/,
notSourceExtensions: [
'.ds_store',
'.jpg',
'.gif',
'.png',
'.include',
'.ignore',
'.ds_store',
'.git',
'.bin'
],
showIncludedSourceFiles: true,
dirIncludeFilename: 'particle.include',
dirExcludeFilename: 'particle.ignore',
knownApps: {
'deep_update_2014_06': true,
'cc3000': true,
'cc3000_1_14': true,
'tinker': true,
'voodoo': true
},
knownPlatforms: {
0: 'Core',
6: 'Photon',
8: 'P1',
10: 'Electron',
88: 'Duo',
103: 'Bluz'
},
updates: {
'2b04:d006': {
systemFirmwareOne: 'system-part1-0.5.3-photon.bin',
systemFirmwareTwo: 'system-part2-0.5.3-photon.bin'
},
'2b04:d008': {
systemFirmwareOne: 'system-part1-0.5.3-p1.bin',
systemFirmwareTwo: 'system-part2-0.5.3-p1.bin'
},
'2b04:d00a': {
systemFirmwareOne: 'system-part1-0.5.3-electron.bin',
systemFirmwareTwo: 'system-part2-0.5.3-electron.bin'
}
},
commandMappings: path.join(__dirname, 'mappings.json')
};
//fix the paths on the known apps mappings
Object.keys(specs).forEach(function (id) {
var deviceSpecs = specs[id];
var knownApps = deviceSpecs['knownApps'];
for (var appName in knownApps) {
knownApps[appName] = path.join(__dirname,'binaries', knownApps[appName]);
};
});
settings.commandPath = __dirname + '/commands/';
settings.findHomePath = function() {
var envVars = [
'home',
'HOME',
'HOMEPATH',
'USERPROFILE'
];
for (var i=0;i<envVars.length;i++) {
var dir = process.env[envVars[i]];
if (dir && fs.existsSync(dir)) {
return dir;
}
}
return __dirname;
};
settings.ensureFolder = function() {
var particleDir = path.join(settings.findHomePath(), '.particle');
console.log('Settings path for CLI: ' + particleDir);
if (!fs.existsSync(particleDir)) {
fs.mkdirSync(particleDir);
}
return particleDir;
};
settings.findOverridesFile = function(profile) {
profile = profile || settings.profile || 'particle';
var particleDir = settings.ensureFolder();
console.log('Profile file: ' + path.join(particleDir, profile + '.config.json'));
return path.join(particleDir, profile + '.config.json');
};
settings.loadOverrides = function (profile) {
profile = profile || settings.profile || 'particle';
try {
var filename = settings.findOverridesFile(profile);
if (fs.existsSync(filename)) {
console.log('Reading profile file ' + filename);
settings.overrides = JSON.parse(fs.readFileSync(filename));
console.log('Done reading profile');
settings = extend(settings, settings.overrides);
}
} catch (ex) {
console.error('There was an error reading ' + settings.overrides + ': ', ex);
}
return settings;
};
settings.whichProfile = function() {
settings.profile = 'particle';
settings.readProfileData();
};
/**
* in another file in our user dir, we store a profile name that switches between setting override files
*/
settings.switchProfile = function(profileName) {
if (!settings.profile_json) {
settings.profile_json = {};
}
settings.profile_json.name = profileName;
settings.saveProfileData();
};
settings.readProfileData = function() {
var particleDir = settings.ensureFolder();
var proFile = path.join(particleDir, 'profile.json'); //proFile, get it?
try {
if (fs.existsSync(proFile)) {
console.log('Reading overall config file ' + proFile);
var data = JSON.parse(fs.readFileSync(proFile));
console.log('Done reading overall config file');
settings.profile = (data) ? data.name : 'particle';
settings.profile_json = data;
} else {
settings.profile = 'particle';
settings.profile_json = {};
}
} catch (ex) {
console.error('There was an error reading ' + proFile + ': ', ex);
}
};
settings.saveProfileData = function() {
var particleDir = settings.ensureFolder();
var proFile = path.join(particleDir, 'profile.json'); //proFile, get it?
fs.writeFileSync(proFile, JSON.stringify(settings.profile_json, null, 2), { mode: '600' });
};
// this is here instead of utilities to prevent a require-loop
// when files that utilties requires need settings
function matchKey(needle, obj, caseInsensitive) {
needle = (caseInsensitive) ? needle.toLowerCase() : needle;
for (var key in obj) {
var keyCopy = (caseInsensitive) ? key.toLowerCase() : key;
if (keyCopy === needle) {
//return the original
return key;
}
}
return null;
};
settings.override = function (profile, key, value) {
if (!settings.overrides) {
settings.overrides = {};
}
if (!settings[key]) {
// find any key that matches our key, regardless of case
var realKey = matchKey(key, settings, true);
if (realKey) {
//console.log("Using the setting \"" + realKey + "\" instead ");
key = realKey;
}
}
//store the new value (redundant)
settings[key] = value;
//store that in overrides
settings.overrides[key] = value;
//make sure our overrides are in sync
settings = extend(settings, settings.overrides);
try {
var filename = settings.findOverridesFile(profile);
fs.writeFileSync(filename, JSON.stringify(settings.overrides, null, 2), { mode: '600' });
} catch (ex) {
console.error('There was an error writing ' + settings.overrides + ': ', ex);
}
};
settings.transitionSparkProfiles = function() {
var sparkDir = path.join(settings.findHomePath(), '.spark');
var particleDir = path.join(settings.findHomePath(), '.particle');
if (fs.existsSync(sparkDir) && !fs.existsSync(particleDir)) {
fs.mkdirSync(particleDir);
console.log();
console.log(chalk.yellow('!!!'), 'I detected a Spark profile directory, and will now migrate your settings.');
console.log(chalk.yellow('!!!'), 'This will only happen once, since you previously used our Spark-CLI tools.');
console.log();
var files = fs.readdirSync(sparkDir);
files.forEach(function (filename) {
var data = fs.readFileSync(path.join(sparkDir, filename));
var jsonData;
try {
jsonData = JSON.parse(data);
} catch (ex) {
// invalid JSON, don't transition
return;
}
if (filename === 'profile.json') {
if (jsonData.name === 'spark') {
jsonData.name = 'particle';
}
}
if (filename === 'spark.config.json') {
filename = 'particle.config.json';
}
if (jsonData.apiUrl && jsonData.apiUrl.indexOf('.spark.io') > 0) {
jsonData.apiUrl = jsonData.apiUrl.replace('.spark.io', '.particle.io');
}
data = JSON.stringify(jsonData, null, 2);
fs.writeFileSync(path.join(particleDir, filename), data, { mode: '600' });
});
}
};
settings.transitionSparkProfiles();
settings.whichProfile();
settings.loadOverrides();
module.exports = settings;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment