blob: df5e9b7a67adda9889a4701c4d080c8e41ad7e00 [file] [log] [blame]
/*
* Copyright 2012 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals Buffer */
var fs = require('fs'),
exit = require('exit'),
async = require('async'),
path = require('path'),
childProcess = require('child_process'),
wrench = require('wrench'),
os = require('os'),
promptLib = require("prompt"),
DEFAULT_BAR_NAME = "bb10app",
PROPERTY_FILE_NAME = 'blackberry10.json',
CORDOVA_DIR = '.cordova',
ERROR_VALUE = 2,
DEFAULT_PROPERTY_FILE = {
targets: {
}
},
_self;
function swapBytes(buffer) {
var l = buffer.length,
i,
a;
if (l % 2 === 0x01) {
throw new Exception("Buffer error");
}
for (i = 0; i < l; i += 2) {
a = buffer[i];
buffer[i] = buffer[i + 1];
buffer[i + 1] = a;
}
return buffer;
}
_self = {
writeFile: function (fileLocation, fileName, fileData) {
//If directory does not exist, create it.
if (!fs.existsSync(fileLocation)) {
wrench.mkdirSyncRecursive(fileLocation, "0755");
}
fs.writeFile(path.join(fileLocation, fileName), fileData, function (err) {
if (err) throw err;
});
},
copyFile: function (srcFile, destDir, baseDir) {
var filename = path.basename(srcFile),
fileBuffer = fs.readFileSync(srcFile),
fileLocation;
//if a base directory was provided, determine
//folder structure from the relative path of the base folder
if (baseDir && srcFile.indexOf(baseDir) === 0) {
fileLocation = srcFile.replace(baseDir, destDir);
wrench.mkdirSyncRecursive(path.dirname(fileLocation), "0755");
fs.writeFileSync(fileLocation, fileBuffer);
} else {
if (!fs.existsSync(destDir)) {
wrench.mkdirSyncRecursive(destDir, "0755");
}
fs.writeFileSync(path.join(destDir, filename), fileBuffer);
}
},
listFiles: function (directory, filter) {
var files = wrench.readdirSyncRecursive(directory),
filteredFiles = [];
files.forEach(function (file) {
//On mac wrench.readdirSyncRecursive does not return absolute paths, so resolve one.
file = path.resolve(directory, file);
if (filter(file)) {
filteredFiles.push(file);
}
});
return filteredFiles;
},
readdirSyncRecursive: function (baseDir) {
var files = [],
curFiles = [],
nextDirs,
isDir = function (f) {
return fs.statSync(f).isDirectory();
},
isFile = function (f) {
return !isDir(f);
},
prependBaseDir = function (fname) {
return path.join(baseDir, fname);
};
try {
curFiles = fs.readdirSync(baseDir);
if (curFiles && curFiles.length > 0) {
curFiles = curFiles.map(prependBaseDir);
nextDirs = curFiles.filter(isDir);
curFiles = curFiles.filter(isFile);
files = files.concat(curFiles);
while (nextDirs.length) {
files = files.concat(_self.readdirSyncRecursive(nextDirs.shift()));
}
}
} catch (e) {
}
return files;
},
isWindows: function () {
return os.type().toLowerCase().indexOf("windows") >= 0;
},
isOSX: function () {
return os.type().toLowerCase().indexOf("darwin") >= 0;
},
isArray: function (obj) {
return obj.constructor.toString().indexOf("Array") !== -1;
},
isEmpty : function (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop))
return false;
}
return true;
},
toBoolean: function (myString, defaultVal) {
// if defaultVal is not passed, default value is undefined
return myString === "true" ? true : myString === "false" ? false : defaultVal;
},
parseUri : function (str) {
var i, uri = {},
key = [ "source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor" ],
matcher = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str);
for (i = key.length - 1; i >= 0; i--) {
uri[key[i]] = matcher[i] || "";
}
return uri;
},
// uri - output from parseUri
isAbsoluteURI : function (uri) {
if (uri && uri.source) {
return uri.relative !== uri.source;
}
return false;
},
isLocalURI : function (uri) {
return uri && uri.scheme && uri.scheme.toLowerCase() === "local";
},
// Convert node.js Buffer data (encoded) to String
bufferToString : function (data) {
var s = "";
if (Buffer.isBuffer(data)) {
if (data.length >= 2 && data[0] === 0xFF && data[1] === 0xFE) {
s = data.toString("ucs2", 2);
} else if (data.length >= 2 && data[0] === 0xFE && data[1] === 0xFF) {
swapBytes(data);
s = data.toString("ucs2", 2);
} else if (data.length >= 3 && data[0] === 0xEF && data[1] === 0xBB && data[2] === 0xBF) {
s = data.toString("utf8", 3);
} else {
s = data.toString("ascii");
}
}
return s;
},
// Wrap object property in an Array if the property is defined and it is not an Array
wrapPropertyInArray : function (obj, property) {
if (obj && obj[property] && !(obj[property] instanceof Array)) {
obj[property] = [ obj[property] ];
}
},
inQuotes : function (property) {
//wrap in quotes if it's not already wrapped
if (property.indexOf("\"") === -1) {
return "\"" + property + "\"";
} else {
return property;
}
},
exec : function (command, args, options, callback) {
//Optional params handling [args, options]
if (typeof args === "object" && !Array.isArray(args)) {
callback = options;
options = args;
args = [];
} else if (typeof args === "function") {
callback = args;
options = {};
args = [];
} else if (typeof options === "function") {
callback = options;
options = {};
}
//insert executable portion at beginning of arg array
args.splice(0, 0, command);
var pkgrUtils = require("./packager-utils"),
customOptions = options._customOptions,
proc,
i;
for (i = 0; i < args.length; i++) {
if (args[i] && args[i].indexOf(" ") !== -1) {
if (!_self.isWindows()) {
//remove any escaped spaces on non-Windows platforms and simply use quotes
args[i] = args[i].replace(/\\ /g, " ");
}
//put any args with spaces in quotes
args[i] = _self.inQuotes(args[i]);
}
}
//delete _customOptions from options object before sending to exec
delete options._customOptions;
//Use the process env by default
options.env = options.env || process.env;
proc = childProcess.exec(args.join(" "), options, callback);
if (!customOptions || !customOptions.silent) {
proc.stdout.on("data", pkgrUtils.handleProcessOutput);
proc.stderr.on("data", pkgrUtils.handleProcessOutput);
}
},
loadModule: function (path) {
return require(path);
},
findHomePath : function () {
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
},
getCordovaDir: function () {
var cordovaPath = path.join(_self.findHomePath(), CORDOVA_DIR);
if (!fs.existsSync(cordovaPath)) {
fs.mkdirSync(cordovaPath);
}
return cordovaPath;
},
getPropertiesFilePath: function () {
var propertiesFile = path.join(_self.getCordovaDir(), PROPERTY_FILE_NAME);
if (!fs.existsSync(propertiesFile)) {
_self.writeToPropertiesFile(DEFAULT_PROPERTY_FILE);
}
return propertiesFile;
},
getPropertiesFileName: function () {
return PROPERTY_FILE_NAME;
},
getProperties: function () {
var props = require(_self.getPropertiesFilePath());
if (!props.targets) {
props.targets = {};
}
return props;
},
writeToPropertiesFile: function (data) {
var contents = JSON.stringify(data, null, 4) + "\n",
propertiesFile = path.join(_self.getCordovaDir(), PROPERTY_FILE_NAME);
fs.writeFileSync(propertiesFile, contents, 'utf-8');
},
genBarName: function () {
return DEFAULT_BAR_NAME;
},
clone: function (original) {
var clone = {},
prop;
if (typeof original !== "object") {
clone = original;
} else if (Array.isArray(original)) {
clone = original.slice();
} else {
/* jshint ignore:start */
for (prop in original) {
clone[prop] = original[prop];
}
/* jshint ignore:end */
}
return clone;
},
prompt: function (options, done) {
var promptSchema = {
properties: {
"property": options
}
};
promptLib.start();
promptLib.colors = false;
promptLib.message = "";
promptLib.delimiter = "";
promptLib.get(promptSchema, function (err, results) {
done(err, !err && results.property);
});
},
mixin: function (mixin, to) {
Object.getOwnPropertyNames(mixin).forEach(function (prop) {
if (Object.hasOwnProperty.call(mixin, prop)) {
Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(mixin, prop));
}
});
return to;
},
series: function (steps) {
async.series(steps, this.exit_handler);
},
waterfall: function (steps) {
async.waterfall(steps, this.exit_handler);
},
exit_handler: function (err) {
if (err) {
if (typeof err === "string") {
console.error(err);
} else {
console.error("An error has occurred");
}
exit(ERROR_VALUE);
} else {
exit(0);
}
}
};
module.exports = _self;