feat: 초기 프로젝트 설정 및 룰.md 파일 추가
This commit is contained in:
247
api.hyungi.net/node_modules/pm2/lib/tools/Config.js
generated
vendored
Normal file
247
api.hyungi.net/node_modules/pm2/lib/tools/Config.js
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
|
||||
* Use of this source code is governed by a license that
|
||||
* can be found in the LICENSE file.
|
||||
*/
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* Validator of configured file / commander options.
|
||||
*/
|
||||
var Config = module.exports = {
|
||||
_errMsgs: {
|
||||
'require': '"%s" is required',
|
||||
'type' : 'Expect "%s" to be a typeof %s, but now is %s',
|
||||
'regex' : 'Verify "%s" with regex failed, %s',
|
||||
'max' : 'The maximum of "%s" is %s, but now is %s',
|
||||
'min' : 'The minimum of "%s" is %s, but now is %s'
|
||||
},
|
||||
/**
|
||||
* Schema definition.
|
||||
* @returns {exports|*}
|
||||
*/
|
||||
get schema(){
|
||||
// Cache.
|
||||
if (this._schema) {
|
||||
return this._schema;
|
||||
}
|
||||
// Render aliases.
|
||||
this._schema = require('../API/schema');
|
||||
for (var k in this._schema) {
|
||||
if (k.indexOf('\\') > 0) {
|
||||
continue;
|
||||
}
|
||||
var aliases = [
|
||||
k.split('_').map(function(n, i){
|
||||
if (i != 0 && n && n.length > 1) {
|
||||
return n[0].toUpperCase() + n.slice(1);
|
||||
}
|
||||
return n;
|
||||
}).join('')
|
||||
];
|
||||
|
||||
if (this._schema[k].alias && Array.isArray(this._schema[k].alias)) {
|
||||
// If multiple aliases, merge
|
||||
this._schema[k].alias.forEach(function(alias) {
|
||||
aliases.splice(0, 0, alias);
|
||||
});
|
||||
}
|
||||
else if (this._schema[k].alias)
|
||||
aliases.splice(0, 0, this._schema[k].alias);
|
||||
|
||||
this._schema[k].alias = aliases;
|
||||
}
|
||||
return this._schema;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter / Alias options
|
||||
*/
|
||||
Config.filterOptions = function(cmd) {
|
||||
var conf = {};
|
||||
var schema = this.schema;
|
||||
|
||||
for (var key in schema) {
|
||||
var aliases = schema[key].alias;
|
||||
aliases && aliases.forEach(function(alias){
|
||||
if (typeof(cmd[alias]) !== 'undefined') {
|
||||
conf[key] || (conf[key] = cmd[alias]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return conf;
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify JSON configurations.
|
||||
* @param {Object} json
|
||||
* @returns {{errors: Array, config: {}}}
|
||||
*/
|
||||
Config.validateJSON = function(json){
|
||||
// clone config
|
||||
var conf = Object.assign({}, json),
|
||||
res = {};
|
||||
this._errors = [];
|
||||
|
||||
var regexKeys = {}, defines = this.schema;
|
||||
|
||||
for (var sk in defines) {
|
||||
// Pick up RegExp keys.
|
||||
if (sk.indexOf('\\') >= 0) {
|
||||
regexKeys[sk] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
var aliases = defines[sk].alias;
|
||||
|
||||
aliases && aliases.forEach(function(alias){
|
||||
conf[sk] || (conf[sk] = json[alias]);
|
||||
})
|
||||
|
||||
var val = conf[sk];
|
||||
delete conf[sk];
|
||||
|
||||
// Validate key-value pairs.
|
||||
if (val === undefined ||
|
||||
val === null ||
|
||||
((val = this._valid(sk, val)) === null)) {
|
||||
|
||||
// If value is not defined
|
||||
// Set default value (via schema.json)
|
||||
if (typeof(defines[sk].default) !== 'undefined')
|
||||
res[sk] = defines[sk].default;
|
||||
continue;
|
||||
}
|
||||
//console.log(sk, val, val === null, val === undefined);
|
||||
res[sk] = val;
|
||||
}
|
||||
|
||||
// Validate RegExp values.
|
||||
var hasRegexKey = false;
|
||||
for (var k in regexKeys) {
|
||||
hasRegexKey = true;
|
||||
regexKeys[k] = new RegExp(k);
|
||||
}
|
||||
if (hasRegexKey) {
|
||||
for (var k in conf) {
|
||||
for (var rk in regexKeys) {
|
||||
if (regexKeys[rk].test(k))
|
||||
if (this._valid(k, conf[k], defines[rk])) {
|
||||
res[k] = conf[k];
|
||||
delete conf[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {errors: this._errors, config: res};
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate key-value pairs by specific schema
|
||||
* @param {String} key
|
||||
* @param {Mixed} value
|
||||
* @param {Object} sch
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
Config._valid = function(key, value, sch){
|
||||
var sch = sch || this.schema[key],
|
||||
scht = typeof sch.type == 'string' ? [sch.type] : sch.type;
|
||||
|
||||
// Required value.
|
||||
var undef = typeof value == 'undefined';
|
||||
if(this._error(sch.require && undef, 'require', key)){
|
||||
return null;
|
||||
}
|
||||
|
||||
// If undefined, make a break.
|
||||
if (undef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wrap schema types.
|
||||
scht = scht.map(function(t){
|
||||
return '[object ' + t[0].toUpperCase() + t.slice(1) + ']'
|
||||
});
|
||||
|
||||
// Typeof value.
|
||||
var type = Object.prototype.toString.call(value), nt = '[object Number]';
|
||||
|
||||
// Auto parse Number
|
||||
if (type != '[object Boolean]' && scht.indexOf(nt) >= 0 && !isNaN(value)) {
|
||||
value = parseFloat(value);
|
||||
type = nt;
|
||||
}
|
||||
|
||||
// Verify types.
|
||||
if (this._error(!~scht.indexOf(type), 'type', key, scht.join(' / '), type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify RegExp if exists.
|
||||
if (this._error(type == '[object String]' && sch.regex && !(new RegExp(sch.regex)).test(value),
|
||||
'regex', key, sch.desc || ('should match ' + sch.regex))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify maximum / minimum of Number value.
|
||||
if (type == '[object Number]') {
|
||||
if (this._error(typeof sch.max != 'undefined' && value > sch.max, 'max', key, sch.max, value)) {
|
||||
return null;
|
||||
}
|
||||
if (this._error(typeof sch.min != 'undefined' && value < sch.min, 'min', key, sch.min, value)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// If first type is Array, but current is String, try to split them.
|
||||
if(scht.length > 1 && type != scht[0] && type == '[object String]'){
|
||||
if(scht[0] == '[object Array]') {
|
||||
// unfortunately, js does not support lookahead RegExp (/(?<!\\)\s+/) now (until next ver).
|
||||
value = value.split(/([\w\-]+\="[^"]*")|([\w\-]+\='[^']*')|"([^"]*)"|'([^']*)'|\s/)
|
||||
.filter(function(v){
|
||||
return v && v.trim();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Custom types: sbyte && stime.
|
||||
if(sch.ext_type && type == '[object String]' && value.length >= 2) {
|
||||
var seed = {
|
||||
'sbyte': {
|
||||
'G': 1024 * 1024 * 1024,
|
||||
'M': 1024 * 1024,
|
||||
'K': 1024
|
||||
},
|
||||
'stime': {
|
||||
'h': 60 * 60 * 1000,
|
||||
'm': 60 * 1000,
|
||||
's': 1000
|
||||
}
|
||||
}[sch.ext_type];
|
||||
|
||||
if(seed){
|
||||
value = parseFloat(value.slice(0, -1)) * (seed[value.slice(-1)]);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap errors.
|
||||
* @param {Boolean} possible A value indicates whether it is an error or not.
|
||||
* @param {String} type
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
Config._error = function(possible, type){
|
||||
if (possible) {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args.splice(0, 2, this._errMsgs[type]);
|
||||
this._errors && this._errors.push(util.format.apply(null, args));
|
||||
}
|
||||
return possible;
|
||||
}
|
||||
20
api.hyungi.net/node_modules/pm2/lib/tools/IsAbsolute.js
generated
vendored
Normal file
20
api.hyungi.net/node_modules/pm2/lib/tools/IsAbsolute.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
function posix(path) {
|
||||
return path.charAt(0) === '/';
|
||||
}
|
||||
|
||||
function win32(path) {
|
||||
// https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56
|
||||
var splitDeviceRe = /^([a-zA-Z]:|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)?([\\/])?([\s\S]*?)$/;
|
||||
var result = splitDeviceRe.exec(path);
|
||||
var device = result[1] || '';
|
||||
var isUnc = Boolean(device && device.charAt(1) !== ':');
|
||||
|
||||
// UNC paths are always absolute
|
||||
return Boolean(result[2] || isUnc);
|
||||
}
|
||||
|
||||
module.exports = process.platform === 'win32' ? win32 : posix;
|
||||
module.exports.posix = posix;
|
||||
module.exports.win32 = win32;
|
||||
101
api.hyungi.net/node_modules/pm2/lib/tools/copydirSync.js
generated
vendored
Normal file
101
api.hyungi.net/node_modules/pm2/lib/tools/copydirSync.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
/*
|
||||
options: {
|
||||
utimes: false, // Boolean | Object, keep utimes if true
|
||||
mode: false, // Boolean | Number, keep file mode if true
|
||||
cover: true, // Boolean, cover if file exists
|
||||
filter: true, // Boolean | Function, file filter
|
||||
}
|
||||
*/
|
||||
function copydirSync(from, to, options) {
|
||||
if (typeof options === 'function') {
|
||||
options = {
|
||||
filter: options
|
||||
};
|
||||
}
|
||||
if(typeof options === 'undefined') options = {};
|
||||
if(typeof options.cover === 'undefined') {
|
||||
options.cover = true;
|
||||
}
|
||||
options.filter = typeof options.filter === 'function' ? options.filter : function(state, filepath, filename) {
|
||||
return options.filter;
|
||||
};
|
||||
var stats = fs.lstatSync(from);
|
||||
var statsname = stats.isDirectory() ? 'directory' :
|
||||
stats.isFile() ? 'file' :
|
||||
stats.isSymbolicLink() ? 'symbolicLink' :
|
||||
'';
|
||||
var valid = options.filter(statsname, from, path.dirname(from), path.basename(from));
|
||||
|
||||
if (statsname === 'directory' || statsname === 'symbolicLink') {
|
||||
// Directory or SymbolicLink
|
||||
if(valid) {
|
||||
try {
|
||||
fs.statSync(to);
|
||||
} catch(err) {
|
||||
if(err.code === 'ENOENT') {
|
||||
fs.mkdirSync(to);
|
||||
options.debug && console.log('>> ' + to);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
rewriteSync(to, options, stats);
|
||||
if (statsname != 'symbolicLink')
|
||||
listDirectorySync(from, to, options);
|
||||
}
|
||||
} else if(stats.isFile()) {
|
||||
// File
|
||||
if(valid) {
|
||||
if(options.cover) {
|
||||
writeFileSync(from, to, options, stats);
|
||||
} else {
|
||||
try {
|
||||
fs.statSync(to);
|
||||
} catch(err) {
|
||||
if(err.code === 'ENOENT') {
|
||||
writeFileSync(from, to, options, stats);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error('stats invalid: '+ from);
|
||||
}
|
||||
};
|
||||
|
||||
function listDirectorySync(from, to, options) {
|
||||
var files = fs.readdirSync(from);
|
||||
copyFromArraySync(files, from, to, options);
|
||||
}
|
||||
|
||||
function copyFromArraySync(files, from, to, options) {
|
||||
if(files.length === 0) return true;
|
||||
var f = files.shift();
|
||||
copydirSync(path.join(from, f), path.join(to, f), options);
|
||||
copyFromArraySync(files, from, to, options);
|
||||
}
|
||||
|
||||
function writeFileSync(from, to, options, stats) {
|
||||
fs.writeFileSync(to, fs.readFileSync(from, 'binary'), 'binary');
|
||||
options.debug && console.log('>> ' + to);
|
||||
rewriteSync(to, options, stats);
|
||||
}
|
||||
|
||||
function rewriteSync(f, options, stats, callback) {
|
||||
if(options.cover) {
|
||||
var mode = options.mode === true ? stats.mode : options.mode;
|
||||
var utimes = options.utimes === true ? {
|
||||
atime: stats.atime,
|
||||
mtime: stats.mtime
|
||||
} : options.utimes;
|
||||
mode && fs.chmodSync(f, mode);
|
||||
utimes && fs.utimesSync(f, utimes.atime, utimes.mtime);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = copydirSync;
|
||||
19
api.hyungi.net/node_modules/pm2/lib/tools/deleteFolderRecursive.js
generated
vendored
Normal file
19
api.hyungi.net/node_modules/pm2/lib/tools/deleteFolderRecursive.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const Path = require('path');
|
||||
|
||||
const deleteFolderRecursive = function(path) {
|
||||
if (fs.existsSync(path)) {
|
||||
fs.readdirSync(path).forEach((file, index) => {
|
||||
const curPath = Path.join(path, file);
|
||||
if (fs.lstatSync(curPath).isDirectory()) { // recurse
|
||||
deleteFolderRecursive(curPath);
|
||||
} else { // delete file
|
||||
fs.unlinkSync(curPath);
|
||||
}
|
||||
});
|
||||
fs.rmdirSync(path);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = deleteFolderRecursive
|
||||
74
api.hyungi.net/node_modules/pm2/lib/tools/find-package-json.js
generated
vendored
Normal file
74
api.hyungi.net/node_modules/pm2/lib/tools/find-package-json.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path')
|
||||
, fs = require('fs');
|
||||
|
||||
/**
|
||||
* Attempt to somewhat safely parse the JSON.
|
||||
*
|
||||
* @param {String} data JSON blob that needs to be parsed.
|
||||
* @returns {Object|false} Parsed JSON or false.
|
||||
* @api private
|
||||
*/
|
||||
function parse(data) {
|
||||
data = data.toString('utf-8');
|
||||
|
||||
//
|
||||
// Remove a possible UTF-8 BOM (byte order marker) as this can lead to parse
|
||||
// values when passed in to the JSON.parse.
|
||||
//
|
||||
if (data.charCodeAt(0) === 0xFEFF) data = data.slice(1);
|
||||
|
||||
try { return JSON.parse(data); }
|
||||
catch (e) { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Find package.json files.
|
||||
*
|
||||
* @param {String|Object} root The root directory we should start searching in.
|
||||
* @returns {Object} Iterator interface.
|
||||
* @api public
|
||||
*/
|
||||
module.exports = function find(root) {
|
||||
root = root || process.cwd();
|
||||
if (typeof root !== "string") {
|
||||
if (typeof root === "object" && typeof root.filename === 'string') {
|
||||
root = root.filename;
|
||||
} else {
|
||||
throw new Error("Must pass a filename string or a module object to finder");
|
||||
}
|
||||
}
|
||||
return {
|
||||
/**
|
||||
* Return the parsed package.json that we find in a parent folder.
|
||||
*
|
||||
* @returns {Object} Value, filename and indication if the iteration is done.
|
||||
* @api public
|
||||
*/
|
||||
next: function next() {
|
||||
if (root.match(/^(\w:\\|\/)$/)) return {
|
||||
value: undefined,
|
||||
filename: undefined,
|
||||
done: true
|
||||
};
|
||||
|
||||
var file = path.join(root, 'package.json')
|
||||
, data;
|
||||
|
||||
root = path.resolve(root, '..');
|
||||
|
||||
if (fs.existsSync(file) && (data = parse(fs.readFileSync(file)))) {
|
||||
data.__path = file;
|
||||
|
||||
return {
|
||||
value: data,
|
||||
filename: file,
|
||||
done: false
|
||||
};
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
};
|
||||
};
|
||||
72
api.hyungi.net/node_modules/pm2/lib/tools/fmt.js
generated
vendored
Normal file
72
api.hyungi.net/node_modules/pm2/lib/tools/fmt.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// fmt.js - Command line output formatting.
|
||||
//
|
||||
// Copyright (c) 2012 Andrew Chilton - http://chilts.org/
|
||||
// Written by Andrew Chilton <andychilton@gmail.com>
|
||||
//
|
||||
// License: http://opensource.org/licenses/MIT
|
||||
//
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
var util = require('util');
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
var sep = '===============================================================================';
|
||||
var line = '-------------------------------------------------------------------------------';
|
||||
var field = ' ';
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// separator
|
||||
module.exports.separator = function() {
|
||||
console.log(sep);
|
||||
};
|
||||
|
||||
// alias the above
|
||||
module.exports.sep = module.exports.separator;
|
||||
|
||||
// line
|
||||
module.exports.line = function() {
|
||||
console.log(line);
|
||||
};
|
||||
|
||||
// title
|
||||
module.exports.title = function(title) {
|
||||
var out = '--- ' + title + ' ';
|
||||
out += line.substr(out.length);
|
||||
console.log(out);
|
||||
};
|
||||
|
||||
// field
|
||||
module.exports.field = function(key, value) {
|
||||
console.log('' + key + field.substr(key.length) + ' : ' + value);
|
||||
};
|
||||
|
||||
// subfield
|
||||
module.exports.subfield = function(key, value) {
|
||||
console.log('- ' + key + field.substr(key.length + 2) + ' : ' + value);
|
||||
};
|
||||
|
||||
// list item
|
||||
module.exports.li = function(msg) {
|
||||
console.log('* ' + msg);
|
||||
};
|
||||
|
||||
// dump
|
||||
module.exports.dump = function(data, name) {
|
||||
if ( name ) {
|
||||
console.log(name + ' :', util.inspect(data, false, null, true));
|
||||
}
|
||||
else {
|
||||
console.log(util.inspect(data, false, null, true));
|
||||
}
|
||||
};
|
||||
|
||||
// msg
|
||||
module.exports.msg = function(msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
94
api.hyungi.net/node_modules/pm2/lib/tools/isbinaryfile.js
generated
vendored
Normal file
94
api.hyungi.net/node_modules/pm2/lib/tools/isbinaryfile.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
|
||||
* Use of this source code is governed by a license that
|
||||
* can be found in the LICENSE file.
|
||||
*/
|
||||
var fs = require('fs');
|
||||
var max_bytes = 512;
|
||||
|
||||
module.exports = function(bytes, size) {
|
||||
// Read the file with no encoding for raw buffer access.
|
||||
if (size === undefined) {
|
||||
var file = bytes;
|
||||
try {
|
||||
if(!fs.statSync(file).isFile()) return false;
|
||||
} catch (err) {
|
||||
// otherwise continue on
|
||||
}
|
||||
var descriptor = fs.openSync(file, 'r');
|
||||
try {
|
||||
bytes = Buffer.alloc(max_bytes);
|
||||
size = fs.readSync(descriptor, bytes, 0, bytes.length, 0);
|
||||
} finally {
|
||||
fs.closeSync(descriptor);
|
||||
}
|
||||
}
|
||||
// async version has a function instead of a `size`
|
||||
else if (typeof size === "function") {
|
||||
var file = bytes, callback = size;
|
||||
fs.stat(file, function(err, stat) {
|
||||
if (err || !stat.isFile()) return callback(null, false);
|
||||
|
||||
fs.open(file, 'r', function(err, descriptor){
|
||||
if (err) return callback(err);
|
||||
var bytes = Buffer.alloc(max_bytes);
|
||||
// Read the file with no encoding for raw buffer access.
|
||||
fs.read(descriptor, bytes, 0, bytes.length, 0, function(err, size, bytes){
|
||||
fs.close(descriptor, function(err2){
|
||||
if (err || err2)
|
||||
return callback(err || err2);
|
||||
return callback(null, isBinaryCheck(bytes, size));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return isBinaryCheck(bytes, size);
|
||||
}
|
||||
|
||||
function isBinaryCheck(bytes, size) {
|
||||
if (size === 0)
|
||||
return false;
|
||||
|
||||
var suspicious_bytes = 0;
|
||||
var total_bytes = Math.min(size, max_bytes);
|
||||
|
||||
if (size >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {
|
||||
// UTF-8 BOM. This isn't binary.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < total_bytes; i++) {
|
||||
if (bytes[i] === 0) { // NULL byte--it's binary!
|
||||
return true;
|
||||
}
|
||||
else if ((bytes[i] < 7 || bytes[i] > 14) && (bytes[i] < 32 || bytes[i] > 127)) {
|
||||
// UTF-8 detection
|
||||
if (bytes[i] > 193 && bytes[i] < 224 && i + 1 < total_bytes) {
|
||||
i++;
|
||||
if (bytes[i] > 127 && bytes[i] < 192) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (bytes[i] > 223 && bytes[i] < 240 && i + 2 < total_bytes) {
|
||||
i++;
|
||||
if (bytes[i] > 127 && bytes[i] < 192 && bytes[i + 1] > 127 && bytes[i + 1] < 192) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
suspicious_bytes++;
|
||||
// Read at least 32 bytes before making a decision
|
||||
if (i > 32 && (suspicious_bytes * 100) / total_bytes > 10) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((suspicious_bytes * 100) / total_bytes > 10) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
752
api.hyungi.net/node_modules/pm2/lib/tools/json5.js
generated
vendored
Normal file
752
api.hyungi.net/node_modules/pm2/lib/tools/json5.js
generated
vendored
Normal file
@@ -0,0 +1,752 @@
|
||||
// json5.js
|
||||
// Modern JSON. See README.md for details.
|
||||
//
|
||||
// This file is based directly off of Douglas Crockford's json_parse.js:
|
||||
// https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
|
||||
|
||||
var JSON5 = (typeof exports === 'object' ? exports : {});
|
||||
|
||||
JSON5.parse = (function () {
|
||||
"use strict";
|
||||
|
||||
// This is a function that can parse a JSON5 text, producing a JavaScript
|
||||
// data structure. It is a simple, recursive descent parser. It does not use
|
||||
// eval or regular expressions, so it can be used as a model for implementing
|
||||
// a JSON5 parser in other languages.
|
||||
|
||||
// We are defining the function inside of another function to avoid creating
|
||||
// global variables.
|
||||
|
||||
var at, // The index of the current character
|
||||
ch, // The current character
|
||||
escapee = {
|
||||
"'": "'",
|
||||
'"': '"',
|
||||
'\\': '\\',
|
||||
'/': '/',
|
||||
'\n': '', // Replace escaped newlines in strings w/ empty string
|
||||
b: '\b',
|
||||
f: '\f',
|
||||
n: '\n',
|
||||
r: '\r',
|
||||
t: '\t'
|
||||
},
|
||||
ws = [
|
||||
' ',
|
||||
'\t',
|
||||
'\r',
|
||||
'\n',
|
||||
'\v',
|
||||
'\f',
|
||||
'\xA0',
|
||||
'\uFEFF'
|
||||
],
|
||||
text,
|
||||
|
||||
error = function (m) {
|
||||
|
||||
// Call error when something is wrong.
|
||||
|
||||
var error = new SyntaxError();
|
||||
error.message = m;
|
||||
error.at = at;
|
||||
error.text = text;
|
||||
throw error;
|
||||
},
|
||||
|
||||
next = function (c) {
|
||||
|
||||
// If a c parameter is provided, verify that it matches the current character.
|
||||
|
||||
if (c && c !== ch) {
|
||||
error("Expected '" + c + "' instead of '" + ch + "'");
|
||||
}
|
||||
|
||||
// Get the next character. When there are no more characters,
|
||||
// return the empty string.
|
||||
|
||||
ch = text.charAt(at);
|
||||
at += 1;
|
||||
return ch;
|
||||
},
|
||||
|
||||
peek = function () {
|
||||
|
||||
// Get the next character without consuming it or
|
||||
// assigning it to the ch varaible.
|
||||
|
||||
return text.charAt(at);
|
||||
},
|
||||
|
||||
identifier = function () {
|
||||
|
||||
// Parse an identifier. Normally, reserved words are disallowed here, but we
|
||||
// only use this for unquoted object keys, where reserved words are allowed,
|
||||
// so we don't check for those here. References:
|
||||
// - http://es5.github.com/#x7.6
|
||||
// - https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Variables
|
||||
// - http://docstore.mik.ua/orelly/webprog/jscript/ch02_07.htm
|
||||
|
||||
var key = ch;
|
||||
|
||||
// Identifiers must start with a letter, _ or $.
|
||||
if ((ch !== '_' && ch !== '$') &&
|
||||
(ch < 'a' || ch > 'z') &&
|
||||
(ch < 'A' || ch > 'Z')) {
|
||||
error("Bad identifier");
|
||||
}
|
||||
|
||||
// Subsequent characters can contain digits.
|
||||
while (next() && (
|
||||
ch === '_' || ch === '$' ||
|
||||
(ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9'))) {
|
||||
key += ch;
|
||||
}
|
||||
|
||||
return key;
|
||||
},
|
||||
|
||||
number = function () {
|
||||
|
||||
// Parse a number value.
|
||||
|
||||
var number,
|
||||
sign = '',
|
||||
string = '',
|
||||
base = 10;
|
||||
|
||||
if (ch === '-' || ch === '+') {
|
||||
sign = ch;
|
||||
next(ch);
|
||||
}
|
||||
|
||||
// support for Infinity (could tweak to allow other words):
|
||||
if (ch === 'I') {
|
||||
number = word();
|
||||
if (typeof number !== 'number' || isNaN(number)) {
|
||||
error('Unexpected word for number');
|
||||
}
|
||||
return (sign === '-') ? -number : number;
|
||||
}
|
||||
|
||||
// support for NaN
|
||||
if (ch === 'N' ) {
|
||||
number = word();
|
||||
if (!isNaN(number)) {
|
||||
error('expected word to be NaN');
|
||||
}
|
||||
// ignore sign as -NaN also is NaN
|
||||
return number;
|
||||
}
|
||||
|
||||
if (ch === '0') {
|
||||
string += ch;
|
||||
next();
|
||||
if (ch === 'x' || ch === 'X') {
|
||||
string += ch;
|
||||
next();
|
||||
base = 16;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
error('Octal literal');
|
||||
}
|
||||
}
|
||||
|
||||
switch (base) {
|
||||
case 10:
|
||||
while (ch >= '0' && ch <= '9' ) {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
if (ch === '.') {
|
||||
string += '.';
|
||||
while (next() && ch >= '0' && ch <= '9') {
|
||||
string += ch;
|
||||
}
|
||||
}
|
||||
if (ch === 'e' || ch === 'E') {
|
||||
string += ch;
|
||||
next();
|
||||
if (ch === '-' || ch === '+') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
while (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(sign === '-') {
|
||||
number = -string;
|
||||
} else {
|
||||
number = +string;
|
||||
}
|
||||
|
||||
if (!isFinite(number)) {
|
||||
error("Bad number");
|
||||
} else {
|
||||
return number;
|
||||
}
|
||||
},
|
||||
|
||||
string = function () {
|
||||
|
||||
// Parse a string value.
|
||||
|
||||
var hex,
|
||||
i,
|
||||
string = '',
|
||||
delim, // double quote or single quote
|
||||
uffff;
|
||||
|
||||
// When parsing for string values, we must look for ' or " and \ characters.
|
||||
|
||||
if (ch === '"' || ch === "'") {
|
||||
delim = ch;
|
||||
while (next()) {
|
||||
if (ch === delim) {
|
||||
next();
|
||||
return string;
|
||||
} else if (ch === '\\') {
|
||||
next();
|
||||
if (ch === 'u') {
|
||||
uffff = 0;
|
||||
for (i = 0; i < 4; i += 1) {
|
||||
hex = parseInt(next(), 16);
|
||||
if (!isFinite(hex)) {
|
||||
break;
|
||||
}
|
||||
uffff = uffff * 16 + hex;
|
||||
}
|
||||
string += String.fromCharCode(uffff);
|
||||
} else if (ch === '\r') {
|
||||
if (peek() === '\n') {
|
||||
next();
|
||||
}
|
||||
} else if (typeof escapee[ch] === 'string') {
|
||||
string += escapee[ch];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (ch === '\n') {
|
||||
// unescaped newlines are invalid; see:
|
||||
// https://github.com/aseemk/json5/issues/24
|
||||
// invalid unescaped chars?
|
||||
break;
|
||||
} else {
|
||||
string += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
error("Bad string");
|
||||
},
|
||||
|
||||
inlineComment = function () {
|
||||
|
||||
// Skip an inline comment, assuming this is one. The current character should
|
||||
// be the second / character in the // pair that begins this inline comment.
|
||||
// To finish the inline comment, we look for a newline or the end of the text.
|
||||
|
||||
if (ch !== '/') {
|
||||
error("Not an inline comment");
|
||||
}
|
||||
|
||||
do {
|
||||
next();
|
||||
if (ch === '\n' || ch === '\r') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
} while (ch);
|
||||
},
|
||||
|
||||
blockComment = function () {
|
||||
|
||||
// Skip a block comment, assuming this is one. The current character should be
|
||||
// the * character in the /* pair that begins this block comment.
|
||||
// To finish the block comment, we look for an ending */ pair of characters,
|
||||
// but we also watch for the end of text before the comment is terminated.
|
||||
|
||||
if (ch !== '*') {
|
||||
error("Not a block comment");
|
||||
}
|
||||
|
||||
do {
|
||||
next();
|
||||
while (ch === '*') {
|
||||
next('*');
|
||||
if (ch === '/') {
|
||||
next('/');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (ch);
|
||||
|
||||
error("Unterminated block comment");
|
||||
},
|
||||
|
||||
comment = function () {
|
||||
|
||||
// Skip a comment, whether inline or block-level, assuming this is one.
|
||||
// Comments always begin with a / character.
|
||||
|
||||
if (ch !== '/') {
|
||||
error("Not a comment");
|
||||
}
|
||||
|
||||
next('/');
|
||||
|
||||
if (ch === '/') {
|
||||
inlineComment();
|
||||
} else if (ch === '*') {
|
||||
blockComment();
|
||||
} else {
|
||||
error("Unrecognized comment");
|
||||
}
|
||||
},
|
||||
|
||||
white = function () {
|
||||
|
||||
// Skip whitespace and comments.
|
||||
// Note that we're detecting comments by only a single / character.
|
||||
// This works since regular expressions are not valid JSON(5), but this will
|
||||
// break if there are other valid values that begin with a / character!
|
||||
|
||||
while (ch) {
|
||||
if (ch === '/') {
|
||||
comment();
|
||||
} else if (ws.indexOf(ch) >= 0) {
|
||||
next();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
word = function () {
|
||||
|
||||
// true, false, or null.
|
||||
|
||||
switch (ch) {
|
||||
case 't':
|
||||
next('t');
|
||||
next('r');
|
||||
next('u');
|
||||
next('e');
|
||||
return true;
|
||||
case 'f':
|
||||
next('f');
|
||||
next('a');
|
||||
next('l');
|
||||
next('s');
|
||||
next('e');
|
||||
return false;
|
||||
case 'n':
|
||||
next('n');
|
||||
next('u');
|
||||
next('l');
|
||||
next('l');
|
||||
return null;
|
||||
case 'I':
|
||||
next('I');
|
||||
next('n');
|
||||
next('f');
|
||||
next('i');
|
||||
next('n');
|
||||
next('i');
|
||||
next('t');
|
||||
next('y');
|
||||
return Infinity;
|
||||
case 'N':
|
||||
next( 'N' );
|
||||
next( 'a' );
|
||||
next( 'N' );
|
||||
return NaN;
|
||||
}
|
||||
error("Unexpected '" + ch + "'");
|
||||
},
|
||||
|
||||
value, // Place holder for the value function.
|
||||
|
||||
array = function () {
|
||||
|
||||
// Parse an array value.
|
||||
|
||||
var array = [];
|
||||
|
||||
if (ch === '[') {
|
||||
next('[');
|
||||
white();
|
||||
while (ch) {
|
||||
if (ch === ']') {
|
||||
next(']');
|
||||
return array; // Potentially empty array
|
||||
}
|
||||
// ES5 allows omitting elements in arrays, e.g. [,] and
|
||||
// [,null]. We don't allow this in JSON5.
|
||||
if (ch === ',') {
|
||||
error("Missing array element");
|
||||
} else {
|
||||
array.push(value());
|
||||
}
|
||||
white();
|
||||
// If there's no comma after this value, this needs to
|
||||
// be the end of the array.
|
||||
if (ch !== ',') {
|
||||
next(']');
|
||||
return array;
|
||||
}
|
||||
next(',');
|
||||
white();
|
||||
}
|
||||
}
|
||||
error("Bad array");
|
||||
},
|
||||
|
||||
object = function () {
|
||||
|
||||
// Parse an object value.
|
||||
|
||||
var key,
|
||||
object = {};
|
||||
|
||||
if (ch === '{') {
|
||||
next('{');
|
||||
white();
|
||||
while (ch) {
|
||||
if (ch === '}') {
|
||||
next('}');
|
||||
return object; // Potentially empty object
|
||||
}
|
||||
|
||||
// Keys can be unquoted. If they are, they need to be
|
||||
// valid JS identifiers.
|
||||
if (ch === '"' || ch === "'") {
|
||||
key = string();
|
||||
} else {
|
||||
key = identifier();
|
||||
}
|
||||
|
||||
white();
|
||||
next(':');
|
||||
object[key] = value();
|
||||
white();
|
||||
// If there's no comma after this pair, this needs to be
|
||||
// the end of the object.
|
||||
if (ch !== ',') {
|
||||
next('}');
|
||||
return object;
|
||||
}
|
||||
next(',');
|
||||
white();
|
||||
}
|
||||
}
|
||||
error("Bad object");
|
||||
};
|
||||
|
||||
value = function () {
|
||||
|
||||
// Parse a JSON value. It could be an object, an array, a string, a number,
|
||||
// or a word.
|
||||
|
||||
white();
|
||||
switch (ch) {
|
||||
case '{':
|
||||
return object();
|
||||
case '[':
|
||||
return array();
|
||||
case '"':
|
||||
case "'":
|
||||
return string();
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
return number();
|
||||
default:
|
||||
return ch >= '0' && ch <= '9' ? number() : word();
|
||||
}
|
||||
};
|
||||
|
||||
// Return the json_parse function. It will have access to all of the above
|
||||
// functions and variables.
|
||||
|
||||
return function (source, reviver) {
|
||||
var result;
|
||||
|
||||
text = String(source);
|
||||
at = 0;
|
||||
ch = ' ';
|
||||
result = value();
|
||||
white();
|
||||
if (ch) {
|
||||
error("Syntax error");
|
||||
}
|
||||
|
||||
// If there is a reviver function, we recursively walk the new structure,
|
||||
// passing each name/value pair to the reviver function for possible
|
||||
// transformation, starting with a temporary root object that holds the result
|
||||
// in an empty key. If there is not a reviver function, we simply return the
|
||||
// result.
|
||||
|
||||
return typeof reviver === 'function' ? (function walk(holder, key) {
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}({'': result}, '')) : result;
|
||||
};
|
||||
}());
|
||||
|
||||
// JSON5 stringify will not quote keys where appropriate
|
||||
JSON5.stringify = function (obj, replacer, space) {
|
||||
if (replacer && (typeof(replacer) !== "function" && !isArray(replacer))) {
|
||||
throw new Error('Replacer must be a function or an array');
|
||||
}
|
||||
var getReplacedValueOrUndefined = function(holder, key, isTopLevel) {
|
||||
var value = holder[key];
|
||||
|
||||
// Replace the value with its toJSON value first, if possible
|
||||
if (value && value.toJSON && typeof value.toJSON === "function") {
|
||||
value = value.toJSON();
|
||||
}
|
||||
|
||||
// If the user-supplied replacer if a function, call it. If it's an array, check objects' string keys for
|
||||
// presence in the array (removing the key/value pair from the resulting JSON if the key is missing).
|
||||
if (typeof(replacer) === "function") {
|
||||
return replacer.call(holder, key, value);
|
||||
} else if(replacer) {
|
||||
if (isTopLevel || isArray(holder) || replacer.indexOf(key) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
function isWordChar(char) {
|
||||
return (char >= 'a' && char <= 'z') ||
|
||||
(char >= 'A' && char <= 'Z') ||
|
||||
(char >= '0' && char <= '9') ||
|
||||
char === '_' || char === '$';
|
||||
}
|
||||
|
||||
function isWordStart(char) {
|
||||
return (char >= 'a' && char <= 'z') ||
|
||||
(char >= 'A' && char <= 'Z') ||
|
||||
char === '_' || char === '$';
|
||||
}
|
||||
|
||||
function isWord(key) {
|
||||
if (typeof key !== 'string') {
|
||||
return false;
|
||||
}
|
||||
if (!isWordStart(key[0])) {
|
||||
return false;
|
||||
}
|
||||
var i = 1, length = key.length;
|
||||
while (i < length) {
|
||||
if (!isWordChar(key[i])) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// export for use in tests
|
||||
JSON5.isWord = isWord;
|
||||
|
||||
// polyfills
|
||||
function isArray(obj) {
|
||||
if (Array.isArray) {
|
||||
return Array.isArray(obj);
|
||||
} else {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||
}
|
||||
}
|
||||
|
||||
function isDate(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Date]';
|
||||
}
|
||||
|
||||
isNaN = isNaN || function(val) {
|
||||
return typeof val === 'number' && val !== val;
|
||||
};
|
||||
|
||||
var objStack = [];
|
||||
function checkForCircular(obj) {
|
||||
for (var i = 0; i < objStack.length; i++) {
|
||||
if (objStack[i] === obj) {
|
||||
throw new TypeError("Converting circular structure to JSON");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeIndent(str, num, noNewLine) {
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
// indentation no more than 10 chars
|
||||
if (str.length > 10) {
|
||||
str = str.substring(0, 10);
|
||||
}
|
||||
|
||||
var indent = noNewLine ? "" : "\n";
|
||||
for (var i = 0; i < num; i++) {
|
||||
indent += str;
|
||||
}
|
||||
|
||||
return indent;
|
||||
}
|
||||
|
||||
var indentStr;
|
||||
if (space) {
|
||||
if (typeof space === "string") {
|
||||
indentStr = space;
|
||||
} else if (typeof space === "number" && space >= 0) {
|
||||
indentStr = makeIndent(" ", space, true);
|
||||
} else {
|
||||
// ignore space parameter
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from Crokford's implementation of JSON
|
||||
// See https://github.com/douglascrockford/JSON-js/blob/e39db4b7e6249f04a195e7dd0840e610cc9e941e/json2.js#L195
|
||||
// Begin
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
function escapeString(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ?
|
||||
c :
|
||||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
// End
|
||||
|
||||
function internalStringify(holder, key, isTopLevel) {
|
||||
var buffer, res;
|
||||
|
||||
// Replace the value, if necessary
|
||||
var obj_part = getReplacedValueOrUndefined(holder, key, isTopLevel);
|
||||
|
||||
if (obj_part && !isDate(obj_part)) {
|
||||
// unbox objects
|
||||
// don't unbox dates, since will turn it into number
|
||||
obj_part = obj_part.valueOf();
|
||||
}
|
||||
switch(typeof obj_part) {
|
||||
case "boolean":
|
||||
return obj_part.toString();
|
||||
|
||||
case "number":
|
||||
if (isNaN(obj_part) || !isFinite(obj_part)) {
|
||||
return "null";
|
||||
}
|
||||
return obj_part.toString();
|
||||
|
||||
case "string":
|
||||
return escapeString(obj_part.toString());
|
||||
|
||||
case "object":
|
||||
if (obj_part === null) {
|
||||
return "null";
|
||||
} else if (isArray(obj_part)) {
|
||||
checkForCircular(obj_part);
|
||||
buffer = "[";
|
||||
objStack.push(obj_part);
|
||||
|
||||
for (var i = 0; i < obj_part.length; i++) {
|
||||
res = internalStringify(obj_part, i, false);
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
if (res === null || typeof res === "undefined") {
|
||||
buffer += "null";
|
||||
} else {
|
||||
buffer += res;
|
||||
}
|
||||
if (i < obj_part.length-1) {
|
||||
buffer += ",";
|
||||
} else if (indentStr) {
|
||||
buffer += "\n";
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
buffer += makeIndent(indentStr, objStack.length, true) + "]";
|
||||
} else {
|
||||
checkForCircular(obj_part);
|
||||
buffer = "{";
|
||||
var nonEmpty = false;
|
||||
objStack.push(obj_part);
|
||||
for (var prop in obj_part) {
|
||||
if (obj_part.hasOwnProperty(prop)) {
|
||||
var value = internalStringify(obj_part, prop, false);
|
||||
isTopLevel = false;
|
||||
if (typeof value !== "undefined" && value !== null) {
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
nonEmpty = true;
|
||||
var key = isWord(prop) ? prop : escapeString(prop);
|
||||
buffer += key + ":" + (indentStr ? ' ' : '') + value + ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (nonEmpty) {
|
||||
buffer = buffer.substring(0, buffer.length-1) + makeIndent(indentStr, objStack.length) + "}";
|
||||
} else {
|
||||
buffer = '{}';
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
default:
|
||||
// functions and undefined should be ignored
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// special case...when undefined is used inside of
|
||||
// a compound object/array, return null.
|
||||
// but when top-level, return undefined
|
||||
var topLevelHolder = {"":obj};
|
||||
if (obj === undefined) {
|
||||
return getReplacedValueOrUndefined(topLevelHolder, '', true);
|
||||
}
|
||||
return internalStringify(topLevelHolder, '', true);
|
||||
};
|
||||
63
api.hyungi.net/node_modules/pm2/lib/tools/open.js
generated
vendored
Normal file
63
api.hyungi.net/node_modules/pm2/lib/tools/open.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
var exec = require('child_process').exec
|
||||
, path = require('path')
|
||||
;
|
||||
|
||||
|
||||
/**
|
||||
* open a file or uri using the default application for the file type.
|
||||
*
|
||||
* @return {ChildProcess} - the child process object.
|
||||
* @param {string} target - the file/uri to open.
|
||||
* @param {string} appName - (optional) the application to be used to open the
|
||||
* file (for example, "chrome", "firefox")
|
||||
* @param {function(Error)} callback - called with null on success, or
|
||||
* an error object that contains a property 'code' with the exit
|
||||
* code of the process.
|
||||
*/
|
||||
|
||||
module.exports = open;
|
||||
|
||||
function open(target, appName, callback) {
|
||||
var opener;
|
||||
|
||||
if (typeof(appName) === 'function') {
|
||||
callback = appName;
|
||||
appName = null;
|
||||
}
|
||||
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
if (appName) {
|
||||
opener = 'open -a "' + escape(appName) + '"';
|
||||
} else {
|
||||
opener = 'open';
|
||||
}
|
||||
break;
|
||||
case 'win32':
|
||||
// if the first parameter to start is quoted, it uses that as the title
|
||||
// so we pass a blank title so we can quote the file we are opening
|
||||
if (appName) {
|
||||
opener = 'start "" "' + escape(appName) + '"';
|
||||
} else {
|
||||
opener = 'start ""';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (appName) {
|
||||
opener = escape(appName);
|
||||
} else {
|
||||
// use Portlands xdg-open everywhere else
|
||||
opener = path.join(__dirname, './xdg-open');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (process.env.SUDO_USER) {
|
||||
opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener;
|
||||
}
|
||||
return exec(opener + ' "' + escape(target) + '"', callback);
|
||||
}
|
||||
|
||||
function escape(s) {
|
||||
return s.replace(/"/g, '\\\"');
|
||||
}
|
||||
58
api.hyungi.net/node_modules/pm2/lib/tools/passwd.js
generated
vendored
Normal file
58
api.hyungi.net/node_modules/pm2/lib/tools/passwd.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
var fs = require('fs')
|
||||
|
||||
var getUsers = function() {
|
||||
return fs.readFileSync('/etc/passwd')
|
||||
.toString()
|
||||
.split('\n')
|
||||
.filter(function (user) {
|
||||
return user.length && user[0] != '#';
|
||||
})
|
||||
.reduce(function(map, user) {
|
||||
var fields = user.split(':');
|
||||
|
||||
map[fields[0]] = map[fields[2]] = {
|
||||
username : fields[0],
|
||||
password : fields[1],
|
||||
userId : fields[2],
|
||||
groupId : fields[3],
|
||||
name : fields[4].split(',')[0],
|
||||
homedir : fields[5],
|
||||
shell : fields[6]
|
||||
};
|
||||
|
||||
return map
|
||||
}, {})
|
||||
}
|
||||
|
||||
var getGroups = function(cb) {
|
||||
var groups
|
||||
|
||||
try {
|
||||
groups = fs.readFileSync('/etc/group')
|
||||
} catch(e) {
|
||||
return e
|
||||
}
|
||||
|
||||
return groups
|
||||
.toString()
|
||||
.split('\n')
|
||||
.filter(function (group) {
|
||||
return group.length && group[0] != '#';
|
||||
})
|
||||
.reduce(function(map, group) {
|
||||
var fields = group.split(':');
|
||||
map[fields[0]] = map[fields[2]] = {
|
||||
name : fields[0],
|
||||
password : fields[1],
|
||||
id : fields[2],
|
||||
members : fields[3].split(',')
|
||||
};
|
||||
return map;
|
||||
}, {})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUsers,
|
||||
getGroups
|
||||
}
|
||||
1
api.hyungi.net/node_modules/pm2/lib/tools/promise.min.js
generated
vendored
Normal file
1
api.hyungi.net/node_modules/pm2/lib/tools/promise.min.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(e){function n(){}function t(e,n){return function(){e.apply(n,arguments)}}function o(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],s(e,this)}function i(e,n){for(;3===e._state;)e=e._value;return 0===e._state?void e._deferreds.push(n):(e._handled=!0,void o._immediateFn(function(){var t=1===e._state?n.onFulfilled:n.onRejected;if(null===t)return void(1===e._state?r:u)(n.promise,e._value);var o;try{o=t(e._value)}catch(e){return void u(n.promise,e)}r(n.promise,o)}))}function r(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var i=n.then;if(n instanceof o)return e._state=3,e._value=n,void f(e);if("function"==typeof i)return void s(t(i,n),e)}e._state=1,e._value=n,f(e)}catch(n){u(e,n)}}function u(e,n){e._state=2,e._value=n,f(e)}function f(e){2===e._state&&0===e._deferreds.length&&o._immediateFn(function(){e._handled||o._unhandledRejectionFn(e._value)});for(var n=0,t=e._deferreds.length;n<t;n++)i(e,e._deferreds[n]);e._deferreds=null}function c(e,n,t){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof n?n:null,this.promise=t}function s(e,n){var t=!1;try{e(function(e){t||(t=!0,r(n,e))},function(e){t||(t=!0,u(n,e))})}catch(e){if(t)return;t=!0,u(n,e)}}var a=setTimeout;o.prototype.catch=function(e){return this.then(null,e)},o.prototype.then=function(e,t){var o=new this.constructor(n);return i(this,new c(e,t,o)),o},o.all=function(e){var n=Array.prototype.slice.call(e);return new o(function(e,t){function o(r,u){try{if(u&&("object"==typeof u||"function"==typeof u)){var f=u.then;if("function"==typeof f)return void f.call(u,function(e){o(r,e)},t)}n[r]=u,0===--i&&e(n)}catch(e){t(e)}}if(0===n.length)return e([]);for(var i=n.length,r=0;r<n.length;r++)o(r,n[r])})},o.resolve=function(e){return e&&"object"==typeof e&&e.constructor===o?e:new o(function(n){n(e)})},o.reject=function(e){return new o(function(n,t){t(e)})},o.race=function(e){return new o(function(n,t){for(var o=0,i=e.length;o<i;o++)e[o].then(n,t)})},o._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){a(e,0)},o._unhandledRejectionFn=function(e){"undefined"!=typeof console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)},o._setImmediateFn=function(e){o._immediateFn=e},o._setUnhandledRejectionFn=function(e){o._unhandledRejectionFn=e},"undefined"!=typeof module&&module.exports?module.exports=o:e.Promise||(e.Promise=o)}(this);
|
||||
55
api.hyungi.net/node_modules/pm2/lib/tools/sexec.js
generated
vendored
Normal file
55
api.hyungi.net/node_modules/pm2/lib/tools/sexec.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var child = require('child_process');
|
||||
|
||||
var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024;
|
||||
|
||||
function _exec(command, options, callback) {
|
||||
options = options || {};
|
||||
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
}
|
||||
|
||||
if (typeof options === 'object' && typeof callback === 'function') {
|
||||
options.async = true;
|
||||
}
|
||||
|
||||
if (!command) {
|
||||
try {
|
||||
console.error('[sexec] must specify command');
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
options = Object.assign({
|
||||
silent: false,
|
||||
cwd: path.resolve(process.cwd()).toString(),
|
||||
env: process.env,
|
||||
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
|
||||
encoding: 'utf8',
|
||||
}, options);
|
||||
|
||||
var c = child.exec(command, options, function (err, stdout, stderr) {
|
||||
if (callback) {
|
||||
if (!err) {
|
||||
callback(0, stdout, stderr);
|
||||
} else if (err.code === undefined) {
|
||||
// See issue #536
|
||||
/* istanbul ignore next */
|
||||
callback(1, stdout, stderr);
|
||||
} else {
|
||||
callback(err.code, stdout, stderr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!options.silent) {
|
||||
c.stdout.pipe(process.stdout);
|
||||
c.stderr.pipe(process.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = _exec;
|
||||
113
api.hyungi.net/node_modules/pm2/lib/tools/treeify.js
generated
vendored
Normal file
113
api.hyungi.net/node_modules/pm2/lib/tools/treeify.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// treeify.js
|
||||
// Luke Plaster <notatestuser@gmail.com>
|
||||
// https://github.com/notatestuser/treeify.js
|
||||
|
||||
// do the universal module definition dance
|
||||
(function (root, factory) {
|
||||
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
} else {
|
||||
root.treeify = factory();
|
||||
}
|
||||
|
||||
}(this, function() {
|
||||
|
||||
function makePrefix(key, last) {
|
||||
var str = (last ? '└' : '├');
|
||||
if (key) {
|
||||
str += '─ ';
|
||||
} else {
|
||||
str += '──┐';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function filterKeys(obj, hideFunctions) {
|
||||
var keys = [];
|
||||
for (var branch in obj) {
|
||||
// always exclude anything in the object's prototype
|
||||
if (!obj.hasOwnProperty(branch)) {
|
||||
continue;
|
||||
}
|
||||
// ... and hide any keys mapped to functions if we've been told to
|
||||
if (hideFunctions && ((typeof obj[branch])==="function")) {
|
||||
continue;
|
||||
}
|
||||
keys.push(branch);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
function growBranch(key, root, last, lastStates, showValues, hideFunctions, callback) {
|
||||
var line = '', index = 0, lastKey, circular, lastStatesCopy = lastStates.slice(0);
|
||||
|
||||
if (lastStatesCopy.push([ root, last ]) && lastStates.length > 0) {
|
||||
// based on the "was last element" states of whatever we're nested within,
|
||||
// we need to append either blankness or a branch to our line
|
||||
lastStates.forEach(function(lastState, idx) {
|
||||
if (idx > 0) {
|
||||
line += (lastState[1] ? ' ' : '│') + ' ';
|
||||
}
|
||||
if ( ! circular && lastState[0] === root) {
|
||||
circular = true;
|
||||
}
|
||||
});
|
||||
|
||||
// the prefix varies based on whether the key contains something to show and
|
||||
// whether we're dealing with the last element in this collection
|
||||
line += makePrefix(key, last) + key;
|
||||
|
||||
// append values and the circular reference indicator
|
||||
showValues && (typeof root !== 'object' || root instanceof Date) && (line += ': ' + root);
|
||||
circular && (line += ' (circular ref.)');
|
||||
|
||||
callback(line);
|
||||
}
|
||||
|
||||
// can we descend into the next item?
|
||||
if ( ! circular && typeof root === 'object') {
|
||||
var keys = filterKeys(root, hideFunctions);
|
||||
keys.forEach(function(branch){
|
||||
// the last key is always printed with a different prefix, so we'll need to know if we have it
|
||||
lastKey = ++index === keys.length;
|
||||
|
||||
// hold your breath for recursive action
|
||||
growBranch(branch, root[branch], lastKey, lastStatesCopy, showValues, hideFunctions, callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------
|
||||
|
||||
var Treeify = {};
|
||||
|
||||
// Treeify.asLines
|
||||
// --------------------
|
||||
// Outputs the tree line-by-line, calling the lineCallback when each one is available.
|
||||
|
||||
Treeify.asLines = function(obj, showValues, hideFunctions, lineCallback) {
|
||||
/* hideFunctions and lineCallback are curried, which means we don't break apps using the older form */
|
||||
var hideFunctionsArg = typeof hideFunctions !== 'function' ? hideFunctions : false;
|
||||
growBranch('.', obj, false, [], showValues, hideFunctionsArg, lineCallback || hideFunctions);
|
||||
};
|
||||
|
||||
// Treeify.asTree
|
||||
// --------------------
|
||||
// Outputs the entire tree, returning it as a string with line breaks.
|
||||
|
||||
Treeify.asTree = function(obj, showValues, hideFunctions) {
|
||||
var tree = '';
|
||||
growBranch('.', obj, false, [], showValues, hideFunctions, function(line) {
|
||||
tree += line + '\n';
|
||||
});
|
||||
return tree;
|
||||
};
|
||||
|
||||
// --------------------
|
||||
|
||||
return Treeify;
|
||||
|
||||
}));
|
||||
120
api.hyungi.net/node_modules/pm2/lib/tools/which.js
generated
vendored
Normal file
120
api.hyungi.net/node_modules/pm2/lib/tools/which.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var cst = require('../../constants.js')
|
||||
|
||||
// XP's system default value for `PATHEXT` system variable, just in case it's not
|
||||
// set on Windows.
|
||||
var XP_DEFAULT_PATHEXT = '.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh';
|
||||
|
||||
// For earlier versions of NodeJS that doesn't have a list of constants (< v6)
|
||||
var FILE_EXECUTABLE_MODE = 1;
|
||||
|
||||
function statFollowLinks() {
|
||||
return fs.statSync.apply(fs, arguments);
|
||||
}
|
||||
|
||||
function isWindowsPlatform() {
|
||||
return cst.IS_WINDOWS;
|
||||
}
|
||||
|
||||
// Cross-platform method for splitting environment `PATH` variables
|
||||
function splitPath(p) {
|
||||
return p ? p.split(path.delimiter) : [];
|
||||
}
|
||||
|
||||
// Tests are running all cases for this func but it stays uncovered by codecov due to unknown reason
|
||||
/* istanbul ignore next */
|
||||
function isExecutable(pathName) {
|
||||
try {
|
||||
// TODO(node-support): replace with fs.constants.X_OK once remove support for node < v6
|
||||
fs.accessSync(pathName, FILE_EXECUTABLE_MODE);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkPath(pathName) {
|
||||
return fs.existsSync(pathName) && !statFollowLinks(pathName).isDirectory()
|
||||
&& (isWindowsPlatform() || isExecutable(pathName));
|
||||
}
|
||||
|
||||
//@
|
||||
//@ ### which(command)
|
||||
//@
|
||||
//@ Examples:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var nodeExec = which('node');
|
||||
//@ ```
|
||||
//@
|
||||
//@ Searches for `command` in the system's `PATH`. On Windows, this uses the
|
||||
//@ `PATHEXT` variable to append the extension if it's not already executable.
|
||||
//@ Returns a [ShellString](#shellstringstr) containing the absolute path to
|
||||
//@ `command`.
|
||||
function _which(cmd) {
|
||||
if (!cmd) console.error('must specify command');
|
||||
|
||||
var options = {}
|
||||
|
||||
var isWindows = isWindowsPlatform();
|
||||
var pathArray = splitPath(process.env.PATH);
|
||||
|
||||
var queryMatches = [];
|
||||
|
||||
// No relative/absolute paths provided?
|
||||
if (cmd.indexOf('/') === -1) {
|
||||
// Assume that there are no extensions to append to queries (this is the
|
||||
// case for unix)
|
||||
var pathExtArray = [''];
|
||||
if (isWindows) {
|
||||
// In case the PATHEXT variable is somehow not set (e.g.
|
||||
// child_process.spawn with an empty environment), use the XP default.
|
||||
var pathExtEnv = process.env.PATHEXT || XP_DEFAULT_PATHEXT;
|
||||
pathExtArray = splitPath(pathExtEnv.toUpperCase());
|
||||
}
|
||||
|
||||
// Search for command in PATH
|
||||
for (var k = 0; k < pathArray.length; k++) {
|
||||
// already found it
|
||||
if (queryMatches.length > 0 && !options.all) break;
|
||||
|
||||
var attempt = path.resolve(pathArray[k], cmd);
|
||||
|
||||
if (isWindows) {
|
||||
attempt = attempt.toUpperCase();
|
||||
}
|
||||
|
||||
var match = attempt.match(/\.[^<>:"/|?*.]+$/);
|
||||
if (match && pathExtArray.indexOf(match[0]) >= 0) { // this is Windows-only
|
||||
// The user typed a query with the file extension, like
|
||||
// `which('node.exe')`
|
||||
if (checkPath(attempt)) {
|
||||
queryMatches.push(attempt);
|
||||
break;
|
||||
}
|
||||
} else { // All-platforms
|
||||
// Cycle through the PATHEXT array, and check each extension
|
||||
// Note: the array is always [''] on Unix
|
||||
for (var i = 0; i < pathExtArray.length; i++) {
|
||||
var ext = pathExtArray[i];
|
||||
var newAttempt = attempt + ext;
|
||||
if (checkPath(newAttempt)) {
|
||||
queryMatches.push(newAttempt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (checkPath(cmd)) { // a valid absolute or relative path
|
||||
queryMatches.push(path.resolve(cmd));
|
||||
}
|
||||
|
||||
if (queryMatches.length > 0) {
|
||||
return options.all ? queryMatches : queryMatches[0];
|
||||
}
|
||||
return options.all ? [] : null;
|
||||
}
|
||||
|
||||
module.exports = _which;
|
||||
861
api.hyungi.net/node_modules/pm2/lib/tools/xdg-open
generated
vendored
Normal file
861
api.hyungi.net/node_modules/pm2/lib/tools/xdg-open
generated
vendored
Normal file
@@ -0,0 +1,861 @@
|
||||
#!/bin/sh
|
||||
#---------------------------------------------
|
||||
# xdg-open
|
||||
#
|
||||
# Utility script to open a URL in the registered default application.
|
||||
#
|
||||
# Refer to the usage() function below for usage.
|
||||
#
|
||||
# Copyright 2009-2010, Fathi Boudra <fabo@freedesktop.org>
|
||||
# Copyright 2009-2010, Rex Dieter <rdieter@fedoraproject.org>
|
||||
# Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
|
||||
# Copyright 2006, Jeremy White <jwhite@codeweavers.com>
|
||||
#
|
||||
# LICENSE:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
# to deal in the Software without restriction, including without limitation
|
||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
# and/or sell copies of the Software, and to permit persons to whom the
|
||||
# Software is furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
#---------------------------------------------
|
||||
|
||||
manualpage()
|
||||
{
|
||||
cat << _MANUALPAGE
|
||||
Name
|
||||
|
||||
xdg-open - opens a file or URL in the user's preferred
|
||||
application
|
||||
|
||||
Synopsis
|
||||
|
||||
xdg-open { file | URL }
|
||||
|
||||
xdg-open { --help | --manual | --version }
|
||||
|
||||
Description
|
||||
|
||||
xdg-open opens a file or URL in the user's preferred
|
||||
application. If a URL is provided the URL will be opened in the
|
||||
user's preferred web browser. If a file is provided the file
|
||||
will be opened in the preferred application for files of that
|
||||
type. xdg-open supports file, ftp, http and https URLs.
|
||||
|
||||
xdg-open is for use inside a desktop session only. It is not
|
||||
recommended to use xdg-open as root.
|
||||
|
||||
Options
|
||||
|
||||
--help
|
||||
Show command synopsis.
|
||||
|
||||
--manual
|
||||
Show this manual page.
|
||||
|
||||
--version
|
||||
Show the xdg-utils version information.
|
||||
|
||||
Exit Codes
|
||||
|
||||
An exit code of 0 indicates success while a non-zero exit code
|
||||
indicates failure. The following failure codes can be returned:
|
||||
|
||||
1
|
||||
Error in command line syntax.
|
||||
|
||||
2
|
||||
One of the files passed on the command line did not
|
||||
exist.
|
||||
|
||||
3
|
||||
A required tool could not be found.
|
||||
|
||||
4
|
||||
The action failed.
|
||||
|
||||
Examples
|
||||
|
||||
xdg-open 'http://www.freedesktop.org/'
|
||||
|
||||
Opens the freedesktop.org website in the user's default
|
||||
browser.
|
||||
|
||||
xdg-open /tmp/foobar.png
|
||||
|
||||
Opens the PNG image file /tmp/foobar.png in the user's default
|
||||
image viewing application.
|
||||
_MANUALPAGE
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << _USAGE
|
||||
xdg-open - opens a file or URL in the user's preferred
|
||||
application
|
||||
|
||||
Synopsis
|
||||
|
||||
xdg-open { file | URL }
|
||||
|
||||
xdg-open { --help | --manual | --version }
|
||||
|
||||
_USAGE
|
||||
}
|
||||
|
||||
#@xdg-utils-common@
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Common utility functions included in all XDG wrapper scripts
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
DEBUG()
|
||||
{
|
||||
[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0;
|
||||
[ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0;
|
||||
shift
|
||||
echo "$@" >&2
|
||||
}
|
||||
|
||||
# This handles backslashes but not quote marks.
|
||||
first_word()
|
||||
{
|
||||
read first rest
|
||||
echo "$first"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# map a binary to a .desktop file
|
||||
binary_to_desktop_file()
|
||||
{
|
||||
search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
|
||||
binary="`which "$1"`"
|
||||
binary="`readlink -f "$binary"`"
|
||||
base="`basename "$binary"`"
|
||||
IFS=:
|
||||
for dir in $search; do
|
||||
unset IFS
|
||||
[ "$dir" ] || continue
|
||||
[ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue
|
||||
for file in "$dir"/applications/*.desktop "$dir"/applications/*/*.desktop "$dir"/applnk/*.desktop "$dir"/applnk/*/*.desktop; do
|
||||
[ -r "$file" ] || continue
|
||||
# Check to make sure it's worth the processing.
|
||||
grep -q "^Exec.*$base" "$file" || continue
|
||||
# Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop").
|
||||
grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue
|
||||
command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`"
|
||||
command="`which "$command"`"
|
||||
if [ x"`readlink -f "$command"`" = x"$binary" ]; then
|
||||
# Fix any double slashes that got added path composition
|
||||
echo "$file" | sed -e 's,//*,/,g'
|
||||
return
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# map a .desktop file to a binary
|
||||
## FIXME: handle vendor dir case
|
||||
desktop_file_to_binary()
|
||||
{
|
||||
search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
|
||||
desktop="`basename "$1"`"
|
||||
IFS=:
|
||||
for dir in $search; do
|
||||
unset IFS
|
||||
[ "$dir" ] && [ -d "$dir/applications" ] || continue
|
||||
file="$dir/applications/$desktop"
|
||||
[ -r "$file" ] || continue
|
||||
# Remove any arguments (%F, %f, %U, %u, etc.).
|
||||
command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`"
|
||||
command="`which "$command"`"
|
||||
readlink -f "$command"
|
||||
return
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Exit script on successfully completing the desired operation
|
||||
|
||||
exit_success()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "$@"
|
||||
echo
|
||||
fi
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
#-----------------------------------------
|
||||
# Exit script on malformed arguments, not enough arguments
|
||||
# or missing required option.
|
||||
# prints usage information
|
||||
|
||||
exit_failure_syntax()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
echo "Try 'xdg-open --help' for more information." >&2
|
||||
else
|
||||
usage
|
||||
echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info."
|
||||
fi
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Exit script on missing file specified on command line
|
||||
|
||||
exit_failure_file_missing()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
fi
|
||||
|
||||
exit 2
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Exit script on failure to locate necessary tool applications
|
||||
|
||||
exit_failure_operation_impossible()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
fi
|
||||
|
||||
exit 3
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Exit script on failure returned by a tool application
|
||||
|
||||
exit_failure_operation_failed()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
fi
|
||||
|
||||
exit 4
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Exit script on insufficient permission to read a specified file
|
||||
|
||||
exit_failure_file_permission_read()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
fi
|
||||
|
||||
exit 5
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Exit script on insufficient permission to write a specified file
|
||||
|
||||
exit_failure_file_permission_write()
|
||||
{
|
||||
if [ $# -gt 0 ]; then
|
||||
echo "xdg-open: $@" >&2
|
||||
fi
|
||||
|
||||
exit 6
|
||||
}
|
||||
|
||||
check_input_file()
|
||||
{
|
||||
if [ ! -e "$1" ]; then
|
||||
exit_failure_file_missing "file '$1' does not exist"
|
||||
fi
|
||||
if [ ! -r "$1" ]; then
|
||||
exit_failure_file_permission_read "no permission to read file '$1'"
|
||||
fi
|
||||
}
|
||||
|
||||
check_vendor_prefix()
|
||||
{
|
||||
file_label="$2"
|
||||
[ -n "$file_label" ] || file_label="filename"
|
||||
file=`basename "$1"`
|
||||
case "$file" in
|
||||
[[:alpha:]]*-*)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "xdg-open: $file_label '$file' does not have a proper vendor prefix" >&2
|
||||
echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2
|
||||
echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2
|
||||
echo "Use --novendor to override or 'xdg-open --manual' for additional info." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_output_file()
|
||||
{
|
||||
# if the file exists, check if it is writeable
|
||||
# if it does not exist, check if we are allowed to write on the directory
|
||||
if [ -e "$1" ]; then
|
||||
if [ ! -w "$1" ]; then
|
||||
exit_failure_file_permission_write "no permission to write to file '$1'"
|
||||
fi
|
||||
else
|
||||
DIR=`dirname "$1"`
|
||||
if [ ! -w "$DIR" ] || [ ! -x "$DIR" ]; then
|
||||
exit_failure_file_permission_write "no permission to create file '$1'"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------
|
||||
# Checks for shared commands, e.g. --help
|
||||
|
||||
check_common_commands()
|
||||
{
|
||||
while [ $# -gt 0 ] ; do
|
||||
parm="$1"
|
||||
shift
|
||||
|
||||
case "$parm" in
|
||||
--help)
|
||||
usage
|
||||
echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info."
|
||||
exit_success
|
||||
;;
|
||||
|
||||
--manual)
|
||||
manualpage
|
||||
exit_success
|
||||
;;
|
||||
|
||||
--version)
|
||||
echo "xdg-open 1.1.0 rc3"
|
||||
exit_success
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
check_common_commands "$@"
|
||||
|
||||
[ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL;
|
||||
if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then
|
||||
# Be silent
|
||||
xdg_redirect_output=" > /dev/null 2> /dev/null"
|
||||
else
|
||||
# All output to stderr
|
||||
xdg_redirect_output=" >&2"
|
||||
fi
|
||||
|
||||
#--------------------------------------
|
||||
# Checks for known desktop environments
|
||||
# set variable DE to the desktop environments name, lowercase
|
||||
|
||||
detectDE()
|
||||
{
|
||||
# see https://bugs.freedesktop.org/show_bug.cgi?id=34164
|
||||
unset GREP_OPTIONS
|
||||
|
||||
if [ -n "${XDG_CURRENT_DESKTOP}" ]; then
|
||||
case "${XDG_CURRENT_DESKTOP}" in
|
||||
ENLIGHTENMENT)
|
||||
DE=enlightenment;
|
||||
;;
|
||||
GNOME)
|
||||
DE=gnome;
|
||||
;;
|
||||
KDE)
|
||||
DE=kde;
|
||||
;;
|
||||
LXDE)
|
||||
DE=lxde;
|
||||
;;
|
||||
MATE)
|
||||
DE=mate;
|
||||
;;
|
||||
XFCE)
|
||||
DE=xfce
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ x"$DE" = x"" ]; then
|
||||
# classic fallbacks
|
||||
if [ x"$KDE_FULL_SESSION" != x"" ]; then DE=kde;
|
||||
elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
|
||||
elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then DE=mate;
|
||||
elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then DE=gnome;
|
||||
elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
|
||||
elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce
|
||||
elif echo $DESKTOP | grep -q '^Enlightenment'; then DE=enlightenment;
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ x"$DE" = x"" ]; then
|
||||
# fallback to checking $DESKTOP_SESSION
|
||||
case "$DESKTOP_SESSION" in
|
||||
gnome)
|
||||
DE=gnome;
|
||||
;;
|
||||
LXDE|Lubuntu)
|
||||
DE=lxde;
|
||||
;;
|
||||
MATE)
|
||||
DE=mate;
|
||||
;;
|
||||
xfce|xfce4|'Xfce Session')
|
||||
DE=xfce;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ x"$DE" = x"" ]; then
|
||||
# fallback to uname output for other platforms
|
||||
case "$(uname 2>/dev/null)" in
|
||||
Darwin)
|
||||
DE=darwin;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ x"$DE" = x"gnome" ]; then
|
||||
# gnome-default-applications-properties is only available in GNOME 2.x
|
||||
# but not in GNOME 3.x
|
||||
which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3"
|
||||
fi
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4
|
||||
# It also always returns 1 in KDE 3.4 and earlier
|
||||
# Simply return 0 in such case
|
||||
|
||||
kfmclient_fix_exit_code()
|
||||
{
|
||||
version=`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'`
|
||||
major=`echo $version | sed 's/KDE.*: \([0-9]\).*/\1/'`
|
||||
minor=`echo $version | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/'`
|
||||
release=`echo $version | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'`
|
||||
test "$major" -gt 3 && return $1
|
||||
test "$minor" -gt 5 && return $1
|
||||
test "$release" -gt 4 && return $1
|
||||
return 0
|
||||
}
|
||||
|
||||
# This handles backslashes but not quote marks.
|
||||
last_word()
|
||||
{
|
||||
read first rest
|
||||
echo "$rest"
|
||||
}
|
||||
|
||||
# Get the value of a key in a desktop file's Desktop Entry group.
|
||||
# Example: Use get_key foo.desktop Exec
|
||||
# to get the values of the Exec= key for the Desktop Entry group.
|
||||
get_key()
|
||||
{
|
||||
local file="${1}"
|
||||
local key="${2}"
|
||||
local desktop_entry=""
|
||||
|
||||
IFS_="${IFS}"
|
||||
IFS=""
|
||||
while read line
|
||||
do
|
||||
case "$line" in
|
||||
"[Desktop Entry]")
|
||||
desktop_entry="y"
|
||||
;;
|
||||
# Reset match flag for other groups
|
||||
"["*)
|
||||
desktop_entry=""
|
||||
;;
|
||||
"${key}="*)
|
||||
# Only match Desktop Entry group
|
||||
if [ -n "${desktop_entry}" ]
|
||||
then
|
||||
echo "${line}" | cut -d= -f 2-
|
||||
fi
|
||||
esac
|
||||
done < "${file}"
|
||||
IFS="${IFS_}"
|
||||
}
|
||||
|
||||
open_darwin()
|
||||
{
|
||||
open "$1"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
open_kde()
|
||||
{
|
||||
if [ -n "${KDE_SESSION_VERSION}" ]; then
|
||||
case "${KDE_SESSION_VERSION}" in
|
||||
4)
|
||||
kde-open "$1"
|
||||
;;
|
||||
5)
|
||||
kde-open${KDE_SESSION_VERSION} "$1"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
kfmclient exec "$1"
|
||||
kfmclient_fix_exit_code $?
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
open_gnome()
|
||||
{
|
||||
if gvfs-open --help 2>/dev/null 1>&2; then
|
||||
gvfs-open "$1"
|
||||
else
|
||||
gnome-open "$1"
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
open_mate()
|
||||
{
|
||||
if gvfs-open --help 2>/dev/null 1>&2; then
|
||||
gvfs-open "$1"
|
||||
else
|
||||
mate-open "$1"
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
open_xfce()
|
||||
{
|
||||
exo-open "$1"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
open_enlightenment()
|
||||
{
|
||||
enlightenment_open "$1"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
#-----------------------------------------
|
||||
# Recursively search .desktop file
|
||||
|
||||
search_desktop_file()
|
||||
{
|
||||
local default="$1"
|
||||
local dir="$2"
|
||||
local target="$3"
|
||||
|
||||
local file=""
|
||||
# look for both vendor-app.desktop, vendor/app.desktop
|
||||
if [ -r "$dir/$default" ]; then
|
||||
file="$dir/$default"
|
||||
elif [ -r "$dir/`echo $default | sed -e 's|-|/|'`" ]; then
|
||||
file="$dir/`echo $default | sed -e 's|-|/|'`"
|
||||
fi
|
||||
|
||||
if [ -r "$file" ] ; then
|
||||
command="$(get_key "${file}" "Exec" | first_word)"
|
||||
command_exec=`which $command 2>/dev/null`
|
||||
icon="$(get_key "${file}" "Icon")"
|
||||
# FIXME: Actually LC_MESSAGES should be used as described in
|
||||
# http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html
|
||||
localised_name="$(get_key "${file}" "Name")"
|
||||
set -- $(get_key "${file}" "Exec" | last_word)
|
||||
# We need to replace any occurrence of "%f", "%F" and
|
||||
# the like by the target file. We examine each
|
||||
# argument and append the modified argument to the
|
||||
# end then shift.
|
||||
local args=$#
|
||||
local replaced=0
|
||||
while [ $args -gt 0 ]; do
|
||||
case $1 in
|
||||
%[c])
|
||||
replaced=1
|
||||
arg="${localised_name}"
|
||||
shift
|
||||
set -- "$@" "$arg"
|
||||
;;
|
||||
%[fFuU])
|
||||
replaced=1
|
||||
arg="$target"
|
||||
shift
|
||||
set -- "$@" "$arg"
|
||||
;;
|
||||
%[i])
|
||||
replaced=1
|
||||
shift
|
||||
set -- "$@" "--icon" "$icon"
|
||||
;;
|
||||
*)
|
||||
arg="$1"
|
||||
shift
|
||||
set -- "$@" "$arg"
|
||||
;;
|
||||
esac
|
||||
args=$(( $args - 1 ))
|
||||
done
|
||||
[ $replaced -eq 1 ] || set -- "$@" "$target"
|
||||
"$command_exec" "$@"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
fi
|
||||
fi
|
||||
|
||||
for d in $dir/*/; do
|
||||
[ -d "$d" ] && search_desktop_file "$default" "$d" "$target"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
open_generic_xdg_mime()
|
||||
{
|
||||
filetype="$2"
|
||||
default=`xdg-mime query default "$filetype"`
|
||||
if [ -n "$default" ] ; then
|
||||
xdg_user_dir="$XDG_DATA_HOME"
|
||||
[ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
|
||||
|
||||
xdg_system_dirs="$XDG_DATA_DIRS"
|
||||
[ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
|
||||
|
||||
DEBUG 3 "$xdg_user_dir:$xdg_system_dirs"
|
||||
for x in `echo "$xdg_user_dir:$xdg_system_dirs" | sed 's/:/ /g'`; do
|
||||
search_desktop_file "$default" "$x/applications/" "$1"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
open_generic_xdg_file_mime()
|
||||
{
|
||||
filetype=`xdg-mime query filetype "$1" | sed "s/;.*//"`
|
||||
open_generic_xdg_mime "$1" "$filetype"
|
||||
}
|
||||
|
||||
open_generic_xdg_x_scheme_handler()
|
||||
{
|
||||
scheme="`echo $1 | sed -n 's/\(^[[:alnum:]+\.-]*\):.*$/\1/p'`"
|
||||
if [ -n $scheme ]; then
|
||||
filetype="x-scheme-handler/$scheme"
|
||||
open_generic_xdg_mime "$1" "$filetype"
|
||||
fi
|
||||
}
|
||||
|
||||
open_generic()
|
||||
{
|
||||
# Paths or file:// URLs
|
||||
if (echo "$1" | grep -q '^file://' ||
|
||||
! echo "$1" | egrep -q '^[[:alpha:]+\.\-]+:'); then
|
||||
|
||||
local file="$1"
|
||||
|
||||
# Decode URLs
|
||||
if echo "$file" | grep -q '^file:///'; then
|
||||
file=${file#file://}
|
||||
file="$(printf "$(echo "$file" | sed -e 's@%\([a-f0-9A-F]\{2\}\)@\\x\1@g')")"
|
||||
fi
|
||||
file_check=${file%%#*}
|
||||
file_check=${file_check%%\?*}
|
||||
check_input_file "$file_check"
|
||||
|
||||
filetype=`xdg-mime query filetype "$file_check" | sed "s/;.*//"`
|
||||
open_generic_xdg_mime "$file" "$filetype"
|
||||
|
||||
if which run-mailcap 2>/dev/null 1>&2; then
|
||||
run-mailcap --action=view "$file"
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
fi
|
||||
fi
|
||||
|
||||
if mimeopen -v 2>/dev/null 1>&2; then
|
||||
mimeopen -L -n "$file"
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
open_generic_xdg_x_scheme_handler "$1"
|
||||
|
||||
IFS=":"
|
||||
for browser in $BROWSER; do
|
||||
if [ x"$browser" != x"" ]; then
|
||||
|
||||
browser_with_arg=`printf "$browser" "$1" 2>/dev/null`
|
||||
if [ $? -ne 0 ]; then
|
||||
browser_with_arg=$browser;
|
||||
fi
|
||||
|
||||
if [ x"$browser_with_arg" = x"$browser" ]; then
|
||||
eval '$browser "$1"'$xdg_redirect_output;
|
||||
else eval '$browser_with_arg'$xdg_redirect_output;
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit_failure_operation_impossible "no method available for opening '$1'"
|
||||
}
|
||||
|
||||
open_lxde()
|
||||
{
|
||||
# pcmanfm only knows how to handle file:// urls and filepaths, it seems.
|
||||
if (echo "$1" | grep -q '^file://' ||
|
||||
! echo "$1" | egrep -q '^[[:alpha:]+\.\-]+:')
|
||||
then
|
||||
local file="$1"
|
||||
|
||||
# handle relative paths
|
||||
if ! echo "$file" | egrep -q '^(file://)?/'; then
|
||||
file="$(pwd)/$file"
|
||||
fi
|
||||
|
||||
pcmanfm "$file"
|
||||
|
||||
else
|
||||
open_generic "$1"
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
exit_success
|
||||
else
|
||||
exit_failure_operation_failed
|
||||
fi
|
||||
}
|
||||
|
||||
[ x"$1" != x"" ] || exit_failure_syntax
|
||||
|
||||
url=
|
||||
while [ $# -gt 0 ] ; do
|
||||
parm="$1"
|
||||
shift
|
||||
|
||||
case "$parm" in
|
||||
-*)
|
||||
exit_failure_syntax "unexpected option '$parm'"
|
||||
;;
|
||||
|
||||
*)
|
||||
if [ -n "$url" ] ; then
|
||||
exit_failure_syntax "unexpected argument '$parm'"
|
||||
fi
|
||||
url="$parm"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${url}" ] ; then
|
||||
exit_failure_syntax "file or URL argument missing"
|
||||
fi
|
||||
|
||||
detectDE
|
||||
|
||||
if [ x"$DE" = x"" ]; then
|
||||
DE=generic
|
||||
fi
|
||||
|
||||
DEBUG 2 "Selected DE $DE"
|
||||
|
||||
# sanitize BROWSER (avoid caling ourselves in particular)
|
||||
case "${BROWSER}" in
|
||||
*:"xdg-open"|"xdg-open":*)
|
||||
BROWSER=$(echo $BROWSER | sed -e 's|:xdg-open||g' -e 's|xdg-open:||g')
|
||||
;;
|
||||
"xdg-open")
|
||||
BROWSER=
|
||||
;;
|
||||
esac
|
||||
|
||||
# if BROWSER variable is not set, check some well known browsers instead
|
||||
if [ x"$BROWSER" = x"" ]; then
|
||||
BROWSER=links2:elinks:links:lynx:w3m
|
||||
if [ -n "$DISPLAY" ]; then
|
||||
BROWSER=x-www-browser:firefox:seamonkey:mozilla:epiphany:konqueror:chromium-browser:google-chrome:$BROWSER
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$DE" in
|
||||
kde)
|
||||
open_kde "$url"
|
||||
;;
|
||||
|
||||
gnome*)
|
||||
open_gnome "$url"
|
||||
;;
|
||||
|
||||
mate)
|
||||
open_mate "$url"
|
||||
;;
|
||||
|
||||
xfce)
|
||||
open_xfce "$url"
|
||||
;;
|
||||
|
||||
lxde)
|
||||
open_lxde "$url"
|
||||
;;
|
||||
|
||||
enlightenment)
|
||||
open_enlightenment "$url"
|
||||
;;
|
||||
|
||||
generic)
|
||||
open_generic "$url"
|
||||
;;
|
||||
|
||||
*)
|
||||
exit_failure_operation_impossible "no method available for opening '$url'"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user