Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-10767] Implemented support for working with modules #7

Merged
merged 3 commits into from
Oct 5, 2012
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
246 changes: 184 additions & 62 deletions lib/timodule.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,77 @@
* Please see the LICENSE file for information about licensing.
*/

var afs = require('./fs'),
sdkPaths = require('./environ').os.sdkPaths,
var path = require('path'),
fs = require('fs'),

async = require('async'),

afs = require('./fs'),
util = require('./util'),
version = require('./version'),
zip = require('./zip'),
async = require('async'),
fs = require('fs'),
path = require('path');

exports.detect = function (projectDir, logger, callback) {
var searchPaths = (projectDir ? [projectDir] : []).concat(sdkPaths.map(function (p) {
return afs.resolvePath(p);
})),
moduleZipRegExp = /^.+\-.+?\-.+?\.zip$/,
modules = {};
mix = util.mix,
sdkPaths = require('./environ').os.sdkPaths,

function searchModuleDir(moduleName, modulePath, platform) {
globalModulesManifestPath = afs.resolvePath(path.join('~', '.titanium', 'modules.json')),
globalModules,
moduleZipRegExp = /^.+\-.+?\-.+?\.zip$/;

exports.getGlobalModules = function(callback) {
if (!globalModules) {
globalModules = {};
async.parallel(sdkPaths.map(function (p) {
return function(cb) {
detectModules(p, globalModules, cb);
};
}), function() {
var globalModulesManifest = loadModulesManifest(globalModulesManifestPath);
for(var mod in globalModules) {
for(var version in globalModules[mod]) {
globalModules[mod][version].activated = !!globalModulesManifest[mod] &&
globalModulesManifest[mod]['activated-version'] === version;
}
}
callback && callback(globalModules);
});
} else {
callback && callback(globalModules);
}
};

exports.getProjectModules = function(projectDir, callback) {
var modules = {};
if (afs.exists(afs.resolvePath(projectDir))) {
detectModules(projectDir, modules, function() {
var projectModulesManifest = loadModulesManifest(path.join(projectDir, '.modules.json'));
for(var mod in modules) {
for(var version in modules[mod]) {
modules[mod][version].activated = !!projectModulesManifest[mod] &&
projectModulesManifest[mod]['activated-version'] === version;

}
}
callback && callback(modules);
});
} else {
callback && callback(modules);
}
};

function detectModules(searchPath, modules, callback) {

function searchModuleDir(moduleName, modulePath, platform, isGlobal) {
afs.visitDirsSync(modulePath, function (version, versionPath) {
var manifestFile = path.join(versionPath, 'manifest');
if (afs.exists(manifestFile)) {
var module = modules[moduleName] || (modules[moduleName] = {}),
details = module[version] || (module[version] = {
modulePath: versionPath,
manifest: {},
platforms: {}
platforms: {},
global: isGlobal
});

fs.readFileSync(manifestFile).toString().split('\n').forEach(function (line) {
var p = line.indexOf(':'),
key,
Expand All @@ -50,60 +94,133 @@ exports.detect = function (projectDir, logger, callback) {
}
}
});

logger && logger.debug(__('Detected module for %s: %s %s @ %s', Object.keys(details.platforms).join(','), details.manifest.moduleid.cyan, details.manifest.version, details.modulePath));
}
});
}

async.parallel(searchPaths.map(function (titaniumRoot) {
return function(cb) {
afs.exists(titaniumRoot, function (exists) {
if (!exists) return cb();

var moduleRoot = path.join(titaniumRoot, 'modules'),
tasks = [];

// auto-install zipped modules
fs.readdirSync(titaniumRoot).forEach(function (file) {
var moduleZip = path.join(titaniumRoot, file);
if (fs.statSync(moduleZip).isFile() && moduleZipRegExp.test(file)) {
tasks.push(function (taskDone) {
logger && logger.info(__('Installing module: %s', file));
zip.unzip(moduleZip, titaniumRoot, function () {
try {
fs.unlinkSync(moduleZip);
} catch (e) {}
taskDone();
});
});
}
});

async.parallel(tasks, function () {
// search module directories
logger && logger.debug(__('Detecting modules in %s', moduleRoot.cyan));
afs.visitDirs(moduleRoot, function (platform, modulesPath) {
if (/^osx|win32|linux$/.test(platform)) {
// skip old Titanium Desktop directories
} else if (/^android|iphone|mobileweb|commonjs$/.test(platform)) {
// old style module directory
afs.visitDirsSync(modulesPath, function (moduleName, modulePath) {
searchModuleDir(moduleName, modulePath, platform);
});
} else {
// possibly a new style module directory
searchModuleDir(platform, modulesPath);
}
}, cb);

searchPath = afs.resolvePath(searchPath);
afs.exists(searchPath, function (exists) {
if (!exists) return callback();

var moduleRoot = path.join(searchPath, 'modules'),
tasks = [];

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um, I sorta need this function. I pass it a list of modules from the tiapp.xml and it determines which ones are installed, missing, or incompatible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it called from? I couldn't find it anywhere.

// auto-install zipped modules
fs.readdirSync(searchPath).forEach(function (file) {
var moduleZip = path.join(searchPath, file);
if (fs.lstatSync(moduleZip).isFile() && moduleZipRegExp.test(file)) {
tasks.push(function (taskDone) {
zip.unzip(moduleZip, searchPath, function () {
try {
fs.unlinkSync(moduleZip);
} catch (e) {}
taskDone();
});
});
}
});

async.parallel(tasks, function () {
// search module directories
afs.visitDirs(moduleRoot, function (platform, modulesPath) {
if (/^osx|win32|linux$/.test(platform)) {
// skip old Titanium Desktop directories
} else if (/^android|iphone|mobileweb|commonjs$/.test(platform)) {
// old style module directory
afs.visitDirsSync(modulesPath, function (moduleName, modulePath) {
searchModuleDir(moduleName, modulePath, platform);
});
} else {
// possibly a new style module directory
searchModuleDir(platform, modulesPath);
}
}, callback);
});
});
}

exports.getModules = function(projectDir, callback) {
async.parallel([
function(next) {
exports.getGlobalModules(function(modules) {
next(null, modules);
});
};
}), function () {
callback(modules);
},
function(next) {
exports.getProjectModules(projectDir, function(modules) {
next(null, modules);
});
}
], function(err, results) {
callback && callback(mix(results[0], results[1]));
});
};

exports.getActivatedModules = function(projectDir, callback) {
exports.getModules(projectDir, function(modules) {
for(var mod in modules) {
for(var version in modules[mod]) {
if (!modules[mod][version].activated) {
delete modules[mod][version];
}
}
if (!Object.keys(modules[mod]).length) {
delete modules[mod];
}
}
callback && callback(modules);
});
};

exports.activateGlobalModule = function(name, version) {
var globalModulesManifest = loadModulesManifest(globalModulesManifestPath);
globalModulesManifest[name] || (globalModulesManifest[name] = {});
globalModulesManifest[name] = {
'activated-version': version
};
saveModulesManifest(globalModulesManifestPath, globalModulesManifest);
};

exports.deactivateGlobalModule = function(name) {
var globalModulesManifest = loadModulesManifest(globalModulesManifestPath);
delete globalModulesManifest[name];
saveModulesManifest(globalModulesManifestPath, globalModulesManifest);
};

exports.activateProjectModule = function(projectDir, name, version) {
var projectModulesManifestPath = path.join(projectDir, '.modules.json'),
projectModulesManifest = loadModulesManifest(projectModulesManifestPath);
projectModulesManifest[name] || (projectModulesManifest[name] = {});
projectModulesManifest[name] = {
'activated-version': version
};
saveModulesManifest(projectModulesManifestPath, projectModulesManifest);
};

exports.deactivateProjectModule = function(projectDir, name) {
var projectModulesManifestPath = path.join(projectDir, '.modules.json'),
projectModulesManifest = loadModulesManifest(projectModulesManifestPath);
delete projectModulesManifest[name];
saveModulesManifest(projectModulesManifestPath, projectModulesManifest);
};

function loadModulesManifest(path) {
path = afs.resolvePath(path);
if (afs.exists(path)) {
try {
return JSON.parse(fs.readFileSync(path));
} catch (e) {
return {};
}
} else {
return {};
}
}

function saveModulesManifest(path, content) {
fs.writeFileSync(afs.resolvePath(path), JSON.stringify(content, null, '\t'));
}

exports.find = function (modules, platforms, deployType, projectDir, logger, callback) {
var result = {
found: [],
Expand Down Expand Up @@ -175,4 +292,9 @@ exports.find = function (modules, platforms, deployType, projectDir, logger, cal

callback(result);
});
};
};

// Here for backwards compatibility
exports.detect = function (projectDir, logger, callback) {
exports.getModules(projectDir, callback);
}