Comparar commits
91 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 1578886584 | |||
| 0927c2c270 | |||
| bd329bdfe3 | |||
| e3a499f409 | |||
| 63c78426d3 | |||
| 6ec2f69268 | |||
| 1ccd193ddd | |||
| a5d52dce33 | |||
| ca358ae7b9 | |||
| 0a1177c299 | |||
| 46bf346c5c | |||
| 8a94496e01 | |||
| d3cf339856 | |||
| 5c0c58c3be | |||
| ef607e0e76 | |||
| 305503ac7a | |||
| c76e62b976 | |||
| 554065ee11 | |||
| 7fba52ad97 | |||
| c56de24e7d | |||
| 6e16087fc3 | |||
| 8133acbb46 | |||
| d974cb8215 | |||
| 68021c1903 | |||
| 7178b89578 | |||
| 0935abe858 | |||
| 22225922e5 | |||
| 343f2ffa61 | |||
| 477d38d313 | |||
| 84e5377b8a | |||
| 1abbecc54c | |||
| af2f34545b | |||
| f7499c4599 | |||
| ad52fe7d70 | |||
| 5ddeb6f331 | |||
| 7cd3d961cf | |||
| c38b38b4a1 | |||
| 6ae73ece70 | |||
| b5512d8228 | |||
| 89c871412a | |||
| 33e28aa3f1 | |||
| 3899c3cb16 | |||
| eb4f97e9b5 | |||
| 16e37043f4 | |||
| 261ffd1eba | |||
| 9167b33e18 | |||
| 6f7f0d01e5 | |||
| c11b1fe812 | |||
| 306425cae1 | |||
| 6d70728b54 | |||
| fadb654883 | |||
| 6528bbdbc6 | |||
| 23852de607 | |||
| 9cf66a0e02 | |||
| ad19e0fb57 | |||
| 14f222bf6f | |||
| 95141d1a42 | |||
| 93aaf72372 | |||
| 47a6612ed0 | |||
| fe48af8bf4 | |||
| 78ca4f8762 | |||
| a7e08aa279 | |||
| e2980d616f | |||
| 96f2090d9e | |||
| 8a86a114db | |||
| cb757da118 | |||
| 31711e079a | |||
| 16ebb83ae6 | |||
| 65304b2645 | |||
| b44c6a104b | |||
| a8e5876f83 | |||
| 2d9d1e71c0 | |||
| 475bdfed50 | |||
| c36f12ccb2 | |||
| 0b8b5b8adf | |||
| e981c97c71 | |||
| 748461f3c6 | |||
| a51f55dd66 | |||
| 7ba2c59265 | |||
| dcc833a957 | |||
| 8c35af6554 | |||
| 70fe60a45d | |||
| 98c64fc37a | |||
| efa88194a1 | |||
| f1a5fb18e9 | |||
| 084f79c51a | |||
| 2561b1c43a | |||
| a0b20408fd | |||
| 5f3bf23a6a | |||
| 4badd0d001 | |||
| 383eda1f2b |
+1
-2
@@ -2,5 +2,4 @@ language: node_js
|
||||
services: mongodb
|
||||
sudo: false
|
||||
node_js:
|
||||
- "4.1.1"
|
||||
- "4.2.5"
|
||||
- "6.2.1"
|
||||
|
||||
+9
-1
@@ -16,9 +16,17 @@ Simply run the following command to install deepforge with its dependencies:
|
||||
curl -o- https://raw.githubusercontent.com/dfst/deepforge/master/install.sh | bash
|
||||
```
|
||||
|
||||
Or, if you already have NodeJS (v6) installed, simply run
|
||||
|
||||
```
|
||||
npm install -g deepforge
|
||||
```
|
||||
|
||||
Next, start deepforge with `deepforge start`!
|
||||
|
||||
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions,check out our [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
|
||||
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions, check out the [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
|
||||
|
||||
Also, be sure to check out the other available features of the `deepforge` cli; it can be used to update, manage your torch installation, uninstall deepforge and run individual components!
|
||||
|
||||
## Interested in contributing?
|
||||
Contributions are welcome! Either fork the project and submit some PR's or shoot me an email about getting more involved!
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
"torch": {
|
||||
"dir": "~/.deepforge/torch"
|
||||
},
|
||||
"blob": {
|
||||
"dir": "~/.deepforge/blob"
|
||||
},
|
||||
"worker": {
|
||||
"cache": {
|
||||
"useBlob": true,
|
||||
"dir": "~/.deepforge/worker/cache"
|
||||
},
|
||||
"dir": "~/.deepforge/worker"
|
||||
},
|
||||
"mongo": {
|
||||
"dir": "~/.deepforge/data"
|
||||
}
|
||||
|
||||
+167
-112
@@ -3,15 +3,15 @@
|
||||
var Command = require('commander').Command,
|
||||
program = new Command(),
|
||||
childProcess = require('child_process'),
|
||||
spawn = childProcess.spawn,
|
||||
rawSpawn = childProcess.spawn,
|
||||
Q = require('q'),
|
||||
execSync = childProcess.execSync,
|
||||
path = require('path'),
|
||||
fs = require('fs'),
|
||||
version = require('../package.json').version,
|
||||
exists = require('exists-file'),
|
||||
forever = require('forever-monitor'),
|
||||
DEFAULT_CONFIG = require('./config.json'),
|
||||
assign = require('lodash.assign'),
|
||||
merge = require('lodash.merge'),
|
||||
config,
|
||||
|
||||
configDir = path.join(process.env.HOME, '.deepforge'),
|
||||
@@ -20,7 +20,12 @@ var Command = require('commander').Command,
|
||||
|
||||
localConfig,
|
||||
rm_rf = require('rimraf'),
|
||||
p = dir => dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
|
||||
p = dir => {
|
||||
if (typeof dir === 'string') {
|
||||
return dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
|
||||
}
|
||||
return dir;
|
||||
};
|
||||
|
||||
// Check for any commands
|
||||
if (process.argv.length === 2) {
|
||||
@@ -39,17 +44,17 @@ if (!exists.sync(configPath)) {
|
||||
}
|
||||
|
||||
localConfig = require(configPath);
|
||||
config = assign(DEFAULT_CONFIG, require(configPath));
|
||||
config = merge({}, DEFAULT_CONFIG, localConfig);
|
||||
|
||||
var getConfigValue = function(id) {
|
||||
var getConfigValue = function(id, srcConfig) {
|
||||
var keys = id.split('.'),
|
||||
value = config;
|
||||
value = srcConfig || config;
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
value = value[keys[i]];
|
||||
if (!value) {
|
||||
if (!value.hasOwnProperty(keys[i])) {
|
||||
return null;
|
||||
}
|
||||
value = value[keys[i]];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
@@ -59,7 +64,8 @@ var storeConfig = function(id, value) {
|
||||
var keys = id.split('.').filter(k => k),
|
||||
lastKey = keys.pop(),
|
||||
currentObj = localConfig,
|
||||
current = getConfigValue(id);
|
||||
current = getConfigValue(id),
|
||||
expType = typeof getConfigValue(id, DEFAULT_CONFIG);
|
||||
|
||||
// Check if it is a valid key
|
||||
if (current === null) {
|
||||
@@ -73,25 +79,39 @@ var storeConfig = function(id, value) {
|
||||
currentObj = currentObj[keys[i]];
|
||||
}
|
||||
|
||||
if (expType !== 'string') {
|
||||
try { // try to downcast
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {
|
||||
console.log(`Invalid value: "${value}" (expected ${expType})`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentObj[lastKey] = value;
|
||||
fs.writeFileSync(configPath, JSON.stringify(localConfig, null, 2));
|
||||
return true;
|
||||
};
|
||||
|
||||
(function() { // Load config to env
|
||||
var envToConf = require('./envConfig.json');
|
||||
Object.keys(envToConf).forEach(env => {
|
||||
var cKey = envToConf[env];
|
||||
process.env[env] = process.env[env] || p(getConfigValue(cKey));
|
||||
});
|
||||
|
||||
// Special cases
|
||||
if (process.env.DEEPFORGE_WORKER_USE_BLOB === 'true' &&
|
||||
exists.sync(process.env.DEEPFORGE_BLOB_DIR)) {
|
||||
|
||||
process.env.DEEPFORGE_WORKER_CACHE = process.env.DEEPFORGE_BLOB_DIR + '/wg-content';
|
||||
}
|
||||
})();
|
||||
|
||||
program
|
||||
.version('v' + version)
|
||||
.description('Command line interface for managing deepforge');
|
||||
|
||||
// start
|
||||
var start = function(main, opts) {
|
||||
var child = new forever.Monitor(main, opts);
|
||||
child.on('exit', function () {
|
||||
console.log('Exited after 3 failed restarts');
|
||||
});
|
||||
|
||||
child.start();
|
||||
};
|
||||
|
||||
var isLocalUri = function(protocol, uri) {
|
||||
return uri.indexOf(protocol + '://localhost') === 0 ||
|
||||
uri.indexOf(protocol + '://127.0.0.1') === 0;
|
||||
@@ -115,7 +135,7 @@ var checkMongo = function(args) {
|
||||
};
|
||||
|
||||
var startMongo = function(args, silent) {
|
||||
var job = spawn('mongod', ['--dbpath', p(config.mongo.dir)], {
|
||||
var job = rawSpawn('mongod', ['--dbpath', p(config.mongo.dir)], {
|
||||
cwd: process.env.HOME
|
||||
});
|
||||
if (!silent) {
|
||||
@@ -147,63 +167,95 @@ var startMongo = function(args, silent) {
|
||||
}
|
||||
});
|
||||
};
|
||||
var checkTorch = function() {
|
||||
return new Promise(_checkTorch)
|
||||
.catch(() => 'Torch installation failed');
|
||||
|
||||
var hasTorch = function() {
|
||||
var result = childProcess.spawnSync('th', ['--help']);
|
||||
return !result.error;
|
||||
};
|
||||
|
||||
var _checkTorch = function(resolve, reject) {
|
||||
var result = childProcess.spawnSync('th', ['--help']),
|
||||
tgtDir = p(config.torch.dir),
|
||||
gcl = `git clone https://github.com/torch/distro.git ${tgtDir} --recursive`;
|
||||
var installTorchExtras = function() {
|
||||
// Check if rnn is installed
|
||||
var result = childProcess.spawnSync('luarocks', ['list', '--porcelain']),
|
||||
pkgs = result.stdout.toString().split('\n')
|
||||
.map(line => line.match(/^[a-zA-Z0-9]+/g))
|
||||
.map(m => m && m[0]);
|
||||
|
||||
if (result.error) {
|
||||
if (pkgs.indexOf('rnn') === -1) {
|
||||
return spawn('luarocks', ['install', 'rnn']);
|
||||
} else {
|
||||
return Q();
|
||||
}
|
||||
};
|
||||
|
||||
var installTorch = function() {
|
||||
var tgtDir = p(config.torch.dir),
|
||||
args;
|
||||
|
||||
if (!hasTorch()) {
|
||||
// Try to install torch
|
||||
console.log(`Torch7 not found. Installing to ${tgtDir}...`);
|
||||
args = `clone https://github.com/torch/distro.git ${tgtDir} --recursive`.split(' ');
|
||||
|
||||
spawnMany([gcl],
|
||||
() => {
|
||||
process.chdir(tgtDir);
|
||||
spawnMany([
|
||||
'bash install-deps',
|
||||
'./install.sh'
|
||||
], () => {
|
||||
storeConfig('torch.dir', tgtDir);
|
||||
resolve(true);
|
||||
}, reject);
|
||||
},
|
||||
reject
|
||||
);
|
||||
return spawn('git', args)
|
||||
.then(code => {
|
||||
if (code !== 0) {
|
||||
if (code === 128) {
|
||||
console.error(`${tgtDir} is not empty. ` +
|
||||
'Please empty it or change the torch directory:\n' +
|
||||
'\n deepforge config torch.dir NEW/TORCH/PATH\n');
|
||||
|
||||
}
|
||||
|
||||
throw `Torch install Failed with exit code ${code}`;
|
||||
} else { // continue installation
|
||||
process.chdir(tgtDir);
|
||||
return spawn('bash', ['install-deps'])
|
||||
.then(() => spawn('bash', ['install.sh'], true))
|
||||
.then(() => {
|
||||
storeConfig('torch.dir', tgtDir);
|
||||
console.log('Installed torch. Please close and ' +
|
||||
're-open your terminal to use DeepForge w/ ' +
|
||||
'torch support!');
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolve(false);
|
||||
return Q();
|
||||
}
|
||||
};
|
||||
|
||||
var spawnMany = function(cmds, succ, err) {
|
||||
var rawCmd,
|
||||
cmd,
|
||||
args,
|
||||
job;
|
||||
var spawn = function(cmd, args, opts) {
|
||||
var deferred = Q.defer(),
|
||||
job,
|
||||
spawnOpts = typeof opts === 'object' ? opts : null,
|
||||
forwardStdin = opts === true,
|
||||
isOpen = true,
|
||||
err;
|
||||
|
||||
if (cmds.length === 0) {
|
||||
return succ();
|
||||
}
|
||||
|
||||
rawCmd = cmds.shift();
|
||||
args = rawCmd.split(' ');
|
||||
cmd = args.shift();
|
||||
job = spawn(cmd, args);
|
||||
args = args || [];
|
||||
job = spawnOpts ? rawSpawn(cmd, args, spawnOpts) : rawSpawn(cmd, args);
|
||||
job.stdout.on('data', data => process.stdout.write(data));
|
||||
job.stderr.on('data', data => process.stderr.write(data));
|
||||
job.on('close', code => {
|
||||
if (code) {
|
||||
console.log(`${rawCmd} failed w/ error code ${code}`);
|
||||
err(code, rawCmd);
|
||||
isOpen = false;
|
||||
if (err) {
|
||||
deferred.reject(err, code);
|
||||
} else {
|
||||
spawnMany(cmds, succ, err);
|
||||
deferred.resolve(code);
|
||||
}
|
||||
});
|
||||
job.on('error', e => err = e);
|
||||
|
||||
if (forwardStdin) {
|
||||
process.stdin.on('data', data => {
|
||||
if (isOpen) {
|
||||
job.stdin.write(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
program.command('start')
|
||||
@@ -213,34 +265,31 @@ program.command('start')
|
||||
.option('-w, --worker [url]', 'start a worker and connect to given url. Defaults to local deepforge')
|
||||
.option('-m, --mongo', 'start MongoDB')
|
||||
.action(args => {
|
||||
var main = path.join(__dirname, 'start-local.js'),
|
||||
opts;
|
||||
|
||||
opts = {
|
||||
max: 3,
|
||||
args: []
|
||||
};
|
||||
var main = path.join(__dirname, 'start-local.js');
|
||||
|
||||
if (args.port) {
|
||||
opts.env = {
|
||||
PORT: args.port
|
||||
};
|
||||
process.env.PORT = args.port;
|
||||
}
|
||||
|
||||
if (args.server) {
|
||||
checkMongo(args);
|
||||
main = path.join(__dirname, '..', 'app.js');
|
||||
start(main, opts);
|
||||
spawn('node', [main]);
|
||||
}
|
||||
|
||||
if (args.worker) {
|
||||
checkTorch().then(() => {
|
||||
main = path.join(__dirname, 'start-worker.js');
|
||||
if (args.worker !== true) {
|
||||
opts.args.push(args.worker);
|
||||
}
|
||||
start(main, opts);
|
||||
});
|
||||
if (hasTorch()) {
|
||||
installTorchExtras().then(() => {
|
||||
main = path.join(__dirname, 'start-worker.js');
|
||||
if (args.worker !== true) {
|
||||
spawn('node', [main, args.worker]);
|
||||
} else {
|
||||
spawn('node', [main]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
installTorch();
|
||||
}
|
||||
}
|
||||
|
||||
if (args.mongo) {
|
||||
@@ -250,7 +299,11 @@ program.command('start')
|
||||
if (!args.server && !args.worker && !args.mongo) {
|
||||
// Starting everything
|
||||
checkMongo(args);
|
||||
checkTorch().then(() => start(main, opts));
|
||||
if (hasTorch()) {
|
||||
installTorchExtras().then(() => spawn('node', [main]));
|
||||
} else {
|
||||
installTorch();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@@ -264,7 +317,6 @@ program
|
||||
.option('-s, --server', 'update deepforge')
|
||||
.action(args => {
|
||||
var pkg = 'deepforge',
|
||||
job,
|
||||
latestVersion;
|
||||
|
||||
// Install the project
|
||||
@@ -287,38 +339,43 @@ program
|
||||
}
|
||||
}
|
||||
|
||||
job = spawn('npm', ['install', '-g', pkg]);
|
||||
job.stdout.on('data', data => process.stdout.write(data.toString()));
|
||||
job.stderr.on('data', data => process.stderr.write(data.toString()));
|
||||
job.on('close', code => {
|
||||
if (!code) {
|
||||
spawn('npm', ['install', '-g', pkg])
|
||||
.then(() => {
|
||||
console.log('Upgrade successful!');
|
||||
} else {
|
||||
console.log('Upgrade failed w/ error code: ' + code);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(code => console.log('Upgrade failed w/ error code: ' + code));
|
||||
}
|
||||
|
||||
if (args.torch || !args.server) {
|
||||
// Update torch
|
||||
checkTorch().then(justInstalled => {
|
||||
if (!justInstalled) {
|
||||
// Upgrade torch
|
||||
console.log('Upgrading torch...');
|
||||
job = spawn('bash', ['./update.sh'], {
|
||||
cwd: p(config.torch.dir)
|
||||
});
|
||||
job.stdout.on('data', data => process.stdout.write(data.toString()));
|
||||
job.stderr.on('data', data => process.stderr.write(data.toString()));
|
||||
job.on('close', code => {
|
||||
if (!code) {
|
||||
console.log('Upgrade successful!');
|
||||
} else {
|
||||
console.log('Upgrade failed w/ error code: ' + code);
|
||||
}
|
||||
});
|
||||
if (hasTorch()) {
|
||||
// Upgrade torch
|
||||
console.log('Upgrading torch...');
|
||||
console.log(`Checking for torch in ${config.torch.dir}`);
|
||||
// Verify that torch is installed in the config's location
|
||||
if (!exists.sync(path.join(config.torch.dir, 'update.sh'))) {
|
||||
// config is incorrect!
|
||||
console.log('Could not find torch installation. Please update the deepforge config with:');
|
||||
console.log('');
|
||||
console.log(' deepforge config torch.dir ~/path/to/torch/install');
|
||||
console.log('');
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
spawn('bash', ['./update.sh'], {cwd: p(config.torch.dir)})
|
||||
.catch(err => console.log('Upgrade failed w/ error code: ' + err.code))
|
||||
.then(() => {
|
||||
console.log('About to update rnn package...');
|
||||
// Update rnn
|
||||
return spawn('luarocks', ['install', 'rnn']);
|
||||
})
|
||||
.then(() => {
|
||||
console.log('Upgrade successful!');
|
||||
})
|
||||
.catch(code => console.log('Upgrade failed w/ error code: ' + code));
|
||||
} else {
|
||||
installTorch();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -343,11 +400,9 @@ program
|
||||
}
|
||||
|
||||
if (!opts.torch || opts.clean) { // uninstall deepforge
|
||||
spawnMany(
|
||||
['npm uninstall -g deepforge'],
|
||||
() => console.log('deepforge has been uninstalled!'),
|
||||
() => console.log('uninstall failed')
|
||||
);
|
||||
spawn('npm', ['uninstall', '-g', 'deepforge'])
|
||||
.then(() => console.log('deepforge has been uninstalled!'))
|
||||
.catch(() => console.log('uninstall failed'));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -383,8 +438,8 @@ program
|
||||
|
||||
module.exports = function(cmd) {
|
||||
var cmds = cmd.split(/\s+/).filter(w => !!w);
|
||||
cmds.unshift('node');
|
||||
cmds.unshift('./bin/deepforge');
|
||||
cmds.unshift('node');
|
||||
program.parse(cmds);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"DEEPFORGE_BLOB_DIR": "blob.dir",
|
||||
"DEEPFORGE_WORKER_CACHE": "worker.cache.dir",
|
||||
"DEEPFORGE_WORKER_DIR": "worker.dir",
|
||||
"DEEPFORGE_WORKER_USE_BLOB": "worker.cache.useBlob"
|
||||
}
|
||||
@@ -4,7 +4,13 @@ var spawn = require('child_process').spawn,
|
||||
execJob,
|
||||
path = require('path'),
|
||||
env = {cwd: path.join(__dirname, '..')},
|
||||
workerJob = null;
|
||||
workerJob = null,
|
||||
gmeConfig = require(__dirname + '/../config');
|
||||
|
||||
// Set the cache to the blob
|
||||
if (gmeConfig.blob.type === 'FS') {
|
||||
process.env.DEEPFORGE_WORKER_CACHE = path.resolve(gmeConfig.blob.fsDir + '/wg-content');
|
||||
}
|
||||
|
||||
process.env.NODE_ENV = 'local';
|
||||
execJob = spawn('npm', [
|
||||
|
||||
+36
-2
@@ -4,15 +4,42 @@ var path = require('path'),
|
||||
fs = require('fs'),
|
||||
childProcess = require('child_process'),
|
||||
spawn = childProcess.spawn,
|
||||
rm_rf = require('rimraf'),
|
||||
projectConfig = require(__dirname + '/../config'),
|
||||
executorSrc = path.join(__dirname, '..', 'node_modules', 'webgme', 'src',
|
||||
'server', 'middleware', 'executor', 'worker'),
|
||||
workerPath = path.join(__dirname, '..', 'src', 'worker'),
|
||||
id = Date.now(),
|
||||
workerRootPath = process.env.DEEPFORGE_WORKER_DIR || path.join(__dirname, '..', 'src', 'worker'),
|
||||
workerPath = path.join(workerRootPath, `worker_${id}`),
|
||||
workerConfigPath = path.join(workerPath, 'config.json'),
|
||||
workerTmp = path.join(workerPath, 'tmp'),
|
||||
address,
|
||||
config = {};
|
||||
|
||||
var createDir = function(dir) {
|
||||
try {
|
||||
fs.statSync(dir);
|
||||
} catch (e) {
|
||||
// Create dir
|
||||
fs.mkdirSync(dir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
createDir(workerRootPath);
|
||||
createDir(workerPath);
|
||||
createDir(workerTmp);
|
||||
|
||||
// Create sym link to the node_modules
|
||||
var modules = path.join(workerRootPath, 'node_modules');
|
||||
try {
|
||||
fs.statSync(modules);
|
||||
} catch (e) {
|
||||
// Create dir
|
||||
childProcess.spawnSync('ln', ['-s', `${__dirname}/../node_modules`, modules]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check torch support
|
||||
var result = childProcess.spawnSync('th', ['--help']);
|
||||
if (result.error) {
|
||||
@@ -22,7 +49,15 @@ if (result.error) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var cleanUp = function() {
|
||||
console.log('removing worker directory ', workerPath);
|
||||
rm_rf.sync(workerPath);
|
||||
};
|
||||
|
||||
var startExecutor = function() {
|
||||
process.on('SIGINT', cleanUp);
|
||||
process.on('uncaughtException', cleanUp);
|
||||
|
||||
// Start the executor
|
||||
var execJob = spawn('node', [
|
||||
'node_worker.js',
|
||||
@@ -42,7 +77,6 @@ var createConfigJson = function() {
|
||||
}
|
||||
|
||||
config[address] = {};
|
||||
// TODO: Check if the config already exists
|
||||
fs.writeFile(workerConfigPath, JSON.stringify(config), startExecutor);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"LayerColors": {}
|
||||
},
|
||||
"BreadcrumbHeader": {
|
||||
"pathRule": "history"
|
||||
"pathRule": "history",
|
||||
"cachePrefix": "deepforge-header"
|
||||
},
|
||||
"FloatingActionButton": {
|
||||
"hideOnEmpty": true
|
||||
|
||||
@@ -9,7 +9,10 @@ require('dotenv').load({silent: true});
|
||||
// Add/overwrite any additional settings here
|
||||
config.server.port = +process.env.PORT || config.server.port;
|
||||
config.mongo.uri = process.env.MONGO_URI || config.mongo.uri;
|
||||
config.blob.fsDir = process.env.DEEPFORGE_BLOB_DIR || config.blob.fsDir;
|
||||
|
||||
config.requirejsPaths.deepforge = './src/common';
|
||||
config.requirejsPaths.ace = './src/visualizers/widgets/TextEditor/lib/ace';
|
||||
config.seedProjects.defaultProject = 'project';
|
||||
|
||||
config.plugin.allowBrowserExecution = true;
|
||||
@@ -20,5 +23,7 @@ config.executor.clearOldDataAtStartUp = true;
|
||||
|
||||
config.visualization.extraCss.push('deepforge/styles/global.css');
|
||||
|
||||
config.storage.autoMerge.enable = true;
|
||||
|
||||
validateConfig(config);
|
||||
module.exports = config;
|
||||
|
||||
@@ -20,6 +20,7 @@ config.seedProjects.basePaths.push('src/seeds/pipeline');
|
||||
config.seedProjects.basePaths.push('src/seeds/devPipelineTests');
|
||||
config.seedProjects.basePaths.push('src/seeds/project');
|
||||
config.seedProjects.basePaths.push('src/seeds/cifar10');
|
||||
config.seedProjects.basePaths.push('src/seeds/xor');
|
||||
|
||||
|
||||
|
||||
|
||||
+5
-6
@@ -12,23 +12,22 @@
|
||||
"watch-test": "./node_modules/nodemon/bin/nodemon.js --exec 'node ./node_modules/mocha/bin/mocha --recursive test'",
|
||||
"build-nn": "node ./utils/nn-parser.js"
|
||||
},
|
||||
"version": "0.10.1",
|
||||
"version": "0.14.0",
|
||||
"dependencies": {
|
||||
"commander": "^2.9.0",
|
||||
"dotenv": "^2.0.0",
|
||||
"exists-file": "^2.1.0",
|
||||
"forever-monitor": "^1.7.0",
|
||||
"lodash.assign": "^4.0.9",
|
||||
"lodash.difference": "^4.1.2",
|
||||
"lodash.merge": "^4.5.1",
|
||||
"nodemon": "^1.9.2",
|
||||
"rimraf": "^2.4.0",
|
||||
"webgme": "^2.0.0",
|
||||
"webgme-autoviz": "dfst/webgme-autoviz",
|
||||
"webgme-breadcrumbheader": "^2.1.0",
|
||||
"webgme-breadcrumbheader": "^2.1.1",
|
||||
"webgme-chflayout": "^2.0.0",
|
||||
"webgme-easydag": "dfst/webgme-easydag",
|
||||
"webgme-fab": "dfst/webgme-fab",
|
||||
"webgme-simple-nodes": "^2.0.0",
|
||||
"rimraf": "^2.4.0"
|
||||
"webgme-simple-nodes": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^3.0.0",
|
||||
|
||||
@@ -4,7 +4,13 @@ define({
|
||||
|
||||
// DeepForge metadata creation in dist execution
|
||||
START_CMD: 'deepforge-cmd',
|
||||
|
||||
IMAGE: 'IMG',
|
||||
|
||||
GRAPH_CREATE: 'GRAPH',
|
||||
GRAPH_PLOT: 'PLOT',
|
||||
GRAPH_CREATE_LINE: 'LINE'
|
||||
GRAPH_CREATE_LINE: 'LINE',
|
||||
|
||||
// Code Generation Constants
|
||||
CTOR_ARGS_ATTR: 'ctor_arg_order'
|
||||
});
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
/* globals define*/
|
||||
(function(root, factory){
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define(['./lua'], function(luajs){
|
||||
return (root.LayerParser = factory(luajs));
|
||||
});
|
||||
} else if(typeof module === 'object' && module.exports) {
|
||||
var luajs = require('./lua');
|
||||
module.exports = (root.LayerParser = factory(luajs));
|
||||
}
|
||||
}(this, function(luajs) {
|
||||
var LayerParser = {};
|
||||
|
||||
//////////////////////// Setters ////////////////////////
|
||||
var returnsSelf = function(fnNode){
|
||||
var stats = fnNode.block.stats,
|
||||
last = stats[stats.length-1];
|
||||
|
||||
if (last.type === 'stat.return') {
|
||||
return last.nret[0].type === 'variable' && last.nret[0].val === 'self';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var isAttrSetter = function(node){
|
||||
if (node.type === 'stat.assignment' && node.lefts.length === 1) {
|
||||
var left = node.lefts[0];
|
||||
return left.type === 'expr.index' && left.self.val === 'self';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var getSettingAttrName = function(node){
|
||||
if (isAttrSetter(node)) {
|
||||
var left = node.lefts[0];
|
||||
return left.key.val;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var getSettingAttrValue = function(node){
|
||||
if (isAttrSetter(node)) {
|
||||
return node.right;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var isSetterMethod = function(curr, parent, className){
|
||||
if (parent && parent.type === 'stat.method') {
|
||||
// is it a fn w/ two statements (stats)
|
||||
if (parent.self.val === className && curr.type === 'function' &&
|
||||
curr.block.stats.length === 2) {
|
||||
// Is the first statement setting a value?
|
||||
return returnsSelf(curr) && getSettingAttrName(curr.block.stats[0]); // does it return itself?
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var isFnArg = function(method, name) {
|
||||
return method.args.indexOf(name) !== -1;
|
||||
};
|
||||
|
||||
var getSetterSchema = function(node, method) {
|
||||
var setterType,
|
||||
setterFn,
|
||||
value = getSettingAttrValue(node);
|
||||
|
||||
if (value[0].type === 'variable' && isFnArg(method.func, value[0].val)) {
|
||||
setterType = 'arg';
|
||||
setterFn = method.key.val;
|
||||
} else {
|
||||
setterType = 'const';
|
||||
setterFn = {};
|
||||
setterFn[value[0].val] = method.key.val;
|
||||
}
|
||||
|
||||
return {
|
||||
setterType,
|
||||
setterFn
|
||||
};
|
||||
};
|
||||
|
||||
//////////////////////// Setters END ////////////////////////
|
||||
|
||||
var isInitFn = function(node, className) {
|
||||
if (node.type === 'stat.method' && node.self.val === className) {
|
||||
return node.key.val === '__init';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var getClassAttrDefs = function(method) {
|
||||
var fn = method.func,
|
||||
dict = {},
|
||||
attr,
|
||||
right,
|
||||
value;
|
||||
|
||||
luajs.codegen.traverse(curr => {
|
||||
if (isAttrSetter(curr)) {
|
||||
// Store the value if it is set to a constant
|
||||
attr = curr.lefts[0].key.val;
|
||||
right = curr.right[0];
|
||||
if (right.type.indexOf('const.') !== -1) {
|
||||
value = right.val;
|
||||
|
||||
if (right.type === 'const.nil') {
|
||||
value = null;
|
||||
}
|
||||
|
||||
dict[attr] = value;
|
||||
}
|
||||
}
|
||||
})(fn);
|
||||
|
||||
return dict;
|
||||
};
|
||||
|
||||
var getAttrsAndVals = function(method) {
|
||||
// Given a method, get the 'self' attributes and the default values
|
||||
var fn = method.func,
|
||||
dict = {},
|
||||
varName,
|
||||
value,
|
||||
varUsageCnt = {};
|
||||
|
||||
// Get the variables that are used only once (or updating themselves)
|
||||
luajs.codegen.traverse(curr => {
|
||||
if (curr.type === 'variable') {
|
||||
varUsageCnt[curr.val] = varUsageCnt[curr.val] ?
|
||||
varUsageCnt[curr.val] + 1 : 1;
|
||||
}
|
||||
})(method);
|
||||
|
||||
luajs.codegen.traverse(curr => {
|
||||
// If the variable is only used once and is 'or'-ed w/ a constant
|
||||
// during this use, we can infer that this is the default value
|
||||
if (curr.type === 'expr.op' && curr.op === 'op.or' &&
|
||||
curr.left.type === 'variable' && curr.right.type.indexOf('const') !== -1) {
|
||||
varName = curr.left.val;
|
||||
if (varUsageCnt[varName] === 1) {
|
||||
value = curr.right.type === 'const.nil' ? null : curr.right;
|
||||
dict[varName] = value;
|
||||
}
|
||||
}
|
||||
})(fn);
|
||||
|
||||
return dict;
|
||||
};
|
||||
|
||||
var copyNodeValues = function(attrs, from, to) {
|
||||
var value;
|
||||
for (var i = attrs.length; i--;) {
|
||||
value = from[attrs[i]] || null;
|
||||
if (value) {
|
||||
value = (value && value.hasOwnProperty('val')) ? value.val : value;
|
||||
to[attrs[i]] = value;
|
||||
}
|
||||
}
|
||||
return to;
|
||||
};
|
||||
|
||||
var getTypeCheckInfo = function(cond) {
|
||||
var caller,
|
||||
method,
|
||||
target,
|
||||
expType;
|
||||
|
||||
// Check for torch.isTypeOf:
|
||||
if (cond.type === 'expr.call' && cond.func.type === 'expr.index') {
|
||||
caller = cond.func.self.val;
|
||||
method = cond.func.key.val;
|
||||
|
||||
if (cond.type === 'expr.call' && caller === 'torch') {
|
||||
target = cond.args[0].val;
|
||||
if (method === 'isTypeOf' && target) {
|
||||
expType = cond.args[1].val;
|
||||
return {
|
||||
target,
|
||||
type: expType
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (cond.type === 'expr.op') { // torch.type() === ''
|
||||
// Check right side, too!
|
||||
var sides = [cond.left, cond.right],
|
||||
side,
|
||||
otherSide;
|
||||
|
||||
for (var i = sides.length; i--;) {
|
||||
side = sides[i];
|
||||
otherSide = sides[(i+1)%2];
|
||||
if (side.type === 'expr.call' && side.func.type === 'expr.index') {
|
||||
// Is it torch?
|
||||
caller = side.func.self.val;
|
||||
method = side.func.key.val;
|
||||
if (caller === 'torch' && method === 'type') {
|
||||
if (side.args[0].type === 'variable') {
|
||||
target = side.args[0].val;
|
||||
if (otherSide.type === 'const.string') {
|
||||
expType = otherSide.val;
|
||||
|
||||
return {
|
||||
target: target,
|
||||
type: expType
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var isError = function(stat) {
|
||||
var fn;
|
||||
if (stat.type === 'stat.expr' && stat.expr.type === 'expr.call') {
|
||||
fn = stat.expr.func.val;
|
||||
return fn === 'error';
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var inferParamTypes = function(node, paramDefs) {
|
||||
var types = {},
|
||||
check,
|
||||
cond;
|
||||
|
||||
// Infer from assertions
|
||||
luajs.codegen.traverse(curr => {
|
||||
// check for 'assert's that check type
|
||||
if (curr.type === 'expr.call' && curr.func.val === 'assert') {
|
||||
cond = curr.args[0];
|
||||
check = getTypeCheckInfo(cond);
|
||||
if (check) {
|
||||
types[check.target] = check.type;
|
||||
}
|
||||
} else if (curr.type === 'stat.if' && curr.cond.op === 'uop.not') {
|
||||
// if statements throwing errors on type mismatch
|
||||
cond = curr.cond.operand; // non-negated version
|
||||
// Check that it throws an error on true
|
||||
if (curr.tblock.stats.some(isError)) {
|
||||
check = getTypeCheckInfo(cond);
|
||||
if (check) {
|
||||
types[check.target] = check.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
})(node);
|
||||
|
||||
// Infer from defaults
|
||||
Object.keys(paramDefs).forEach(param => {
|
||||
var val = paramDefs[param];
|
||||
if (val) { // initialized to 'null' doesn't help us...
|
||||
types[param] = val.type.replace('const.', '');
|
||||
}
|
||||
});
|
||||
|
||||
return types;
|
||||
};
|
||||
|
||||
var findTorchClass = function(ast){
|
||||
var torchClassArgs, // args for `torch.class(...)`
|
||||
name = '',
|
||||
baseType,
|
||||
params,
|
||||
setters = {},
|
||||
defaults = {},
|
||||
paramDefs,
|
||||
attrDefs;
|
||||
|
||||
if(ast.type == 'function'){
|
||||
ast.block.stats.forEach(function(func){
|
||||
if(func.type == 'stat.local' && func.right && func.right[0] &&
|
||||
func.right[0].func && func.right[0].func.self &&
|
||||
func.right[0].func.self.val == 'torch' &&
|
||||
func.right[0].func.key.val == 'class'){
|
||||
|
||||
torchClassArgs = func.right[0].args.map(arg => arg.val);
|
||||
name = torchClassArgs[0];
|
||||
if(name !== ''){
|
||||
name = name.replace('nn.', '');
|
||||
if (torchClassArgs.length > 1) {
|
||||
baseType = torchClassArgs[1].replace('nn.', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get the setters, defaults and type info (inferred)
|
||||
var setterNames,
|
||||
schema,
|
||||
types,
|
||||
values;
|
||||
|
||||
luajs.codegen.traverse((curr, parent) => {
|
||||
var firstLine,
|
||||
attrName;
|
||||
|
||||
// Record the setter functions
|
||||
if (isSetterMethod(curr, parent, name)) {
|
||||
firstLine = curr.block.stats[0];
|
||||
// just use the attribute attrName for now...
|
||||
attrName = getSettingAttrName(firstLine);
|
||||
|
||||
// merge schemas
|
||||
schema = getSetterSchema(firstLine, parent);
|
||||
if (setters[attrName] && setters[attrName].setterType === 'const') { // merge
|
||||
for (var val in schema.setterFn) {
|
||||
setters[attrName].setterFn[val] = schema.setterFn[val];
|
||||
}
|
||||
} else {
|
||||
setters[attrName] = schema;
|
||||
}
|
||||
} else if (isInitFn(curr, name)) { // Record the defaults
|
||||
paramDefs = getAttrsAndVals(curr);
|
||||
attrDefs = getClassAttrDefs(curr);
|
||||
types = inferParamTypes(curr, paramDefs);
|
||||
|
||||
// get ctor args
|
||||
params = curr.func.args;
|
||||
if(params.length === 0 && curr.func.varargs){
|
||||
params.push('params');
|
||||
}
|
||||
}
|
||||
|
||||
})(ast);
|
||||
|
||||
// Get the defaults for the params from defs
|
||||
if (paramDefs && params) {
|
||||
copyNodeValues(params, paramDefs, defaults);
|
||||
}
|
||||
|
||||
// Get the defaults for the setters from attrDefs
|
||||
if (attrDefs) {
|
||||
setterNames = Object.keys(setters);
|
||||
copyNodeValues(setterNames, attrDefs, defaults);
|
||||
}
|
||||
|
||||
// Remove any const setters w/ only one value and no default
|
||||
setterNames = Object.keys(setters);
|
||||
for (var i = setterNames.length; i--;) {
|
||||
schema = setters[setterNames[i]];
|
||||
if (schema.setterType === 'const') {
|
||||
values = Object.keys(schema.setterFn);
|
||||
if (values.length === 1 &&
|
||||
// boolean setters can have the default value inferred
|
||||
values[0] !== 'true' && values[0] !== 'false' &&
|
||||
!defaults[setterNames[i]]) {
|
||||
|
||||
delete setters[setterNames[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
baseType,
|
||||
params,
|
||||
setters,
|
||||
types,
|
||||
defaults
|
||||
};
|
||||
};
|
||||
|
||||
LayerParser.parse = function(text) {
|
||||
try {
|
||||
var ast = luajs.parser.parse(text);
|
||||
return findTorchClass(ast);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return LayerParser;
|
||||
}));
|
||||
+54
-23
@@ -1,13 +1,17 @@
|
||||
/* globals Materialize, WebGMEGlobal, define*/
|
||||
/* globals WebGMEGlobal, define*/
|
||||
// This file creates the DeepForge namespace and defines basic actions
|
||||
define([
|
||||
'panel/FloatingActionButton/styles/Materialize',
|
||||
'js/RegistryKeys',
|
||||
'js/Panels/MetaEditor/MetaEditorConstants',
|
||||
'js/Constants'
|
||||
'js/Constants',
|
||||
'q'
|
||||
], function(
|
||||
Materialize,
|
||||
REGISTRY_KEYS,
|
||||
META_CONSTANTS,
|
||||
CONSTANTS
|
||||
CONSTANTS,
|
||||
Q
|
||||
) {
|
||||
var DeepForge = {},
|
||||
placesTerritoryId,
|
||||
@@ -90,6 +94,7 @@ define([
|
||||
};
|
||||
|
||||
//////////////////// DeepForge places detection ////////////////////
|
||||
DeepForge.places = {};
|
||||
var TYPE_TO_CONTAINER = {
|
||||
|
||||
Architecture: 'MyArchitectures',
|
||||
@@ -105,10 +110,29 @@ define([
|
||||
PLACE_NAMES = Object.keys(TYPE_TO_CONTAINER).map(key => TYPE_TO_CONTAINER[key]);
|
||||
|
||||
// Add DeepForge directories
|
||||
var placePromises = {},
|
||||
setPlaceId = {},
|
||||
firstProject = true;
|
||||
|
||||
var getPlace = function(name) {
|
||||
return placePromises[name];
|
||||
};
|
||||
|
||||
var initializePlaces = function() {
|
||||
PLACE_NAMES.forEach(name => {
|
||||
var deferred = Q.defer();
|
||||
placePromises[name] = deferred.promise;
|
||||
setPlaceId[name] = deferred.resolve;
|
||||
});
|
||||
};
|
||||
|
||||
var updateDeepForgeNamespace = function() {
|
||||
var territory = {};
|
||||
|
||||
DeepForge.places = {};
|
||||
if (!firstProject) {
|
||||
initializePlaces();
|
||||
}
|
||||
firstProject = false;
|
||||
|
||||
// Create a territory
|
||||
if (placesTerritoryId) {
|
||||
@@ -135,13 +159,16 @@ define([
|
||||
nodes.forEach(node =>
|
||||
nodeIdsByName[node.getAttribute('name')] = node.getId());
|
||||
|
||||
PLACE_NAMES.forEach(name => DeepForge.places[name] = nodeIdsByName[name]);
|
||||
PLACE_NAMES.forEach(name => setPlaceId[name](nodeIdsByName[name]));
|
||||
|
||||
// Remove the territory
|
||||
client.removeUI(placesTerritoryId);
|
||||
placesTerritoryId = null;
|
||||
};
|
||||
|
||||
initializePlaces();
|
||||
PLACE_NAMES.forEach(name => DeepForge.places[name] = getPlace.bind(null, name));
|
||||
|
||||
//////////////////// DeepForge creation actions ////////////////////
|
||||
var instances = [
|
||||
'Architecture',
|
||||
@@ -154,8 +181,7 @@ define([
|
||||
];
|
||||
|
||||
var createNew = function(type, metasheetName) {
|
||||
var parentId,
|
||||
placeName = TYPE_TO_CONTAINER[type],
|
||||
var placeName = TYPE_TO_CONTAINER[type],
|
||||
newId,
|
||||
baseId,
|
||||
msg = `Created new ${type + (metasheetName ? ' prototype' : '')}`;
|
||||
@@ -165,19 +191,20 @@ define([
|
||||
.getId();
|
||||
|
||||
// Look up the parent container
|
||||
parentId = DeepForge.places[placeName];
|
||||
DeepForge.places[placeName]().then(parentId => {
|
||||
|
||||
client.startTransaction(msg);
|
||||
newId = createNamedNode(baseId, parentId, !!metasheetName);
|
||||
client.startTransaction(msg);
|
||||
newId = createNamedNode(baseId, parentId, !!metasheetName);
|
||||
|
||||
if (metasheetName) {
|
||||
addToMetaSheet(newId, metasheetName);
|
||||
}
|
||||
if (metasheetName) {
|
||||
addToMetaSheet(newId, metasheetName);
|
||||
}
|
||||
|
||||
client.completeTransaction();
|
||||
client.completeTransaction();
|
||||
|
||||
WebGMEGlobal.State.registerActiveObject(newId);
|
||||
return newId;
|
||||
WebGMEGlobal.State.registerActiveObject(newId);
|
||||
return newId;
|
||||
});
|
||||
};
|
||||
|
||||
var createCustomLayer = function(typeName) {
|
||||
@@ -198,16 +225,20 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
client.startTransaction(msg);
|
||||
return DeepForge.places.MyLayers()
|
||||
.then(id => {
|
||||
|
||||
newId = createNamedNode(baseId, DeepForge.places.MyLayers, true);
|
||||
addToMetaSheet(newId, 'CustomLayers');
|
||||
client.addMixin(newId, customLayerId);
|
||||
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
|
||||
client.startTransaction(msg);
|
||||
|
||||
client.completeTransaction();
|
||||
newId = createNamedNode(baseId, id, true);
|
||||
addToMetaSheet(newId, 'CustomLayers');
|
||||
client.addMixin(newId, customLayerId);
|
||||
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
|
||||
|
||||
WebGMEGlobal.State.registerActiveObject(newId);
|
||||
client.completeTransaction();
|
||||
|
||||
WebGMEGlobal.State.registerActiveObject(newId);
|
||||
});
|
||||
};
|
||||
|
||||
// Creating Artifacts
|
||||
|
||||
+30
-11
@@ -1,6 +1,8 @@
|
||||
/* globals define*/
|
||||
define([
|
||||
'deepforge/Constants'
|
||||
], function(
|
||||
Constants
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
@@ -15,32 +17,49 @@ define([
|
||||
return result;
|
||||
};
|
||||
|
||||
var isArgument = function(arg) {
|
||||
return arg.hasOwnProperty('argindex');
|
||||
};
|
||||
|
||||
var sortByIndex = function(a, b) {
|
||||
return a.argindex > b.argindex;
|
||||
var isSetter = function(arg) {
|
||||
return arg.hasOwnProperty('setterType');
|
||||
};
|
||||
|
||||
var createLayerDict = function(core, meta) {
|
||||
var node,
|
||||
names = Object.keys(meta),
|
||||
layers = {};
|
||||
layers = {},
|
||||
setters,
|
||||
ctorData,
|
||||
ctorArgs,
|
||||
attrs;
|
||||
|
||||
for (var i = names.length; i--;) {
|
||||
node = meta[names[i]];
|
||||
layers[names[i]] = core.getValidAttributeNames(node)
|
||||
ctorData = core.getAttribute(node, Constants.CTOR_ARGS_ATTR);
|
||||
attrs = core.getValidAttributeNames(node);
|
||||
|
||||
layers[names[i]] = {};
|
||||
if (ctorData) {
|
||||
ctorArgs = ctorData.split(',')
|
||||
.map(attr => prepAttribute(core, node, attr));
|
||||
|
||||
// Get the constructor args
|
||||
layers[names[i]].args = ctorArgs;
|
||||
} else {
|
||||
layers[names[i]].args = [];
|
||||
}
|
||||
|
||||
layers[names[i]].setters = {};
|
||||
setters = attrs
|
||||
.map(attr => prepAttribute(core, node, attr))
|
||||
.filter(isArgument)
|
||||
.sort(sortByIndex);
|
||||
.filter(isSetter);
|
||||
for (var j = setters.length; j--;) {
|
||||
layers[names[i]].setters[setters[j].name] = setters[j];
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
};
|
||||
|
||||
// When provided with the META, create the given LayerDict object
|
||||
// - Sort (and filter) by argindex
|
||||
// - Filter out the ctor args (in order)
|
||||
// - add name attribute to schema
|
||||
// - store this array under the META name
|
||||
|
||||
|
||||
@@ -1,546 +0,0 @@
|
||||
# This file should actually be an alternative way of viewing the metamodel.
|
||||
#
|
||||
# This contains metadata about the Torch nn library used for
|
||||
# creating the metamodel
|
||||
#
|
||||
# By default...
|
||||
# - all attributes are a number
|
||||
# - default values are optional
|
||||
# - all booleans default to false
|
||||
# - list attributes are specified with WORD...WORD
|
||||
# - if `ignore` is set, the attribute is not added to the metamodel
|
||||
|
||||
# This should have tests to verify that this document is up to date...
|
||||
# TODO
|
||||
|
||||
Containers:
|
||||
- Concat:
|
||||
- dim:
|
||||
min: 1 # TODO: Figure out exactly how this works
|
||||
|
||||
Module:
|
||||
- SpatialBatchNormalization:
|
||||
- input:
|
||||
infer: dimensionality # change this to `infer: 'dimensionality'`
|
||||
- eps:
|
||||
default: 0.00001
|
||||
- momentum:
|
||||
default: 0.1
|
||||
- affine:
|
||||
default: true
|
||||
|
||||
- BatchNormalization:
|
||||
- input:
|
||||
infer: dimensionality # change this to `infer: 'dimensionality'`
|
||||
- eps:
|
||||
default: 0.00001
|
||||
- momentum:
|
||||
default: 0.1
|
||||
- affine:
|
||||
default: true
|
||||
|
||||
- Threshold:
|
||||
- threshold:
|
||||
type: float
|
||||
default: 1e-6
|
||||
- value:
|
||||
type: float
|
||||
default: 0
|
||||
- inplace:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
ConvLayer:
|
||||
- TemporalConvolution:
|
||||
- inputFrameSize:
|
||||
min: 1
|
||||
- outputFrameSize:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- step:
|
||||
default: 1
|
||||
|
||||
- TemporalMaxPooling:
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- step: # FIXME: defaults to 'kernelWidth'
|
||||
min: 1
|
||||
|
||||
- TemporalSubSampling:
|
||||
- inputFrameSize:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- step:
|
||||
min: 1
|
||||
# TODO: What is the default?
|
||||
|
||||
- LookupTable:
|
||||
- nIndex:
|
||||
min: 1
|
||||
- sizes:
|
||||
min: 1
|
||||
|
||||
# Spatial Modules
|
||||
- SpatialConvolutionMM:
|
||||
- nInputPlane: # TODO: Infer this
|
||||
min: 1
|
||||
- nOutputPlane:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
- padWidth:
|
||||
min: 0
|
||||
default: 0
|
||||
- padHeight: # FIXME: this defaults to padWidth - not 0
|
||||
min: 0
|
||||
default: 0
|
||||
|
||||
- SpatialConvolution:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- nOutputPlane:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialConvolutionMap:
|
||||
- connectionMatrix:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialLPPooling:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- norm:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialMaxPooling:
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialAveragePooling:
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialAdaptiveMaxPooling: # output is width x height
|
||||
- width:
|
||||
min: 1
|
||||
- height:
|
||||
min: 1
|
||||
|
||||
- SpatialSubSampling:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
- SpatialUpSamplingNearest:
|
||||
- scale: # upscale ratio
|
||||
min: 1
|
||||
|
||||
- SpatialZeroPadding:
|
||||
- left:
|
||||
min: 0
|
||||
- right:
|
||||
min: 0
|
||||
- top:
|
||||
min: 0
|
||||
- bottom:
|
||||
min: 0
|
||||
|
||||
- SpatialSubtractiveNormalization:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- kernel:
|
||||
min: 1
|
||||
|
||||
- SpatialCrossMapLRN:
|
||||
- size:
|
||||
min: 1
|
||||
- alpha:
|
||||
default: 0.0001
|
||||
- beta:
|
||||
default: 0.75
|
||||
- k:
|
||||
default: 1
|
||||
|
||||
- SpatialConvolutionLocal:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- nOutputPlane:
|
||||
min: 1
|
||||
- inputWidth: # TODO: infer this
|
||||
min: 1
|
||||
- inputHeight: # TODO: infer this
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
- padWidth:
|
||||
min: 0
|
||||
default: 0
|
||||
- padHeight: # FIXME: this defaults to padWidth - not 0
|
||||
min: 0
|
||||
default: 0
|
||||
|
||||
- SpatialDropout:
|
||||
- probability:
|
||||
default: 0.5
|
||||
|
||||
- SpatialFractionalMaxPooling:
|
||||
- poolWidth:
|
||||
- min: 2
|
||||
- poolHeight:
|
||||
- min: 2
|
||||
- outWidth: # Optionally, these could be ratioW/H FIXME
|
||||
- min: 1
|
||||
- outHeight:
|
||||
- min: 1
|
||||
|
||||
- SpatialDivisiveNormalization:
|
||||
- nInputPlane: # TODO: infer this
|
||||
- default: 1
|
||||
- kernel: # TODO: this is a tensor type...
|
||||
- threshold:
|
||||
- default: 0.0001
|
||||
- thresval:
|
||||
- default: 0.0001 # FIXME: this defaults to "threshold"
|
||||
|
||||
- SpatialContrastiveNormalization:
|
||||
- nInputPlane: # TODO: infer this
|
||||
- default: 1
|
||||
- kernel: # TODO: this is a tensor type...
|
||||
- threshold:
|
||||
- default: 0.0001
|
||||
- thresval:
|
||||
- default: 0.0001 # FIXME: this defaults to "threshold"
|
||||
|
||||
- SpatialFullConvolution:
|
||||
- nInputPlane: # TODO: should infer this
|
||||
min: 1
|
||||
- nOutputPlane:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
- padWidth:
|
||||
min: 0
|
||||
default: 0
|
||||
- padHeight:
|
||||
min: 0
|
||||
default: 0
|
||||
- adjWidth:
|
||||
min: 0
|
||||
default: 0
|
||||
- adjHeight:
|
||||
min: 0
|
||||
default: 0
|
||||
# Additional constraint:
|
||||
|
||||
# Volumetric Modules
|
||||
- VolumetricConvolution:
|
||||
- nInputPlane:
|
||||
min: 1
|
||||
- nOutputPlane:
|
||||
min: 1
|
||||
- kernelTime:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideTime:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
- VolumetricMaxPooling:
|
||||
- kernelTime:
|
||||
min: 1
|
||||
- kernelWidth:
|
||||
min: 1
|
||||
- kernelHeight:
|
||||
min: 1
|
||||
- strideTime:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideWidth:
|
||||
min: 1
|
||||
default: 1
|
||||
- strideHeight:
|
||||
min: 1
|
||||
default: 1
|
||||
|
||||
SimpleLayer:
|
||||
- Linear: # FIXME: These should contain the actual args
|
||||
- input:
|
||||
infer: dimensionality
|
||||
- output:
|
||||
min: 1
|
||||
- SparseLinear:
|
||||
- input:
|
||||
infer: dimensionality
|
||||
- output:
|
||||
min: 1
|
||||
|
||||
- Dropout:
|
||||
- probability:
|
||||
type: float
|
||||
- Abs:
|
||||
- Add:
|
||||
- isScalar:
|
||||
type: boolean
|
||||
- Mul:
|
||||
- CMul:
|
||||
- size: null
|
||||
- Max:
|
||||
- dimension:
|
||||
min: 0
|
||||
- Min:
|
||||
- dimension:
|
||||
min: 0
|
||||
- Mean:
|
||||
- dimension:
|
||||
min: 0
|
||||
- Sum:
|
||||
- dimension:
|
||||
min: 0
|
||||
|
||||
- Euclidean:
|
||||
- output:
|
||||
min: 0
|
||||
- WeightedEuclidean:
|
||||
- output:
|
||||
min: 0
|
||||
- Identity:
|
||||
- Copy: # Casts types
|
||||
- inputType:
|
||||
type: string
|
||||
- outputType:
|
||||
type: string
|
||||
- forceCopy:
|
||||
type: boolean
|
||||
- Narrow:
|
||||
- dimension:
|
||||
min: 0
|
||||
- offset:
|
||||
min: 0
|
||||
- length:
|
||||
min: 0
|
||||
- Replicate:
|
||||
- nFeature:
|
||||
min: 0
|
||||
- Reshape:
|
||||
- dimensions:
|
||||
type: list
|
||||
- View:
|
||||
- sizes: # list
|
||||
type: list
|
||||
min: 0
|
||||
- Select:
|
||||
- dimensions:
|
||||
type: list
|
||||
- Exp
|
||||
- Square
|
||||
- Sqrt
|
||||
- Power:
|
||||
- p: null
|
||||
- MM:
|
||||
- transA:
|
||||
type: boolean
|
||||
- transB:
|
||||
type: boolean
|
||||
|
||||
TransferLayer:
|
||||
- HardTanh
|
||||
- HardShrink:
|
||||
- lambda:
|
||||
type: float
|
||||
- SoftShrink:
|
||||
- lambda:
|
||||
type: float
|
||||
- SoftMax
|
||||
- SoftMin
|
||||
- SoftPlus
|
||||
- SoftSign # Typo in the docs on this one
|
||||
- LogSigmoid
|
||||
- LogSoftMax # Also in Criterion?
|
||||
- Sigmoid
|
||||
- Tanh
|
||||
- ReLU
|
||||
- PReLU # Missing from docs
|
||||
- RReLU # Missing from docs
|
||||
- LeakyReLU # Missing from docs
|
||||
- AddConstant:
|
||||
- scalar:
|
||||
type: float
|
||||
- MulConstant:
|
||||
- scalar:
|
||||
type: float
|
||||
min: 1
|
||||
- inplace:
|
||||
default: false
|
||||
|
||||
Criterion:
|
||||
- BCECriterion
|
||||
- WeightedMSECriterion
|
||||
- SmoothL1Criterion
|
||||
- MSECriterion
|
||||
- AbsCriterion
|
||||
- MultiCriterion
|
||||
- DistKLDivCriterion
|
||||
- HingeEmbeddingCriterion
|
||||
- CriterionTable
|
||||
- MultiMarginCriterion
|
||||
- MultiLabelMarginCriterion
|
||||
- L1HingeEmbeddingCriterion
|
||||
- CosineEmbeddingCriterion
|
||||
- MarginRankingCriterion
|
||||
- CrossEntropyCriterion
|
||||
- MarginCriterion
|
||||
- ClassNLLCriterion
|
||||
- ParallelCriterion
|
||||
|
||||
MiscLayers:
|
||||
- Jacobian
|
||||
- ConcatTable
|
||||
- CMulTable
|
||||
- CAddTable
|
||||
- TanhShrink
|
||||
- Padding:
|
||||
- dim:
|
||||
- pad:
|
||||
min: 0
|
||||
- nInputDim: # TODO: infer?
|
||||
min: 1
|
||||
- value:
|
||||
min: 0
|
||||
default: 0
|
||||
|
||||
# TODO: Add the following layers
|
||||
#VolumetricMaxUnpooling
|
||||
# Takes a poolingModule as an arg...
|
||||
|
||||
#MixtureTable
|
||||
#NarrowTable
|
||||
#SplitTable
|
||||
#DotProduct
|
||||
#DepthConcat
|
||||
#Parallel
|
||||
#Log
|
||||
#hessian
|
||||
#ELU
|
||||
#CSubTable
|
||||
#VolumetricAveragePooling
|
||||
#StochasticGradient
|
||||
#Bilinear
|
||||
#VolumetricFullConvolution
|
||||
#SparseJacobian
|
||||
#Contiguous
|
||||
#L1Cost
|
||||
#JoinTable
|
||||
#CosineDistance
|
||||
#Index
|
||||
#L1Penalty
|
||||
#Cosine
|
||||
#Clamp
|
||||
#SpatialConvolutionMM
|
||||
#LogSigmoid
|
||||
#ParallelTable
|
||||
#CDivTable
|
||||
#SpatialFullConvolutionMap
|
||||
#GradientReversal
|
||||
#SpatialMaxUnpooling
|
||||
#Transpose
|
||||
#Normalize
|
||||
#SpatialSoftMax
|
||||
#SelectTable
|
||||
#FlattenTable
|
||||
|
||||
# CONTAINERS and TableLayouts
|
||||
# Some of these are captured by the visual structure of the architecture and are not needed
|
||||
# as explicit layers in the metamodel
|
||||
#TableLayer:
|
||||
#- ConcatTable
|
||||
#Container:
|
||||
|
||||
@@ -106,21 +106,30 @@ define([
|
||||
};
|
||||
|
||||
LocalExecutor.prototype.Save = function(node) {
|
||||
var nodeId = this.core.getPath(node),
|
||||
parentNode;
|
||||
var parentNode,
|
||||
currNameHashPairs;
|
||||
|
||||
// Get the input node
|
||||
this.logger.info('Calling save operation!');
|
||||
return this._getSaveDir()
|
||||
.then(_saveDir => {
|
||||
parentNode = _saveDir;
|
||||
return this.core.loadChildren(_saveDir);
|
||||
})
|
||||
.then(artifacts => {
|
||||
currNameHashPairs = artifacts
|
||||
.map(node => [
|
||||
this.core.getAttribute(node, 'name'),
|
||||
this.core.getAttribute(node, 'data')
|
||||
]);
|
||||
return this.getInputs(node);
|
||||
})
|
||||
.then(inputs => {
|
||||
var ids = inputs.map(i => this.core.getPath(i[2])),
|
||||
allDataNodes,
|
||||
dataNodes;
|
||||
|
||||
dataNodes = Object.keys(this.nodes)
|
||||
allDataNodes = Object.keys(this.nodes)
|
||||
.map(id => this.nodes[id])
|
||||
.filter(node => this.isMetaTypeOf(node, this.META.Transporter))
|
||||
.filter(node =>
|
||||
@@ -129,10 +138,18 @@ define([
|
||||
.map(node => this.core.getPointerPath(node, 'src'))
|
||||
.map(id => this.nodes[id]);
|
||||
|
||||
// Remove nodes that already exist
|
||||
dataNodes = allDataNodes.filter(dataNode => {
|
||||
var hash = this.core.getAttribute(dataNode, 'data'),
|
||||
name = this.core.getOwnAttribute(node, 'saveName') ||
|
||||
this.core.getAttribute(dataNode, 'name');
|
||||
|
||||
return !(currNameHashPairs
|
||||
.find(pair => pair[0] === name && pair[1] === hash));
|
||||
});
|
||||
|
||||
// get the input node
|
||||
if (dataNodes.length === 0) {
|
||||
this.logger.error(`Could not find data to save! ${nodeId}`);
|
||||
} else {
|
||||
if (dataNodes.length !== 0) {
|
||||
var newNodes = this.core.copyNodes(dataNodes, parentNode),
|
||||
newName = this.core.getOwnAttribute(node, 'saveName');
|
||||
if (newName) {
|
||||
@@ -140,9 +157,14 @@ define([
|
||||
this.core.setAttribute(node, 'name', newName)
|
||||
);
|
||||
}
|
||||
var hashes = dataNodes.map(n => this.core.getAttribute(n, 'data'));
|
||||
this.logger.info(`saving hashes: ${hashes.map(h => `"${h}"`)}`);
|
||||
} else if (allDataNodes.length === 0) {
|
||||
this.logger.warn('No data nodes found!');
|
||||
} else {
|
||||
this.logger.info('Using cached artifact(s)');
|
||||
}
|
||||
var hashes = dataNodes.map(n => this.core.getAttribute(n, 'data'));
|
||||
this.logger.info(`saving hashes: ${hashes.map(h => `"${h}"`)}`);
|
||||
|
||||
this.onOperationComplete(node);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/*globals define, WebGMEGlobal*/
|
||||
/*globals define, requirejs*/
|
||||
define([
|
||||
'plugin/util',
|
||||
'q'
|
||||
], function(
|
||||
PluginUtils,
|
||||
Q
|
||||
) {
|
||||
var PtrCodeGen = function() {
|
||||
@@ -14,34 +16,67 @@ define([
|
||||
var metanode = this.core.getMetaType(ptrNode),
|
||||
pluginId;
|
||||
|
||||
this.logger.debug(`loaded pointer target of ${ptrId}: ${ptrNode}`);
|
||||
pluginId = this.core.getRegistry(ptrNode, 'validPlugins').split(' ').shift();
|
||||
this.logger.info(`generating code for ${this.core.getAttribute(ptrNode, 'name')} using ${pluginId}`);
|
||||
|
||||
var context = WebGMEGlobal.Client.getCurrentPluginContext(pluginId);
|
||||
|
||||
context.managerConfig.namespace = this.core.getNamespace(metanode);
|
||||
context.managerConfig.activeNode = this.core.getPath(ptrNode);
|
||||
var context = {
|
||||
namespace: this.core.getNamespace(metanode),
|
||||
activeNode: this.core.getPath(ptrNode)
|
||||
};
|
||||
|
||||
// Load and run the plugin
|
||||
return Q.nfcall(this.executePlugin.bind(this), pluginId, context);
|
||||
return this.executePlugin(pluginId, context);
|
||||
})
|
||||
.then(hashes => hashes[0]); // Grab the first asset for now
|
||||
};
|
||||
|
||||
PtrCodeGen.prototype.executePlugin = function(pluginId, config, callback) {
|
||||
// Call the Interpreter manager in a Q.ninvoke friendly way
|
||||
// I need to create a custom context for the given plugin:
|
||||
// - Set the activeNode to the given referenced node
|
||||
// - If the activeNode is namespaced, set META to the given namespace
|
||||
//
|
||||
// FIXME: Check if it is running in the browser or on the server
|
||||
WebGMEGlobal.Client.runBrowserPlugin(pluginId, config, (err, result) => {
|
||||
if (!result.success) {
|
||||
return callback(result.getError());
|
||||
}
|
||||
this.logger.info('Finished calling ' + pluginId);
|
||||
callback(null, result.artifacts);
|
||||
PtrCodeGen.prototype.createPlugin = function(pluginId) {
|
||||
var deferred = Q.defer(),
|
||||
pluginPath = [
|
||||
'plugin',
|
||||
pluginId,
|
||||
pluginId,
|
||||
pluginId
|
||||
].join('/');
|
||||
|
||||
requirejs([pluginPath], Plugin => {
|
||||
var plugin = new Plugin();
|
||||
deferred.resolve(plugin);
|
||||
}, err => {
|
||||
this.logger.error(`Could not load ${pluginId}: ${err}`);
|
||||
deferred.reject(err);
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
PtrCodeGen.prototype.configurePlugin = function(plugin, opts) {
|
||||
var logger = this.logger.fork(plugin.getName());
|
||||
|
||||
return PluginUtils.loadNodesAtCommitHash(
|
||||
this.project,
|
||||
this.core,
|
||||
this.commitHash,
|
||||
this.logger,
|
||||
opts
|
||||
).then(config => {
|
||||
plugin.initialize(logger, this.blobClient, this.gmeConfig);
|
||||
config.core = this.core;
|
||||
plugin.configure(config);
|
||||
return plugin;
|
||||
});
|
||||
};
|
||||
|
||||
PtrCodeGen.prototype.executePlugin = function(pluginId, config) {
|
||||
return this.createPlugin(pluginId)
|
||||
.then(plugin => this.configurePlugin(plugin, config))
|
||||
.then(plugin => {
|
||||
return Q.ninvoke(plugin, 'main');
|
||||
})
|
||||
.then(result => {
|
||||
this.logger.info('Finished calling ' + pluginId);
|
||||
return result.artifacts;
|
||||
});
|
||||
};
|
||||
|
||||
return PtrCodeGen;
|
||||
|
||||
@@ -22,3 +22,7 @@
|
||||
.create-node text {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.job-canceled {
|
||||
background-color: #ffe0b2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* globals define*/
|
||||
define([
|
||||
], function(
|
||||
) {
|
||||
var isBoolean = txt => {
|
||||
return typeof txt === 'boolean' || (txt === 'false' || txt === 'true');
|
||||
};
|
||||
|
||||
var getSetterSchema = function(name, setters, defaults) {
|
||||
var values,
|
||||
schema = setters[name];
|
||||
|
||||
if (defaults.hasOwnProperty(name)) {
|
||||
schema.default = defaults[name];
|
||||
}
|
||||
schema.type = 'string';
|
||||
if (schema.setterType === 'const') {
|
||||
values = Object.keys(schema.setterFn);
|
||||
schema.isEnum = true;
|
||||
schema.enumValues = values;
|
||||
if (values.every(isBoolean)) {
|
||||
if (!defaults.hasOwnProperty(name) && values.length === 1) {
|
||||
// there is only a method to toggle the flag to true/false,
|
||||
// then the default must be the other one
|
||||
schema.default = values[0] === 'true' ? false : true;
|
||||
}
|
||||
|
||||
if (isBoolean(schema.default)) {
|
||||
schema.type = 'boolean';
|
||||
}
|
||||
}
|
||||
}
|
||||
return schema;
|
||||
};
|
||||
|
||||
var abbrWord = function(word) { // camelcase
|
||||
word = word.substring(0, 1).toUpperCase() + word.substring(1);
|
||||
return word.split(/[a-z]+/g).join('').toLowerCase();
|
||||
};
|
||||
|
||||
var abbrPhrase = function(words) { // dashes, spaces, underscores, etc
|
||||
return words.map(word => word[0]).join('');
|
||||
};
|
||||
|
||||
var abbr = function(phrase) {
|
||||
var words = phrase.split(/[^a-zA-Z0-9]+/g);
|
||||
if (words.length === 1) {
|
||||
return abbrWord(phrase);
|
||||
} else {
|
||||
return abbrPhrase(words);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getSetterSchema: getSetterSchema,
|
||||
abbr: abbr
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,102 @@
|
||||
/* globals define, WebGMEGlobal */
|
||||
// Mixin for executing jobs and pipelines
|
||||
define([
|
||||
'executor/ExecutorClient',
|
||||
'panel/FloatingActionButton/styles/Materialize'
|
||||
], function(
|
||||
ExecutorClient,
|
||||
Materialize
|
||||
) {
|
||||
|
||||
var Execute = function(client, logger) {
|
||||
this.client = this.client || client;
|
||||
this.logger = this.logger || logger;
|
||||
this._executor = new ExecutorClient({
|
||||
logger: this.logger.fork('ExecutorClient'),
|
||||
serverPort: WebGMEGlobal.gmeConfig.server.port,
|
||||
httpsecure: window.location.protocol === 'https:'
|
||||
});
|
||||
};
|
||||
|
||||
Execute.prototype.executeJob = function(node) {
|
||||
return this.runExecutionPlugin('ExecuteJob', {node: node});
|
||||
};
|
||||
|
||||
Execute.prototype.executePipeline = function(node) {
|
||||
return this.runExecutionPlugin('ExecutePipeline', {node: node});
|
||||
};
|
||||
|
||||
Execute.prototype.runExecutionPlugin = function(pluginId, opts) {
|
||||
var context = this.client.getCurrentPluginContext(pluginId),
|
||||
node = opts.node || this.client.getNode(this._currentNodeId),
|
||||
name = node.getAttribute('name'),
|
||||
method;
|
||||
|
||||
// Set the activeNode
|
||||
context.managerConfig.namespace = 'pipeline';
|
||||
context.managerConfig.activeNode = node.getId();
|
||||
method = opts.useSecondary ? 'runBrowserPlugin' : 'runServerPlugin';
|
||||
this.client[method](pluginId, context, (err, result) => {
|
||||
var msg = err ? `${name} failed!` : `${name} executed successfully!`,
|
||||
duration = err ? 4000 : 2000;
|
||||
|
||||
// Check if it was canceled - if so, show that type of message
|
||||
if (result) {
|
||||
msg = result.messages[0].message;
|
||||
duration = 4000;
|
||||
}
|
||||
|
||||
Materialize.toast(msg, duration);
|
||||
});
|
||||
};
|
||||
|
||||
Execute.prototype.isRunning = function(node) {
|
||||
var baseId,
|
||||
base,
|
||||
type;
|
||||
|
||||
node = node || this.client.getNode(this._currentNodeId);
|
||||
baseId = node.getBaseId();
|
||||
base = this.client.getNode(baseId);
|
||||
type = base.getAttribute('name');
|
||||
|
||||
if (type === 'Execution') {
|
||||
return node.getAttribute('status') === 'running';
|
||||
} else if (type === 'Job') {
|
||||
return this.isRunningJob(node);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Execute.prototype.isRunningJob = function(job) {
|
||||
var status = job.getAttribute('status');
|
||||
|
||||
return (status === 'running' || status === 'pending') &&
|
||||
job.getAttribute('secret') && job.getAttribute('jobId');
|
||||
};
|
||||
|
||||
Execute.prototype.stopJob = function(job) {
|
||||
var jobHash,
|
||||
jobId,
|
||||
secret;
|
||||
|
||||
job = job || this.client.getNode(this._currentNodeId);
|
||||
jobId = job.getId();
|
||||
jobHash = job.getAttribute('jobId');
|
||||
secret = job.getAttribute('secret');
|
||||
if (!jobHash || !secret) {
|
||||
this.logger.error('Cannot stop job. Missing jobHash or secret');
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.delAttributes(jobId, 'jobId');
|
||||
this.client.delAttributes(jobId, 'secret');
|
||||
this.client.setAttributes(jobId, 'status', 'canceled');
|
||||
|
||||
return this._executor.cancelJob(jobHash, secret)
|
||||
.then(() => this.logger.info(`${jobHash} has been cancelled!`))
|
||||
.fail(err => this.logger.error(`Job cancel failed: ${err}`));
|
||||
};
|
||||
|
||||
return Execute;
|
||||
});
|
||||
@@ -21,7 +21,7 @@ define([
|
||||
|
||||
RenameablePanel.OPTIONS = PanelBaseWithHeader.OPTIONS;
|
||||
RenameablePanel.prototype.initializeRenameable = function () {
|
||||
this.$panelHeaderTitle.on('dblclick', this.editTitle.bind(this));
|
||||
this.$panelHeaderTitle.on('click', this.editTitle.bind(this));
|
||||
};
|
||||
|
||||
RenameablePanel.prototype.currentNodeId = function () {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* globals define*/
|
||||
define({
|
||||
getDisplayTime: timestamp => {
|
||||
var today = new Date().toLocaleDateString(),
|
||||
date = new Date(timestamp).toLocaleDateString();
|
||||
|
||||
if (date === today) {
|
||||
date = `Today (${new Date(timestamp).toLocaleTimeString()})`;
|
||||
}
|
||||
return date;
|
||||
},
|
||||
ClassForJobStatus: {
|
||||
success: 'success',
|
||||
canceled: 'job-canceled',
|
||||
failed: 'danger',
|
||||
pending: '',
|
||||
running: 'warning'
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/*globals define*/
|
||||
define([
|
||||
'decorators/EllipseDecorator/EasyDAG/AttributeField'
|
||||
], function(
|
||||
BaseAttributeField
|
||||
) {
|
||||
var AttributeField = function() {
|
||||
BaseAttributeField.apply(this, arguments);
|
||||
};
|
||||
|
||||
AttributeField.prototype = Object.create(BaseAttributeField.prototype);
|
||||
|
||||
AttributeField.prototype.onClick = function() {
|
||||
};
|
||||
|
||||
return AttributeField;
|
||||
});
|
||||
@@ -1,15 +1,15 @@
|
||||
/*globals define, _*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
/**
|
||||
* @author brollb / https://github.com/brollb
|
||||
*/
|
||||
|
||||
define([
|
||||
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
|
||||
'./PointerField.RO',
|
||||
'./AttributeField.RO',
|
||||
'css!./JobDecorator.EasyDAGWidget.css'
|
||||
], function (
|
||||
EllipseDecorator
|
||||
EllipseDecorator,
|
||||
PointerField,
|
||||
AttributeField
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
@@ -20,6 +20,7 @@ define([
|
||||
pending: '#9e9e9e',
|
||||
queued: '#cfd8dc',
|
||||
running: '#fff59d',
|
||||
canceled: '#ffcc80',
|
||||
success: '#66bb6a',
|
||||
fail: '#e57373'
|
||||
};
|
||||
@@ -35,6 +36,8 @@ define([
|
||||
status: true,
|
||||
execFiles: true,
|
||||
stdout: true,
|
||||
secret: true,
|
||||
jobId: true,
|
||||
debug: true
|
||||
};
|
||||
EllipseDecorator.call(this, options);
|
||||
@@ -43,18 +46,46 @@ define([
|
||||
_.extend(JobDecorator.prototype, EllipseDecorator.prototype);
|
||||
|
||||
JobDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
|
||||
JobDecorator.prototype.AttributeField = AttributeField;
|
||||
JobDecorator.prototype.PointerField = PointerField;
|
||||
|
||||
JobDecorator.prototype.isArtifactLoader = function() {
|
||||
return this._node.name === 'ArtifactLoader';
|
||||
};
|
||||
|
||||
JobDecorator.prototype.getDisplayName = function() {
|
||||
if (this.isArtifactLoader()) {
|
||||
var id = this._node.pointers.artifact;
|
||||
|
||||
// Try to look up the pointer name
|
||||
return this.nameFor[id] || this._node.name;
|
||||
}
|
||||
return this._node.name;
|
||||
};
|
||||
|
||||
JobDecorator.prototype.setAttributes = function() {
|
||||
EllipseDecorator.prototype.setAttributes.call(this);
|
||||
var attrs = this._node.attributes,
|
||||
status = attrs.status && attrs.status.value;
|
||||
status = attrs.status && attrs.status.value,
|
||||
opAttrs = Object.keys(this._node.opAttributes);
|
||||
|
||||
// Update the color based on the 'status' attr
|
||||
this.color = COLORS[status] || COLORS.fail;
|
||||
|
||||
// Set _attributes from opAttributes
|
||||
for (var i = opAttrs.length; i--;) {
|
||||
this._attributes[opAttrs[i]] = this._node.opAttributes[opAttrs[i]];
|
||||
}
|
||||
};
|
||||
|
||||
JobDecorator.prototype.updateTargetName = function() {
|
||||
EllipseDecorator.prototype.updateTargetName.apply(this, arguments);
|
||||
var name = this.getDisplayName();
|
||||
|
||||
if (name !== this.name) {
|
||||
this.name = name;
|
||||
this.onResize();
|
||||
}
|
||||
};
|
||||
|
||||
return JobDecorator;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*globals define*/
|
||||
define([
|
||||
'decorators/EllipseDecorator/EasyDAG/PointerField'
|
||||
], function(
|
||||
BasePointerField
|
||||
) {
|
||||
var PointerField = function() {
|
||||
BasePointerField.apply(this, arguments);
|
||||
};
|
||||
|
||||
PointerField.prototype = Object.create(BasePointerField.prototype);
|
||||
|
||||
PointerField.prototype.onClick = function() {
|
||||
};
|
||||
|
||||
// Remove the delete icon and adjust the text location
|
||||
PointerField.prototype.hasIcon = function() {
|
||||
return false;
|
||||
};
|
||||
|
||||
return PointerField;
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
/*globals define, _, WebGMEGlobal*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
define([
|
||||
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
|
||||
'deepforge/Constants',
|
||||
'./LayerField'
|
||||
], function (
|
||||
EllipseDecorator,
|
||||
Constants,
|
||||
LayerField
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var LayerDecorator,
|
||||
DECORATOR_ID = 'LayerDecorator';
|
||||
|
||||
// Layer nodes need to be able to...
|
||||
// - show their ports
|
||||
// - highlight ports
|
||||
// - unhighlight ports
|
||||
// - report the location of specific ports
|
||||
LayerDecorator = function (options) {
|
||||
options.skipAttributes = {name: true};
|
||||
options.skipAttributes[Constants.CTOR_ARGS_ATTR] = true;
|
||||
EllipseDecorator.call(this, options);
|
||||
};
|
||||
|
||||
_.extend(LayerDecorator.prototype, EllipseDecorator.prototype);
|
||||
|
||||
LayerDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
|
||||
LayerDecorator.prototype.PointerField = LayerField;
|
||||
LayerDecorator.prototype.getDisplayName = function() {
|
||||
return this._node.name;
|
||||
};
|
||||
|
||||
// Create the pointer fields and change the event handlers
|
||||
LayerDecorator.prototype.createPointerFields = function() {
|
||||
var i = this.fields.length,
|
||||
y,
|
||||
ptr;
|
||||
|
||||
// Get the fields
|
||||
y = EllipseDecorator.prototype.createPointerFields.apply(this, arguments);
|
||||
while (i < this.fields.length) {
|
||||
// Update the event handlers
|
||||
ptr = this.fields[i].name;
|
||||
// TODO: This should be changed in EasyDAG
|
||||
this.fields[i].selectTarget = this.getValidNestedLayers.bind(this, ptr);
|
||||
i++;
|
||||
}
|
||||
return y;
|
||||
};
|
||||
|
||||
LayerDecorator.prototype.getValidNestedLayers = function(ptr) {
|
||||
var tgtId = this._node.pointers[ptr];
|
||||
if (tgtId) {
|
||||
WebGMEGlobal.State.registerActiveObject(tgtId);
|
||||
} else {
|
||||
this.createLayerArg(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
LayerDecorator.prototype.createLayerArg = function(ptr) {
|
||||
// Find the Architecture node type
|
||||
var metanodes = this.client.getAllMetaNodes(),
|
||||
base = metanodes.find(node => node.getAttribute('name') === 'Architecture'),
|
||||
baseId,
|
||||
msg = `Creating layers for "${ptr}" of ${this._node.name}`,
|
||||
tgtId;
|
||||
|
||||
if (!base) {
|
||||
return this.logger.error('Could not find "Architecture" type!');
|
||||
}
|
||||
|
||||
// Create a nested "architecture" node and set the ptr target to it
|
||||
baseId = base.getId();
|
||||
this.client.startTransaction(msg);
|
||||
tgtId = this.client.createChild({
|
||||
parentId: this._node.id,
|
||||
baseId: baseId
|
||||
});
|
||||
this.client.setAttributes(tgtId, 'name', `${ptr} (${this._node.name})`);
|
||||
this.savePointer(ptr, tgtId);
|
||||
this.client.completeTransaction();
|
||||
WebGMEGlobal.State.registerActiveObject(tgtId);
|
||||
};
|
||||
|
||||
LayerDecorator.prototype.savePointer = function(ptr, to) {
|
||||
if (!to) { // delete the current target
|
||||
var currentId = this._node.pointers[ptr],
|
||||
name = this._node.name;
|
||||
|
||||
// If the target is contained in the current node, delete it!
|
||||
if (currentId.indexOf(this._node.id) === 0) {
|
||||
this.client.startTransaction(`Removing layer for ${ptr} of ${name}`);
|
||||
this.client.delMoreNodes([currentId]);
|
||||
this.client.completeTransaction();
|
||||
this.logger.info(`Removed ${ptr} and deleted target (${currentId})`);
|
||||
} else {
|
||||
this.logger.info(`Removed ${ptr} (external architecture)`);
|
||||
}
|
||||
} else { // create and set the node
|
||||
EllipseDecorator.prototype.savePointer.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
return LayerDecorator;
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
/* globals define, _ */
|
||||
define([
|
||||
'decorators/EllipseDecorator/EasyDAG/PointerField'
|
||||
], function(
|
||||
PointerField
|
||||
) {
|
||||
// The LayerField behaves the same as PointerFields but it shows "click to view"
|
||||
// if it has a value
|
||||
var LayerField = function() {
|
||||
PointerField.apply(this, arguments);
|
||||
};
|
||||
|
||||
_.extend(LayerField.prototype, PointerField.prototype);
|
||||
|
||||
LayerField.prototype.getContent = function(content) {
|
||||
return content && 'click to view';
|
||||
};
|
||||
|
||||
LayerField.prototype.createContent = function(w, y, content) {
|
||||
PointerField.prototype.createContent.call(this, w, y, this.getContent(content));
|
||||
this.$content.attr('font-style', 'italic');
|
||||
};
|
||||
|
||||
LayerField.prototype.setValue = function(content) {
|
||||
PointerField.prototype.setValue.call(this, this.getContent(content));
|
||||
};
|
||||
|
||||
return LayerField;
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
/*globals define, _*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
define([
|
||||
'js/Decorators/DecoratorBase',
|
||||
'./EasyDAG/LayerDecorator.EasyDAGWidget'
|
||||
], function (
|
||||
DecoratorBase,
|
||||
LayerDecoratorEasyDAGWidget
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var LayerDecorator,
|
||||
__parent__ = DecoratorBase,
|
||||
__parent_proto__ = DecoratorBase.prototype,
|
||||
DECORATOR_ID = 'LayerDecorator';
|
||||
|
||||
LayerDecorator = function (params) {
|
||||
var opts = _.extend({loggerName: this.DECORATORID}, params);
|
||||
|
||||
__parent__.apply(this, [opts]);
|
||||
|
||||
this.logger.debug('LayerDecorator ctor');
|
||||
};
|
||||
|
||||
_.extend(LayerDecorator.prototype, __parent_proto__);
|
||||
LayerDecorator.prototype.DECORATORID = DECORATOR_ID;
|
||||
|
||||
/*********************** OVERRIDE DecoratorBase MEMBERS **************************/
|
||||
|
||||
LayerDecorator.prototype.initializeSupportedWidgetMap = function () {
|
||||
this.supportedWidgetMap = {
|
||||
EasyDAG: LayerDecoratorEasyDAGWidget
|
||||
};
|
||||
};
|
||||
|
||||
return LayerDecorator;
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
/*globals define, $,_*/
|
||||
/*globals define, _*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,7 +79,11 @@ define([
|
||||
};
|
||||
|
||||
CreateExecution.prototype.createExecution = function (node) {
|
||||
var name = this.core.getAttribute(node, 'name');
|
||||
// Get the user supplied name
|
||||
var name = this.core.getAttribute(node, 'name'),
|
||||
config = this.getCurrentConfig(),
|
||||
basename = config.name || (name + '_execution');
|
||||
|
||||
|
||||
// Given a pipeline, copy all the operations to a custom job
|
||||
// - Copy the operations
|
||||
@@ -89,38 +93,46 @@ define([
|
||||
// - 'console' show console output (future feature)
|
||||
// - Update the references
|
||||
var tgtNode,
|
||||
execName,
|
||||
copies,
|
||||
opTuples, // [[op, index], [op, index], ...]
|
||||
dataMapping = {};
|
||||
|
||||
return this.getExecutionDir()
|
||||
.then(execDir => {
|
||||
var execDirId = this.core.getPath(execDir),
|
||||
execTypeId = this.core.getPath(this.META.Execution);
|
||||
|
||||
this.logger.debug(`Creating execution node in ${execDirId} (type is ${execTypeId})`);
|
||||
tgtNode = this.core.createNode({
|
||||
base: this.META.Execution,
|
||||
parent: execDir
|
||||
});
|
||||
|
||||
// Get a unique name
|
||||
return this.getUniqueExecName(name + '_execution');
|
||||
this.logger.debug(`About to get a unique name starting w/ ${basename}`);
|
||||
return this.getUniqueExecName(basename);
|
||||
})
|
||||
.then(execName => {
|
||||
var isSnapshot = this.getCurrentConfig().snapshot;
|
||||
.then(_execName => {
|
||||
var isSnapshot = !this.getCurrentConfig().debug,
|
||||
originName = this.core.getAttribute(this.activeNode, 'name'),
|
||||
oId = this.core.getPath(this.activeNode),
|
||||
tgtId = this.core.getPath(tgtNode);
|
||||
|
||||
this.logger.debug(`Creating execution ${execName}`);
|
||||
execName = _execName;
|
||||
this.logger.debug(`Configuring execution attributes (${execName})`);
|
||||
|
||||
// Set all the metadata for the new execution
|
||||
this.core.setAttribute(tgtNode, 'name', execName);
|
||||
this.core.setAttribute(tgtNode, 'snapshot', isSnapshot);
|
||||
this.core.setAttribute(tgtNode, 'tagname', execName);
|
||||
this.core.setAttribute(tgtNode, 'createdAt', Date.now());
|
||||
this.logger.debug(`Setting origin pipeline to ${originName} (${oId})`);
|
||||
this.core.setPointer(tgtNode, 'origin', this.activeNode);
|
||||
this.logger.debug(`Adding ${tgtId} to execution list of ${originName} (${oId})`);
|
||||
this.core.addMember(this.activeNode, 'executions', tgtNode);
|
||||
|
||||
return this.project.createTag(
|
||||
execName.replace(/[ -]/g, '_'),
|
||||
this.currentHash
|
||||
);
|
||||
this.logger.debug(`Creating tag "${execName}"`);
|
||||
})
|
||||
.then(() => this.core.loadChildren(node))
|
||||
.then(children => {
|
||||
@@ -128,6 +140,7 @@ define([
|
||||
this.logger.warn('No children in pipeline. Will proceed anyway');
|
||||
}
|
||||
|
||||
this.logger.debug(`Copying operations to "${execName}"`);
|
||||
return this.copyOperations(children, tgtNode);
|
||||
})
|
||||
.then(copiedPairs => {
|
||||
@@ -138,6 +151,7 @@ define([
|
||||
.filter(pair => this.core.isTypeOf(pair[0], this.META.Operation));
|
||||
|
||||
// Create a mapping of old names to new names
|
||||
this.logger.debug('Creating mapping of old->new');
|
||||
return Q.all(opTuples.map(pair =>
|
||||
// Add the input/output mappings to the dataMapping
|
||||
this.addDataToMap(originals[pair[1]], pair[0], dataMapping)
|
||||
@@ -145,22 +159,30 @@ define([
|
||||
);
|
||||
})
|
||||
.then(() => { // datamapping is set!
|
||||
this.logger.debug('Updating references...');
|
||||
this.updateReferences(copies, dataMapping);
|
||||
this.logger.debug('Placing operations in Job containers');
|
||||
this.boxOperations(opTuples.map(o => o[0]), tgtNode);
|
||||
this.logger.debug('Finished! Saving...');
|
||||
return this.save(`Created execution from ${name}`);
|
||||
})
|
||||
.then(() => this.project.createTag(execName, this.currentHash))
|
||||
.then(() => tgtNode); // return tgtNode
|
||||
};
|
||||
|
||||
CreateExecution.prototype.getUniqueExecName = function (basename) {
|
||||
var name = basename,
|
||||
taken = {},
|
||||
var taken = {},
|
||||
name,
|
||||
i = 2;
|
||||
|
||||
basename = basename.replace(/[^\da-zA-Z_]/g, '_');
|
||||
name = basename;
|
||||
|
||||
// Get a unique name wrt the tags and the other executions
|
||||
return this.project.getTags()
|
||||
.then(tags => {
|
||||
Object.keys(tags).forEach(name => taken[name] = true);
|
||||
this.logger.debug(`Existing tags are ${Object.keys(tags).join(',')}`);
|
||||
|
||||
// Get the other executions
|
||||
return this.getExecutionDir();
|
||||
@@ -171,19 +193,22 @@ define([
|
||||
})
|
||||
.then(execs => {
|
||||
var names = execs.map(exec => this.core.getAttribute(exec, 'name'));
|
||||
this.logger.debug(`Existing names are ${names.join(',')}`);
|
||||
names.forEach(name => taken[name] = true);
|
||||
|
||||
while (taken[name]) {
|
||||
name = basename + '_' + (i++);
|
||||
}
|
||||
this.logger.debug(`Unique name is "${name}"`);
|
||||
return name;
|
||||
});
|
||||
};
|
||||
|
||||
CreateExecution.prototype.copyOperations = function (nodes, dst) {
|
||||
var snapshot = this.getCurrentConfig().snapshot;
|
||||
var snapshot = !this.getCurrentConfig().debug;
|
||||
|
||||
if (snapshot) {
|
||||
this.logger.debug('Execution is a snapshot -> severing the inheritance');
|
||||
return Q.all(nodes.map(node => {
|
||||
if (this.isLocalOperation(node) ||
|
||||
this.isMetaTypeOf(node, this.META.Transporter)) {
|
||||
@@ -198,6 +223,7 @@ define([
|
||||
);
|
||||
|
||||
} else if (nodes.length) {
|
||||
this.logger.debug('Execution is not a snapshot -> doing a simple copy');
|
||||
var copies = this.core.copyNodes(nodes, dst);
|
||||
return nodes.map((node, i) => [node, copies[i]]);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,25 @@
|
||||
/*globals define*/
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
/**
|
||||
* Generated by PluginGenerator 0.14.0 from webgme on Tue Mar 15 2016 21:19:45 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define([
|
||||
'plugin/PluginConfig',
|
||||
'plugin/PluginBase',
|
||||
'deepforge/js-yaml.min',
|
||||
'common/util/guid',
|
||||
'deepforge/Constants',
|
||||
'deepforge/utils',
|
||||
'js/RegistryKeys',
|
||||
'js/Constants',
|
||||
'js/Panels/MetaEditor/MetaEditorConstants',
|
||||
'underscore',
|
||||
'text!deepforge/layers.json',
|
||||
'./schemas/index',
|
||||
'text!./metadata.json'
|
||||
], function (
|
||||
PluginConfig,
|
||||
PluginBase,
|
||||
yaml,
|
||||
generateGuid,
|
||||
Constants,
|
||||
utils,
|
||||
REGISTRY_KEYS,
|
||||
CONSTANTS,
|
||||
META_CONSTANTS,
|
||||
_,
|
||||
DEFAULT_LAYERS,
|
||||
Schemas,
|
||||
metadata
|
||||
) {
|
||||
'use strict';
|
||||
@@ -61,110 +55,102 @@ define([
|
||||
* @param {function(string, plugin.PluginResult)} callback - the result callback
|
||||
*/
|
||||
CreateTorchMeta.prototype.main = function (callback) {
|
||||
// Use self to access core, project, result, logger etc from PluginBase.
|
||||
// These are all instantiated at this point.
|
||||
var self = this;
|
||||
|
||||
if (!this.META.Language) {
|
||||
callback('"Language" container required to run plugin', this.result);
|
||||
return callback('"Language" container required to run plugin', this.result);
|
||||
}
|
||||
|
||||
// Extra layer names
|
||||
this.getJsonLayers((err, text) => {
|
||||
if (err) {
|
||||
return callback(err, this.result);
|
||||
// The format is...
|
||||
// - (Abstract) CategoryLayerTypes
|
||||
// - LayerName
|
||||
// - Attributes (if exists)
|
||||
var layers,
|
||||
content = {},
|
||||
categories,
|
||||
config = this.getCurrentConfig(),
|
||||
nodes = {};
|
||||
|
||||
try {
|
||||
layers = this.getJsonLayers();
|
||||
} catch (e) {
|
||||
return callback('JSON parse error: ' + e, this.result);
|
||||
}
|
||||
layers.forEach(layer => {
|
||||
if (!content[layer.type]) {
|
||||
content[layer.type] = [];
|
||||
}
|
||||
|
||||
// The format is...
|
||||
// - (Abstract) CategoryLayerTypes
|
||||
// - LayerName
|
||||
// - Attributes (if exists)
|
||||
var content = {},
|
||||
categories,
|
||||
config = this.getCurrentConfig(),
|
||||
nodes = {},
|
||||
layers;
|
||||
|
||||
try {
|
||||
layers = JSON.parse(text);
|
||||
} catch (e) {
|
||||
return callback('JSON parse error: ' + e, this.result);
|
||||
}
|
||||
layers.forEach(layer => {
|
||||
if (!content[layer.type]) {
|
||||
content[layer.type] = [];
|
||||
}
|
||||
content[layer.type].push(layer);
|
||||
});
|
||||
|
||||
categories = Object.keys(content);
|
||||
// Create the base class, if needed
|
||||
if (!this.META.Layer) {
|
||||
this.META.Layer = this.createMetaNode('Layer', this.META.FCO);
|
||||
}
|
||||
|
||||
// Create the category nodes
|
||||
categories
|
||||
.forEach(name => {
|
||||
// Create a tab for each
|
||||
this.metaSheets[name] = this.createMetaSheetTab(name);
|
||||
this.sheetCounts[name] = 0;
|
||||
nodes[name] = this.createMetaNode(name, this.META.Layer, name);
|
||||
});
|
||||
|
||||
// Make them abstract
|
||||
categories
|
||||
.forEach(name => this.core.setRegistry(nodes[name], 'isAbstract', true));
|
||||
|
||||
if (config.removeOldLayers) {
|
||||
var isNewLayer = {},
|
||||
newLayers = layers.map(layer => layer.name),
|
||||
oldLayers,
|
||||
oldNames;
|
||||
|
||||
newLayers = newLayers.concat(categories); // add the category nodes
|
||||
newLayers.forEach(name => isNewLayer[name] = true);
|
||||
|
||||
// Set the newLayer nodes 'base' to 'Layer' so we don't accidentally
|
||||
// delete them
|
||||
newLayers
|
||||
.map(name => this.META[name])
|
||||
.filter(layer => !!layer)
|
||||
.forEach(layer => this.core.setPointer(layer, 'base', this.META.Layer));
|
||||
|
||||
oldLayers = Object.keys(this.META)
|
||||
.filter(name => name !== 'Layer')
|
||||
.map(name => this.META[name])
|
||||
.filter(node => this.isMetaTypeOf(node, this.META.Layer))
|
||||
.filter(node => !isNewLayer[this.core.getAttribute(node, 'name')]);
|
||||
|
||||
oldNames = oldLayers.map(l => this.core.getAttribute(l, 'name'));
|
||||
// Get the old layer names
|
||||
this.logger.debug(`Removing layers: ${oldNames.join(', ')}`);
|
||||
oldLayers.forEach(layer => this.core.deleteNode(layer));
|
||||
}
|
||||
|
||||
// Create the actual nodes
|
||||
categories.forEach(cat => {
|
||||
content[cat]
|
||||
.forEach(layer => {
|
||||
var attrs = layer.params,
|
||||
name = layer.name;
|
||||
nodes[name] = this.createMetaNode(name, nodes[cat], cat, attrs);
|
||||
// Make the node non-abstract
|
||||
this.core.setRegistry(nodes[name], 'isAbstract', false);
|
||||
});
|
||||
});
|
||||
|
||||
self.save('CreateTorchMeta updated model.', function (err) {
|
||||
if (err) {
|
||||
callback(err, self.result);
|
||||
return;
|
||||
}
|
||||
self.result.setSuccess(true);
|
||||
callback(null, self.result);
|
||||
});
|
||||
content[layer.type].push(layer);
|
||||
});
|
||||
|
||||
categories = Object.keys(content);
|
||||
// Create the base class, if needed
|
||||
if (!this.META.Layer) {
|
||||
this.META.Layer = this.createMetaNode('Layer', this.META.FCO);
|
||||
}
|
||||
|
||||
// Create the category nodes
|
||||
categories
|
||||
.forEach(name => {
|
||||
// Create a tab for each
|
||||
this.metaSheets[name] = this.createMetaSheetTab(name);
|
||||
this.sheetCounts[name] = 0;
|
||||
nodes[name] = this.createMetaNode(name, this.META.Layer, name);
|
||||
});
|
||||
|
||||
// Make them abstract
|
||||
categories
|
||||
.forEach(name => this.core.setRegistry(nodes[name], 'isAbstract', true));
|
||||
|
||||
if (config.removeOldLayers) {
|
||||
var isNewLayer = {},
|
||||
newLayers = layers.map(layer => layer.name),
|
||||
oldLayers,
|
||||
oldNames;
|
||||
|
||||
newLayers = newLayers.concat(categories); // add the category nodes
|
||||
newLayers.forEach(name => isNewLayer[name] = true);
|
||||
|
||||
// Set the newLayer nodes 'base' to 'Layer' so we don't accidentally
|
||||
// delete them
|
||||
newLayers
|
||||
.map(name => this.META[name])
|
||||
.filter(layer => !!layer)
|
||||
.forEach(layer => this.core.setBase(layer, this.META.Layer));
|
||||
|
||||
oldLayers = Object.keys(this.META)
|
||||
.filter(name => name !== 'Layer')
|
||||
.map(name => this.META[name])
|
||||
.filter(node => this.isMetaTypeOf(node, this.META.Layer))
|
||||
.filter(node => !isNewLayer[this.core.getAttribute(node, 'name')]);
|
||||
|
||||
oldNames = oldLayers.map(l => this.core.getAttribute(l, 'name'));
|
||||
// Get the old layer names
|
||||
this.logger.debug(`Removing layers: ${oldNames.join(', ')}`);
|
||||
oldLayers.forEach(layer => this.core.deleteNode(layer));
|
||||
}
|
||||
|
||||
// Create the actual nodes
|
||||
categories.forEach(cat => {
|
||||
content[cat]
|
||||
.forEach(layer => {
|
||||
var name = layer.name,
|
||||
node;
|
||||
|
||||
node = this.createMetaNode(name, nodes[cat], cat, layer);
|
||||
// Make the node non-abstract
|
||||
if (node) {
|
||||
this.core.setRegistry(node, 'isAbstract', false);
|
||||
nodes[name] = node;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.save('CreateTorchMeta updated model.')
|
||||
.then(() => {
|
||||
this.result.setSuccess(true);
|
||||
callback(null, this.result);
|
||||
})
|
||||
.fail(err => callback(err, this.result));
|
||||
};
|
||||
|
||||
CreateTorchMeta.prototype.removeFromMeta = function (nodeId) {
|
||||
@@ -206,28 +192,45 @@ define([
|
||||
return sheet.SetID;
|
||||
};
|
||||
|
||||
CreateTorchMeta.prototype.getJsonLayers = function (callback) {
|
||||
var config = this.getCurrentConfig();
|
||||
CreateTorchMeta.prototype.getJsonLayers = function () {
|
||||
var config = this.getCurrentConfig(),
|
||||
schema = config.layerSchema;
|
||||
|
||||
if (config.layerNameHash) {
|
||||
this.blobClient.getObject(config.layerNameHash, (err, buffer) => {
|
||||
if (err) {
|
||||
return callback(err, this.result);
|
||||
}
|
||||
var text = String.fromCharCode.apply(null, new Uint8Array(buffer));
|
||||
return callback(null, text);
|
||||
});
|
||||
} else {
|
||||
return callback(null, DEFAULT_LAYERS);
|
||||
if (schema === 'all') {
|
||||
return Object.keys(Schemas).map(key => JSON.parse(Schemas[key]))
|
||||
.reduce((l1, l2) => l1.concat(l2), []);
|
||||
}
|
||||
|
||||
return JSON.parse(Schemas[schema]);
|
||||
};
|
||||
|
||||
CreateTorchMeta.prototype.createMetaNode = function (name, base, tabName, attrs) {
|
||||
// Some helper methods w/ attribute handling
|
||||
var LUA_TO_GME = {
|
||||
boolean: 'boolean',
|
||||
number: 'float',
|
||||
string: 'string'
|
||||
};
|
||||
|
||||
var isLayerAttribute = type => type && type.substring(0, 3) === 'nn.';
|
||||
|
||||
CreateTorchMeta.prototype.createMetaNode = function (name, base, tabName, layer) {
|
||||
var node = this.META[name],
|
||||
nodeId = node && this.core.getPath(node),
|
||||
tabId = this.metaSheets[tabName],
|
||||
position = this.getPositionFor(name, tabName);
|
||||
position = this.getPositionFor(name, tabName),
|
||||
setters = {},
|
||||
defaults = {},
|
||||
types = {},
|
||||
type,
|
||||
attrs,
|
||||
desc;
|
||||
|
||||
if (layer) {
|
||||
attrs = layer.params;
|
||||
setters = layer.setters;
|
||||
defaults = layer.defaults;
|
||||
types = layer.types || types;
|
||||
}
|
||||
if (!tabId) {
|
||||
this.logger.error(`No meta sheet for ${tabName}`);
|
||||
}
|
||||
@@ -244,7 +247,7 @@ define([
|
||||
} else {
|
||||
// Remove from meta
|
||||
this.removeFromMeta(nodeId);
|
||||
this.core.setPointer(node, 'base', base);
|
||||
this.core.setBase(node, base);
|
||||
}
|
||||
|
||||
// Add it to the meta sheet
|
||||
@@ -269,14 +272,16 @@ define([
|
||||
if (attrs) { // Add the attributes
|
||||
// Remove attributes not in the given list
|
||||
var currentAttrs = this.core.getValidAttributeNames(node),
|
||||
rmAttrs;
|
||||
defVal,
|
||||
rmAttrs,
|
||||
simpleAttrs,
|
||||
rmPtrs;
|
||||
|
||||
rmAttrs = _.difference(currentAttrs, attrs) // old attribute names
|
||||
.filter(attr => attr !== 'name');
|
||||
simpleAttrs = attrs.filter(name => !isLayerAttribute(types[name]));
|
||||
rmAttrs = _.difference(currentAttrs, simpleAttrs) // old attribute names
|
||||
.filter(attr => attr !== 'name')
|
||||
.filter(attr => !setters[attr]);
|
||||
|
||||
if (rmAttrs.length) {
|
||||
this.logger.debug(`Removing ${rmAttrs.join(', ')} from ${name}`);
|
||||
}
|
||||
rmAttrs.forEach(attr => {
|
||||
this.core.delAttributeMeta(node, attr);
|
||||
if (this.core.getOwnAttribute(node, attr) !== undefined) {
|
||||
@@ -284,11 +289,38 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
attrs.forEach((name, index) => {
|
||||
var desc = {};
|
||||
desc.argindex = index;
|
||||
desc.default = '';
|
||||
this.addAttribute(name, node, desc);
|
||||
// Remove all old pointers
|
||||
rmPtrs = _.difference(this.core.getPointerNames(node), currentAttrs)
|
||||
.filter(ptr => ptr !== 'base');
|
||||
|
||||
if (rmPtrs.length + rmAttrs.length) {
|
||||
this.logger.debug(`Removing ${rmPtrs.concat(rmAttrs).join(', ')} from ${name}`);
|
||||
}
|
||||
rmPtrs.forEach(ptr => this.core.delPointerMeta(node, ptr));
|
||||
|
||||
attrs.forEach(name => {
|
||||
desc = {};
|
||||
defVal = defaults.hasOwnProperty(name) ? defaults[name] : '';
|
||||
type = LUA_TO_GME[types[name]];
|
||||
if (type) {
|
||||
desc.type = type;
|
||||
}
|
||||
if (isLayerAttribute(types[name])) { // Check if it is an nn layer type
|
||||
// If so, create a pointer rather than attribute
|
||||
this.addLayerAttribute(name, node);
|
||||
this.logger.debug(`${name} is a layer type attribute`);
|
||||
} else {
|
||||
this.addAttribute(name, node, desc, defVal);
|
||||
}
|
||||
});
|
||||
this.core.setAttribute(node, Constants.CTOR_ARGS_ATTR, attrs.join(','));
|
||||
|
||||
// Add the setters to the meta
|
||||
Object.keys(setters).forEach(name => {
|
||||
desc = utils.getSetterSchema(name, setters, defaults);
|
||||
defVal = desc.default;
|
||||
delete desc.default;
|
||||
this.addAttribute(name, node, desc, defVal);
|
||||
});
|
||||
}
|
||||
this.logger.debug(`added ${name} to the meta`);
|
||||
@@ -323,41 +355,34 @@ define([
|
||||
};
|
||||
};
|
||||
|
||||
CreateTorchMeta.prototype.addAttribute = function (name, node, def) {
|
||||
var initial,
|
||||
schema = {};
|
||||
CreateTorchMeta.prototype.addLayerAttribute = function (name, node) {
|
||||
// No default value support for now...
|
||||
// Create a pointer of the given type on the node
|
||||
this.core.setPointerMetaTarget(node, name, this.META.Architecture, 1, 1);
|
||||
this.core.setPointerMetaLimits(node, name, 1, 1);
|
||||
};
|
||||
|
||||
schema.type = def.type || 'string';
|
||||
CreateTorchMeta.prototype.addAttribute = function (name, node, schema, defVal) {
|
||||
schema.type = schema.type || 'string';
|
||||
if (schema.type === 'list') { // FIXME: add support for lists
|
||||
schema.type = 'string';
|
||||
}
|
||||
|
||||
if (def.min !== undefined) {
|
||||
schema.min = +def.min;
|
||||
if (schema.min !== undefined) {
|
||||
schema.min = +schema.min;
|
||||
}
|
||||
|
||||
if (def.max !== undefined) {
|
||||
if (schema.max !== undefined) {
|
||||
// Set the min, max
|
||||
schema.max = +def.max;
|
||||
schema.max = +schema.max;
|
||||
}
|
||||
|
||||
// Add the infer flag
|
||||
if (def.infer) {
|
||||
schema.infer = def.infer;
|
||||
}
|
||||
|
||||
// Add the argindex flag
|
||||
schema.argindex = def.argindex;
|
||||
|
||||
// Create the attribute and set the schema
|
||||
this.core.setAttributeMeta(node, name, schema);
|
||||
|
||||
// Determine a default value
|
||||
initial = def.hasOwnProperty('default') ? def.default : def.min || null;
|
||||
if (schema.type === 'boolean') {
|
||||
initial = initial !== null ? initial : false;
|
||||
if (defVal) {
|
||||
this.core.setAttribute(node, name, defVal);
|
||||
}
|
||||
this.core.setAttribute(node, name, initial);
|
||||
};
|
||||
|
||||
return CreateTorchMeta;
|
||||
|
||||
@@ -7,24 +7,29 @@
|
||||
"src": "",
|
||||
"class": "glyphicon glyphicon-ok-circle"
|
||||
},
|
||||
"disableServerSideExecution": false,
|
||||
"disableServerSideExecution": true,
|
||||
"disableBrowserSideExecution": false,
|
||||
"configStructure": [
|
||||
{
|
||||
"name": "layerNameHash",
|
||||
"displayName": "Torch Layers",
|
||||
"description": "Yaml file of torch layer descriptors (optional)",
|
||||
"value": "",
|
||||
"valueType": "asset",
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"name": "removeOldLayers",
|
||||
"displayName": "Delete old layers",
|
||||
"description": "Delete all layers not in the current description",
|
||||
"value": true,
|
||||
"valueType": "boolean",
|
||||
"readOnly": false
|
||||
}
|
||||
{
|
||||
"name": "layerSchema",
|
||||
"displayName": "Torch Libraries",
|
||||
"description": "Torch nn libraries to create layers from",
|
||||
"value": "all",
|
||||
"valueItems": [
|
||||
"nn",
|
||||
"rnn",
|
||||
"all"
|
||||
],
|
||||
"valueType": "string",
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"name": "removeOldLayers",
|
||||
"displayName": "Delete old layers",
|
||||
"description": "Delete all layers not in the current description",
|
||||
"value": true,
|
||||
"valueType": "boolean",
|
||||
"readOnly": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*globals define*/
|
||||
define([
|
||||
'text!./nn.json',
|
||||
'text!./rnn.json'
|
||||
], function(
|
||||
nn,
|
||||
rnn
|
||||
) {
|
||||
return {
|
||||
nn: nn,
|
||||
rnn: rnn
|
||||
};
|
||||
});
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -0,0 +1,178 @@
|
||||
[
|
||||
{
|
||||
"name": "CopyGrad",
|
||||
"baseType": "Identity",
|
||||
"setters": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "FastLSTM",
|
||||
"baseType": "LSTM",
|
||||
"params": [
|
||||
"inputSize",
|
||||
"outputSize",
|
||||
"rho",
|
||||
"eps",
|
||||
"momentum",
|
||||
"affine"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {
|
||||
"eps": "number",
|
||||
"momentum": "number"
|
||||
},
|
||||
"defaults": {
|
||||
"momentum": 0.1,
|
||||
"eps": 0.1
|
||||
},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "LSTM",
|
||||
"baseType": "AbstractRecurrent",
|
||||
"params": [
|
||||
"inputSize",
|
||||
"outputSize",
|
||||
"rho",
|
||||
"cell2gate"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {
|
||||
"rho": "number"
|
||||
},
|
||||
"defaults": {
|
||||
"rho": 9999
|
||||
},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "LinearNoBias",
|
||||
"baseType": "Linear",
|
||||
"params": [
|
||||
"inputSize",
|
||||
"outputSize"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "Simple"
|
||||
},
|
||||
{
|
||||
"name": "LookupTableMaskZero",
|
||||
"baseType": "LookupTable",
|
||||
"params": [
|
||||
"nIndex",
|
||||
"nOutput"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "NormStabilizer",
|
||||
"baseType": "AbstractRecurrent",
|
||||
"params": [
|
||||
"beta"
|
||||
],
|
||||
"setters": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "Recurrent",
|
||||
"baseType": "AbstractRecurrent",
|
||||
"params": [
|
||||
"start",
|
||||
"input",
|
||||
"feedback",
|
||||
"transfer",
|
||||
"rho",
|
||||
"merge"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {
|
||||
"start": "nn.Module",
|
||||
"transfer": "nn.Module",
|
||||
"feedback": "nn.Module",
|
||||
"input": "nn.Module"
|
||||
},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SAdd",
|
||||
"baseType": "Module",
|
||||
"params": [
|
||||
"addend",
|
||||
"negate"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SeqBRNN",
|
||||
"baseType": "Container",
|
||||
"params": [
|
||||
"inputDim",
|
||||
"hiddenDim",
|
||||
"batchFirst"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SeqGRU",
|
||||
"baseType": "Module",
|
||||
"params": [
|
||||
"inputSize",
|
||||
"outputSize"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SeqLSTM",
|
||||
"baseType": "Module",
|
||||
"params": [
|
||||
"inputsize",
|
||||
"hiddensize",
|
||||
"outputsize"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SeqLSTMP",
|
||||
"baseType": "SeqLSTM",
|
||||
"params": [
|
||||
"inputsize",
|
||||
"hiddensize",
|
||||
"outputsize"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
},
|
||||
{
|
||||
"name": "SeqReverseSequence",
|
||||
"baseType": "Module",
|
||||
"params": [
|
||||
"dim"
|
||||
],
|
||||
"setters": {},
|
||||
"types": {},
|
||||
"defaults": {},
|
||||
"type": "RNN"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
/* eslint-disable no-console */
|
||||
// Update the metadata and schemas/index based on the new schemas in schemas/
|
||||
|
||||
// Update metadata
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
schemas,
|
||||
metadata = require('./metadata.json'),
|
||||
schemaList;
|
||||
|
||||
schemas = fs.readdirSync(__dirname + '/schemas/')
|
||||
.filter(name => path.extname(name) === '.json')
|
||||
.map(name => name.replace(/\.json$/, ''));
|
||||
|
||||
console.log('Discovered schemas: ' + schemas.join(', '));
|
||||
|
||||
schemaList = metadata.configStructure.find(struct => struct.name === 'layerSchema');
|
||||
schemaList.valueItems = schemas.concat('all');
|
||||
|
||||
console.log('Updating metadata...');
|
||||
fs.writeFileSync(__dirname + '/metadata.json', JSON.stringify(metadata, null, 2));
|
||||
|
||||
// Update index.js
|
||||
var index =
|
||||
`/*globals define*/
|
||||
define([
|
||||
${schemas.map(s => `'text!./${s}.json'`).join(',\n ')}
|
||||
], function(
|
||||
${schemas.map(s => s).join(',\n ')}
|
||||
) {
|
||||
return {
|
||||
${schemas.map(s => s + ': ' + s).join(',\n ')}
|
||||
};
|
||||
});`;
|
||||
|
||||
console.log('Updating index.js...');
|
||||
fs.writeFileSync(__dirname + '/schemas/index.js', index);
|
||||
@@ -2,6 +2,7 @@
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
define([
|
||||
'common/storage/constants',
|
||||
'text!./metadata.json',
|
||||
'executor/ExecutorClient',
|
||||
'plugin/PluginBase',
|
||||
@@ -12,6 +13,7 @@ define([
|
||||
'q',
|
||||
'underscore'
|
||||
], function (
|
||||
STORAGE_CONSTANTS,
|
||||
pluginMetadata,
|
||||
ExecutorClient,
|
||||
PluginBase,
|
||||
@@ -46,6 +48,7 @@ define([
|
||||
this._markForDeletion = {}; // id -> node
|
||||
this._oldMetadataByName = {}; // name -> id
|
||||
this.lastAppliedCmd = {};
|
||||
this.canceled = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -79,10 +82,43 @@ define([
|
||||
}
|
||||
|
||||
this._callback = callback;
|
||||
this.currentForkName = null;
|
||||
this.prepare()
|
||||
.then(() => this.executeJob(this.activeNode));
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.updateForkName = function (basename) {
|
||||
basename = basename + '_fork';
|
||||
basename = basename.replace(/[- ]/g, '_');
|
||||
return this.project.getBranches().then(branches => {
|
||||
var names = Object.keys(branches),
|
||||
name = basename,
|
||||
i = 2;
|
||||
|
||||
while (names.indexOf(name) !== -1) {
|
||||
name = basename + '_' + i;
|
||||
i++;
|
||||
}
|
||||
|
||||
this.forkName = name;
|
||||
});
|
||||
};
|
||||
|
||||
// Override 'save' to notify the user on fork
|
||||
ExecuteJob.prototype.save = function (msg) {
|
||||
var name = this.core.getAttribute(this.activeNode, 'name');
|
||||
return this.updateForkName(name)
|
||||
.then(() => PluginBase.prototype.save.call(this, msg))
|
||||
.then(result => {
|
||||
var msg;
|
||||
if (result.status === STORAGE_CONSTANTS.FORKED) {
|
||||
msg = `"${name}" execution has forked to "${result.forkName}"`;
|
||||
this.currentForkName = result.forkName;
|
||||
this.sendNotification(msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.getConnections = function (nodes) {
|
||||
var conns = [];
|
||||
for (var i = nodes.length; i--;) {
|
||||
@@ -129,6 +165,8 @@ define([
|
||||
name,
|
||||
id,
|
||||
idsToDelete = [],
|
||||
type,
|
||||
base,
|
||||
child;
|
||||
|
||||
this.lastAppliedCmd[nodeId] = 0;
|
||||
@@ -142,9 +180,16 @@ define([
|
||||
if (this.isMetaTypeOf(child, this.META.Metadata)) {
|
||||
id = this.core.getPath(child);
|
||||
name = this.core.getAttribute(child, 'name');
|
||||
base = this.core.getBase(child);
|
||||
type = this.core.getAttribute(base, 'name');
|
||||
|
||||
this._markForDeletion[nodeId][id] = child;
|
||||
this._oldMetadataByName[nodeId][name] = id;
|
||||
// namespace by metadata type
|
||||
if (!this._oldMetadataByName[nodeId][type]) {
|
||||
this._oldMetadataByName[nodeId][type] = {};
|
||||
}
|
||||
|
||||
this._oldMetadataByName[nodeId][type][name] = id;
|
||||
|
||||
// children of metadata nodes get deleted
|
||||
idsToDelete = idsToDelete
|
||||
@@ -168,6 +213,24 @@ define([
|
||||
}
|
||||
delete this.lastAppliedCmd[nodeId];
|
||||
delete this._markForDeletion[nodeId];
|
||||
|
||||
this.core.delAttribute(job, 'jobId');
|
||||
this.core.delAttribute(job, 'secret');
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.resultMsg = function(msg) {
|
||||
this.sendNotification(msg);
|
||||
this.createMessage(null, msg);
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.onOperationCanceled = function(op) {
|
||||
var job = this.core.getParent(op),
|
||||
name = this.core.getAttribute(op, 'name'),
|
||||
msg = `"${name}" canceled!`;
|
||||
|
||||
this.core.setAttribute(job, 'status', 'canceled');
|
||||
this.resultMsg(msg);
|
||||
this.onComplete(op, null);
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.onOperationFail =
|
||||
@@ -177,8 +240,8 @@ define([
|
||||
exec = this.core.getParent(job),
|
||||
name = this.core.getAttribute(job, 'name'),
|
||||
jobId = this.core.getPath(job),
|
||||
status = err ? 'fail' : 'success',
|
||||
msg = err ? `${name} execution failed: ${err}` :
|
||||
status = err ? 'fail' : (this.canceled ? 'canceled' : 'success'),
|
||||
msg = err ? `${name} execution failed!` :
|
||||
`${name} executed successfully!`,
|
||||
promise = Q();
|
||||
|
||||
@@ -186,8 +249,16 @@ define([
|
||||
this.logger.info(`Setting ${name} (${jobId}) status to ${status}`);
|
||||
this.clearOldMetadata(job);
|
||||
|
||||
if (this.currentForkName) {
|
||||
// notify client that the job has completed
|
||||
this.sendNotification(`"${name}" execution completed on branch "${this.currentForkName}"`);
|
||||
}
|
||||
if (err) {
|
||||
this.logger.warn(`${name} failed: ${err}`);
|
||||
this.core.setAttribute(exec, 'status', 'failed');
|
||||
} else if (this.canceled) {
|
||||
// Should I set this to 'canceled'?
|
||||
this.core.setAttribute(exec, 'status', 'canceled');
|
||||
} else {
|
||||
// Check if all the other jobs are successful. If so, set the
|
||||
// execution status to 'success'
|
||||
@@ -213,6 +284,7 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
this.createMessage(null, msg);
|
||||
promise
|
||||
.then(() => this.save(msg))
|
||||
.then(() => {
|
||||
@@ -230,6 +302,24 @@ define([
|
||||
children.find(child => this.isMetaTypeOf(child, this.META.Operation)));
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.onBlobRetrievalFail = function (node, input, err) {
|
||||
var job = this.core.getParent(node),
|
||||
e = `Failed to retrieve "${input}" (${err})`,
|
||||
consoleErr = `[0;31mFailed to execute operation: ${e}[0m`;
|
||||
|
||||
consoleErr += [
|
||||
'\n\nA couple things to check out:\n',
|
||||
'- Has the location of DeepForge\'s blob changed?',
|
||||
' (Configurable using "blob.dir" in the deepforge config' +
|
||||
' or setting the DEEPFORGE_BLOB_DIR environment variable)\n',
|
||||
|
||||
'- Was this project created using a different blob location?'
|
||||
].join('\n ');
|
||||
|
||||
this.core.setAttribute(job, 'stdout', consoleErr);
|
||||
this.onOperationFail(node, `Blob retrieval failed for "${name}": ${e}`);
|
||||
};
|
||||
|
||||
ExecuteJob.prototype.executeJob = function (job) {
|
||||
return this.getOperation(job).then(node => {
|
||||
var jobId = this.core.getPath(job),
|
||||
@@ -263,37 +353,46 @@ define([
|
||||
var hash = files.inputAssets[input];
|
||||
|
||||
// data asset for "input"
|
||||
return this.blobClient.getMetadata(hash);
|
||||
return this.blobClient.getMetadata(hash)
|
||||
.fail(err => this.onBlobRetrievalFail(job, input, err));
|
||||
})
|
||||
);
|
||||
})
|
||||
.then(mds => {
|
||||
// get (input, filename) tuples
|
||||
// Record the large files
|
||||
var inputData = {};
|
||||
mds.forEach((metadata, i) => {
|
||||
// add the hashes for each input
|
||||
var input = inputs[i],
|
||||
name = metadata.name,
|
||||
hash = files.inputAssets[input];
|
||||
|
||||
data['inputs/' + input + '/' + name] = hash;
|
||||
inputData['inputs/' + input + '/data'] = {
|
||||
req: hash,
|
||||
cache: metadata.content
|
||||
};
|
||||
});
|
||||
|
||||
delete files.inputAssets;
|
||||
files['input-data.json'] = JSON.stringify(inputData, null, 2);
|
||||
|
||||
// Add pointer assets
|
||||
Object.keys(files.ptrAssets)
|
||||
.forEach(path => data[path] = files.ptrAssets[path]);
|
||||
|
||||
delete files.ptrAssets;
|
||||
|
||||
// Add the executor config
|
||||
return this.getOutputs(node);
|
||||
})
|
||||
.then(outputArgs => {
|
||||
var config,
|
||||
outputs,
|
||||
fileList,
|
||||
ptrFiles = Object.keys(files.ptrAssets),
|
||||
file;
|
||||
|
||||
files['start.js'] = _.template(Templates.START)(CONSTANTS);
|
||||
delete files.ptrAssets;
|
||||
fileList = Object.keys(files).concat(ptrFiles);
|
||||
|
||||
outputs = outputArgs.map(pair => pair[0])
|
||||
.map(name => {
|
||||
return {
|
||||
@@ -309,18 +408,17 @@ define([
|
||||
},
|
||||
{
|
||||
name: name + '-all-files',
|
||||
resultPatterns: []
|
||||
resultPatterns: fileList
|
||||
}
|
||||
);
|
||||
|
||||
config = {
|
||||
cmd: 'bash',
|
||||
args: ['run.sh'],
|
||||
cmd: 'node',
|
||||
args: ['start.js'],
|
||||
outputInterval: OUTPUT_INTERVAL,
|
||||
resultArtifacts: outputs
|
||||
};
|
||||
files['executor_config.json'] = JSON.stringify(config, null, 4);
|
||||
files['run.sh'] = Templates.BASH;
|
||||
|
||||
// Save the artifact
|
||||
// Remove empty hashes
|
||||
@@ -373,7 +471,13 @@ define([
|
||||
this.logger.debug(`Making a commit from ${this.currentHash}`);
|
||||
this.save(`Queued "${name}" operation in ${this.pipelineName}`)
|
||||
.then(() => executor.createJob({hash}))
|
||||
.then(() => this.watchOperation(executor, hash, opNode, job))
|
||||
.then(info => {
|
||||
this.core.setAttribute(job, 'jobId', info.hash);
|
||||
if (info.secret) { // o.w. it is a cached job!
|
||||
this.core.setAttribute(job, 'secret', info.secret);
|
||||
}
|
||||
return this.watchOperation(executor, hash, opNode, job);
|
||||
})
|
||||
.catch(err => this.logger.error(`Could not execute "${name}": ${err}`));
|
||||
|
||||
};
|
||||
@@ -427,6 +531,7 @@ define([
|
||||
isClass,
|
||||
metanodes,
|
||||
classNodes,
|
||||
inheritanceLvl = {},
|
||||
code;
|
||||
|
||||
this.logger.info('Creating custom layer file...');
|
||||
@@ -435,13 +540,31 @@ define([
|
||||
|
||||
classNodes = metanodes.filter(node => {
|
||||
var base = this.core.getBase(node),
|
||||
baseId = this.core.getPath(base);
|
||||
baseId = this.core.getPath(base),
|
||||
count = 1;
|
||||
|
||||
return isClass[baseId];
|
||||
// Count the sets back to a class node
|
||||
while (base) {
|
||||
if (isClass[baseId]) {
|
||||
inheritanceLvl[this.core.getPath(node)] = count;
|
||||
return true;
|
||||
}
|
||||
base = this.core.getBase(base);
|
||||
baseId = this.core.getPath(base);
|
||||
count++;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Get the code definitions for each
|
||||
code = classNodes.map(node =>
|
||||
// Sort by levels of inheritance...
|
||||
code = classNodes.sort((a, b) => {
|
||||
var aId = this.core.getPath(a),
|
||||
bId = this.core.getPath(b);
|
||||
|
||||
return inheritanceLvl[aId] > inheritanceLvl[bId];
|
||||
}).map(node =>
|
||||
`require './${this.core.getAttribute(node, 'name')}.lua'`
|
||||
).join('\n');
|
||||
|
||||
@@ -542,12 +665,18 @@ define([
|
||||
})
|
||||
.then(_tplContents => {
|
||||
tplContents = _tplContents;
|
||||
var hashes = inputs
|
||||
// storing the hash for now...
|
||||
.map(pair =>
|
||||
files.inputAssets[pair[0]] = this.core.getAttribute(pair[2], 'data')
|
||||
);
|
||||
return Q.all(hashes.map(h => this.blobClient.getMetadata(h)));
|
||||
var hashes = inputs.map(pair => {
|
||||
var hash = this.core.getAttribute(pair[2], 'data');
|
||||
files.inputAssets[pair[0]] = hash;
|
||||
return {
|
||||
hash: hash,
|
||||
name: pair[0]
|
||||
};
|
||||
});
|
||||
|
||||
return Q.all(hashes.map(pair =>
|
||||
this.blobClient.getMetadata(pair.hash)
|
||||
.fail(err => this.onBlobRetrievalFail(node, pair.name, err))));
|
||||
})
|
||||
.then(metadatas => {
|
||||
// Create the deserializer
|
||||
@@ -666,7 +795,7 @@ define([
|
||||
return cb(null, files);
|
||||
})
|
||||
.fail(e => {
|
||||
this.logger.error(`Could not generate pointer files for ${this.core.getAttribute(node, 'name')}: ${JSON.stringify(e)}`);
|
||||
this.logger.error(`Could not generate pointer files for ${this.core.getAttribute(node, 'name')}: ${e.toString()}`);
|
||||
return cb(e);
|
||||
});
|
||||
};
|
||||
@@ -675,7 +804,19 @@ define([
|
||||
var jobId = this.core.getPath(job),
|
||||
opId = this.core.getPath(op),
|
||||
info,
|
||||
name;
|
||||
secret,
|
||||
name = this.core.getAttribute(job, 'name');
|
||||
|
||||
// If canceled, stop the operation
|
||||
if (this.canceled) {
|
||||
secret = this.core.getAttribute(job, 'secret');
|
||||
if (secret) {
|
||||
executor.cancelJob(hash, secret);
|
||||
this.core.delAttribute(job, 'secret');
|
||||
this.canceled = true;
|
||||
return this.onOperationCanceled(op);
|
||||
}
|
||||
}
|
||||
|
||||
return executor.getInfo(hash)
|
||||
.then(_info => { // Update the job's stdout
|
||||
@@ -690,15 +831,21 @@ define([
|
||||
.then(outputLines => {
|
||||
var stdout = this.core.getAttribute(job, 'stdout'),
|
||||
output = outputLines.map(o => o.output).join(''),
|
||||
jobName = this.core.getAttribute(job, 'name');
|
||||
last = stdout.lastIndexOf('\n'),
|
||||
lastLine;
|
||||
|
||||
// parse deepforge commands
|
||||
output = this.parseForMetadataCmds(job, output);
|
||||
if (last !== -1) {
|
||||
stdout = stdout.substring(0, last+1);
|
||||
lastLine = stdout.substring(last+1);
|
||||
output = lastLine + output;
|
||||
}
|
||||
output = this.processStdout(job, output, true);
|
||||
|
||||
if (output) {
|
||||
stdout += output;
|
||||
this.core.setAttribute(job, 'stdout', stdout);
|
||||
return this.save(`Received stdout for ${jobName}`);
|
||||
return this.save(`Received stdout for ${name}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -708,7 +855,6 @@ define([
|
||||
if (info.status === 'RUNNING' &&
|
||||
this.core.getAttribute(job, 'status') !== 'running') {
|
||||
|
||||
name = this.core.getAttribute(job, 'name');
|
||||
this.core.setAttribute(job, 'status', 'running');
|
||||
this.save(`Started "${name}" operation in ${this.pipelineName}`);
|
||||
}
|
||||
@@ -720,26 +866,40 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
name = this.core.getAttribute(job, 'name');
|
||||
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
|
||||
return this.blobClient.getArtifact(info.resultHashes.stdout)
|
||||
.then(artifact => {
|
||||
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
|
||||
return this.blobClient.getObjectAsString(stdoutHash);
|
||||
})
|
||||
.then(stdout => {
|
||||
// Parse the remaining code
|
||||
stdout = this.parseForMetadataCmds(job, stdout, true);
|
||||
this.core.setAttribute(job, 'stdout', stdout);
|
||||
if (info.status !== 'SUCCESS') {
|
||||
// Download all files
|
||||
this.result.addArtifact(info.resultHashes[name + '-all-files']);
|
||||
// Set the job to failed! Store the error
|
||||
this.onOperationFail(op, `Operation "${opId}" failed! ${JSON.stringify(info)}`);
|
||||
} else {
|
||||
this.onDistOperationComplete(op, info);
|
||||
}
|
||||
});
|
||||
if (info.status === 'CANCELED') {
|
||||
// If it was cancelled, the pipeline has been stopped
|
||||
this.logger.debug(`"${name}" has been CANCELED!`);
|
||||
this.canceled = true;
|
||||
return this.onOperationCanceled(op);
|
||||
}
|
||||
|
||||
if (info.status === 'SUCCESS' || info.status === 'FAILED_TO_EXECUTE') {
|
||||
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
|
||||
return this.blobClient.getArtifact(info.resultHashes.stdout)
|
||||
.then(artifact => {
|
||||
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
|
||||
return this.blobClient.getObjectAsString(stdoutHash);
|
||||
})
|
||||
.then(stdout => {
|
||||
// Parse the remaining code
|
||||
stdout = this.processStdout(job, stdout);
|
||||
this.core.setAttribute(job, 'stdout', stdout);
|
||||
if (info.status !== 'SUCCESS') {
|
||||
// Download all files
|
||||
this.result.addArtifact(info.resultHashes[name + '-all-files']);
|
||||
// Set the job to failed! Store the error
|
||||
this.onOperationFail(op, `Operation "${opId}" failed! ${JSON.stringify(info)}`);
|
||||
} else {
|
||||
this.onDistOperationComplete(op, info);
|
||||
}
|
||||
});
|
||||
} else { // something bad happened...
|
||||
var err = `Failed to execute operation "${opId}": ${info.status}`,
|
||||
consoleErr = `[0;31mFailed to execute operation: ${info.status}[0m`;
|
||||
this.core.setAttribute(job, 'stdout', consoleErr);
|
||||
this.logger.error(err);
|
||||
this.onOperationFail(op, err);
|
||||
}
|
||||
})
|
||||
.catch(err => this.logger.error(`Could not get op info for ${opId}: ${err}`));
|
||||
};
|
||||
@@ -825,18 +985,47 @@ define([
|
||||
LocalExecutor.prototype
|
||||
);
|
||||
|
||||
ExecuteJob.prototype.processStdout = function (job, text, continued) {
|
||||
// resolve \r
|
||||
var lines,
|
||||
chars,
|
||||
result,
|
||||
i = 0;
|
||||
|
||||
text = text.replace(/\u0000/g, '');
|
||||
lines = text.split('\n');
|
||||
for (var l = lines.length-1; l >= 0; l--) {
|
||||
i = 0;
|
||||
chars = lines[l].split('');
|
||||
result = [];
|
||||
|
||||
for (var c = 0; c < chars.length; c++) {
|
||||
if (chars[c] === '\r') {
|
||||
i = 0;
|
||||
}
|
||||
result[i] = chars[c];
|
||||
i++;
|
||||
}
|
||||
lines[l] = result.join('');
|
||||
}
|
||||
|
||||
// ... and metadata commands
|
||||
return this.parseForMetadataCmds(job, lines, !continued);
|
||||
};
|
||||
|
||||
//////////////////////////// Metadata ////////////////////////////
|
||||
ExecuteJob.prototype.parseForMetadataCmds = function (job, text, skip) {
|
||||
ExecuteJob.prototype.parseForMetadataCmds = function (job, lines, skip) {
|
||||
var jobId = this.core.getPath(job),
|
||||
lines = text.split('\n'),
|
||||
args,
|
||||
result = [],
|
||||
cmdCnt = 0,
|
||||
ansiRegex = /\[\d+(;\d+)?m/g,
|
||||
cmd;
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
// Check for a deepforge command
|
||||
if (lines[i].indexOf(CONSTANTS.START_CMD) === 0) {
|
||||
if (lines[i].indexOf(CONSTANTS.START_CMD) !== -1) {
|
||||
lines[i] = lines[i].replace(ansiRegex, '');
|
||||
cmdCnt++;
|
||||
args = lines[i].split(/\s+/);
|
||||
args.shift();
|
||||
@@ -858,23 +1047,14 @@ define([
|
||||
ExecuteJob.prototype[CONSTANTS.GRAPH_CREATE] = function (job, id) {
|
||||
var graph,
|
||||
name = Array.prototype.slice.call(arguments, 2).join(' '),
|
||||
jobId = this.core.getPath(job),
|
||||
oldMetadata = this._oldMetadataByName[jobId],
|
||||
oldId;
|
||||
jobId = this.core.getPath(job);
|
||||
|
||||
id = jobId + '/' + id;
|
||||
this.logger.info(`Creating graph ${id} named ${name}`);
|
||||
|
||||
// Check if the graph already exists
|
||||
if (oldMetadata && oldMetadata[name]) {
|
||||
oldId = oldMetadata[name];
|
||||
graph = this._markForDeletion[jobId][oldId];
|
||||
|
||||
// Reset points
|
||||
this.core.setAttribute(graph, 'points', '');
|
||||
|
||||
delete this._markForDeletion[jobId][oldId];
|
||||
} else { // create new graph
|
||||
graph = this._getExistingMetadata(jobId, 'Graph', name);
|
||||
if (!graph) {
|
||||
graph = this.core.createNode({
|
||||
base: this.META.Graph,
|
||||
parent: job
|
||||
@@ -890,6 +1070,7 @@ define([
|
||||
|
||||
ExecuteJob.prototype[CONSTANTS.GRAPH_PLOT] = function (job, id, x, y) {
|
||||
var jobId = this.core.getPath(job),
|
||||
nonNum = /[^\d\.]*/g,
|
||||
graph,
|
||||
points;
|
||||
|
||||
@@ -902,6 +1083,9 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean the points by removing and special characters
|
||||
x = x.replace(nonNum, '');
|
||||
y = y.replace(nonNum, '');
|
||||
points = this.core.getAttribute(graph, 'points');
|
||||
points += `${x},${y};`;
|
||||
this.core.setAttribute(graph, 'points', points);
|
||||
@@ -923,5 +1107,46 @@ define([
|
||||
this._metadata[jobId + '/' + id] = line;
|
||||
};
|
||||
|
||||
ExecuteJob.prototype[CONSTANTS.IMAGE] = function (job, hash) {
|
||||
var jobId = this.core.getPath(job),
|
||||
name = Array.prototype.slice.call(arguments, 2).join(' '),
|
||||
id = jobId + '/IMAGE/' + name,
|
||||
imageNode = this._metadata[id]; // Look for the metadata imageNode
|
||||
|
||||
id = jobId + '/' + id;
|
||||
this.logger.info(`Creating graph ${id} named ${name}`);
|
||||
|
||||
if (!imageNode) {
|
||||
|
||||
// Check if the imageNode already exists
|
||||
imageNode = this._getExistingMetadata(jobId, 'Image', name);
|
||||
if (!imageNode) {
|
||||
imageNode = this.core.createNode({
|
||||
base: this.META.Image,
|
||||
parent: job
|
||||
});
|
||||
this.core.setAttribute(imageNode, 'name', name);
|
||||
}
|
||||
this._metadata[id] = imageNode;
|
||||
}
|
||||
|
||||
this.core.setAttribute(imageNode, 'data', hash);
|
||||
};
|
||||
|
||||
ExecuteJob.prototype._getExistingMetadata = function (jobId, type, name) {
|
||||
var oldMetadata = this._oldMetadataByName[jobId] &&
|
||||
this._oldMetadataByName[jobId][type],
|
||||
node,
|
||||
id;
|
||||
|
||||
if (oldMetadata && oldMetadata[name]) {
|
||||
id = oldMetadata[name];
|
||||
node = this._markForDeletion[jobId][id];
|
||||
delete this._markForDeletion[jobId][id];
|
||||
}
|
||||
|
||||
return node || null;
|
||||
};
|
||||
|
||||
return ExecuteJob;
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ function deepforge._cmd(...)
|
||||
print(cmd)
|
||||
end
|
||||
|
||||
-- Graph support
|
||||
Graph = torch.class('deepforge.Graph')
|
||||
|
||||
function Graph:__init(name)
|
||||
@@ -36,6 +37,7 @@ function _Line:__init(graphId, name, opts)
|
||||
end
|
||||
|
||||
function _Line:add(x, y)
|
||||
assert(type(x) == "number" and type(y) == "number", "adding point (" .. tostring(x) .. ", " .. tostring(y) .. ") to " .. self.name .. " failed: expected (number, number)")
|
||||
deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
|
||||
end
|
||||
|
||||
@@ -43,4 +45,21 @@ function Graph:line(name, opts)
|
||||
return deepforge._Line(self.id, name, opts)
|
||||
end
|
||||
|
||||
-- Image support
|
||||
function deepforge.image(name, tensor)
|
||||
require 'image'
|
||||
require 'paths'
|
||||
|
||||
-- save it in the tmp directory
|
||||
local filename = name .. '.png'
|
||||
local path = paths.concat('metadata', filename)
|
||||
|
||||
if paths.dir('metadata') == nil then
|
||||
paths.mkdir('metadata')
|
||||
end
|
||||
|
||||
image.save(path, tensor)
|
||||
deepforge._cmd("<%= IMAGE %>", name)
|
||||
end
|
||||
|
||||
return deepforge
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'paths'
|
||||
|
||||
local path = 'inputs/<%= name %>/<%= filename %>'
|
||||
local abs_path = paths.concat('inputs', '<%= name %>', '<%= filename %>')
|
||||
local path = 'inputs/<%= name %>/data'
|
||||
local abs_path = paths.concat('inputs', '<%= name %>', 'data')
|
||||
|
||||
<%= code %>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/*globals define*/
|
||||
define([
|
||||
'text!./start.ejs',
|
||||
'text!./entry.ejs',
|
||||
'text!./main.ejs',
|
||||
'text!./deepforge.ejs',
|
||||
'text!./serialize.ejs',
|
||||
'text!./deserialize.ejs'
|
||||
], function(
|
||||
START,
|
||||
ENTRY,
|
||||
MAIN,
|
||||
DEEPFORGE,
|
||||
@@ -13,9 +15,8 @@ define([
|
||||
DESERIALIZE
|
||||
) {
|
||||
|
||||
var BASH = 'th init.lua 2>&1';
|
||||
return {
|
||||
BASH,
|
||||
START,
|
||||
ENTRY,
|
||||
MAIN,
|
||||
SERIALIZE,
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
// A wrapper for the torch script which:
|
||||
// - merges stdout, stderr
|
||||
// - receives some commands and uploads intermediate data
|
||||
var spawn = require('child_process').spawn,
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
log = console.error,
|
||||
logger = {};
|
||||
|
||||
// Create the stderr only logger
|
||||
['error', 'warn', 'info', 'log', 'debug'].forEach(method => logger[method] = log);
|
||||
|
||||
// Get the BlobClient...
|
||||
var COMMAND_PREFIX = '<%= START_CMD %>',
|
||||
IMAGE = '<%= IMAGE %>',
|
||||
requirejs = require('webgme').requirejs,
|
||||
remainingImageCount = 0,
|
||||
exitCode = null;
|
||||
|
||||
requirejs([
|
||||
'q',
|
||||
'blob/BlobClient'
|
||||
], function(
|
||||
Q,
|
||||
BlobClient
|
||||
) {
|
||||
var url = process.env.ORIGIN_URL || 'http://127.0.0.1:8888',
|
||||
CACHE_DIR = process.env.DEEPFORGE_WORKER_CACHE || './worker-cache',
|
||||
protocol = url.split('://').shift(),
|
||||
address,
|
||||
port = (url.split(':') || ['80']).pop();
|
||||
|
||||
address = url.replace(protocol + '://', '')
|
||||
.replace(':' + port, '');
|
||||
|
||||
// Create CACHE_DIR if it doesn't exist
|
||||
var prepareCache = function() {
|
||||
var dirs = CACHE_DIR.replace(/\/$/, '').split('/'),
|
||||
cacheParent;
|
||||
|
||||
dirs.pop();
|
||||
cacheParent = dirs.join('/');
|
||||
return makeIfNeeded(cacheParent).then(() => makeIfNeeded(CACHE_DIR));
|
||||
};
|
||||
|
||||
var makeIfNeeded = function(dir) {
|
||||
var deferred = Q.defer(),
|
||||
job;
|
||||
|
||||
log(`makeIfNeeded: ${JSON.stringify(dir)}`);
|
||||
fs.lstat(dir, (err, stat) => {
|
||||
|
||||
if (err || !stat.isDirectory()) {
|
||||
fs.mkdir(dir, err => {
|
||||
if (err) {
|
||||
return deferred.reject(err);
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var blobClient = new BlobClient({
|
||||
server: address,
|
||||
httpsecure: protocol === 'https',
|
||||
serverPort: port,
|
||||
logger: logger
|
||||
});
|
||||
|
||||
var checkFinished = () => {
|
||||
if (exitCode !== null && remainingImageCount === 0) {
|
||||
log('finished!');
|
||||
process.exit(exitCode);
|
||||
}
|
||||
};
|
||||
|
||||
var uploadImage = function(line) {
|
||||
var args = line.split(/\s+/),
|
||||
name = args.slice(2).join(' ').replace(/\s+$/, ''),
|
||||
filename = 'metadata/' + name + '.png';
|
||||
|
||||
// Upload the image from metadata/
|
||||
remainingImageCount++;
|
||||
fs.readFile(filename, (err, content) => {
|
||||
if (err) {
|
||||
logger.error(`Could not read ${filename}: ${err}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add hash to the image command
|
||||
log('about to putFile', filename);
|
||||
blobClient.putFile(filename, content)
|
||||
.then(hash => {
|
||||
args.splice(2, 0, hash);
|
||||
console.log(args.join(' '));
|
||||
log('printing cmd:', args.join(' '));
|
||||
--remainingImageCount;
|
||||
log('finished uploading ' + filename + ' ' + remainingImageCount + ' remain');
|
||||
checkFinished();
|
||||
})
|
||||
.fail(err => logger.error(`${filename} upload failed: ${err}`));
|
||||
});
|
||||
};
|
||||
|
||||
var onStderr = function(data) {
|
||||
var text = data.toString();
|
||||
// Filter out directory label from stack traces
|
||||
process.stdout.write(text.replace(/\.\.\.\/.*\/(main|deepforge|init).lua/g, '$1'));
|
||||
};
|
||||
|
||||
var onStdout = function(data) {
|
||||
var lines = data.toString().split('\n'),
|
||||
result = [],
|
||||
cmdStart;
|
||||
|
||||
// Check for commands...
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
cmdStart = lines[i].indexOf(COMMAND_PREFIX);
|
||||
if (cmdStart !== -1 && lines[i].indexOf(IMAGE) !== -1) {
|
||||
uploadImage(lines[i]);
|
||||
} else {
|
||||
result.push(lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write(result.join('\n'));
|
||||
};
|
||||
|
||||
var createCacheDir = function(hash) {
|
||||
var dir = hash.substring(0, 2);
|
||||
return makeIfNeeded(CACHE_DIR + '/' + dir);
|
||||
};
|
||||
|
||||
var dataCachePath = function(hash) {
|
||||
var dir = hash.substring(0, 2),
|
||||
filename = hash.substring(2),
|
||||
cachePath = `${CACHE_DIR}/${dir}/${filename}`;
|
||||
|
||||
// Get the path for data in the cache
|
||||
return cachePath;
|
||||
};
|
||||
|
||||
var makeSymLink = function(target, src) {
|
||||
var deferred = Q.defer(),
|
||||
job;
|
||||
|
||||
src = path.resolve(src);
|
||||
target = path.resolve(target);
|
||||
fs.stat(src, err => {
|
||||
if (err.code === 'ENOENT') {
|
||||
logger.debug(`creating symlink "ln -s ${target} ${src}"`);
|
||||
job = spawn('ln', ['-s', target, src || '.']);
|
||||
job.on('exit', code => {
|
||||
if (code) {
|
||||
deferred.reject(`Could not create symlink ${target} -> ${src||'.'}`);
|
||||
return;
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
var getData = function(ipath, hashes) {
|
||||
// Download the data and put it in the given path
|
||||
var deferred = Q.defer(),
|
||||
inputName = ipath.split('/')[1],
|
||||
cachePath = dataCachePath(hashes.cache);
|
||||
|
||||
|
||||
logger.debug(`retrieving ${ipath}`);
|
||||
fs.lstat(cachePath, (err, cacheStats) => {
|
||||
// Check if the data exists in the cache
|
||||
if (!err && cacheStats.isFile()) {
|
||||
logger.info(`${inputName} already cached. Skipping retrieval from blob`);
|
||||
return makeSymLink(cachePath, ipath).then(deferred.resolve);
|
||||
}
|
||||
|
||||
createCacheDir(hashes.cache)
|
||||
.then(() => blobClient.getObject(hashes.req))
|
||||
.then(buffer => fs.writeFile(cachePath, buffer, (err, result) => {
|
||||
if (err) {
|
||||
logger.error('Retrieving ' + ipath + ' failed!');
|
||||
return deferred.reject(`Could not write to ${ipath}: ${err}`);
|
||||
}
|
||||
// Create the symlink
|
||||
logger.info('Retrieved ' + ipath);
|
||||
return makeSymLink(cachePath, ipath).then(deferred.resolve);
|
||||
}))
|
||||
.fail(err => deferred.reject(`Could not retrieve "${inputName}" (${err})`));
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
// Download the large files
|
||||
var inputData = JSON.parse(fs.readFileSync('./input-data.json')),
|
||||
inputPaths = Object.keys(inputData);
|
||||
|
||||
// Request the data from the blob
|
||||
prepareCache()
|
||||
.then(() => Q.all(inputPaths.map(ipath => getData(ipath, inputData[ipath]))))
|
||||
.then(() => {
|
||||
// Run 'th init.lua' and merge the stdout, stderr
|
||||
var job = spawn('th', ['init.lua']);
|
||||
job.stdout.on('data', onStdout);
|
||||
job.stderr.on('data', onStderr);
|
||||
job.on('close', code => {
|
||||
exitCode = code;
|
||||
log('script finished w/ exit code:', code);
|
||||
checkFinished();
|
||||
});
|
||||
})
|
||||
.fail(err => {
|
||||
console.log(`Data retrieval failed: ${err}`);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
@@ -74,6 +74,7 @@ define([
|
||||
// - keep track if the pipeline has errored
|
||||
// - if so, don't start any more jobs
|
||||
this.pipelineError = null;
|
||||
this.canceled = false;
|
||||
this.runningJobs = 0;
|
||||
|
||||
// metadata records
|
||||
@@ -103,17 +104,18 @@ define([
|
||||
// If starting with a pipeline, we will create an Execution first
|
||||
startPromise = this.createExecution(this.activeNode)
|
||||
.then(execNode => {
|
||||
this.logger.debug(`Finished creating execution "${this.core.getAttribute(execNode, 'name')}"`);
|
||||
this.activeNode = execNode;
|
||||
});
|
||||
} else if (this.core.isTypeOf(this.activeNode, this.META.Execution)) {
|
||||
this.logger.debug('Restarting execution');
|
||||
startPromise = Q();
|
||||
} else {
|
||||
return callback('Current node is not a Pipeline or Execution!', this.result);
|
||||
}
|
||||
|
||||
// Set debug and the final callback
|
||||
this.debug = true; // this.getCurrentConfig().debug;
|
||||
this._callback = callback;
|
||||
this.currentForkName = null;
|
||||
|
||||
startPromise
|
||||
.then(() => this.core.loadSubTree(this.activeNode))
|
||||
@@ -122,41 +124,29 @@ define([
|
||||
.filter(n => this.core.getParent(n) === this.activeNode);
|
||||
|
||||
this.pipelineName = this.core.getAttribute(this.activeNode, 'name');
|
||||
this.logger.debug(`Loaded subtree of ${this.pipelineName}. About to build cache`);
|
||||
this.buildCache(subtree);
|
||||
this.logger.debug('Parsing execution for job inter-dependencies');
|
||||
this.parsePipeline(children); // record deps, etc
|
||||
|
||||
this.logger.debug('Clearing old results');
|
||||
return this.clearResults();
|
||||
})
|
||||
.then(() => this.executePipeline())
|
||||
.fail(e => this.logger.error(e));
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.updateForkName = function () {
|
||||
var basename = this.pipelineName + '_fork';
|
||||
return this.project.getBranches().then(branches => {
|
||||
var names = Object.keys(branches),
|
||||
name = basename,
|
||||
i = 2;
|
||||
|
||||
while (names.indexOf(name) !== -1) {
|
||||
name = basename + '_' + i;
|
||||
i++;
|
||||
}
|
||||
|
||||
this.forkName = name;
|
||||
});
|
||||
};
|
||||
|
||||
// Override 'save' to prevent race conditions while saving
|
||||
ExecutePipeline.prototype.save = function (msg) {
|
||||
// When 'save' is called, it should still finish any current save op
|
||||
// before continuing
|
||||
this._currentSave = this._currentSave
|
||||
.then(() => this.updateForkName())
|
||||
.then(() => this.updateForkName(this.pipelineName))
|
||||
.then(() => CreateExecution.prototype.save.call(this, msg))
|
||||
.then(result => {
|
||||
var msg;
|
||||
if (result.status === STORAGE_CONSTANTS.FORKED) {
|
||||
this.currentForkName = result.forkName;
|
||||
msg = `"${this.pipelineName}" execution has forked to "${result.forkName}"`;
|
||||
this.sendNotification(msg);
|
||||
}
|
||||
@@ -191,6 +181,8 @@ define([
|
||||
this.core.setAttribute(this.activeNode, 'status', 'running');
|
||||
this.logger.info('Setting all jobs status to "pending"');
|
||||
this.logger.debug(`Making a commit from ${this.currentHash}`);
|
||||
this.core.setAttribute(this.activeNode, 'startTime', Date.now());
|
||||
this.core.delAttribute(this.activeNode, 'endTime');
|
||||
return this.save(`Initializing ${this.pipelineName} for execution`);
|
||||
};
|
||||
|
||||
@@ -289,8 +281,17 @@ define([
|
||||
this.onPipelineComplete(err);
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onOperationCanceled = function(op) {
|
||||
var job = this.core.getParent(op);
|
||||
this.core.setAttribute(job, 'status', 'canceled');
|
||||
this.runningJobs--;
|
||||
this.logger.debug(`${this.core.getAttribute(job, 'name')} has been canceled`);
|
||||
this.onPipelineComplete();
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onPipelineComplete = function(err) {
|
||||
var name = this.core.getAttribute(this.activeNode, 'name');
|
||||
var name = this.core.getAttribute(this.activeNode, 'name'),
|
||||
msg = `"${this.pipelineName}" `;
|
||||
|
||||
if (err) {
|
||||
this.runningJobs--;
|
||||
@@ -298,17 +299,34 @@ define([
|
||||
|
||||
this.pipelineError = this.pipelineError || err;
|
||||
|
||||
if (this.pipelineError && this.runningJobs > 0) {
|
||||
this.logger.info('Pipeline errored but is waiting for the running ' +
|
||||
this.logger.debug(`${this.runningJobs} remaining jobs`);
|
||||
if ((this.pipelineError || this.canceled) && this.runningJobs > 0) {
|
||||
var action = this.pipelineError ? 'error' : 'cancel';
|
||||
this.logger.info(`Pipeline ${action}ed but is waiting for the running ` +
|
||||
'jobs to finish');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentForkName) {
|
||||
// notify client that the job has completed
|
||||
this.sendNotification(`"${this.pipelineName}" execution completed on branch "${this.currentForkName}"`);
|
||||
}
|
||||
|
||||
if (this.pipelineError) {
|
||||
msg += 'failed!';
|
||||
} else if (this.canceled) {
|
||||
msg += 'canceled!';
|
||||
} else {
|
||||
msg += 'finished!';
|
||||
}
|
||||
|
||||
this.logger.debug(`Pipeline "${name}" complete!`);
|
||||
this.core.setAttribute(this.activeNode, 'endTime', Date.now());
|
||||
this.core.setAttribute(this.activeNode, 'status',
|
||||
(!this.pipelineError ? 'success' : 'failed'));
|
||||
(this.pipelineError ? 'failed' : (this.canceled ? 'canceled' : 'success')));
|
||||
|
||||
this._finished = true;
|
||||
this.resultMsg(msg);
|
||||
this.save('Pipeline execution finished')
|
||||
.then(() => {
|
||||
this.result.setSuccess(!this.pipelineError);
|
||||
@@ -325,7 +343,7 @@ define([
|
||||
this.logger.info(`About to execute ${readyOps.length} operations`);
|
||||
|
||||
// If the pipeline has errored don't start any more jobs
|
||||
if (this.pipelineError) {
|
||||
if (this.pipelineError || this.canceled) {
|
||||
if (this.runningJobs === 0) {
|
||||
this.onPipelineComplete();
|
||||
}
|
||||
|
||||
@@ -11,17 +11,17 @@
|
||||
"disableBrowserSideExecution": true,
|
||||
"configStructure": [
|
||||
{
|
||||
"name": "snapshot",
|
||||
"displayName": "Snapshot",
|
||||
"description": "Freeze the operation definitions and attributes at current value",
|
||||
"value": true,
|
||||
"valueType": "boolean",
|
||||
"name": "name",
|
||||
"displayName": "Execution name",
|
||||
"description": "Optional name for this execution instance",
|
||||
"value": "",
|
||||
"valueType": "string",
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"name": "debug",
|
||||
"displayName": "Debug Mode",
|
||||
"description": "Download all files for each operation",
|
||||
"description": "Allow for operation editing after creation",
|
||||
"value": false,
|
||||
"valueType": "boolean",
|
||||
"readOnly": false
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
/*globals define*/
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
/**
|
||||
* Generated by PluginGenerator 0.14.0 from webgme on Sun Mar 20 2016 16:49:12 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define([
|
||||
'SimpleNodes/SimpleNodes',
|
||||
'SimpleNodes/Constants',
|
||||
'deepforge/layer-args',
|
||||
'./dimensionality',
|
||||
'deepforge/utils',
|
||||
'underscore',
|
||||
'text!./metadata.json'
|
||||
], function (
|
||||
PluginBase,
|
||||
Constants,
|
||||
createLayerDict,
|
||||
dimensionality,
|
||||
utils,
|
||||
_,
|
||||
metadata
|
||||
) {
|
||||
@@ -42,11 +38,15 @@ define([
|
||||
GenerateArchitecture.prototype = Object.create(PluginBase.prototype);
|
||||
GenerateArchitecture.prototype.constructor = GenerateArchitecture;
|
||||
|
||||
GenerateArchitecture.prototype.getTemplateSettings = function () {
|
||||
return null;
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.main = function () {
|
||||
this.addCustomLayersToMeta();
|
||||
this.LayerDict = createLayerDict(this.core, this.META);
|
||||
this.uniqueId = 2;
|
||||
this._oldTemplateSettings = _.templateSettings;
|
||||
this.varnames = {};
|
||||
return PluginBase.prototype.main.apply(this, arguments);
|
||||
};
|
||||
|
||||
@@ -60,25 +60,36 @@ define([
|
||||
.forEach(node => this.META[this.core.getAttribute(node, 'name')] = node);
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.hoist = function (code) {
|
||||
this.definitions.push(code);
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.createOutputFiles = function (tree) {
|
||||
var layers = tree[Constants.CHILDREN],
|
||||
//initialLayers,
|
||||
result = {},
|
||||
code = 'require \'nn\'\n';
|
||||
code = '';
|
||||
|
||||
this.definitions = [
|
||||
'require \'nn\'',
|
||||
'require \'rnn\''
|
||||
];
|
||||
|
||||
//initialLayers = layers.filter(layer => layer[Constants.PREV].length === 0);
|
||||
// Add an index to each layer
|
||||
layers.forEach((l, index) => l[INDEX] = index);
|
||||
|
||||
// Define custom layers
|
||||
if (this.getCurrentConfig().standalone) {
|
||||
this.logger.debug('Generating layer definitions');
|
||||
code += this.genLayerDefinitions(layers);
|
||||
}
|
||||
|
||||
this.logger.debug('Generating architecture code...');
|
||||
code += this.genArchCode(layers);
|
||||
this.logger.debug('Prepending hoisted code...');
|
||||
code = this.definitions.join('\n') + '\n' + code;
|
||||
|
||||
result[tree.name + '.lua'] = code;
|
||||
_.templateSettings = this._oldTemplateSettings; // FIXME: Fix this in SimpleNodes
|
||||
this.logger.debug(`Finished generating ${tree.name}.lua`);
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -89,10 +100,38 @@ define([
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.genRawArchCode = function (layers, name) {
|
||||
var result = '';
|
||||
if (layers.length > 1) {
|
||||
return this.createSequential(layers[0], name).code;
|
||||
} else if (name) {
|
||||
result = `\nlocal ${name} = `;
|
||||
}
|
||||
result += this.createLayer(layers[0]);
|
||||
return result;
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.getVarName = function (base) {
|
||||
// Check "this.varnames"
|
||||
var name = base,
|
||||
i = 2;
|
||||
|
||||
while (this.varnames[name]) {
|
||||
name = base + '_' + (i++);
|
||||
}
|
||||
this.varnames[name] = true;
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.createLayer = function (layer) {
|
||||
var args = this.createArgString(layer);
|
||||
return `nn.${layer.name}${args}`;
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.createSequential = function (layer, name) {
|
||||
var next = layer[Constants.NEXT][0],
|
||||
args,
|
||||
template,
|
||||
snippet,
|
||||
snippets,
|
||||
code = `\nlocal ${name} = nn.Sequential()`,
|
||||
@@ -107,10 +146,8 @@ define([
|
||||
next = layer; // the given layer will be added by the caller
|
||||
break;
|
||||
} else { // add the given layer
|
||||
args = this.createArgString(layer);
|
||||
template = _.template(name + ':add(nn.{{= name }}' + args + ')');
|
||||
snippet = template(layer);
|
||||
code += '\n' + snippet;
|
||||
snippet = this.createLayer(layer);
|
||||
code += `\n${name}:add(${snippet})`;
|
||||
|
||||
}
|
||||
|
||||
@@ -119,7 +156,7 @@ define([
|
||||
|
||||
this.logger.debug(`detected fork of size ${layer[Constants.NEXT].length}`);
|
||||
snippets = layer[Constants.NEXT].map(nlayer =>
|
||||
this.createSequential(nlayer, 'net_'+(this.uniqueId++)));
|
||||
this.createSequential(nlayer, this.getVarName('net')));
|
||||
code += '\n' + snippets.map(snippet => snippet.code).join('\n');
|
||||
|
||||
// Make sure all snippets end at the same concat node
|
||||
@@ -157,7 +194,7 @@ define([
|
||||
|
||||
// merge the elements in the group
|
||||
if (snippets.length) { // prepare next iteration
|
||||
result = this.createSequential(next, 'net_'+(this.uniqueId++));
|
||||
result = this.createSequential(next, this.getVarName('net'));
|
||||
code += result.code;
|
||||
group = [result];
|
||||
this.logger.debug('updating group ('+ snippets.length+ ' left)');
|
||||
@@ -177,11 +214,65 @@ define([
|
||||
};
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.getValue = function (arg, layer) {
|
||||
var content = layer[arg];
|
||||
|
||||
if (typeof content === 'object') { // layer as arg
|
||||
if (content[Constants.CHILDREN].length) {
|
||||
// Generate the code for the children of layer[arg]
|
||||
var name = this.getVarName(utils.abbr(arg)),
|
||||
layers;
|
||||
|
||||
this.logger.debug(`Adding layer arg for ${arg} (${layer.name})`);
|
||||
try {
|
||||
layers = this.genRawArchCode(layer[arg][Constants.CHILDREN], name);
|
||||
} catch (e) {
|
||||
this.logger.error(`Layer arg creation failed: ${e}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// hoist layer definitions to the top of the file
|
||||
this.hoist(layers);
|
||||
return name;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
GenerateArchitecture.prototype.createArgString = function (layer) {
|
||||
return '(' + this.LayerDict[layer.name]
|
||||
.map(arg => layer[arg.name])
|
||||
var setters = this.LayerDict[layer.name].setters,
|
||||
setterNames = Object.keys(this.LayerDict[layer.name].setters),
|
||||
base = layer[Constants.BASE],
|
||||
desc,
|
||||
fn,
|
||||
layerCode;
|
||||
|
||||
this.logger.debug(`Creating arg string for ${layer.name}`);
|
||||
layerCode = '(' + this.LayerDict[layer.name].args
|
||||
.map(arg => this.getValue(arg.name, layer))
|
||||
.filter(GenerateArchitecture.isSet)
|
||||
.join(', ') + ')';
|
||||
.join(', ') + ')';
|
||||
|
||||
// Add any setters
|
||||
// For each setter, check if it has been changed (and needs to be set)
|
||||
for (var i = setterNames.length; i--;) {
|
||||
desc = setters[setterNames[i]];
|
||||
if (desc.setterType === 'const') {
|
||||
// if the value is not the default, add the given fn
|
||||
if (layer[setterNames[i]] !== base[setterNames[i]]) {
|
||||
fn = desc.setterFn[layer[setterNames[i]]];
|
||||
layerCode += `:${fn}()`;
|
||||
}
|
||||
} else if (layer[setterNames[i]] !== null && layer[setterNames[i]] !== undefined) {
|
||||
fn = desc.setterFn;
|
||||
layerCode += `:${fn}(${layer[setterNames[i]]})`;
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.debug(`Created nn.${layer.name}${layerCode}`);
|
||||
return layerCode;
|
||||
};
|
||||
|
||||
GenerateArchitecture.isSet = function (value) {
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/* globals define */
|
||||
define([
|
||||
'SimpleNodes/Constants',
|
||||
'deepforge/lua'
|
||||
], function(
|
||||
Constants,
|
||||
luajs
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var dimensionality = function(node) {
|
||||
var transform = node.dimensionalityTransform;
|
||||
return dimensionality[transform](node);
|
||||
};
|
||||
|
||||
// If 'same', return the input dimensions
|
||||
dimensionality.same = function(node) {
|
||||
var prev = node[Constants.PREV][0];
|
||||
return dimensionality(prev);
|
||||
};
|
||||
|
||||
dimensionality.custom = function(node) {
|
||||
var luaFn = node.calculateDimensionality,
|
||||
cxt = luajs.newContext(),
|
||||
layer, // lua layer
|
||||
bin,
|
||||
dims;
|
||||
|
||||
cxt.loadStdLib();
|
||||
// - cross compile to js
|
||||
bin = cxt.loadString(luaFn);
|
||||
bin(); // load the calc fn to global context
|
||||
|
||||
// Create the layer
|
||||
layer = new luajs.types.LuaTable();
|
||||
var attrs = Object.keys(node).filter(attr => attr.indexOf('_') !== 0);
|
||||
for (var i = attrs.length; i--;) {
|
||||
layer.set(attrs[i], node[attrs[i]]);
|
||||
}
|
||||
cxt._G.set('layer', layer);
|
||||
|
||||
// call the function with layer and input dimensions
|
||||
bin = cxt.loadString('return calcDims(layer)');
|
||||
dims = bin()[0]; // TODO: Add support for multiple dimensions
|
||||
|
||||
// TODO: return a fn if it depends on the previous value
|
||||
|
||||
return dims;
|
||||
};
|
||||
|
||||
return dimensionality;
|
||||
});
|
||||
@@ -1,18 +1,12 @@
|
||||
/*globals define*/
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
/**
|
||||
* Generated by PluginGenerator 0.14.0 from webgme on Thu Mar 10 2016 04:16:02 GMT-0600 (CST).
|
||||
*/
|
||||
|
||||
define([
|
||||
'deepforge/layer-args',
|
||||
'deepforge/lua',
|
||||
'./nn',
|
||||
'plugin/PluginBase',
|
||||
'text!./metadata.json'
|
||||
], function (
|
||||
LayerDict,
|
||||
luajs,
|
||||
createNNSearcher,
|
||||
PluginBase,
|
||||
@@ -55,6 +49,8 @@ define([
|
||||
return callback('Torch code not provided.', this.result);
|
||||
}
|
||||
|
||||
this.addCustomLayersToMeta();
|
||||
|
||||
this.blobClient.getMetadata(srcHash)
|
||||
.then(mdata => { // Create the new model
|
||||
// If the current node is an architecture, assume we are just extending it
|
||||
@@ -78,11 +74,10 @@ define([
|
||||
this.loadNNMock();
|
||||
|
||||
// Cross compile to js and run
|
||||
src = 'require \'nn\'\n' + src; // guarantee it loads nn
|
||||
this.bin = this.context.loadString(src);
|
||||
this.bin();
|
||||
|
||||
this.afterExecution();
|
||||
|
||||
return this.save('ImportTorch updated model.');
|
||||
})
|
||||
.then(() => { // changes saved successfully
|
||||
@@ -97,6 +92,22 @@ define([
|
||||
);
|
||||
};
|
||||
|
||||
ImportTorch.prototype.addCustomLayersToMeta = function () {
|
||||
// Add custom layers to the metamodel
|
||||
var metanodes = this.core.getAllMetaNodes(this.rootNode),
|
||||
name;
|
||||
|
||||
Object.keys(metanodes).map(id => metanodes[id])
|
||||
.filter(node => this.core.isTypeOf(node, this.META.Layer))
|
||||
.forEach(layer => {
|
||||
name = this.core.getAttribute(layer, 'name');
|
||||
if (!this.META[name]) {
|
||||
this.logger.debug(`Adding ${name} to the meta`);
|
||||
this.META[name] = layer;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Create the 'nn' shim and add it to the global context
|
||||
ImportTorch.prototype.loadNNMock = function () {
|
||||
// This needs a refactor...
|
||||
@@ -107,15 +118,10 @@ define([
|
||||
this.context._G.get('package').set('searchers', [function(name) {
|
||||
if (name === 'nn') {
|
||||
return lib;
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
}]);
|
||||
|
||||
// Some scripts don't include `require 'nn'`. I may have to add the
|
||||
// "nn" package to the global scope...
|
||||
};
|
||||
|
||||
ImportTorch.prototype.afterExecution = function () {
|
||||
// TODO
|
||||
};
|
||||
|
||||
return ImportTorch;
|
||||
|
||||
+148
-17
@@ -7,7 +7,7 @@ define([
|
||||
], function(
|
||||
createLayerDict,
|
||||
assert,
|
||||
luajs
|
||||
lua
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
@@ -19,7 +19,8 @@ define([
|
||||
LayerDict = createLayerDict(core, META),
|
||||
helpers = context.__helpers,
|
||||
oldSet = helpers.__set,
|
||||
isSetting = false;
|
||||
isSetting = false,
|
||||
connsFrom = {};
|
||||
|
||||
// Override the helper's '__set' method to detect
|
||||
// if the code is in the middle of a "set".
|
||||
@@ -29,24 +30,68 @@ define([
|
||||
isSetting = false;
|
||||
};
|
||||
|
||||
var stringify = function(table) {
|
||||
var strings = table.array.map(val => {
|
||||
if (val instanceof lua.types.LuaTable) {
|
||||
return stringify(val);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
return '{' + strings.join(', ') + '}';
|
||||
};
|
||||
|
||||
var allConnectedTo = function(current) {
|
||||
var connectedIds = {},
|
||||
node,
|
||||
id;
|
||||
|
||||
while (current.length) {
|
||||
node = current.shift();
|
||||
id = core.getGuid(node);
|
||||
if (connectedIds[id]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
connectedIds[id] = node;
|
||||
if (connsFrom[id]) {
|
||||
current = current.concat(connsFrom[id]);
|
||||
}
|
||||
}
|
||||
// Return an array of all things connected to the
|
||||
// given node
|
||||
return Object.keys(connectedIds).map(key => connectedIds[key]);
|
||||
};
|
||||
|
||||
var connect = function(src, dst) {
|
||||
var conn = core.createNode({
|
||||
var conn,
|
||||
id;
|
||||
|
||||
conn = core.createNode({
|
||||
parent: parent,
|
||||
base: META.Connection
|
||||
});
|
||||
core.setPointer(conn, 'src', src);
|
||||
core.setPointer(conn, 'dst', dst);
|
||||
// Record this
|
||||
id = core.getGuid(src);
|
||||
if (!connsFrom[id]) {
|
||||
connsFrom[id] = [];
|
||||
}
|
||||
connsFrom[id].push(conn, dst);
|
||||
};
|
||||
|
||||
// nn drawing library
|
||||
var Layer = function(base, attrs, args) {
|
||||
this._base = base;
|
||||
this._attrs = attrs;
|
||||
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
this[attrs[i].name] = args[i];
|
||||
}
|
||||
|
||||
// inputs/outputs used for being added to containers
|
||||
this._values = args;
|
||||
this._cachedNode = null;
|
||||
this._inputs = [this._node()];
|
||||
this._outputs = [this._node()];
|
||||
@@ -55,6 +100,10 @@ define([
|
||||
Layer.prototype._node = function() {
|
||||
var name,
|
||||
node,
|
||||
nodes,
|
||||
cntr,
|
||||
layer,
|
||||
cntrName,
|
||||
value;
|
||||
|
||||
if (this._cachedNode) {
|
||||
@@ -70,16 +119,42 @@ define([
|
||||
|
||||
for (var i = this._attrs.length; i--;) {
|
||||
name = this._attrs[i].name;
|
||||
value = this[name];
|
||||
if ((typeof value) === 'object') {
|
||||
// special lua.js object
|
||||
value = value.valueOf();
|
||||
}
|
||||
value = this._values[i];
|
||||
|
||||
// TODO: Update this to check if inferred and the value matches
|
||||
// our inferred value. If so, skip it
|
||||
if (value !== undefined/*&& !this._attrs[i].infer*/) {
|
||||
core.setAttribute(node, name, value);
|
||||
if (value instanceof lua.types.LuaTable) {
|
||||
layer = value.get('_node');
|
||||
if (layer) { // layer arg!
|
||||
// add all the inputs, outputs (and connected elements) to
|
||||
// be in an "Architecture" node in the current node
|
||||
cntr = core.createNode({
|
||||
base: META.Architecture,
|
||||
parent: node
|
||||
});
|
||||
cntrName = `${name} (${this._base})`;
|
||||
logger.debug(`Naming layer arg ${cntrName}`);
|
||||
core.setAttribute(cntr, 'name', cntrName);
|
||||
// Move all connecting elements of the value to
|
||||
// the cntr
|
||||
nodes = allConnectedTo(layer._inputs.concat(layer._outputs));
|
||||
for (var j = nodes.length; j--;) {
|
||||
core.moveNode(nodes[j], cntr);
|
||||
}
|
||||
core.setPointer(node, name, cntr);
|
||||
logger.debug(`Moving ${nodes.length} to ${name}(${this._base})`);
|
||||
} else { // Something like {1, 2, 3}
|
||||
value = stringify(value);
|
||||
logger.debug(`Setting ${name} to ${value} (${this._base})`);
|
||||
core.setAttribute(node, name, value);
|
||||
}
|
||||
} else { // attribute value
|
||||
if ((typeof value) === 'object') {
|
||||
// special lua.js object
|
||||
value = value.valueOf();
|
||||
}
|
||||
if (value !== undefined) {
|
||||
logger.debug(`Setting ${name} to ${value} (${this._base})`);
|
||||
core.setAttribute(node, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +162,13 @@ define([
|
||||
return node;
|
||||
};
|
||||
|
||||
Layer.prototype._setAttribute = function(name, self, value) {
|
||||
var node = this._node();
|
||||
logger.info(`Setting ${name} to ${value}`);
|
||||
core.setAttribute(node, name, value);
|
||||
return self;
|
||||
};
|
||||
|
||||
// Each container will have `inputs` and `outputs`
|
||||
var Container = function() {
|
||||
// inputs and outputs are webgme nodes
|
||||
@@ -153,16 +235,59 @@ define([
|
||||
Sequential: Sequential
|
||||
};
|
||||
|
||||
var getValue = function(txt) {
|
||||
if (txt === 'true') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (txt === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (/^\d+$/.test(txt)) {
|
||||
return +txt;
|
||||
}
|
||||
|
||||
return txt;
|
||||
};
|
||||
|
||||
var addSetterMethods = function(table, attr, dict) {
|
||||
var desc = dict[attr],
|
||||
layer = table.get('_node'),
|
||||
vals,
|
||||
value,
|
||||
fn;
|
||||
|
||||
if (desc.setterType === 'arg') {
|
||||
fn = desc.setterFn;
|
||||
table.set(fn, layer._setAttribute.bind(layer, attr));
|
||||
} else {
|
||||
vals = Object.keys(desc.setterFn);
|
||||
for (var i = vals.length; i--;) {
|
||||
fn = desc.setterFn[vals[i]];
|
||||
value = getValue(vals[i]);
|
||||
table.set(fn, layer._setAttribute.bind(layer, attr, table, value));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var CreateLayer = function(type) {
|
||||
var res = luajs.newContext()._G,
|
||||
var res = lua.newContext()._G,
|
||||
attrs = [].slice.call(arguments, 1),
|
||||
ltGet = luajs.types.LuaTable.prototype.get,
|
||||
ltGet = lua.types.LuaTable.prototype.get,
|
||||
setters = [],
|
||||
args = [],
|
||||
node;
|
||||
|
||||
if (LayerDict[type]) {
|
||||
args = LayerDict[type].args;
|
||||
setters = Object.keys(LayerDict[type].setters);
|
||||
}
|
||||
|
||||
if (LAYERS[type]) {
|
||||
node = new LAYERS[type](LayerDict[type] || [], attrs);
|
||||
node = new LAYERS[type](args, attrs);
|
||||
} else { // Call generic Layer with type name
|
||||
node = new Layer(type, LayerDict[type] || [], attrs);
|
||||
node = new Layer(type, args, attrs);
|
||||
}
|
||||
|
||||
res.set('_node', node);
|
||||
@@ -178,6 +303,12 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
// add setters
|
||||
// look up the setters
|
||||
for (var i = setters.length; i--;) {
|
||||
addSetterMethods(res, setters[i], LayerDict[type].setters);
|
||||
}
|
||||
|
||||
// Override get
|
||||
res.get = function noNilGet(value) {
|
||||
var result = ltGet.call(this, value);
|
||||
@@ -197,7 +328,7 @@ define([
|
||||
}
|
||||
|
||||
// TODO: Create the nn object
|
||||
var nn = luajs.newContext()._G,
|
||||
var nn = lua.newContext()._G,
|
||||
names = Object.keys(LayerDict);
|
||||
|
||||
for (var i = names.length; i--;) {
|
||||
|
||||
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
@@ -88,5 +88,17 @@
|
||||
"title": "LineGraph",
|
||||
"panel": "panels/LineGraph/LineGraphPanel",
|
||||
"DEBUG_ONLY": false
|
||||
},
|
||||
{
|
||||
"id": "ImageViewer",
|
||||
"title": "ImageViewer",
|
||||
"panel": "panels/ImageViewer/ImageViewerPanel",
|
||||
"DEBUG_ONLY": false
|
||||
},
|
||||
{
|
||||
"id": "ExecutionIndex",
|
||||
"title": "ExecutionIndex",
|
||||
"panel": "panels/ExecutionIndex/ExecutionIndexPanel",
|
||||
"DEBUG_ONLY": false
|
||||
}
|
||||
]
|
||||
@@ -2,12 +2,14 @@
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'deepforge/Constants',
|
||||
'deepforge/globals',
|
||||
'panels/EasyDAG/EasyDAGControl',
|
||||
'js/NodePropertyNames',
|
||||
'js/Utils/ComponentSettings',
|
||||
'underscore'
|
||||
], function (
|
||||
Constants,
|
||||
DeepForge,
|
||||
EasyDAGControl,
|
||||
nodePropertyNames,
|
||||
@@ -38,6 +40,7 @@ define([
|
||||
_.extend(ArchEditorControl.prototype, EasyDAGControl.prototype);
|
||||
|
||||
ArchEditorControl.prototype.TERRITORY_RULE = {children: 1};
|
||||
ArchEditorControl.prototype.DEFAULT_DECORATOR = 'LayerDecorator';
|
||||
ArchEditorControl.prototype.getComponentId = function() {
|
||||
return 'ArchEditor';
|
||||
};
|
||||
@@ -59,12 +62,24 @@ define([
|
||||
if (!desc.isConnection) {
|
||||
var allAttrs = desc.attributes,
|
||||
names = Object.keys(allAttrs),
|
||||
schema;
|
||||
ctorInfo = desc.attributes[Constants.CTOR_ARGS_ATTR],
|
||||
ctorAttrs = ctorInfo ? ctorInfo.value.split(','): [],
|
||||
schema,
|
||||
i;
|
||||
|
||||
desc.attributes = {};
|
||||
for (var i = names.length; i--;) {
|
||||
|
||||
// add ctor attributes
|
||||
for (i = 0; i < ctorAttrs.length; i++) {
|
||||
if (allAttrs[ctorAttrs[i]]) { // (not a ref to a layer)
|
||||
desc.attributes[ctorAttrs[i]] = allAttrs[ctorAttrs[i]];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = names.length; i--;) {
|
||||
// check if it is a setter
|
||||
schema = this._client.getAttributeSchema(id, names[i]);
|
||||
if (names[i] === 'name' || schema.hasOwnProperty('argindex')) {
|
||||
if (names[i] === 'name' || schema.setterType) {
|
||||
desc.attributes[names[i]] = allAttrs[names[i]];
|
||||
}
|
||||
}
|
||||
@@ -163,7 +178,7 @@ define([
|
||||
|
||||
ArchEditorControl.prototype.getCreateNewDecorator = function() {
|
||||
return this._client.decoratorManager.getDecoratorForWidget(
|
||||
'EllipseDecorator',
|
||||
'LayerDecorator',
|
||||
'EasyDAG'
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
define([
|
||||
'panels/TextEditor/TextEditorControl',
|
||||
'deepforge/lua',
|
||||
'underscore',
|
||||
'text!./DefaultCodeTemplate.ejs'
|
||||
], function (
|
||||
TextEditorControl,
|
||||
lua,
|
||||
_,
|
||||
CODE_TEMPLATE
|
||||
) {
|
||||
@@ -53,19 +55,95 @@ define([
|
||||
match = returned.match(/[a-zA-Z0-9_]+/),
|
||||
node = this._client.getNode(id),
|
||||
nodeName = node.getAttribute('name'),
|
||||
name;
|
||||
baseName = null,
|
||||
basePath,
|
||||
name,
|
||||
ast;
|
||||
|
||||
if (match) {
|
||||
name = match[0];
|
||||
}
|
||||
|
||||
// Check if the base needs to be updated
|
||||
try {
|
||||
ast = lua.parser.parse(text);
|
||||
lua.codegen.traverse(curr => {
|
||||
// Check for inheritance of the given type
|
||||
if (curr.type === 'expr.call') {
|
||||
var object = curr.func.self.val,
|
||||
method = curr.func.key.val,
|
||||
child,
|
||||
base;
|
||||
|
||||
if (object === 'torch' && method === 'class') {
|
||||
child = curr.args[0];
|
||||
base = curr.args[1];
|
||||
|
||||
// If the first argument is the given class, get the base
|
||||
if (child.type === 'const.string' && child.val === name) {
|
||||
if (base && base.type === 'const.string') {
|
||||
baseName = base.val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})(ast);
|
||||
|
||||
// Get the base path from the base name
|
||||
basePath = this.getBasePathFromName(baseName);
|
||||
if (!basePath) {
|
||||
this._logger.warn(`Could not find base type matching the name ${baseName}`);
|
||||
}
|
||||
} catch(e) {
|
||||
this._logger.warn(`Invalid lua code. Parser failed: ${e}`);
|
||||
}
|
||||
|
||||
this._client.startTransaction(`Updating class "${name || nodeName}"`);
|
||||
if (name) {
|
||||
this._client.setAttributes(id, 'name', name);
|
||||
}
|
||||
if (basePath) {
|
||||
this._client.setBase(id, basePath);
|
||||
} else { // Set base back to 'Complex'
|
||||
while (node && (node.getAttribute('name') !== 'Complex' ||
|
||||
node.isAbstract() !== true)) {
|
||||
node = this._client.getNode(node.getBaseId());
|
||||
}
|
||||
|
||||
if (node) { // node is the base class type
|
||||
this._client.setBase(id, node.getId());
|
||||
} else {
|
||||
this._logger.warn(`Could not find the base class type from ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
TextEditorControl.prototype.saveTextFor.call(this, id, text);
|
||||
this._client.completeTransaction();
|
||||
};
|
||||
|
||||
ClassCodeEditorControl.prototype.getBasePathFromName = function (baseName) {
|
||||
var metanodes = this._client.getAllMetaNodes(),
|
||||
nameMatches = [],
|
||||
classNode,
|
||||
i;
|
||||
|
||||
for (i = metanodes.length; i--;) {
|
||||
if (metanodes[i].getAttribute('name') === baseName) {
|
||||
nameMatches.push(metanodes[i]);
|
||||
}
|
||||
if (metanodes[i].getAttribute('name') === 'Complex') {
|
||||
classNode = metanodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = nameMatches.length; i--;) {
|
||||
if (this._client.isTypeOf(nameMatches[i].getId(), classNode.getId())) {
|
||||
return nameMatches[i].getId();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return ClassCodeEditorControl;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,377 @@
|
||||
/*globals define, WebGMEGlobal*/
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'js/Constants',
|
||||
'deepforge/utils'
|
||||
], function (
|
||||
CONSTANTS,
|
||||
utils
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var ExecutionIndexControl;
|
||||
|
||||
ExecutionIndexControl = function (options) {
|
||||
|
||||
this._logger = options.logger.fork('Control');
|
||||
|
||||
this._client = options.client;
|
||||
this._embedded = options.embedded;
|
||||
|
||||
// Initialize core collections and variables
|
||||
this._widget = options.widget;
|
||||
|
||||
this._currentNodeId = null;
|
||||
this.displayedExecutions = {};
|
||||
this._linesForExecution = {};
|
||||
this._lineToExec = {};
|
||||
this._pipelineNames = {};
|
||||
|
||||
this.abbrToId = {};
|
||||
this.abbrFor = {};
|
||||
|
||||
this._initWidgetEventHandlers();
|
||||
|
||||
this._logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._initWidgetEventHandlers = function () {
|
||||
this._widget.setExecutionDisplayed = this.setExecutionDisplayed.bind(this);
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.setExecutionDisplayed = function (id, bool) {
|
||||
var lines = this._linesForExecution[id] || [],
|
||||
otherLines,
|
||||
wasMultiLine = this.displayedExecCount() > 1,
|
||||
isMultiLine;
|
||||
|
||||
this._logger.info(`setting execution ${id} to ${bool ? 'displayed' : 'hidden'}`);
|
||||
this.displayedExecutions[id] = bool;
|
||||
|
||||
// If we just crossed the multi line threshold, then update all the lines
|
||||
isMultiLine = this.displayedExecCount() > 1;
|
||||
if (isMultiLine !== wasMultiLine) {
|
||||
// Refresh the other lines visible
|
||||
otherLines = Object.keys(this.displayedExecutions)
|
||||
.filter(eId => this.displayedExecutions[eId] && (eId !== id))
|
||||
.map(id => this._linesForExecution[id])
|
||||
.reduce((l1, l2) => l1.concat(l2), []);
|
||||
|
||||
this._updateLines(otherLines, false);
|
||||
this._updateLines(otherLines, true);
|
||||
}
|
||||
|
||||
this._updateLines(lines, bool);
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._updateLines = function (lines, added) {
|
||||
var action = added ? 'addNode' : 'removeNode';
|
||||
|
||||
// If removing, just get the ids
|
||||
lines = !added ? lines : lines.map(line => this._getObjectDescriptor(line));
|
||||
|
||||
// update the given lines
|
||||
for (var i = lines.length; i--;) {
|
||||
this._widget[action](lines[i]);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.clearTerritory = function () {
|
||||
if (this._territoryId) {
|
||||
this._client.removeUI(this._territoryId);
|
||||
this._territoryId = null;
|
||||
}
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
|
||||
ExecutionIndexControl.prototype.selectedObjectChanged = function (nodeId) {
|
||||
var self = this;
|
||||
|
||||
self._logger.debug('activeObject nodeId \'' + nodeId + '\'');
|
||||
|
||||
// Remove current territory patterns
|
||||
self.clearTerritory();
|
||||
self._currentNodeId = nodeId;
|
||||
|
||||
if (typeof self._currentNodeId === 'string') {
|
||||
// Create a territory for the executions
|
||||
self._selfPatterns = {};
|
||||
|
||||
self._territoryId = self._client.addUI(self, function (events) {
|
||||
self._eventCallback(events);
|
||||
});
|
||||
|
||||
// Update the territory
|
||||
self._selfPatterns[nodeId] = {children: 4};
|
||||
self._client.updateTerritory(self._territoryId, self._selfPatterns);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.getUniqAbbreviation = function(desc) {
|
||||
// Get a unique abbreviation for the given execution
|
||||
var base = utils.abbr(desc.name).toLowerCase(),
|
||||
abbr = base,
|
||||
oldAbbr = this.abbrFor[desc.id],
|
||||
i = 2;
|
||||
|
||||
// Make sure it is unique!
|
||||
while (this.abbrToId[abbr] && this.abbrToId[abbr] !== desc.id) {
|
||||
abbr = base + i;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (oldAbbr !== undefined) { // updating abbr
|
||||
delete this.abbrToId[oldAbbr];
|
||||
}
|
||||
|
||||
this.abbrToId[abbr] = desc.id;
|
||||
this.abbrFor[desc.id] = abbr;
|
||||
return abbr;
|
||||
};
|
||||
|
||||
// This next function retrieves the relevant node information for the widget
|
||||
ExecutionIndexControl.prototype._getObjectDescriptor = function (nodeId) {
|
||||
var node = this._client.getNode(nodeId),
|
||||
childIds,
|
||||
desc,
|
||||
base,
|
||||
type;
|
||||
|
||||
if (node) {
|
||||
base = this._client.getNode(node.getBaseId());
|
||||
type = base.getAttribute('name');
|
||||
desc = {
|
||||
id: node.getId(),
|
||||
type: type,
|
||||
name: node.getAttribute('name')
|
||||
};
|
||||
|
||||
if (type === 'Execution') {
|
||||
desc.status = node.getAttribute('status');
|
||||
desc.originTime = node.getAttribute('createdAt');
|
||||
desc.originId = node.getPointer('origin').to;
|
||||
desc.pipelineName = this._pipelineNames[desc.originId];
|
||||
desc.startTime = node.getAttribute('startTime');
|
||||
desc.endTime = node.getAttribute('endTime');
|
||||
this._logger.debug(`Looking up pipeline name for ${desc.name}: ${desc.pipelineName}`);
|
||||
// Add the (unique) abbreviation of the execution!
|
||||
desc.abbr = this.getUniqAbbreviation(desc);
|
||||
|
||||
// Create a territory for this origin and update it!
|
||||
this._selfPatterns[desc.originId] = {children: 0};
|
||||
setTimeout(() => this._client.updateTerritory(this._territoryId, this._selfPatterns), 0);
|
||||
} else if (type === 'Line') {
|
||||
desc = this.getLineDesc(node);
|
||||
} else if (type === 'Pipeline') {
|
||||
desc.execs = node.getMemberIds('executions');
|
||||
this._pipelineNames[desc.id] = desc.name;
|
||||
} else if (type === 'Graph') {
|
||||
childIds = node.getChildrenIds();
|
||||
desc.lines = childIds.map(id => {
|
||||
var n = this._client.getNode(id);
|
||||
return this.getLineDesc(n);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return desc;
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.getLineDesc = function (node) {
|
||||
var id = node.getId(),
|
||||
graphId = node.getParentId(),
|
||||
jobId = this._client.getNode(graphId).getParentId(),
|
||||
execId = this._client.getNode(jobId).getParentId(),
|
||||
points,
|
||||
desc;
|
||||
|
||||
points = node.getAttribute('points').split(';')
|
||||
.filter(data => !!data) // remove any ''
|
||||
.map(pair => {
|
||||
var nums = pair.split(',').map(num => parseFloat(num));
|
||||
return {
|
||||
x: nums[0],
|
||||
y: nums[1]
|
||||
};
|
||||
});
|
||||
|
||||
desc = {
|
||||
id: id,
|
||||
execId: execId,
|
||||
lineName: node.getAttribute('name'),
|
||||
name: node.getAttribute('name'),
|
||||
type: 'line',
|
||||
points: points
|
||||
};
|
||||
|
||||
if (!this._lineToExec[id]) {
|
||||
// Update records
|
||||
if (!this._linesForExecution[execId]) {
|
||||
this._linesForExecution[execId] = [];
|
||||
}
|
||||
this._linesForExecution[execId].push(id);
|
||||
this._lineToExec[id] = execId;
|
||||
}
|
||||
|
||||
// If there are multiple executions, add the exec's abbr
|
||||
var displayedCnt = this.displayedExecCount(),
|
||||
execAbbr;
|
||||
|
||||
if (displayedCnt > 1) {
|
||||
execAbbr = this.abbrFor[execId] || this._getObjectDescriptor(execId).abbr;
|
||||
desc.name = `${desc.name} (${execAbbr})`;
|
||||
}
|
||||
|
||||
return desc;
|
||||
};
|
||||
|
||||
/* * * * * * * * Node Event Handling * * * * * * * */
|
||||
ExecutionIndexControl.prototype._eventCallback = function (events) {
|
||||
var event;
|
||||
|
||||
events = events.filter(event => event.eid !== this._currentNodeId);
|
||||
|
||||
this._logger.debug('received \'' + events.length + '\' events');
|
||||
|
||||
for (var i = events.length; i--;) {
|
||||
event = events[i];
|
||||
switch (event.etype) {
|
||||
|
||||
case CONSTANTS.TERRITORY_EVENT_LOAD:
|
||||
this._onLoad(event.eid);
|
||||
break;
|
||||
case CONSTANTS.TERRITORY_EVENT_UPDATE:
|
||||
this._onUpdate(event.eid);
|
||||
break;
|
||||
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
|
||||
this._onUnload(event.eid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._logger.debug('finished processing events!');
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._onLoad = function (gmeId) {
|
||||
var desc = this._getObjectDescriptor(gmeId);
|
||||
this._logger.debug(`Loading node of type ${desc.type}`);
|
||||
if (desc.type === 'Execution') {
|
||||
this._logger.debug('Adding node to widget...');
|
||||
this._logger.debug('desc:', desc);
|
||||
this._widget.addNode(desc);
|
||||
} else if (desc.type === 'line' && this.isLineDisplayed(desc)) {
|
||||
this._widget.addNode(desc);
|
||||
} else if (desc.type === 'Pipeline') {
|
||||
this.updatePipelineNames(desc);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._onUpdate = function (gmeId) {
|
||||
var desc = this._getObjectDescriptor(gmeId);
|
||||
if (desc.type === 'Execution') {
|
||||
this._widget.updateNode(desc);
|
||||
} else if (desc.type === 'line' && this.isLineDisplayed(desc)) {
|
||||
this._widget.updateNode(desc);
|
||||
} else if (desc.type === 'Pipeline') {
|
||||
this.updatePipelineNames(desc);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.updatePipelineNames = function (desc) {
|
||||
// Get all associated executions and update their pipeline name
|
||||
this._logger.debug('updating pipeline name for ' + desc.execs.join(', '));
|
||||
for (var i = desc.execs.length; i--;) {
|
||||
this._widget.updatePipelineName(desc.execs[i], desc.name);
|
||||
}
|
||||
|
||||
if (desc.execs.length === 0) {
|
||||
// Executions have been deleted - no longer relevant
|
||||
this._logger.debug('pipeline has 0 executions... removing it', desc.id);
|
||||
delete this._selfPatterns[desc.id];
|
||||
delete this._pipelineNames[desc.id];
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._onUnload = function (id) {
|
||||
var execId = this._lineToExec[id],
|
||||
abbr;
|
||||
|
||||
if (execId) { // it is a line
|
||||
delete this._lineToExec[id];
|
||||
for (var k = this._linesForExecution[execId].length; k--;) {
|
||||
if (this._linesForExecution[execId][k] === id) {
|
||||
this._linesForExecution[execId].splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.abbrFor[id]) {
|
||||
abbr = this.abbrFor[id];
|
||||
delete this.abbrFor[id];
|
||||
delete this.abbrToId[abbr];
|
||||
}
|
||||
|
||||
this._widget.removeNode(id);
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.isLineDisplayed = function (line) {
|
||||
// lines are only displayed if their execution is checked
|
||||
return this.displayedExecutions[line.execId];
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.displayedExecCount = function () {
|
||||
return Object.keys(this.displayedExecutions)
|
||||
.map(id => this.displayedExecutions[id])
|
||||
.filter(shown => shown).length;
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
|
||||
if (this._currentNodeId === activeObjectId) {
|
||||
// The same node selected as before - do not trigger
|
||||
} else {
|
||||
this.selectedObjectChanged(activeObjectId);
|
||||
}
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ExecutionIndexControl.prototype.destroy = function () {
|
||||
this._detachClientEventListeners();
|
||||
this.clearTerritory();
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._attachClientEventListeners = function () {
|
||||
this._detachClientEventListeners();
|
||||
if (!this._embedded) {
|
||||
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
|
||||
this._stateActiveObjectChanged, this);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype._detachClientEventListeners = function () {
|
||||
if (!this._embedded) {
|
||||
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
|
||||
this._stateActiveObjectChanged);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.onActivate = function () {
|
||||
this._attachClientEventListeners();
|
||||
|
||||
if (typeof this._currentNodeId === 'string') {
|
||||
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
|
||||
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
|
||||
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexControl.prototype.onDeactivate = function () {
|
||||
this._detachClientEventListeners();
|
||||
};
|
||||
|
||||
return ExecutionIndexControl;
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
/*globals define, _, WebGMEGlobal*/
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'js/PanelBase/PanelBase',
|
||||
'js/PanelManager/IActivePanel',
|
||||
'widgets/ExecutionIndex/ExecutionIndexWidget',
|
||||
'./ExecutionIndexControl'
|
||||
], function (
|
||||
PanelBase,
|
||||
IActivePanel,
|
||||
ExecutionIndexWidget,
|
||||
ExecutionIndexControl
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var ExecutionIndexPanel;
|
||||
|
||||
ExecutionIndexPanel = function (layoutManager, params) {
|
||||
var options = {};
|
||||
//set properties from options
|
||||
options[PanelBase.OPTIONS.LOGGER_INSTANCE_NAME] = 'ExecutionIndexPanel';
|
||||
options[PanelBase.OPTIONS.FLOATING_TITLE] = true;
|
||||
|
||||
//call parent's constructor
|
||||
PanelBase.apply(this, [options, layoutManager]);
|
||||
|
||||
this._client = params.client;
|
||||
this._embedded = params.embedded;
|
||||
|
||||
//initialize UI
|
||||
this._initialize();
|
||||
|
||||
this.logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
//inherit from PanelBase
|
||||
_.extend(ExecutionIndexPanel.prototype, PanelBase.prototype);
|
||||
_.extend(ExecutionIndexPanel.prototype, IActivePanel.prototype);
|
||||
|
||||
ExecutionIndexPanel.prototype._initialize = function () {
|
||||
//set Widget title
|
||||
this.widget = new ExecutionIndexWidget(this.logger, this.$el);
|
||||
|
||||
this.control = new ExecutionIndexControl({
|
||||
logger: this.logger,
|
||||
client: this._client,
|
||||
embedded: this._embedded,
|
||||
widget: this.widget
|
||||
});
|
||||
|
||||
this.onActivate();
|
||||
};
|
||||
|
||||
/* OVERRIDE FROM WIDGET-WITH-HEADER */
|
||||
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
|
||||
ExecutionIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
|
||||
//apply parent's onReadOnlyChanged
|
||||
PanelBase.prototype.onReadOnlyChanged.call(this, isReadOnly);
|
||||
|
||||
};
|
||||
|
||||
ExecutionIndexPanel.prototype.onResize = function (width, height) {
|
||||
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
|
||||
this.widget.onWidgetContainerResize(width, height);
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ExecutionIndexPanel.prototype.destroy = function () {
|
||||
this.control.destroy();
|
||||
this.widget.destroy();
|
||||
|
||||
PanelBase.prototype.destroy.call(this);
|
||||
WebGMEGlobal.KeyboardManager.setListener(undefined);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
ExecutionIndexPanel.prototype.onActivate = function () {
|
||||
this.widget.onActivate();
|
||||
this.control.onActivate();
|
||||
WebGMEGlobal.KeyboardManager.setListener(this.widget);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
ExecutionIndexPanel.prototype.onDeactivate = function () {
|
||||
this.widget.onDeactivate();
|
||||
this.control.onDeactivate();
|
||||
WebGMEGlobal.KeyboardManager.setListener(undefined);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
return ExecutionIndexPanel;
|
||||
});
|
||||
@@ -1,15 +1,14 @@
|
||||
/*globals define, WebGMEGlobal */
|
||||
/*jshint browser: true*/
|
||||
/**
|
||||
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 24 2016 10:15:19 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define([
|
||||
'js/Constants',
|
||||
'deepforge/Constants',
|
||||
'panels/EasyDAG/EasyDAGControl',
|
||||
'deepforge/viz/PipelineControl',
|
||||
'underscore'
|
||||
], function (
|
||||
GME_CONSTANTS,
|
||||
CONSTANTS,
|
||||
EasyDAGControl,
|
||||
PipelineControl,
|
||||
@@ -62,7 +61,7 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.etype === CONSTANTS.TERRITORY_EVENT_UNLOAD) {
|
||||
if (event.etype === GME_CONSTANTS.TERRITORY_EVENT_UNLOAD) {
|
||||
this.originId = null;
|
||||
this._widget.onOriginDeleted();
|
||||
} else {
|
||||
@@ -90,6 +89,65 @@ define([
|
||||
};
|
||||
};
|
||||
|
||||
ExecutionViewControl.prototype._getObjectDescriptor = function(id) {
|
||||
var desc = PipelineControl.prototype._getObjectDescriptor.call(this, id),
|
||||
childrenIds,
|
||||
node,
|
||||
opId;
|
||||
|
||||
// If it is a job, add the operation attributes
|
||||
if (this.hasMetaName(id, 'Job')) {
|
||||
node = this._client.getNode(id);
|
||||
childrenIds = node.getChildrenIds();
|
||||
opId = childrenIds.find(id => this.hasMetaName(id, 'Operation'));
|
||||
|
||||
desc.opAttributes = {};
|
||||
if (opId) {
|
||||
var opNode = this._client.getNode(opId),
|
||||
attrs,
|
||||
allAttrs = {},
|
||||
hiddenAttrs = [
|
||||
CONSTANTS.LINE_OFFSET,
|
||||
'code',
|
||||
'name'
|
||||
],
|
||||
i;
|
||||
|
||||
opNode.getValidAttributeNames().concat(opNode.getAttributeNames())
|
||||
.forEach(attr => allAttrs[attr] = true);
|
||||
|
||||
// Remove skip values
|
||||
hiddenAttrs.forEach(attr => delete allAttrs[attr]);
|
||||
|
||||
attrs = Object.keys(allAttrs);
|
||||
for (i = attrs.length; i--;) {
|
||||
desc.opAttributes[attrs[i]] = {
|
||||
name: attrs[i],
|
||||
value: opNode.getAttribute(attrs[i]),
|
||||
type: 'string'
|
||||
};
|
||||
}
|
||||
|
||||
// Pointers
|
||||
var allPtrs = {},
|
||||
ptrs;
|
||||
|
||||
opNode.getValidPointerNames().concat(opNode.getPointerNames())
|
||||
.filter(ptr => ptr !== 'base')
|
||||
.forEach(ptr => allPtrs[ptr] = true);
|
||||
|
||||
ptrs = Object.keys(allPtrs);
|
||||
for (i = ptrs.length; i--;) {
|
||||
desc.pointers[ptrs[i]] = opNode.getPointer(ptrs[i]).to;
|
||||
}
|
||||
|
||||
} else {
|
||||
this.logger.error(`Job "${desc.name}" (${id}) is missing an operation!`);
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
};
|
||||
|
||||
ExecutionViewControl.prototype._onLoad = function(id) {
|
||||
var desc = this._getObjectDescriptor(id);
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
/*globals DeepForge, define, $, Materialize, WebGMEGlobal*/
|
||||
/*globals define, $, WebGMEGlobal*/
|
||||
// These are actions defined for specific meta types. They are evaluated from
|
||||
// the context of the ForgeActionButton
|
||||
define([
|
||||
'panel/FloatingActionButton/styles/Materialize',
|
||||
'q',
|
||||
'js/RegistryKeys',
|
||||
'deepforge/globals'
|
||||
], function(
|
||||
Materialize,
|
||||
Q,
|
||||
REGISTRY_KEYS
|
||||
REGISTRY_KEYS,
|
||||
DeepForge
|
||||
) {
|
||||
var FILE_UPLOAD_INPUT = $('<input type="file" />');
|
||||
|
||||
@@ -103,6 +106,7 @@ define([
|
||||
name: `Return to ${fromType}`,
|
||||
icon: 'input',
|
||||
priority: 2,
|
||||
color: 'teal',
|
||||
filter: () => {
|
||||
return DeepForge.last[fromType];
|
||||
},
|
||||
@@ -112,6 +116,7 @@ define([
|
||||
name: `Delete ${type} Definition`,
|
||||
icon: 'delete',
|
||||
priority: 1,
|
||||
color: 'red',
|
||||
action: function() {
|
||||
// Delete and go to the last pipeline?
|
||||
var node = this.client.getNode(this._currentNodeId),
|
||||
@@ -134,13 +139,19 @@ define([
|
||||
}
|
||||
];
|
||||
|
||||
var makeRestartButton = function(name, pluginId) {
|
||||
var makeRestartButton = function(name, pluginId, hotkeys) {
|
||||
return {
|
||||
name: 'Restart ' + name,
|
||||
icon: 'replay',
|
||||
priority: 1000,
|
||||
color: 'red',
|
||||
hotkey: hotkeys && 'shift enter',
|
||||
filter: function() {
|
||||
// Only show if stopped!
|
||||
return !this.isRunning();
|
||||
},
|
||||
action: function(event) {
|
||||
this.runExecutionPlugin(pluginId, event.shiftKey);
|
||||
this.runExecutionPlugin(pluginId, {useSecondary: event.shiftKey});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -215,9 +226,47 @@ define([
|
||||
icon: 'play_for_work',
|
||||
priority: 1,
|
||||
href: download.execFiles
|
||||
},
|
||||
// Stop execution button
|
||||
{
|
||||
name: 'Stop Current Job',
|
||||
icon: 'stop',
|
||||
priority: 1001,
|
||||
filter: function() {
|
||||
return this.isRunning();
|
||||
},
|
||||
action: function() {
|
||||
this.stopJob();
|
||||
}
|
||||
}
|
||||
],
|
||||
Execution: [
|
||||
makeRestartButton('Execution', 'ExecutePipeline', true),
|
||||
// Stop execution button
|
||||
{
|
||||
name: 'Stop Running Execution',
|
||||
icon: 'stop',
|
||||
priority: 1001,
|
||||
hotkey: 'shift enter',
|
||||
filter: function() {
|
||||
return this.isRunning();
|
||||
},
|
||||
action: function() {
|
||||
// Stop every running job
|
||||
var execNode = this.client.getNode(this._currentNodeId),
|
||||
jobIds = execNode.getChildrenIds(),
|
||||
msg = `Canceling ${execNode.getAttribute('name')} execution`;
|
||||
|
||||
this.client.startTransaction(msg);
|
||||
jobIds.map(id => this.client.getNode(id))
|
||||
.filter(job => this.isRunning(job)) // get running jobs
|
||||
.forEach(job => this.stopJob(job)); // stop them
|
||||
|
||||
this.client.setAttributes(execNode.getId(), 'status', 'canceled');
|
||||
this.client.completeTransaction();
|
||||
}
|
||||
}
|
||||
],
|
||||
Execution: [makeRestartButton('Execution', 'ExecutePipeline')],
|
||||
Pipeline: [
|
||||
{
|
||||
name: 'Create new node',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*globals DeepForge, $, Materialize, define, _ */
|
||||
/*globals $, window, define, _ */
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
@@ -7,6 +7,7 @@ define([
|
||||
'panel/FloatingActionButton/FloatingActionButton',
|
||||
'deepforge/viz/PipelineControl',
|
||||
'deepforge/viz/NodePrompter',
|
||||
'deepforge/viz/Execute',
|
||||
'./Actions',
|
||||
'widgets/EasyDAG/AddNodeDialog',
|
||||
'js/RegistryKeys',
|
||||
@@ -20,12 +21,14 @@ define([
|
||||
PluginButton,
|
||||
PipelineControl,
|
||||
NodePrompter,
|
||||
Execute,
|
||||
ACTIONS,
|
||||
AddNodeDialog,
|
||||
REGISTRY_KEYS,
|
||||
META_CONSTANTS,
|
||||
Q,
|
||||
PluginConfig
|
||||
PluginConfig,
|
||||
DeepForge
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
@@ -39,6 +42,8 @@ define([
|
||||
logger: this.logger.fork('BlobClient')
|
||||
});
|
||||
|
||||
Execute.call(this, this.client, this.logger);
|
||||
this.initializeKeyListener();
|
||||
this.logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
@@ -46,9 +51,46 @@ define([
|
||||
_.extend(
|
||||
ForgeActionButton.prototype,
|
||||
PluginButton.prototype,
|
||||
Execute.prototype,
|
||||
PipelineControl.prototype
|
||||
);
|
||||
|
||||
ForgeActionButton.prototype.initializeKeyListener = function() {
|
||||
// add key listener to parent?
|
||||
this.oldOnKeyDown = document.body.onkeydown;
|
||||
document.onkeydown = event => {
|
||||
var keys = String.fromCharCode(event.which) || '',
|
||||
names = Object.keys(this.buttons),
|
||||
btn,
|
||||
name;
|
||||
|
||||
// Simple button detection
|
||||
if (event.which === 13) {
|
||||
keys = 'enter';
|
||||
}
|
||||
if (event.shiftKey) {
|
||||
keys = 'shift ' + keys;
|
||||
}
|
||||
|
||||
for (var i = names.length; i--;) {
|
||||
name = names[i];
|
||||
btn = this.buttons[name];
|
||||
if (btn.hotkey && btn.hotkey === keys) {
|
||||
btn.action.call(this, event);
|
||||
}
|
||||
}
|
||||
if (this.oldOnKeyDown) {
|
||||
this.oldOnKeyDown(event);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ForgeActionButton.prototype.destroy = function() {
|
||||
PluginButton.prototype.destroy.call(this);
|
||||
PipelineControl.prototype.destroy.call(this);
|
||||
document.body.onclick = this.oldOnKeyDown;
|
||||
};
|
||||
|
||||
ForgeActionButton.prototype.findActionsFor = function(nodeId) {
|
||||
var node = this.client.getNode(nodeId),
|
||||
base = this.client.getNode(node.getMetaTypeId()),
|
||||
@@ -60,7 +102,7 @@ define([
|
||||
if (!base) { // must be ROOT or FCO
|
||||
basename = node.getAttribute('name') || 'ROOT_NODE';
|
||||
actions = (ACTIONS[basename] || [])
|
||||
.filter(action => !action.filter || action.filter());
|
||||
.filter(action => !action.filter || action.filter.call(this));
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -69,7 +111,7 @@ define([
|
||||
base = this.client.getNode(base.getBaseId());
|
||||
actions = ACTIONS[basename];
|
||||
if (actions) {
|
||||
actions = actions.filter(action => !action.filter || action.filter());
|
||||
actions = actions.filter(action => !action.filter || action.filter.call(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,21 +363,5 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
ForgeActionButton.prototype.runExecutionPlugin = function(pluginId, useSecondary) {
|
||||
var context = this.client.getCurrentPluginContext(pluginId),
|
||||
name = this.client.getNode(this._currentNodeId).getAttribute('name'),
|
||||
method;
|
||||
|
||||
context.managerConfig.namespace = 'pipeline';
|
||||
method = useSecondary ? 'runBrowserPlugin' : 'runServerPlugin';
|
||||
this.client[method](pluginId, context, err => {
|
||||
if (err) {
|
||||
return Materialize.toast(`${name} failed!`, 4000);
|
||||
}
|
||||
|
||||
Materialize.toast(`${name} executed successfully!`, 2000);
|
||||
});
|
||||
};
|
||||
|
||||
return ForgeActionButton;
|
||||
});
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"GenerateArchitecture": {
|
||||
"icon": "description",
|
||||
"hotkey": "shift enter",
|
||||
"priority": -1
|
||||
},
|
||||
"ExecutePipeline": {
|
||||
"icon": "play_arrow",
|
||||
"hotkey": "shift enter",
|
||||
"color": "green",
|
||||
"priority": 1
|
||||
},
|
||||
"ImportTorch": {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*globals define, WebGMEGlobal*/
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'blob/BlobClient',
|
||||
'js/Constants',
|
||||
'js/Utils/GMEConcepts',
|
||||
'js/NodePropertyNames'
|
||||
], function (
|
||||
BlobClient,
|
||||
CONSTANTS,
|
||||
GMEConcepts,
|
||||
nodePropertyNames
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var ImageViewerControl;
|
||||
|
||||
ImageViewerControl = function (options) {
|
||||
|
||||
this._logger = options.logger.fork('Control');
|
||||
|
||||
this._client = options.client;
|
||||
|
||||
// Initialize core collections and variables
|
||||
this._widget = options.widget;
|
||||
this.blobClient = new BlobClient({
|
||||
logger: this._logger.fork('BlobClient')
|
||||
});
|
||||
|
||||
this._currentNodeId = null;
|
||||
|
||||
this._logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
|
||||
// One major concept here is with managing the territory. The territory
|
||||
// defines the parts of the project that the visualizer is interested in
|
||||
// (this allows the browser to then only load those relevant parts).
|
||||
ImageViewerControl.prototype.selectedObjectChanged = function (nodeId) {
|
||||
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
|
||||
|
||||
// Remove current territory patterns
|
||||
if (this._currentNodeId) {
|
||||
this._client.removeUI(this._territoryId);
|
||||
}
|
||||
|
||||
this._currentNodeId = nodeId;
|
||||
|
||||
if (typeof this._currentNodeId === 'string') {
|
||||
// Put new node's info into territory rules
|
||||
this._selfPatterns = {};
|
||||
this._selfPatterns[nodeId] = {children: 0}; // Territory "rule"
|
||||
this._territoryId = this._client.addUI(this, this._eventCallback.bind(this));
|
||||
this._client.updateTerritory(this._territoryId, this._selfPatterns);
|
||||
}
|
||||
};
|
||||
|
||||
// This next function retrieves the relevant node information for the widget
|
||||
ImageViewerControl.prototype._getObjectDescriptor = function (nodeId) {
|
||||
var nodeObj = this._client.getNode(nodeId),
|
||||
objDescriptor,
|
||||
hash;
|
||||
|
||||
if (nodeObj) {
|
||||
objDescriptor = {
|
||||
id: undefined,
|
||||
name: undefined
|
||||
};
|
||||
|
||||
objDescriptor.id = nodeObj.getId();
|
||||
objDescriptor.name = nodeObj.getAttribute(nodePropertyNames.Attributes.name);
|
||||
// Get the blob url
|
||||
hash = nodeObj.getAttribute('data');
|
||||
if (hash) {
|
||||
objDescriptor.src = this.blobClient.getDownloadURL(hash);
|
||||
}
|
||||
}
|
||||
|
||||
return objDescriptor;
|
||||
};
|
||||
|
||||
/* * * * * * * * Node Event Handling * * * * * * * */
|
||||
ImageViewerControl.prototype._eventCallback = function (events) {
|
||||
var i = events ? events.length : 0,
|
||||
event;
|
||||
|
||||
this._logger.debug('_eventCallback \'' + i + '\' items');
|
||||
|
||||
while (i--) {
|
||||
event = events[i];
|
||||
switch (event.etype) {
|
||||
|
||||
case CONSTANTS.TERRITORY_EVENT_LOAD:
|
||||
this._onLoad(event.eid);
|
||||
break;
|
||||
case CONSTANTS.TERRITORY_EVENT_UPDATE:
|
||||
this._onUpdate(event.eid);
|
||||
break;
|
||||
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
|
||||
this._onUnload(event.eid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
|
||||
};
|
||||
|
||||
ImageViewerControl.prototype._onUpdate =
|
||||
ImageViewerControl.prototype._onLoad = function (gmeId) {
|
||||
var description = this._getObjectDescriptor(gmeId);
|
||||
this._widget.updateImage(description.src);
|
||||
};
|
||||
|
||||
ImageViewerControl.prototype._onUnload = function (gmeId) {
|
||||
this._widget.removeImage(gmeId);
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ImageViewerControl.prototype.onActivate = function () {
|
||||
if (typeof this._currentNodeId === 'string') {
|
||||
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
|
||||
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
|
||||
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
|
||||
}
|
||||
};
|
||||
|
||||
ImageViewerControl.prototype.destroy =
|
||||
ImageViewerControl.prototype.onDeactivate = function () {
|
||||
};
|
||||
|
||||
return ImageViewerControl;
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
/*globals define, _, WebGMEGlobal*/
|
||||
/*jshint browser: true*/
|
||||
/**
|
||||
* Generated by VisualizerGenerator 1.7.0 from webgme on Sat Jul 30 2016 07:12:17 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define(['js/PanelBase/PanelBaseWithHeader',
|
||||
'js/PanelManager/IActivePanel',
|
||||
'widgets/ImageViewer/ImageViewerWidget',
|
||||
'./ImageViewerControl'
|
||||
], function (PanelBaseWithHeader,
|
||||
IActivePanel,
|
||||
ImageViewerWidget,
|
||||
ImageViewerControl) {
|
||||
'use strict';
|
||||
|
||||
var ImageViewerPanel;
|
||||
|
||||
ImageViewerPanel = function (layoutManager, params) {
|
||||
var options = {};
|
||||
//set properties from options
|
||||
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ImageViewerPanel';
|
||||
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
|
||||
|
||||
//call parent's constructor
|
||||
PanelBaseWithHeader.apply(this, [options, layoutManager]);
|
||||
|
||||
this._client = params.client;
|
||||
|
||||
//initialize UI
|
||||
this._initialize();
|
||||
|
||||
this.logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
//inherit from PanelBaseWithHeader
|
||||
_.extend(ImageViewerPanel.prototype, PanelBaseWithHeader.prototype);
|
||||
_.extend(ImageViewerPanel.prototype, IActivePanel.prototype);
|
||||
|
||||
ImageViewerPanel.prototype._initialize = function () {
|
||||
var self = this;
|
||||
|
||||
//set Widget title
|
||||
this.setTitle('');
|
||||
|
||||
this.widget = new ImageViewerWidget(this.logger, this.$el);
|
||||
|
||||
this.widget.setTitle = function (title) {
|
||||
self.setTitle(title);
|
||||
};
|
||||
|
||||
this.control = new ImageViewerControl({
|
||||
logger: this.logger,
|
||||
client: this._client,
|
||||
widget: this.widget
|
||||
});
|
||||
|
||||
this.onActivate();
|
||||
};
|
||||
|
||||
/* OVERRIDE FROM WIDGET-WITH-HEADER */
|
||||
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
|
||||
ImageViewerPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
|
||||
//apply parent's onReadOnlyChanged
|
||||
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
|
||||
|
||||
};
|
||||
|
||||
ImageViewerPanel.prototype.onResize = function (width, height) {
|
||||
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
|
||||
this.widget.onWidgetContainerResize(width, height);
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ImageViewerPanel.prototype.destroy = function () {
|
||||
this.control.destroy();
|
||||
this.widget.destroy();
|
||||
|
||||
PanelBaseWithHeader.prototype.destroy.call(this);
|
||||
WebGMEGlobal.KeyboardManager.setListener(undefined);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
ImageViewerPanel.prototype.onActivate = function () {
|
||||
this.widget.onActivate();
|
||||
this.control.onActivate();
|
||||
WebGMEGlobal.KeyboardManager.setListener(this.widget);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
ImageViewerPanel.prototype.onDeactivate = function () {
|
||||
this.widget.onDeactivate();
|
||||
this.control.onDeactivate();
|
||||
WebGMEGlobal.KeyboardManager.setListener(undefined);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
};
|
||||
|
||||
return ImageViewerPanel;
|
||||
});
|
||||
@@ -68,6 +68,9 @@ define([
|
||||
|
||||
// The OperationCodeEditor should receive the
|
||||
if (!this.readOnly) {
|
||||
// Pass a reference to the panel
|
||||
this._panels[0].control.currentJobId = nodeId;
|
||||
|
||||
// Get the operation base node id and pass it to OpCodeEditor selObjChanged
|
||||
if (this._territoryId) {
|
||||
this._client.removeUI(this._territoryId);
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'panels/TextEditor/TextEditorControl'
|
||||
'panels/TextEditor/TextEditorControl',
|
||||
'deepforge/LayerParser',
|
||||
'deepforge/utils',
|
||||
'deepforge/Constants'
|
||||
], function (
|
||||
TextEditorControl
|
||||
TextEditorControl,
|
||||
LayerParser,
|
||||
utils,
|
||||
Constants
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
@@ -50,62 +56,120 @@ define([
|
||||
};
|
||||
|
||||
LayerEditorControl.prototype.saveTextFor = function (id, text) {
|
||||
var r = /:__init\((.*)\)/,
|
||||
match = text.match(r),
|
||||
textMatch = match && match[1],
|
||||
node = this._client.getNode(id),
|
||||
var node = this._client.getNode(id),
|
||||
currentAttrs = node.getValidAttributeNames(),
|
||||
attributes = [],
|
||||
msg = `Updating layer definition for ${node.getAttribute('name')}`;
|
||||
types,
|
||||
ctorAttrs = [],
|
||||
setterNames,
|
||||
schema,
|
||||
currentPtrs = {base: true},
|
||||
type,
|
||||
ptr,
|
||||
msg = `Updating layer definition for ${node.getAttribute('name')}`,
|
||||
i;
|
||||
|
||||
// Parse the attributes and update the node!
|
||||
if (textMatch) {
|
||||
attributes = textMatch.split(',')
|
||||
.map(arg => arg.replace(/\s+/g, '')) // trim white space
|
||||
.filter(arg => !!arg); // no empty strings!
|
||||
// Parse the ctorAttrs and update the node!
|
||||
var layerSchema = LayerParser.parse(text);
|
||||
if (!layerSchema) {
|
||||
return TextEditorControl.prototype.saveTextFor.call(this, id, text);
|
||||
}
|
||||
|
||||
if (layerSchema.params) {
|
||||
ctorAttrs = layerSchema.params;
|
||||
} else { // inheriting __init
|
||||
attributes = this.getInheritedAttrs(text);
|
||||
ctorAttrs = this.getInheritedAttrs(layerSchema);
|
||||
}
|
||||
|
||||
this._client.startTransaction(msg);
|
||||
|
||||
TextEditorControl.prototype.saveTextFor.call(this, id, text);
|
||||
this._client.setAttributes(id, 'name', layerSchema.name);
|
||||
|
||||
this._logger.debug(`Setting ctor args to ${ctorAttrs.join(',')}`);
|
||||
this._client.setAttributes(id, Constants.CTOR_ARGS_ATTR, ctorAttrs.join(','));
|
||||
|
||||
types = layerSchema.types || {};
|
||||
schema = this.getPointerMeta();
|
||||
|
||||
// Handle pointer types
|
||||
for (i = ctorAttrs.length; i--;) {
|
||||
type = types[ctorAttrs[i]];
|
||||
if (type && type.substring(0, 3) === 'nn.') {
|
||||
ptr = ctorAttrs.splice(i, 1)[0];
|
||||
this._client.setPointerMeta(id, ptr, schema);
|
||||
currentPtrs[ptr] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove old pointers
|
||||
node.getPointerNames().filter(ptr => !currentPtrs[ptr])
|
||||
.forEach(ptr => this._client.deleteMetaPointer(id, ptr));
|
||||
|
||||
// Remove old attributes
|
||||
_.difference(currentAttrs, attributes)
|
||||
setterNames = Object.keys(layerSchema.setters);
|
||||
_.difference(currentAttrs, ctorAttrs, setterNames)
|
||||
.forEach(attr => this._client.removeAttributeSchema(id, attr));
|
||||
|
||||
attributes.forEach((attr, i) =>
|
||||
this._client.setAttributeSchema(id, attr, {type: 'string', argindex: i}));
|
||||
// Add setters
|
||||
for (i = setterNames.length; i--;) {
|
||||
schema = utils.getSetterSchema(setterNames[i], layerSchema.setters, layerSchema.defaults);
|
||||
// Get setter attr schema
|
||||
if (schema.hasOwnProperty('default')) {
|
||||
this._client.setAttributes(id, setterNames[i], schema.default);
|
||||
delete schema.default;
|
||||
}
|
||||
if (types[setterNames[i]]) {
|
||||
schema.type = types[setterNames[i]];
|
||||
}
|
||||
this._client.setAttributeSchema(id, setterNames[i], schema);
|
||||
}
|
||||
|
||||
ctorAttrs.forEach(attr =>
|
||||
this._client.setAttributeSchema(id, attr, {
|
||||
type: types[attr] || 'string'
|
||||
})
|
||||
);
|
||||
|
||||
this._client.completeTransaction();
|
||||
};
|
||||
|
||||
LayerEditorControl.prototype.getInheritedAttrs = function (code) {
|
||||
LayerEditorControl.prototype.getPointerMeta = function () {
|
||||
var archNode = this._client.getAllMetaNodes()
|
||||
.find(node => node.getAttribute('name') === 'Architecture');
|
||||
|
||||
if (!archNode) {
|
||||
throw 'Could not find the "Architecture" node!';
|
||||
}
|
||||
|
||||
return {
|
||||
min: 1,
|
||||
max: 1,
|
||||
items: [
|
||||
{
|
||||
id: archNode.getId(),
|
||||
max: 1
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
LayerEditorControl.prototype.getInheritedAttrs = function (layerSchema) {
|
||||
// Get the base class
|
||||
var r = /torch.class\((.*)\)/,
|
||||
match = code.match(r),
|
||||
baseType,
|
||||
metanode,
|
||||
textMatch = match && match[1];
|
||||
var metanode;
|
||||
|
||||
if (textMatch) {
|
||||
baseType = textMatch.split(',')[1]
|
||||
.replace(/^\s*['"]nn\./, '')
|
||||
.replace(/['"]\s*$/, '');
|
||||
|
||||
this._logger.debug(`inheriting the attributes from ${baseType}`);
|
||||
if (layerSchema.baseType) {
|
||||
this._logger.debug(`inheriting the attributes from ${layerSchema.baseType}`);
|
||||
|
||||
// Get the meta node and valid attribute names
|
||||
metanode = this._client.getAllMetaNodes()
|
||||
.find(node => node.getAttribute('name') === baseType);
|
||||
.find(node => node.getAttribute('name') === layerSchema.baseType);
|
||||
|
||||
if (metanode) {
|
||||
return metanode.getValidAttributeNames()
|
||||
.filter(attr => attr !== 'name');
|
||||
} else {
|
||||
// Check if the type is known by torch
|
||||
this._logger.warn(`Unknown base type ${baseType}. Assuming attributes are []`);
|
||||
this._logger.warn(`Unknown base type ${layerSchema.baseType}. Assuming attributes are []`);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
|
||||
@@ -83,17 +83,20 @@ define([
|
||||
|
||||
// Check if it is a line
|
||||
if (desc.id !== this._currentNodeId) {
|
||||
var points = (node.getAttribute('points') || '').split(';')
|
||||
.map(pair => {
|
||||
var nums = pair.split(','),
|
||||
x = +nums[0],
|
||||
y = +nums[1];
|
||||
var rawPoints = node.getAttribute('points') || '',
|
||||
points = rawPoints.split(';')
|
||||
.filter(data => !!data) // remove any ''
|
||||
.map(pair => {
|
||||
var nums = pair.split(','),
|
||||
x = parseFloat(nums[0]),
|
||||
y = parseFloat(nums[1]);
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y:y
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
x: x,
|
||||
y:y
|
||||
};
|
||||
});
|
||||
desc.type = 'line';
|
||||
desc.points = points;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ define([
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this._widget.toggleEmbeddedPanel = () => this.toggleEmbeddedPanel();
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
|
||||
@@ -92,9 +94,11 @@ define([
|
||||
|
||||
// Update the territory
|
||||
this.territory[type] = {};
|
||||
this.territory[type][DeepForge.places[dirname]] = {children: 1};
|
||||
this.ui[type] = this._client.addUI(this, this.handleEvents.bind(this, type));
|
||||
this._client.updateTerritory(this.ui[type], this.territory[type]);
|
||||
DeepForge.places[dirname]().then(id => {
|
||||
this.territory[type][id] = {children: 1};
|
||||
this.ui[type] = this._client.addUI(this, this.handleEvents.bind(this, type));
|
||||
this._client.updateTerritory(this.ui[type], this.territory[type]);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ define([
|
||||
'widgets/MainView/MainViewWidget',
|
||||
'./MainViewControl',
|
||||
'panels/PipelineIndex/PipelineIndexPanel',
|
||||
'panels/ExecutionIndex/ExecutionIndexPanel',
|
||||
'deepforge/globals'
|
||||
], function (
|
||||
PanelBaseWithHeader,
|
||||
@@ -16,6 +17,7 @@ define([
|
||||
MainViewWidget,
|
||||
MainViewControl,
|
||||
PipelineIndexPanel,
|
||||
ExecutionIndexPanel,
|
||||
DeepForge
|
||||
) {
|
||||
'use strict';
|
||||
@@ -38,12 +40,14 @@ define([
|
||||
this.$nav = $('<div>', {id: 'nav-container'});
|
||||
this.$el.css({padding: 0});
|
||||
|
||||
this.embeddedPanel = new PipelineIndexPanel(layoutManager, params);
|
||||
this.$embedded = this.embeddedPanel.$el;
|
||||
this.$embedded.addClass('embedded');
|
||||
|
||||
this.$el.append(this.$nav, this.$embedded);
|
||||
|
||||
this.embeddedPanels = [
|
||||
PipelineIndexPanel,
|
||||
ExecutionIndexPanel
|
||||
];
|
||||
this.nextPanelIndex = 0;
|
||||
this._lm = layoutManager;
|
||||
this._params = params;
|
||||
this.$el.append(this.$nav);
|
||||
this._initialize();
|
||||
|
||||
this.logger.debug('ctor finished');
|
||||
@@ -66,15 +70,48 @@ define([
|
||||
widget: this.widget
|
||||
});
|
||||
|
||||
var controlObjectChanged = this.control.selectedObjectChanged;
|
||||
this.control.selectedObjectChanged = nodeId => {
|
||||
this.embeddedPanel.control.selectedObjectChanged(DeepForge.places.MyPipelines);
|
||||
return controlObjectChanged.call(this.control, nodeId);
|
||||
this.control.toggleEmbeddedPanel = this.toggleEmbeddedPanel.bind(this);
|
||||
var selectedObjectChanged = this.control.selectedObjectChanged;
|
||||
this.control.selectedObjectChanged = id => {
|
||||
this.getEmbeddedNode().then(nodeId =>
|
||||
this.embeddedPanel.control.selectedObjectChanged(nodeId));
|
||||
selectedObjectChanged.call(this.control, id);
|
||||
};
|
||||
|
||||
this.toggleEmbeddedPanel(true);
|
||||
this.onActivate();
|
||||
};
|
||||
|
||||
MainViewPanel.prototype.getEmbeddedNode = function() {
|
||||
if (this.nextPanelIndex === 1) {
|
||||
return DeepForge.places.MyPipelines();
|
||||
} else {
|
||||
return DeepForge.places.MyExecutions();
|
||||
}
|
||||
};
|
||||
|
||||
MainViewPanel.prototype.toggleEmbeddedPanel = function (silent) {
|
||||
var Panel = this.embeddedPanels[this.nextPanelIndex];
|
||||
this.nextPanelIndex = (this.nextPanelIndex + 1) % this.embeddedPanels.length;
|
||||
|
||||
if (this.embeddedPanel) { // Remove current
|
||||
this.embeddedPanel.destroy();
|
||||
this.$embedded.remove();
|
||||
}
|
||||
|
||||
this.embeddedPanel = new Panel(this._lm, this._params);
|
||||
this.$embedded = this.embeddedPanel.$el;
|
||||
this.$embedded.addClass('main-view-embedded');
|
||||
this.$el.append(this.$embedded);
|
||||
|
||||
// Call on Resize and selectedObjectChanged
|
||||
this.onResize(this.width, this.height);
|
||||
if (!silent) {
|
||||
this.getEmbeddedNode().then(nodeId =>
|
||||
this.embeddedPanel.control.selectedObjectChanged(nodeId));
|
||||
}
|
||||
};
|
||||
|
||||
/* OVERRIDE FROM WIDGET-WITH-HEADER */
|
||||
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
|
||||
MainViewPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
|
||||
@@ -98,6 +135,8 @@ define([
|
||||
margin: 'inherit'
|
||||
});
|
||||
this.embeddedPanel.onResize(embeddedWidth, height);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
define([
|
||||
'panels/TextEditor/TextEditorControl',
|
||||
'deepforge/viz/OperationControl',
|
||||
'deepforge/viz/Execute',
|
||||
'deepforge/Constants',
|
||||
'underscore'
|
||||
], function (
|
||||
TextEditorControl,
|
||||
OperationControl,
|
||||
Execute,
|
||||
CONSTANTS,
|
||||
_
|
||||
) {
|
||||
@@ -20,15 +22,23 @@ define([
|
||||
OperationCodeEditorControl = function (options) {
|
||||
options.attributeName = 'code';
|
||||
TextEditorControl.call(this, options);
|
||||
Execute.call(this, this._client, this._logger);
|
||||
this.currentJobId = null;
|
||||
};
|
||||
|
||||
_.extend(
|
||||
OperationCodeEditorControl.prototype,
|
||||
OperationControl.prototype,
|
||||
TextEditorControl.prototype
|
||||
TextEditorControl.prototype,
|
||||
Execute.prototype
|
||||
);
|
||||
|
||||
// Override ObjectDescriptor
|
||||
OperationCodeEditorControl.prototype._initWidgetEventHandlers = function () {
|
||||
TextEditorControl.prototype._initWidgetEventHandlers.call(this);
|
||||
this._widget.getOperationAttributes = this.getOperationAttributes.bind(this);
|
||||
this._widget.executeOrStopJob = this.executeOrStopJob.bind(this);
|
||||
};
|
||||
|
||||
OperationCodeEditorControl.prototype.TERRITORY_RULE = {children: 3};
|
||||
OperationCodeEditorControl.prototype._getObjectDescriptor = function (id) {
|
||||
var desc = TextEditorControl.prototype._getObjectDescriptor.call(this, id),
|
||||
@@ -58,6 +68,35 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
OperationCodeEditorControl.prototype.getOperationAttributes = function () {
|
||||
var node = this._client.getNode(this._currentNodeId),
|
||||
attrs = node.getValidAttributeNames(),
|
||||
rmAttrs = ['name', 'code', CONSTANTS.LINE_OFFSET],
|
||||
i;
|
||||
|
||||
for (var j = rmAttrs.length; j--;) {
|
||||
i = attrs.indexOf(rmAttrs[j]);
|
||||
if (i > -1) {
|
||||
attrs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return attrs;
|
||||
};
|
||||
|
||||
OperationCodeEditorControl.prototype.executeOrStopJob = function () {
|
||||
var job;
|
||||
|
||||
if (this.currentJobId) { // Only if nested in a job
|
||||
job = this._client.getNode(this.currentJobId);
|
||||
if (this.isRunning(job)) {
|
||||
this.stopJob(job);
|
||||
} else {
|
||||
this.executeJob(job);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Line offset handling
|
||||
OperationCodeEditorControl.prototype.offsetNodeChanged = function (id) {
|
||||
// Create a territory for this node
|
||||
|
||||
+24
@@ -9,6 +9,7 @@ define([
|
||||
this._widget.allDataTypeIds = this.allDataTypeIds.bind(this);
|
||||
this._widget.allValidReferences = this.allValidReferences.bind(this);
|
||||
this._widget.addRefTo = this.addRefTo.bind(this);
|
||||
this._widget.setRefType = this.setRefType.bind(this);
|
||||
this._widget.changePtrName = this.changePtrName.bind(this);
|
||||
this._widget.removePtr = this.removePtr.bind(this);
|
||||
this._widget.getCreationNode = this.getCreationNode.bind(this);
|
||||
@@ -138,6 +139,29 @@ define([
|
||||
this._client.completeTransaction();
|
||||
};
|
||||
|
||||
OperationInterfaceEditorEvents.prototype.setRefType = function(ref, targetId) {
|
||||
var meta = this._client.getPointerMeta(this._currentNodeId, ref),
|
||||
msg = `Setting ${ref} reference type to ${targetId}`;
|
||||
|
||||
if (!meta) {
|
||||
this.logger.debug(`No meta found for ${ref}. Creating a new reference to ${targetId}`);
|
||||
meta = {
|
||||
min: 1,
|
||||
max: 1,
|
||||
items: []
|
||||
};
|
||||
}
|
||||
|
||||
meta.items.push({
|
||||
id: targetId,
|
||||
max: 1
|
||||
});
|
||||
|
||||
this._client.startTransaction(msg);
|
||||
this._client.setPointerMeta(this._currentNodeId, ref, meta);
|
||||
this._client.completeTransaction();
|
||||
};
|
||||
|
||||
OperationInterfaceEditorEvents.prototype.changePtrName = function(from, to) {
|
||||
var opNode = this._client.getNode(this._currentNodeId),
|
||||
name = opNode.getAttribute('name'),
|
||||
|
||||
+18
-7
@@ -255,13 +255,23 @@ define([
|
||||
};
|
||||
|
||||
OperationInterfaceEditorControl.prototype.getPtrDescriptor = function(name) {
|
||||
var targetId = this._client.getPointerMeta(this._currentNodeId, name)
|
||||
.items[0].id,
|
||||
target = this._client.getNode(targetId),
|
||||
decManager = this._client.decoratorManager,
|
||||
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
|
||||
var Decorator = this._client.decoratorManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
|
||||
id = 'ptr_'+name,
|
||||
used = this.isUsedInput(name);
|
||||
used = this.isUsedInput(name),
|
||||
ptrMeta = this._client.getPointerMeta(this._currentNodeId, name),
|
||||
targetId,
|
||||
target,
|
||||
baseName;
|
||||
|
||||
if (!ptrMeta || ptrMeta.items.length === 0) {
|
||||
// No known type
|
||||
this._logger.error(`No known target type for "${name}" reference`);
|
||||
baseName = null;
|
||||
} else {
|
||||
targetId = ptrMeta.items[0].id;
|
||||
target = this._client.getNode(targetId);
|
||||
baseName = target.getAttribute('name');
|
||||
}
|
||||
|
||||
if (used === null) {
|
||||
used = this._usage[id] !== undefined ? this._usage[id] : true;
|
||||
@@ -270,7 +280,8 @@ define([
|
||||
return {
|
||||
id: id,
|
||||
isPointer: true,
|
||||
baseName: target.getAttribute('name'),
|
||||
baseName: baseName,
|
||||
isUnknown: !baseName,
|
||||
Decorator: Decorator,
|
||||
used: used,
|
||||
attributes: {},
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// metadata, provides a pagination bar in the lower left to page through
|
||||
// the metadata results
|
||||
define([
|
||||
'text!./icons.json',
|
||||
'js/PanelBase/PanelBaseWithHeader',
|
||||
'js/PanelManager/IActivePanel',
|
||||
'panels/LogViewer/LogViewerPanel',
|
||||
@@ -13,6 +14,7 @@ define([
|
||||
'text!api/visualizers',
|
||||
'css!./OutputViewer.css'
|
||||
], function (
|
||||
IconTxt,
|
||||
PanelBaseWithHeader,
|
||||
IActivePanel,
|
||||
LogViewer,
|
||||
@@ -23,7 +25,8 @@ define([
|
||||
'use strict';
|
||||
|
||||
var OutputViewerPanel,
|
||||
Visualizers = JSON.parse(VisualizersJSON);
|
||||
Visualizers = JSON.parse(VisualizersJSON),
|
||||
IconFor = JSON.parse(IconTxt);
|
||||
|
||||
OutputViewerPanel = function (layoutManager, params) {
|
||||
var options = {};
|
||||
@@ -64,7 +67,7 @@ define([
|
||||
this.$pagerList = $('<ul>', {class: 'pagination'});
|
||||
|
||||
// Add the console item
|
||||
var logviewer = $('<li class="active"><a>Console</a></li>');
|
||||
var logviewer = $('<li class="active"><a><span class="glyphicon glyphicon-console"></span> Console</a></li>');
|
||||
this.$logviewer = logviewer.find('a');
|
||||
this.$selected = this.$logviewer;
|
||||
this.$pagerList.append(logviewer);
|
||||
@@ -89,13 +92,18 @@ define([
|
||||
|
||||
OutputViewerPanel.prototype.selectOutput = function (element) {
|
||||
if (this.$selected !== element) {
|
||||
// Update the panel
|
||||
var dataId = element.data('id');
|
||||
|
||||
while (element.prop('tagName').toLowerCase() !== 'a' && element.length) {
|
||||
element = element.parent();
|
||||
}
|
||||
|
||||
dataId = element.data('id');
|
||||
this.$selected.parent().removeClass('active');
|
||||
element.parent().addClass('active');
|
||||
this.$selected = element;
|
||||
|
||||
// Update the panel
|
||||
var dataId = element.data('id');
|
||||
|
||||
if (dataId) {
|
||||
this.loadOutputFor(dataId);
|
||||
} else { // Set the logviewer
|
||||
@@ -218,10 +226,8 @@ define([
|
||||
};
|
||||
|
||||
OutputViewerPanel.prototype.onUpdate = function (nodeId) {
|
||||
var name = this._client.getNode(nodeId).getAttribute('name');
|
||||
|
||||
if (this._pages[nodeId]) {
|
||||
this._pages[nodeId].find('a').text(name);
|
||||
this.updatePage(nodeId);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -249,14 +255,29 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
OutputViewerPanel.prototype.updatePage = function (nodeId) {
|
||||
var node = this._client.getNode(nodeId),
|
||||
baseId = node.getBaseId(),
|
||||
base = this._client.getNode(baseId),
|
||||
type = base.getAttribute('name'),
|
||||
name = node.getAttribute('name'),
|
||||
icon = IconFor[type] || 'info-sign',
|
||||
anchor = this._pages[nodeId].find('a'),
|
||||
span = document.createElement('span');
|
||||
|
||||
span.className = 'glyphicon glyphicon-' + icon;
|
||||
anchor.empty();
|
||||
anchor.html(span.outerHTML + ' ' + name);
|
||||
};
|
||||
|
||||
OutputViewerPanel.prototype.addToPager = function (name, nodeId) {
|
||||
var $el = $('<li>'),
|
||||
$a = $('<a>');
|
||||
|
||||
$a.text(name);
|
||||
$a.attr('data-id', nodeId);
|
||||
$el.append($a);
|
||||
this._pages[nodeId] = $el;
|
||||
this.updatePage(nodeId);
|
||||
this.$pager.removeClass('empty');
|
||||
this.$pagerList.append($el);
|
||||
|
||||
@@ -284,6 +305,7 @@ define([
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
OutputViewerPanel.prototype.destroy = function () {
|
||||
this.activePanel.destroy();
|
||||
this.clearTerritory();
|
||||
PanelBaseWithHeader.prototype.destroy.call(this);
|
||||
WebGMEGlobal.KeyboardManager.setListener(undefined);
|
||||
WebGMEGlobal.Toolbar.refresh();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"Image": "picture",
|
||||
"Console": "console",
|
||||
"Graph": "random"
|
||||
}
|
||||
@@ -62,7 +62,7 @@ define(['js/PanelBase/PanelBaseWithHeader',
|
||||
});
|
||||
|
||||
// Editable pipeline name
|
||||
this.$panelHeaderTitle.on('dblclick', () => this.editTitle());
|
||||
this.$panelHeaderTitle.on('click', () => this.editTitle());
|
||||
|
||||
this.onActivate();
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ define([
|
||||
'deepforge/globals',
|
||||
'widgets/EasyDAG/EasyDAGWidget',
|
||||
'widgets/EasyDAG/AddNodeDialog',
|
||||
'./SelectionManager',
|
||||
'./Layer',
|
||||
'q',
|
||||
'underscore',
|
||||
@@ -13,6 +14,7 @@ define([
|
||||
DeepForge,
|
||||
EasyDAGWidget,
|
||||
AddNodeDialog,
|
||||
SelectionManager,
|
||||
Layer,
|
||||
Q,
|
||||
_
|
||||
@@ -31,6 +33,7 @@ define([
|
||||
_.extend(ArchEditorWidget.prototype, EasyDAGWidget.prototype);
|
||||
|
||||
ArchEditorWidget.prototype.ItemClass = Layer;
|
||||
ArchEditorWidget.prototype.SelectionManager = SelectionManager;
|
||||
|
||||
ArchEditorWidget.prototype.onCreateInitialNode = function() {
|
||||
var nodes = this.getValidInitialNodes();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* globals _, WebGMEGlobal, define*/
|
||||
define([
|
||||
'widgets/EasyDAG/SelectionManager',
|
||||
'deepforge/viz/Buttons'
|
||||
], function(
|
||||
ManagerBase,
|
||||
Buttons
|
||||
) {
|
||||
|
||||
var client = WebGMEGlobal.Client;
|
||||
var SelectionManager = function() {
|
||||
ManagerBase.apply(this, arguments);
|
||||
};
|
||||
|
||||
_.extend(SelectionManager.prototype, ManagerBase.prototype);
|
||||
|
||||
SelectionManager.prototype.createActionButtons = function(width, height) {
|
||||
var disabled,
|
||||
btn;
|
||||
|
||||
ManagerBase.prototype.createActionButtons.call(this, width, height);
|
||||
|
||||
if (!this.selectedItem.isConnection) {
|
||||
disabled = !this._isCustomLayer();
|
||||
// Check that the base type
|
||||
btn = new Buttons.GoToBase({
|
||||
$pEl: this.$selection,
|
||||
context: this._widget,
|
||||
item: this.selectedItem,
|
||||
disabled: disabled,
|
||||
x: width,
|
||||
y: 0
|
||||
});
|
||||
}
|
||||
|
||||
return btn;
|
||||
};
|
||||
|
||||
SelectionManager.prototype._isCustomLayer = function() {
|
||||
var node = client.getNode(this.selectedItem.id),
|
||||
attrNames;
|
||||
|
||||
if (node) {
|
||||
attrNames = node.getAttributeNames();
|
||||
return attrNames.indexOf('code') !== -1;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
return SelectionManager;
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Name</td>
|
||||
<td>Creation Date</td>
|
||||
<td>Origin Pipeline</td>
|
||||
<td>Duration</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="execs-content">
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1,325 @@
|
||||
/*globals define, WebGMEGlobal, $*/
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'deepforge/viz/Utils',
|
||||
'widgets/LineGraph/LineGraphWidget',
|
||||
'text!./ExecTable.html',
|
||||
'css!./styles/ExecutionIndexWidget.css'
|
||||
], function (
|
||||
Utils,
|
||||
LineGraphWidget,
|
||||
TableHtml
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var ExecutionIndexWidget,
|
||||
WIDGET_CLASS = 'execution-index';
|
||||
|
||||
ExecutionIndexWidget = function (logger, container) {
|
||||
this._logger = logger.fork('Widget');
|
||||
|
||||
this.$el = container;
|
||||
|
||||
this.nodes = {};
|
||||
this.graphs = {};
|
||||
this.checkedIds = [];
|
||||
this._initialize();
|
||||
|
||||
this._logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype._initialize = function () {
|
||||
// set widget class
|
||||
this.$el.addClass(WIDGET_CLASS);
|
||||
|
||||
// Create split screen
|
||||
this.$left = $('<div>', {class: 'left'});
|
||||
this.$right = $('<div>', {class: 'right'});
|
||||
this.$el.append(this.$left, this.$right);
|
||||
|
||||
// Create the table
|
||||
this.$table = $(TableHtml);
|
||||
this.$table.on('click', '.exec-row', event => this.onExecutionClicked(event));
|
||||
this.$table.on('click', '.node-nav', event => this.navToNode(event));
|
||||
this.$left.append(this.$table);
|
||||
this.$execList = this.$table.find('.execs-content');
|
||||
|
||||
// Create the graph in the right half
|
||||
this.lineGraph = new LineGraphWidget(this._logger, this.$right);
|
||||
this.defaultSelection = null;
|
||||
this.hasRunning = false;
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.navToNode = function (event) {
|
||||
var id = event.target.getAttribute('data-id');
|
||||
if (typeof id === 'string') {
|
||||
WebGMEGlobal.State.registerActiveObject(id);
|
||||
event.stopPropagation();
|
||||
}
|
||||
this._logger.warn('No node id found for node-nav!');
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.onExecutionClicked = function (event) {
|
||||
var target = event.target,
|
||||
checked,
|
||||
id;
|
||||
|
||||
while (!target.getAttribute('data-id')) {
|
||||
if (!target.parentNode) {
|
||||
this._logger.error('could not find execution id for ' + event);
|
||||
return;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
id = target.getAttribute('data-id');
|
||||
|
||||
checked = this.nodes[id].$checkbox.checked;
|
||||
if (event.target.tagName.toLowerCase() !== 'input') {
|
||||
this.setSelect(id, !checked);
|
||||
} else {
|
||||
this.setExecutionDisplayed(id, checked);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.onWidgetContainerResize = function (width, height) {
|
||||
this.$left.css({
|
||||
width: width/2,
|
||||
height: height
|
||||
});
|
||||
this.$right.css({
|
||||
left: width/2,
|
||||
width: width/2,
|
||||
height: height
|
||||
});
|
||||
this.lineGraph.onWidgetContainerResize(width/2, height);
|
||||
this._logger.debug('Widget is resizing...');
|
||||
};
|
||||
|
||||
// Adding/Removing/Updating items
|
||||
ExecutionIndexWidget.prototype.addNode = function (desc) {
|
||||
var isFirstNode = Object.keys(this.nodes).length === 0;
|
||||
|
||||
if (desc.type === 'Execution') {
|
||||
// Add node to a table of nodes
|
||||
this.addExecLine(desc);
|
||||
this.updateSelected(desc);
|
||||
} else if (desc.type === 'line') {
|
||||
desc.type = 'line';
|
||||
this.lineGraph.addNode(desc);
|
||||
}
|
||||
|
||||
if (isFirstNode) {
|
||||
this.updateTimes();
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.updatePipelineName = function (execId, name) {
|
||||
if (this.nodes[execId]) {
|
||||
this.nodes[execId].$pipeline.text(name);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.addExecLine = function (desc) {
|
||||
var row = $('<tr>', {class: 'exec-row', 'data-id': desc.id}),
|
||||
checkBox = $('<input>', {type: 'checkbox'}),
|
||||
statusClass = Utils.ClassForJobStatus[desc.status],
|
||||
fields,
|
||||
pipeline,
|
||||
name,
|
||||
duration = $('<div>'),
|
||||
td;
|
||||
|
||||
pipeline = $('<a>', {
|
||||
class: 'node-nav',
|
||||
'data-id': desc.originId
|
||||
}).text(desc.pipelineName || 'view pipeline');
|
||||
|
||||
name = $('<a>', {class: 'node-nav', 'data-id': desc.id})
|
||||
.text(desc.name);
|
||||
|
||||
fields = [
|
||||
checkBox,
|
||||
name,
|
||||
Utils.getDisplayTime(desc.originTime),
|
||||
pipeline,
|
||||
duration
|
||||
];
|
||||
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
td = $('<td>');
|
||||
if ((typeof fields[i]) === 'string') {
|
||||
td.text(fields[i]);
|
||||
} else {
|
||||
td.append(fields[i]);
|
||||
}
|
||||
row.append(td);
|
||||
}
|
||||
|
||||
this._logger.debug(`Adding execution ${desc.name} (${desc.id}) to list`);
|
||||
this.$execList.append(row);
|
||||
row.addClass(statusClass);
|
||||
|
||||
this.nodes[desc.id] = {
|
||||
statusClass: statusClass,
|
||||
desc: desc,
|
||||
$el: row,
|
||||
$checkbox: checkBox[0],
|
||||
$pipeline: pipeline,
|
||||
$duration: duration,
|
||||
$name: name
|
||||
};
|
||||
this.updateTime(desc.id, true);
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.getDurationText = function (duration) {
|
||||
var hours,
|
||||
min,
|
||||
sec;
|
||||
|
||||
sec = duration/1000;
|
||||
hours = Math.floor(sec/3600);
|
||||
sec = sec%3600;
|
||||
min = Math.floor(sec/60);
|
||||
sec = Math.floor(sec%60);
|
||||
|
||||
return `${hours}:${min}:${sec}`;
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.updateTime = function (id, force) {
|
||||
var desc = this.nodes[id].desc,
|
||||
duration = 'unknown';
|
||||
|
||||
if (desc.status === 'running') {
|
||||
if (desc.startTime) {
|
||||
duration = this.getDurationText(Date.now() - desc.startTime);
|
||||
}
|
||||
this.nodes[id].$duration.text(duration);
|
||||
return true;
|
||||
} else if (force) {
|
||||
if (desc.endTime && desc.startTime) {
|
||||
duration = this.getDurationText(desc.endTime - desc.startTime);
|
||||
}
|
||||
this.nodes[id].$duration.text(duration);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.updateTimes = function () {
|
||||
var nodeIds = Object.keys(this.nodes),
|
||||
updated = false;
|
||||
|
||||
for (var i = nodeIds.length; i--;) {
|
||||
updated = this.updateTime(nodeIds[i]) || updated;
|
||||
}
|
||||
|
||||
if (updated) { // if there are still nodes, call again!
|
||||
setTimeout(this.updateTimes.bind(this), 1000);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.removeNode = function (id) {
|
||||
if (this.nodes[id]) {
|
||||
this.nodes[id].$el.remove();
|
||||
} else if (this.graphs[id]) {
|
||||
delete this.graphs[id];
|
||||
}
|
||||
delete this.nodes[id];
|
||||
|
||||
this.lineGraph.removeNode(id); // 'nop' if node is not line
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.updateSelected = function (desc) {
|
||||
// If the running pipeline has been unselected, don't reselect it!
|
||||
if (desc.status === 'running') {
|
||||
this.hasRunning = true;
|
||||
this.setSelect(desc.id, true);
|
||||
if (this.defaultSelection) {
|
||||
this.setSelect(this.defaultSelection, false);
|
||||
}
|
||||
} else if (!this.hasRunning && !this.defaultSelection) {
|
||||
this.defaultSelection = desc.id;
|
||||
this.setSelect(desc.id, true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.toggleAbbreviations = function (show, ids) {
|
||||
var node,
|
||||
desc,
|
||||
name;
|
||||
|
||||
ids = ids || this.checkedIds;
|
||||
for (var i = ids.length; i--;) {
|
||||
node = this.nodes[ids[i]];
|
||||
desc = node.desc;
|
||||
name = show ? `${desc.name} (${desc.abbr})` : desc.name;
|
||||
node.$name.text(name);
|
||||
}
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.setSelect = function (id, checked) {
|
||||
var wasChecked = this.checkedIds.length > 1,
|
||||
isChecked;
|
||||
|
||||
this.nodes[id].$checkbox.checked = checked;
|
||||
|
||||
// If multiple are checked, display the abbreviation
|
||||
if (checked) {
|
||||
this.checkedIds.push(id);
|
||||
} else {
|
||||
var k = this.checkedIds.indexOf(id);
|
||||
if (k !== -1) {
|
||||
this.checkedIds.splice(k, 1);
|
||||
}
|
||||
}
|
||||
|
||||
isChecked = this.checkedIds.length > 1;
|
||||
if (isChecked !== wasChecked) {
|
||||
this.toggleAbbreviations(isChecked);
|
||||
}
|
||||
|
||||
// Update the given node
|
||||
if (!checked || isChecked) {
|
||||
this.toggleAbbreviations(checked, [id]);
|
||||
}
|
||||
|
||||
this.setExecutionDisplayed(id, checked);
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.updateNode = function (desc) {
|
||||
var node = this.nodes[desc.id];
|
||||
if (node) {
|
||||
node.$name.text(desc.name);
|
||||
node.$el.removeClass(node.statusClass);
|
||||
node.$el.addClass(Utils.ClassForJobStatus[desc.status]);
|
||||
|
||||
if (Utils.ClassForJobStatus[desc.status] !== node.statusClass) {
|
||||
// Only update the selection if the status has changed.
|
||||
// ie, it has started running
|
||||
this.updateSelected(desc);
|
||||
}
|
||||
this._logger.debug(`setting execution ${desc.id} to ${desc.status}`);
|
||||
|
||||
node.statusClass = Utils.ClassForJobStatus[desc.status];
|
||||
node.desc = desc;
|
||||
} else if (desc.type === 'line') {
|
||||
this.lineGraph.updateNode(desc);
|
||||
}
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ExecutionIndexWidget.prototype.destroy = function () {
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.onActivate = function () {
|
||||
this._logger.debug('ExecutionIndexWidget has been activated');
|
||||
};
|
||||
|
||||
ExecutionIndexWidget.prototype.onDeactivate = function () {
|
||||
this._logger.debug('ExecutionIndexWidget has been deactivated');
|
||||
};
|
||||
|
||||
return ExecutionIndexWidget;
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* This file is for any css that you may want for this visualizer.
|
||||
*
|
||||
* Ideally, you would use the scss file also provided in this directory
|
||||
* and then generate this file automatically from that. However, you can
|
||||
* simply write css if you prefer
|
||||
*/
|
||||
|
||||
.execution-index.panel-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.execution-index .left {
|
||||
position: absolute;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.execution-index .right {
|
||||
position: absolute;
|
||||
background-color: #eee;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This file is for any scss that you may want for this visualizer.
|
||||
*/
|
||||
|
||||
.execution-index {
|
||||
outline: none;
|
||||
}
|
||||
@@ -48,8 +48,8 @@ define([
|
||||
var title = nodeName === undefined ? this._currentTitle : nodeName;
|
||||
|
||||
this._currentTitle = title;
|
||||
if (this.isSnapshot) {
|
||||
title += ' (SNAPSHOT)';
|
||||
if (!this.isSnapshot) {
|
||||
title += ' (DEBUG)';
|
||||
}
|
||||
|
||||
this._setTitle(title);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*globals define, $*/
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'css!./styles/ImageViewerWidget.css'
|
||||
], function (
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var ImageViewerWidget,
|
||||
NO_IMAGE_URL = 'extlib/src/visualizers/widgets/ImageViewer/no-image.gif',
|
||||
WIDGET_CLASS = 'image-viewer';
|
||||
|
||||
ImageViewerWidget = function (logger, container) {
|
||||
this._logger = logger.fork('Widget');
|
||||
this.$el = container;
|
||||
this._initialize();
|
||||
this._logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype._initialize = function () {
|
||||
// set widget class
|
||||
this.$el.addClass(WIDGET_CLASS);
|
||||
this.zoom = 1;
|
||||
this.left = 0;
|
||||
this.top = 0;
|
||||
this.width = 0;
|
||||
this.height = 0;
|
||||
this.img = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
this.$image = $('<img>');
|
||||
this.$el.append(this.$image);
|
||||
|
||||
this.$image.on('load', () => {
|
||||
this.img.width = this.$image.width();
|
||||
this.img.height = this.$image.height();
|
||||
this.centerImage();
|
||||
});
|
||||
|
||||
this.updateImage(NO_IMAGE_URL);
|
||||
|
||||
// Zoom functionality
|
||||
this.$el[0].onwheel = event => {
|
||||
if (event.ctrlKey || event.metaKey || event.altKey) {
|
||||
var dz = -event.deltaY/20;
|
||||
this.zoom += dz;
|
||||
this.centerImage();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.centerImage = function () {
|
||||
var left,
|
||||
top;
|
||||
|
||||
this.left = this.width/2 - (this.img.width*this.zoom/2);
|
||||
this.top = this.height/2 - (this.img.height*this.zoom/2);
|
||||
|
||||
left = this.left/this.zoom;
|
||||
top = this.top/this.zoom;
|
||||
this.$image.css({
|
||||
left: left,
|
||||
top: top,
|
||||
zoom: this.zoom
|
||||
});
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.onWidgetContainerResize = function (width, height) {
|
||||
this.$el.css({
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.centerImage();
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.updateImage = function (url) {
|
||||
url = url || NO_IMAGE_URL;
|
||||
this.zoom = 1;
|
||||
this.$image.attr('src', url);
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.removeImage = function () {
|
||||
// Change to 'no picture' image
|
||||
this.updateImage(NO_IMAGE_URL);
|
||||
};
|
||||
|
||||
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
|
||||
ImageViewerWidget.prototype.destroy = function () {
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.onActivate = function () {
|
||||
this._logger.debug('ImageViewerWidget has been activated');
|
||||
};
|
||||
|
||||
ImageViewerWidget.prototype.onDeactivate = function () {
|
||||
this._logger.debug('ImageViewerWidget has been deactivated');
|
||||
};
|
||||
|
||||
return ImageViewerWidget;
|
||||
});
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 3.7 KiB |
@@ -0,0 +1,5 @@
|
||||
|
||||
.image-viewer img {
|
||||
position: absolute;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*globals define, d3, nv */
|
||||
/*globals define, d3, nv, _ */
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
@@ -16,7 +16,7 @@ define([
|
||||
|
||||
this.$el = container;
|
||||
|
||||
this.lineData = [];
|
||||
this.lineData = {};
|
||||
this._initialize();
|
||||
|
||||
this._logger.debug('ctor finished');
|
||||
@@ -35,7 +35,6 @@ define([
|
||||
this.$chart = d3.select(this.$el[0]).append('svg');
|
||||
nv.addGraph(() => {
|
||||
var chart = nv.models.lineChart()
|
||||
//.margin({left: 100})
|
||||
.useInteractiveGuideline(true)
|
||||
.showLegend(true)
|
||||
.showYAxis(true)
|
||||
@@ -49,6 +48,7 @@ define([
|
||||
.axisLabel(this.options.xAxis);
|
||||
}
|
||||
|
||||
chart.yAxis.tickFormat(d3.format('.02f'));
|
||||
if (this.options.yAxis) {
|
||||
chart.yAxis
|
||||
.axisLabel(this.options.yAxis);
|
||||
@@ -69,7 +69,9 @@ define([
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype.getData = function () {
|
||||
return Object.keys(this.lineData).map(id => this.lineData[id]);
|
||||
return Object.keys(this.lineData)
|
||||
.map(id => this.lineData[id])
|
||||
.filter(data => data.values.length !== 0); // hide empty lines
|
||||
};
|
||||
|
||||
// Adding/Removing/Updating items
|
||||
@@ -82,20 +84,20 @@ define([
|
||||
values: desc.points
|
||||
};
|
||||
}
|
||||
this.updateChartData();
|
||||
this.refreshChart();
|
||||
}
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype.removeNode = function (id) {
|
||||
delete this.lineData[id];
|
||||
this.updateChartData();
|
||||
this.refreshChart();
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype.updateNode = function (desc) {
|
||||
if (desc && this.lineData[desc.id]) {
|
||||
this.lineData[desc.id].values = desc.points;
|
||||
this.lineData[desc.id].key = desc.name;
|
||||
this.updateChartData();
|
||||
this.refreshChart();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,6 +117,9 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
LineGraphWidget.prototype.refreshChart =
|
||||
_.debounce(LineGraphWidget.prototype.updateChartData, 50);
|
||||
|
||||
LineGraphWidget.prototype.updateChart = function () {
|
||||
if (this.chart) {
|
||||
this.chart.update();
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1 +0,0 @@
|
||||
{"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"AAqBA,oBAfA,oBAgBI,KAAM,KAmXN,gBAAiB,WAhFrB,kBA+DA,uBAnWA,oBAfA,oBAmYI,gBAAiB,WAmErB,UAAW,UAJX,mBAvcA,eAsbA,uBA8BA,uCACI,eAAgB,KA+DpB,WA7QA,aAoRI,QAAS,MAST,sBAAuB,KAEvB,mBAAoB,KAtiBxB,eAEI,QAAS,EAuCb,2BA4JA,0DACI,QAAS,EAjMb,oBAEI,OAAQ,KACR,eAAgB,IAIpB,2BACI,eAAgB,IAGpB,gCACI,eAAgB,EAGpB,oBAEI,OAAQ,QAIZ,0BACI,0BACA,eAAgB,IAGpB,mCACI,YAAa,IAGjB,sCACA,uCACA,uCACI,YAAa,OAOjB,oBACI,aAAc,IAEd,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAG3C,0BACI,aAAc,EAGlB,2BACI,KAAM,QAGV,oBACI,KAAM,YAGV,2BACI,KAAM,cAKV,sCAFA,mCACA,6CAEI,eAAgB,EAEhB,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAK3C,8CACA,4CAHA,yCACA,mDAGI,aAAc,EAGlB,sCACA,6CACI,YAAa,IACb,KAAM,cACN,OAAQ,YAIZ,yBACE,aAAc,GAGhB,+BAIA,6BAHE,aAAc,EAOhB,6BACE,OAAQ,KAGV,uBACE,aAAc,MAGhB,gBAAkB,KAAM,KAAK,WAC7B,4BAA8B,aAAc,GAC5C,kCAAoC,aAAc,EAClD,2BAA6B,OAAQ,KAAM,aAAc,IACzD,mCAAqC,OAAQ,KAAM,KAAM,KAAM,aAAc,MAC7E,+BAAiC,OAAQ,KAAM,aAAc,MAC7D,8BAAgC,OAAQ,KAAM,aAAc,KAC5D,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,0BAA4B,UAAW,KAAM,YAAa,IAC1D,6BAA+B,KAAM,KAGrC,0BACI,KAAM,QACN,aAAc,GAElB,gCACI,aAAc,GAGlB,2CACI,aAAc,IAGlB,iDACI,aAAc,IAGlB,yDACI,OAAQ,QACR,KAAM,QAGV,yDACI,OAAQ,QACR,KAAM,QAGV,wDACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAIxE,uCACI,OAAQ,KAIZ,eACE,OAAQ,KACR,aAAc,MAEhB,eACE,OAAQ,KACR,eAAgB,GAElB,oBACE,aAAc,EAOhB,4BACI,aAAa,EACb,aAAa,EAGjB,8BACI,aAAa,EACb,aAAa,EAGjB,qDACI,aAAa,EACb,eAAe,EAQnB,kCACI,aAAc,IAGlB,wCACI,aAAc,EAElB,8BACI,KAAM,KAGV,8BACI,OAAQ,KAGZ,oDACI,aAAc,EACd,eAAgB,EAGpB,sDACI,aAAc,aACd,eAAgB,aAIpB,6CACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAKxE,iCADA,4CAEI,aAAc,IACd,aAAc,cACd,eAAgB,cAIpB,2BACI,OAAQ,KACR,eAAgB,EAChB,KAAM,KACN,aAAc,EAKlB,oBACI,OAAQ,UAUZ,aAEI,oBAAqB,KAErB,gBAAiB,KACjB,iBAAkB,KAClB,YAAa,KAEb,MAAM,KACN,OAAO,KAMX,0BAA2B,2BACvB,gBAAiB,EAAE,IAAI,KAAK,eAC5B,mBAAoB,EAAE,IAAI,KAAK,eAC/B,WAAY,EAAE,IAAI,KAAK,eAEvB,sBAAuB,IACvB,mBAAoB,IACpB,cAAe,IAInB,WACI,KAAM,IAAO,KAAK,MAGtB,aACI,KAAM,IAAK,KAAK,MAGpB,qBACI,KAAM,KACN,aAAc,EAGlB,gBACI,UAAW,KACX,YAAa,IAQjB,kBACI,aAAc,KAIlB,uBACI,KAAM,KACN,OAAQ,KAQZ,4BACI,OAAQ,QAGZ,qCACI,aAAc,EAIlB,wBACI,aAAc,YAGlB,+BACI,OAAQ,KACR,aAAc,GACd,KAAM,KACN,aAAc,GAOlB,aACE,WACE,aAAc,EACd,aAAc,GAIlB,oCACI,aAAc,IAGlB,0CACI,aAAc,IAGlB,6CACI,OAAQ,QAGZ,6CACI,OAAQ,QAIZ,uBACI,KAAM,KACN,OAAQ,KACR,eAAgB,GAIpB,uBACI,KAAM,KACN,eAAgB,GAGpB,4CAEI,KAAM,KACN,aAAc,GACd,OAAQ,KACR,gBAAiB,WAGrB,qCACI,aAAc,EACjB,aAAc,IAIf,8BACE,KAAM,KACN,OAAQ,KACR,aAAc,EACd,eAAgB,EAChB,iBAAkB,EAAG,EAUvB,2BACI,UAAW,KACX,KAAM,qBAGV,4BACI,OAAQ,KACR,aAAc,EAGlB,kBAhBI,WAAY,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OACvF,gBAAiB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5F,mBAAoB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAe/F,OAAQ,KACR,aAAc,IACd,eAAgB,EAIhB,aAAc,GAElB,yBACI,aAAc,EAKlB,4BACI,aAAc,EACd,eAAgB,EAIpB,iCACI,aAAc,KACd,eAAgB,GAGpB,kCACI,aAAc,EAWlB,wBACI,KAAM,KAOV,2CACI,OAAQ,KACR,aAAc,MAGlB,uBACA,yBACI,eAAgB,IA4LpB,+BAvIA,WAwII,eAAe,KA1LnB,oBACI,aAAc,EACd,eAAgB,EAGpB,kCACA,kCACI,aAAc,EACd,UAAW,KACX,YAAa,IAGjB,kCACI,OAAQ,KAGZ,oCACI,OAAQ,QACR,KAAM,QAGV,oCACI,OAAQ,QACR,KAAM,QAGV,wCACI,YAAa,IACb,UAAW,MAsEf,cAsCA,wBACI,YAAa,IA1GjB,kCACI,aAAc,GACd,eAAgB,EAChB,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAGxE,wCACI,aAAc,GAIlB,0CACI,eAAgB,EAChB,aAAc,EAIlB,WACI,SAAU,SAEV,MAAO,cACP,QAAS,IAET,QAAS,MAGT,YAAa,MACb,UAAW,KACX,WAAY,KAGZ,YAAa,OAGb,oBAAqB,KAErB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAIb,WAAY,qBACZ,OAAQ,IAAI,MAAM,eAClB,cAAe,IAqBnB,cAgBA,aACI,OAAQ,EAER,WAAY,OAlChB,4BAA6B,6BACzB,WAAY,QAAQ,KAAK,OACzB,gBAAiB,QAAQ,KAAK,OAC9B,mBAAoB,QAAQ,KAAK,OAEjC,iBAAkB,MAClB,sBAAuB,MACvB,yBAA0B,MAG9B,uBACA,uBACI,QAAS,IAGb,cAEI,QAAS,IAAI,KACb,YAAa,KAEb,iBAAkB,sBAClB,MAAO,cAGP,cAAe,IAAI,MAAM,QAEzB,sBAAuB,IAAI,IAAI,EAAE,EACjC,mBAAoB,IAAI,IAAI,EAAE,EAC9B,cAAe,IAAI,IAAI,EAAE,EAG7B,aAEI,QAAS,IAAI,KAIjB,gBACI,QAAS,aACT,OAAQ,IAAI,EAGhB,iBACI,OAAQ,IACR,eAAe,EAInB,oBACI,QAAS,IAAI,IAAI,IAAI,EACrB,eAAgB,OAMpB,8BACI,YAAa,IAEjB,0BACI,WAAY,MACZ,YAAa,IAGjB,4BACI,MAAO,QAGX,iCACI,QAAS,IAAI,IAAI,IAAI,EACrB,oBAAqB,MACrB,oBAAqB,IACrB,iBAAkB,MAClB,iBAAkB,IAGtB,2CAGI,eAAgB,OAIhB,MAAO,KACP,OAAQ,KACR,OAAQ,IAAI,MAAM,KAGtB,mBACI,QAAS,IACT,WAAY,OAGhB,2BACI,eAAgB,KAChB,QAAS,KAUb,wBACI,OAAQ"}
|
||||
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -27,6 +27,8 @@ define([
|
||||
this._el.addClass('log-viewer');
|
||||
this.editor.setTheme('ace/theme/twilight');
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.renderer.setScrollMargin(0, 75);
|
||||
this.addKeyListeners();
|
||||
|
||||
// Override the textlayer to add support for ansi colors
|
||||
this.customizeAce();
|
||||
@@ -34,6 +36,24 @@ define([
|
||||
|
||||
_.extend(LogViewerWidget.prototype, TextEditorWidget.prototype);
|
||||
|
||||
LogViewerWidget.prototype.addKeyListeners = function() {
|
||||
// Need to add key listeners to the container itself since ace is in read-only mode
|
||||
this._el.on('keydown', event => {
|
||||
// ctrl-alt-pagedown -> EOF
|
||||
if (event.key === 'PageDown' && event.altKey && (event.ctrlKey || event.metaKey)) {
|
||||
this.editor.gotoLine(Infinity);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
// ctrl-alt-pagedown -> beginning of file
|
||||
if (event.key === 'PageUp' && event.altKey && (event.ctrlKey || event.metaKey)) {
|
||||
this.editor.gotoLine(0);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
LogViewerWidget.prototype.getHeader = function(desc) {
|
||||
return `Console logging for Operation "${desc.name}":\n`;
|
||||
};
|
||||
@@ -64,7 +84,7 @@ define([
|
||||
|
||||
// Get the editor text and update wrt ansi colors
|
||||
LogViewerWidget.renderAnsiFromText = function(remaining) {
|
||||
var r = /\[0(;3([0-7]))?m/,
|
||||
var r = /\[[0-6][0-9]?(;[0-9]([0-7]))?m/,
|
||||
match,
|
||||
ansiCode,
|
||||
text,
|
||||
@@ -77,7 +97,9 @@ define([
|
||||
match = remaining.match(r);
|
||||
if (match) {
|
||||
ansiCode = match[0];
|
||||
nextColor = ANSI_COLORS[match[2]] || null;
|
||||
if (match[1] && match[1][1] === '3') { // foreground color
|
||||
nextColor = ANSI_COLORS[match[2]] || null;
|
||||
}
|
||||
text = remaining.substring(0, match.index);
|
||||
remaining = remaining.substring(match.index+ansiCode.length);
|
||||
} else {
|
||||
|
||||
@@ -17,12 +17,17 @@ define([
|
||||
|
||||
var MainViewWidget,
|
||||
WIDGET_CLASS = 'main-view',
|
||||
CreateListItem = _.template(ListItem);
|
||||
CreateListItem = _.template(ListItem),
|
||||
ToggleLabels = [
|
||||
'Executions',
|
||||
'Pipelines'
|
||||
];
|
||||
|
||||
MainViewWidget = function (logger, container) {
|
||||
this._logger = logger.fork('Widget');
|
||||
this.$el = container;
|
||||
this.$el.addClass(WIDGET_CLASS);
|
||||
this.toggleIndex = 0;
|
||||
this.initialize();
|
||||
this._logger.debug('ctor finished');
|
||||
};
|
||||
@@ -32,6 +37,19 @@ define([
|
||||
this.$nav = $(NavBarHTML);
|
||||
this.$el.append(this.$nav);
|
||||
|
||||
// Execution support
|
||||
this.$toggle = this.$nav.find('#toggle-main');
|
||||
this.$toggleLabel = this.$nav.find('.toggle-label');
|
||||
this.$toggle.on('click', () => {
|
||||
if (this._closed) { // shouldn't be clicked when closed (but it is possible)
|
||||
return;
|
||||
}
|
||||
this.toggleEmbeddedPanel();
|
||||
// Update the toggle name
|
||||
this.toggleIndex = (this.toggleIndex + 1) % 2;
|
||||
this.$toggleLabel.text(ToggleLabels[this.toggleIndex]);
|
||||
});
|
||||
|
||||
this.$archlist = this.$nav.find('#arch-list-content');
|
||||
this.$artifacts = this.$nav.find('#artifact-list-content');
|
||||
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<nav class="side-nav fixed closed hide-list">
|
||||
<li class="pull-right side-nav-control">
|
||||
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
|
||||
</li >
|
||||
<li class="no-padding" id="toggle-main">
|
||||
<ul>
|
||||
<li class="no-padding">
|
||||
<a class="toggle-label">Executions</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="no-padding">
|
||||
<ul class="collapsible" data-collapsible="accordion">
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.main-view-embedded {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.main-view .side-nav-control {
|
||||
padding-right: 1em;
|
||||
padding-top: 1em;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/*globals define */
|
||||
/*jshint browser: true*/
|
||||
|
||||
/**
|
||||
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 12:00:46 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define([
|
||||
'widgets/TextEditor/TextEditorWidget',
|
||||
'underscore',
|
||||
@@ -21,6 +17,15 @@ define([
|
||||
OperationCodeEditorWidget = function (logger, container) {
|
||||
TextEditorWidget.call(this, logger, container);
|
||||
this.lineOffset = 0;
|
||||
// Add the shift-enter command
|
||||
this.editor.commands.addCommand({
|
||||
name: 'executeOrStopJob',
|
||||
bindKey: {
|
||||
mac: 'Shift-Enter',
|
||||
win: 'Shift-Enter'
|
||||
},
|
||||
exec: () => this.executeOrStopJob()
|
||||
});
|
||||
};
|
||||
|
||||
_.extend(OperationCodeEditorWidget.prototype, TextEditorWidget.prototype);
|
||||
@@ -46,7 +51,7 @@ define([
|
||||
header.push('-- The following will be executed when the operation is run:');
|
||||
|
||||
// Add info about outputs
|
||||
outputs = desc.outputs.map(pair => `-- ${pair[0]} = <some ${pair[1]}>`)
|
||||
outputs = desc.outputs.map(pair => `-- ${pair[0]} = <${pair[1]}>`)
|
||||
.join('\n');
|
||||
|
||||
if (outputs.length) {
|
||||
@@ -80,5 +85,27 @@ define([
|
||||
this.editor.setOption('firstLineNumber', actualOffset);
|
||||
};
|
||||
|
||||
OperationCodeEditorWidget.prototype.getCompleter = function () {
|
||||
var completer = TextEditorWidget.prototype.getCompleter.call(this),
|
||||
getBasicCompletions = completer.getCompletionsFor,
|
||||
self = this;
|
||||
|
||||
completer.getCompletionsFor = function(obj) {
|
||||
if (obj === 'attributes') {
|
||||
return self.getOperationAttributes().map(attr => {
|
||||
return {
|
||||
name: attr,
|
||||
value: attr,
|
||||
score: 4,
|
||||
meta: 'operation'
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return getBasicCompletions.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
return completer;
|
||||
};
|
||||
|
||||
return OperationCodeEditorWidget;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*globals define */
|
||||
/*globals define*/
|
||||
define([
|
||||
'widgets/EasyDAG/DAGItem',
|
||||
'underscore'
|
||||
@@ -13,6 +13,7 @@ define([
|
||||
// Show the warnings
|
||||
this.$warning = null;
|
||||
this.updateWarnings();
|
||||
|
||||
};
|
||||
|
||||
_.extend(Item.prototype, DAGItem.prototype);
|
||||
@@ -29,38 +30,55 @@ define([
|
||||
if (this.desc.used === false) {
|
||||
this.warn(msg, isInput ? 'bottom' : 'top');
|
||||
} else {
|
||||
this.clearWarning();
|
||||
this.clearNotification('$warning');
|
||||
}
|
||||
|
||||
if (this.desc.isUnknown) { // ptrs only
|
||||
this.error('Unknown type! Click to set', 'bottom');
|
||||
} else if (this.$error) {
|
||||
// Set the baseName tooltip, if needed
|
||||
this.clearNotification('$error');
|
||||
this.decorator.enableTooltip(this.desc.baseName, 'dark');
|
||||
}
|
||||
};
|
||||
|
||||
Item.prototype.warn = function(message, tipJoint) {
|
||||
// Create a temporary div over the given svg element
|
||||
if (this.$warning) {
|
||||
this.clearWarning();
|
||||
}
|
||||
this.notify(message, '$warning', '#ffeb3b', 'standard', tipJoint);
|
||||
};
|
||||
|
||||
this.decorator.highlight('#ffeb3b');
|
||||
this.$warning = this.createTooltip(message, {
|
||||
Item.prototype.error = function(message, tipJoint) {
|
||||
this.notify(message, '$error', '#ef5350', 'alert', tipJoint);
|
||||
};
|
||||
|
||||
Item.prototype.notify = function(message, varname, color, style, tipJoint) {
|
||||
this.clearNotification(varname);
|
||||
|
||||
this.decorator.highlight(color);
|
||||
this[varname] = this.createTooltip(message, {
|
||||
showIf: () => !this.isSelected(),
|
||||
tipJoint: tipJoint,
|
||||
style: 'standard'
|
||||
style: style
|
||||
});
|
||||
};
|
||||
|
||||
Item.prototype.clearWarning = function() {
|
||||
if (this.$warning) {
|
||||
this.destroyTooltip(this.$warning);
|
||||
this.$warning = null;
|
||||
Item.prototype.clearNotification = function(varname) {
|
||||
if (this[varname]) {
|
||||
this.destroyTooltip(this[varname]);
|
||||
this[varname] = null;
|
||||
}
|
||||
this.decorator.unHighlight();
|
||||
};
|
||||
|
||||
|
||||
Item.prototype.onSelect = function() {
|
||||
DAGItem.prototype.onSelect.call(this);
|
||||
if (this.$warning) {
|
||||
this.$warning.hide();
|
||||
}
|
||||
|
||||
// Add click listener to set type
|
||||
if (this.desc.isUnknown) {
|
||||
this.onSetRefClicked(this.desc.name);
|
||||
}
|
||||
};
|
||||
|
||||
Item.prototype.setupDecoratorCallbacks = function() {
|
||||
|
||||
+27
-1
@@ -37,7 +37,7 @@ define([
|
||||
EasyDAG.prototype.setupItemCallbacks.call(this);
|
||||
// Add ptr rename callback
|
||||
this.ItemClass.prototype.changePtrName = (from, to) => this.changePtrName(from, to);
|
||||
|
||||
this.ItemClass.prototype.onSetRefClicked = OperationInterfaceEditorWidget.prototype.onSetRefClicked.bind(this);
|
||||
};
|
||||
|
||||
OperationInterfaceEditorWidget.prototype.onAddItemSelected = function(selected, isInput) {
|
||||
@@ -77,6 +77,25 @@ define([
|
||||
this.active = true; // keep refreshing the screen -> it is always visible
|
||||
};
|
||||
|
||||
OperationInterfaceEditorWidget.prototype.onSetRefClicked = function(name) {
|
||||
var refs = this.allValidReferences();
|
||||
|
||||
// Get all valid references
|
||||
if (refs.length > 1) {
|
||||
// Create the modal view with all possible subsequent nodes
|
||||
var dialog = new AddNodeDialog();
|
||||
|
||||
dialog.show(null, refs);
|
||||
dialog.onSelect = selected => {
|
||||
if (selected) {
|
||||
this.setRefType(name, selected.node.id);
|
||||
}
|
||||
};
|
||||
} else if (refs[0]) {
|
||||
this.setRefType(name, refs[0].node.id);
|
||||
}
|
||||
};
|
||||
|
||||
OperationInterfaceEditorWidget.prototype.onAddRefClicked = function() {
|
||||
var refs = this.allValidReferences();
|
||||
|
||||
@@ -100,5 +119,12 @@ define([
|
||||
this.addRefTo(target.node.id);
|
||||
};
|
||||
|
||||
OperationInterfaceEditorWidget.prototype.addConnection = function(desc) {
|
||||
EasyDAG.prototype.addConnection.call(this, desc);
|
||||
// Remove connection selection
|
||||
var conn = this.connections[desc.id];
|
||||
conn.$el.on('click', null);
|
||||
};
|
||||
|
||||
return OperationInterfaceEditorWidget;
|
||||
});
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário