Comparar commits
146 Commits
v0.10.0
...
code-coverage
| Autor | SHA1 | Data | |
|---|---|---|---|
| 3676d4c340 | |||
| 16668468f4 | |||
| ffae88a168 | |||
| 25f5759c17 | |||
| 7a0eae386f | |||
| af5d74483a | |||
| 9bf7632aba | |||
| d7f3544bb3 | |||
| 19a7b2a8fa | |||
| aadd581189 | |||
| a5d00efd39 | |||
| a239c7bd44 | |||
| 5871b5058e | |||
| 3a8108b321 | |||
| b18a3b2747 | |||
| 884ba2557f | |||
| e2d3058de1 | |||
| 02739bfd62 | |||
| 89e2e387c7 | |||
| 0ac2b1b6ab | |||
| a36e8df404 | |||
| 93a89ddaa1 | |||
| 7281dcefc6 | |||
| bfc1f08c7e | |||
| ad08fce281 | |||
| bb2a67e3f6 | |||
| 3f0b7e4720 | |||
| 728c56261d | |||
| a3dd12386e | |||
| c017f9a1d7 | |||
| 6d95f21550 | |||
| 11cb9259d8 | |||
| 71f575c857 | |||
| cf4404eaf7 | |||
| 6ef0cb0bdc | |||
| e128cc408e | |||
| 1477421f1a | |||
| 671a8af458 | |||
| a4fcc73e9f | |||
| e88fb302d4 | |||
| ff1f29955a | |||
| 0b71ff6b9d | |||
| 4f3b6c5e39 | |||
| fe0c95116f | |||
| 4429cb11d4 | |||
| 56b20ab429 | |||
| 4d0f4c3609 | |||
| 209f46adb0 | |||
| 2ac374a56e | |||
| fc4c5db0ce | |||
| 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 | |||
| 96edd6c825 | |||
| 4c4b2b02e2 | |||
| 428a0ec92e | |||
| b0679ae5d8 | |||
| bf3fe1ffcd |
@@ -33,3 +33,5 @@ node_modules
|
||||
tmp/
|
||||
test-tmp/
|
||||
blob-local-storage/
|
||||
src/seeds/nn/hash.txt
|
||||
src/seeds/pipeline/hash.txt
|
||||
|
||||
+1
-2
@@ -2,5 +2,4 @@ language: node_js
|
||||
services: mongodb
|
||||
sudo: false
|
||||
node_js:
|
||||
- "4.1.1"
|
||||
- "4.2.5"
|
||||
- "6.2.1"
|
||||
|
||||
+16
-3
@@ -7,7 +7,13 @@
|
||||
**Notice**: DeepForge is still a work in progress and is also lacking significant documentation! That being said, any contributions and/or feedback is greatly appreciated (and feel free to always ask any questions on the gitter)!
|
||||
|
||||
# DeepForge
|
||||
DeepForge is an open-source visual development environment for deep learning. Currently, it supports Convolutional Neural Networks but we are planning on supporting additional deep learning classifiers such as RNNs and LSTMs. Additional features include real-time collaborative editing and version control.
|
||||
DeepForge is an open-source visual development environment for deep learning. Currently, it supports Convolutional Neural Networks, RNNs and LSTMs as well as the creation of custom layers. Additional features include:
|
||||
- Graphical architecture editor
|
||||
- Training/testing pipeline creation
|
||||
- Distributed pipeline execution
|
||||
- Real-time pipeline feedback
|
||||
- Collaborative editing
|
||||
- Automatic version control.
|
||||
|
||||
## Quick Start
|
||||
Simply run the following command to install deepforge with its dependencies:
|
||||
@@ -16,10 +22,17 @@ Simply run the following command to install deepforge with its dependencies:
|
||||
curl -o- https://raw.githubusercontent.com/dfst/deepforge/master/install.sh | bash
|
||||
```
|
||||
|
||||
Next, follow the postinstall instructions to start MongoDB and DeepForge!
|
||||
Or, if you already have NodeJS (v6) installed, simply run
|
||||
|
||||
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).
|
||||
```
|
||||
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 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!
|
||||
|
||||
@@ -3,10 +3,16 @@
|
||||
|
||||
var gmeConfig = require('./config'),
|
||||
webgme = require('webgme'),
|
||||
path = require('path'),
|
||||
rm_rf = require('rimraf'),
|
||||
myServer;
|
||||
|
||||
webgme.addToRequireJsPaths(gmeConfig);
|
||||
|
||||
// Clear seed hash info
|
||||
['nn', 'pipeline'].map(lib => path.join(__dirname, 'src', 'seeds', lib, 'hash.txt'))
|
||||
.forEach(file => rm_rf.sync(file));
|
||||
|
||||
myServer = new webgme.standaloneServer(gmeConfig);
|
||||
myServer.start(function (err) {
|
||||
if (err) {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
+187
-121
@@ -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'),
|
||||
@@ -19,7 +19,13 @@ var Command = require('commander').Command,
|
||||
dataPath = path.join(configDir, 'data'),
|
||||
|
||||
localConfig,
|
||||
p = dir => dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
|
||||
rm_rf = require('rimraf'),
|
||||
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) {
|
||||
@@ -38,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;
|
||||
};
|
||||
@@ -58,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) {
|
||||
@@ -72,31 +79,45 @@ 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;
|
||||
};
|
||||
|
||||
var checkMongo = function(args) {
|
||||
var checkMongo = function(args, notSilent) {
|
||||
// check the webgme config
|
||||
var gmeConfig = require('../config'),
|
||||
mongoUri = gmeConfig.mongo.uri;
|
||||
@@ -108,15 +129,26 @@ var checkMongo = function(args) {
|
||||
console.log('MongoDB is already running!');
|
||||
} catch (e) { // no pIds
|
||||
console.log('Starting MongoDB...');
|
||||
startMongo(args, true);
|
||||
var match = mongoUri.match(/:([0-9]+)/),
|
||||
port = '80';
|
||||
|
||||
if (match) {
|
||||
port = match[1];
|
||||
}
|
||||
|
||||
startMongo(args, port, !notSilent);
|
||||
}
|
||||
} else if (notSilent) {
|
||||
console.log(`Cannot start remote mongo locally: ${mongoUri}`);
|
||||
} else {
|
||||
console.log(`Using remote mongo: ${mongoUri}`);
|
||||
}
|
||||
};
|
||||
|
||||
var startMongo = function(args, silent) {
|
||||
var job = spawn('mongod', ['--dbpath', p(config.mongo.dir)], {
|
||||
cwd: process.env.HOME
|
||||
});
|
||||
var startMongo = function(args, port, silent) {
|
||||
var opts = ['--dbpath', p(config.mongo.dir), '--port', port],
|
||||
job = rawSpawn('mongod', opts, {cwd: process.env.HOME});
|
||||
|
||||
if (!silent) {
|
||||
job.stdout.on('data',
|
||||
data => process.stdout.write(data.toString()));
|
||||
@@ -146,64 +178,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),
|
||||
cmds;
|
||||
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(' ');
|
||||
|
||||
cmds = [
|
||||
`git clone https://github.com/torch/distro.git ${tgtDir} --recursive`,
|
||||
`cd ${tgtDir}`,
|
||||
'bash install-deps',
|
||||
'./install.sh'
|
||||
];
|
||||
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');
|
||||
|
||||
spawnMany(cmds,
|
||||
() => {
|
||||
storeConfig('torch.dir', tgtDir);
|
||||
resolve(true);
|
||||
},
|
||||
reject
|
||||
);
|
||||
}
|
||||
|
||||
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,44 +276,45 @@ 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) {
|
||||
startMongo(args);
|
||||
checkMongo(args, true);
|
||||
}
|
||||
|
||||
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 +328,6 @@ program
|
||||
.option('-s, --server', 'update deepforge')
|
||||
.action(args => {
|
||||
var pkg = 'deepforge',
|
||||
job,
|
||||
latestVersion;
|
||||
|
||||
// Install the project
|
||||
@@ -287,38 +350,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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -333,21 +401,19 @@ program
|
||||
if (opts.torch) {
|
||||
console.log(`uninstalling torch at ${p(config.torch.dir)}`);
|
||||
}
|
||||
fs.unlinkSync(p(config.torch.dir));
|
||||
rm_rf.sync(p(config.torch.dir));
|
||||
}
|
||||
|
||||
if (opts.clean) { // remove the .deepforge directory
|
||||
console.log('removing config and data files...');
|
||||
fs.unlinkSync(p(config.mongo.dir));
|
||||
fs.unlinkSync(p(configDir));
|
||||
rm_rf.sync(p(config.mongo.dir));
|
||||
rm_rf.sync(p(configDir));
|
||||
}
|
||||
|
||||
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 +449,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"
|
||||
}
|
||||
+11
-3
@@ -2,12 +2,20 @@
|
||||
var spawn = require('child_process').spawn,
|
||||
stdout = '',
|
||||
execJob,
|
||||
workerJob = null;
|
||||
path = require('path'),
|
||||
env = {cwd: path.join(__dirname, '..')},
|
||||
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', [
|
||||
'start'
|
||||
]);
|
||||
], env);
|
||||
execJob.stdout.pipe(process.stdout);
|
||||
execJob.stderr.pipe(process.stderr);
|
||||
|
||||
@@ -15,7 +23,7 @@ execJob.stdout.on('data', function(chunk) {
|
||||
if (!workerJob) {
|
||||
stdout += chunk;
|
||||
if (stdout.indexOf('DeepForge') > -1) {
|
||||
workerJob = spawn('npm', ['run', 'worker']);
|
||||
workerJob = spawn('npm', ['run', 'worker'], env);
|
||||
workerJob.stdout.pipe(process.stdout);
|
||||
workerJob.stderr.pipe(process.stderr);
|
||||
workerJob.on('close', code => code && process.exit(code));
|
||||
|
||||
+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,10 +12,32 @@
|
||||
"LayerColors": {}
|
||||
},
|
||||
"BreadcrumbHeader": {
|
||||
"pathRule": "history"
|
||||
"pathRule": "history",
|
||||
"cachePrefix": "deepforge-header"
|
||||
},
|
||||
"FloatingActionButton": {
|
||||
"hideOnEmpty": true
|
||||
"hideOnEmpty": true,
|
||||
"pluginUIConfigs": {
|
||||
"GenerateArchitecture": {
|
||||
"icon": "description",
|
||||
"hotkey": "shift enter",
|
||||
"priority": -1
|
||||
},
|
||||
"ExecutePipeline": {
|
||||
"icon": "play_arrow",
|
||||
"hotkey": "shift enter",
|
||||
"color": "green",
|
||||
"priority": 1
|
||||
},
|
||||
"ImportTorch": {
|
||||
"icon": "import_export",
|
||||
"priority": -1
|
||||
},
|
||||
"GenerateExecFile": {
|
||||
"icon": "play_for_work",
|
||||
"priority": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
"GenericUIProjectNavigatorController": {
|
||||
"rootMenuClass": "deepforge-logo",
|
||||
|
||||
@@ -9,16 +9,20 @@ 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;
|
||||
config.plugin.allowServerExecution = true;
|
||||
|
||||
config.executor.enable = true;
|
||||
config.executor.clearOldDataAtStartUp = true;
|
||||
|
||||
config.visualization.extraCss.push('deepforge/styles/global.css');
|
||||
|
||||
config.storage.autoMerge.enable = true;
|
||||
|
||||
validateConfig(config);
|
||||
module.exports = config;
|
||||
|
||||
@@ -7,7 +7,6 @@ var config = require('./config.default'),
|
||||
|
||||
// Turn up the worker polling rate
|
||||
config.executor.workerRefreshInterval = 150;
|
||||
config.executor.clearOldDataAtStartUp = true,
|
||||
|
||||
validateConfig(config);
|
||||
module.exports = config;
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var config = require('./config.default');
|
||||
var config = require('./config.default'),
|
||||
path = require('path');
|
||||
|
||||
config.server.port = 9001;
|
||||
config.mongo.uri = 'mongodb://127.0.0.1:27017/webgme_tests';
|
||||
config.blob.fsDir = path.join(__dirname, '..', 'test-tmp', 'blob');
|
||||
|
||||
module.exports = config;
|
||||
module.exports = config;
|
||||
|
||||
+22
-19
@@ -6,32 +6,35 @@
|
||||
var config = require('webgme/config/config.default'),
|
||||
validateConfig = require('webgme/config/validator');
|
||||
|
||||
|
||||
// The paths can be loaded from the webgme-setup.json
|
||||
config.plugin.basePaths.push('src/plugins');
|
||||
config.plugin.basePaths.push('node_modules/webgme-simple-nodes/src/plugins');
|
||||
config.visualization.layout.basePaths.push('node_modules/webgme-chflayout/src/layouts');
|
||||
config.visualization.decoratorPaths.push('src/decorators');
|
||||
config.visualization.decoratorPaths.push('node_modules/webgme-easydag/src/decorators');
|
||||
config.seedProjects.basePaths.push('src/seeds/nn');
|
||||
config.seedProjects.basePaths.push('src/seeds/devTests');
|
||||
config.seedProjects.basePaths.push('src/seeds/devUtilTests');
|
||||
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.plugin.basePaths.push(__dirname + '/../src/plugins');
|
||||
config.plugin.basePaths.push(__dirname + '/../node_modules/webgme-simple-nodes/src/plugins');
|
||||
config.visualization.layout.basePaths.push(__dirname + '/../node_modules/webgme-chflayout/src/layouts');
|
||||
config.visualization.decoratorPaths.push(__dirname + '/../src/decorators');
|
||||
config.visualization.decoratorPaths.push(__dirname + '/../node_modules/webgme-easydag/src/decorators');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/nn');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/devTests');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/devUtilTests');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/pipeline');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/devPipelineTests');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/project');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/cifar10');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/xor');
|
||||
config.seedProjects.basePaths.push(__dirname + '/../src/seeds/devProject');
|
||||
|
||||
|
||||
|
||||
config.visualization.panelPaths.push('node_modules/webgme-fab/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push('node_modules/webgme-breadcrumbheader/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push('node_modules/webgme-autoviz/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push('node_modules/webgme-easydag/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push('src/visualizers/panels');
|
||||
config.visualization.panelPaths.push(__dirname + '/../node_modules/webgme-fab/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push(__dirname + '/../node_modules/webgme-breadcrumbheader/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push(__dirname + '/../node_modules/webgme-autoviz/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push(__dirname + '/../node_modules/webgme-easydag/src/visualizers/panels');
|
||||
config.visualization.panelPaths.push(__dirname + '/../src/visualizers/panels');
|
||||
|
||||
|
||||
config.rest.components['execution/logs'] = __dirname + '/../src/routers/JobLogsAPI/JobLogsAPI.js';
|
||||
|
||||
// Visualizer descriptors
|
||||
config.visualization.visualizerDescriptors.push('./src/visualizers/Visualizers.json');
|
||||
config.visualization.visualizerDescriptors.push(__dirname + '/../src/visualizers/Visualizers.json');
|
||||
// Add requirejs paths
|
||||
config.requirejsPaths = {
|
||||
'EllipseDecorator': 'node_modules/webgme-easydag/src/decorators/EllipseDecorator',
|
||||
|
||||
+21
-56
@@ -5,13 +5,6 @@
|
||||
command -v git >/dev/null 2>&1 || { echo >&2 "I require git but it's not installed. Aborting."; exit 1; }
|
||||
|
||||
echo >&2 "Checking DeepForge dependencies...";
|
||||
command -v th >/dev/null 2>&1 || {
|
||||
# No torch!
|
||||
echo >&2 "Torch is not found. Installing...";
|
||||
git clone https://github.com/torch/distro.git ~/torch --recursive;
|
||||
cd ~/torch; bash install-deps;
|
||||
./install.sh;
|
||||
}
|
||||
|
||||
# profile (bash, zsh, profile, etc) borrowed from nvm's installer
|
||||
detect_profile() {
|
||||
@@ -48,15 +41,9 @@ detect_profile() {
|
||||
}
|
||||
detect_profile
|
||||
|
||||
command -v node >/dev/null 2>&1 || {
|
||||
# No node! Install nvm
|
||||
echo >&2 "NodeJS is not found. Installing (using nvm)...";
|
||||
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash;
|
||||
source $DETECTED_PROFILE
|
||||
. $NVM_DIR/nvm.sh
|
||||
|
||||
set_node_version() {
|
||||
# Install nodejs v6.2.0
|
||||
echo "Installing nodejs v6.2.0"
|
||||
echo "Installing NodeJS v6.2.0"
|
||||
nvm install v6.2.0
|
||||
nvm alias default v6.2.0
|
||||
|
||||
@@ -65,62 +52,40 @@ command -v node >/dev/null 2>&1 || {
|
||||
}
|
||||
|
||||
command -v node >/dev/null 2>&1 || {
|
||||
# No mongod!
|
||||
echo >&2 "MongoDB is not found. Installing...";
|
||||
if [[ `uname` == "Darwin" ]]; then
|
||||
brew install mongodb
|
||||
elif [[ "$(uname)" == 'Linux' ]]; then
|
||||
# No node! Install nvm
|
||||
echo >&2 "NodeJS is not found. Installing (using nvm)...";
|
||||
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash;
|
||||
source $DETECTED_PROFILE
|
||||
. $NVM_DIR/nvm.sh
|
||||
|
||||
if [[ -r /etc/os-release ]]; then
|
||||
# this will get the required information without dirtying any env state
|
||||
DIST_VERS="$( ( . /etc/os-release &>/dev/null
|
||||
echo "$ID $VERSION_ID") )"
|
||||
DISTRO="${DIST_VERS%% *}" # get our distro name
|
||||
VERSION="${DIST_VERS##* }" # get our version number
|
||||
elif [[ -r /etc/lsb-release ]]; then
|
||||
DIST_VERS="$( ( . /etc/lsb-release &>/dev/null
|
||||
echo "${DISTRIB_ID,,} $DISTRIB_RELEASE") )"
|
||||
DISTRO="${DIST_VERS%% *}" # get our distro name
|
||||
VERSION="${DIST_VERS##* }" # get our version number
|
||||
else # well, I'm out of ideas for now
|
||||
echo '==> Failed to determine distro and version.'
|
||||
exit 1
|
||||
fi
|
||||
set_node_version
|
||||
}
|
||||
|
||||
# Detect archlinux
|
||||
if [[ "$DISTRO" = "arch" ]]; then
|
||||
distribution="archlinux"
|
||||
sudo pacman -S mongodb
|
||||
# Detect Ubuntu
|
||||
elif [[ "$DISTRO" = "ubuntu" ]]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get install mongodb
|
||||
else
|
||||
NEEDS_MONGO=true
|
||||
fi
|
||||
fi
|
||||
# Check node version supports arrow fns and string templates
|
||||
node -e '() => console.log(`print "3": ${1+2}`)' >/dev/null 2>&1 || {
|
||||
echo "Unsupported version of NodeJS."
|
||||
echo ""
|
||||
echo "Please update NodeJS to version 4.x.x or later (6.x.x recommended)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo >&2 "Installing DeepForge...";
|
||||
|
||||
# Clone deepforge into ~/deepforge
|
||||
git clone https://github.com/dfst/deepforge ~/deepforge
|
||||
cd ~/deepforge
|
||||
npm install
|
||||
npm install -g deepforge
|
||||
|
||||
mkdir ~/deepforge/data 2> /dev/null
|
||||
|
||||
echo "Final Installation steps:"
|
||||
echo "Final Installation Steps:"
|
||||
echo " 1) Close and re-open your terminal"
|
||||
echo " (or run \"source $DETECTED_PROFILE\")"
|
||||
|
||||
if [[ $NEEDS_MONGO ]]; then
|
||||
echo " 2) Install MongoDB for your OS"
|
||||
echo " (available at https://www.mongodb.com/download-center)"
|
||||
echo " Note: for custom installs, this may not be required"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Then run DeepForge!"
|
||||
echo " 1) make sure MongoDB is running locally"
|
||||
echo " (start mongo w/ \"mongod --dbpath ~/deepforge/data\")"
|
||||
echo " 2) Run \"npm run local\" from ~/deepforge"
|
||||
echo " 1) run \"deepforge start\""
|
||||
echo " 2) open a browser to http://localhost:8888"
|
||||
echo " 3) start building neural nets!"
|
||||
|
||||
+11
-8
@@ -8,32 +8,35 @@
|
||||
"start-dev": "NODE_ENV=dev node app.js",
|
||||
"local": "node ./bin/start-local.js",
|
||||
"worker": "node ./bin/start-worker.js",
|
||||
"test": "node ./node_modules/mocha/bin/mocha --recursive test",
|
||||
"test": "mkdir ./test-tmp; node ./node_modules/mocha/bin/mocha --recursive test",
|
||||
"test-cover": "node node_modules/istanbul/lib/cli.js --hook-run-in-context cover node_modules/mocha/bin/_mocha -- -R spec test/**/*",
|
||||
"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.0",
|
||||
"version": "0.16.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",
|
||||
"express": "^4.14.0",
|
||||
"lodash.difference": "^4.1.2",
|
||||
"lodash.merge": "^4.5.1",
|
||||
"nodemon": "^1.9.2",
|
||||
"q": "1.4.1",
|
||||
"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"
|
||||
"webgme-simple-nodes": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^3.0.0",
|
||||
"jszip": "^2.5.0",
|
||||
"mocha": "^2.2.5",
|
||||
"mockery": "^1.7.0",
|
||||
"rimraf": "^2.4.0"
|
||||
"istanbul": "^0.4.5",
|
||||
"mockery": "^1.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,28 @@ define({
|
||||
|
||||
// DeepForge metadata creation in dist execution
|
||||
START_CMD: 'deepforge-cmd',
|
||||
|
||||
IMAGE: { // all prefixed w/ 'IMG' for simple upload detection
|
||||
PREFIX: 'IMG',
|
||||
BASIC: 'IMG-B',
|
||||
CREATE: 'IMG-C',
|
||||
UPDATE: 'IMG-U',
|
||||
NAME: 'IMAGE-N' // No upload required
|
||||
},
|
||||
|
||||
GRAPH_CREATE: 'GRAPH',
|
||||
GRAPH_PLOT: 'PLOT',
|
||||
GRAPH_CREATE_LINE: 'LINE'
|
||||
GRAPH_CREATE_LINE: 'LINE',
|
||||
|
||||
// Code Generation Constants
|
||||
CTOR_ARGS_ATTR: 'ctor_arg_order',
|
||||
|
||||
// Operation types
|
||||
OP: {
|
||||
INPUT: 'Input',
|
||||
OUTPUT: 'Output'
|
||||
},
|
||||
|
||||
// Job stdout update
|
||||
STDOUT_UPDATE: 'stdout_update'
|
||||
});
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/* globals define */
|
||||
define([
|
||||
'q',
|
||||
'superagent'
|
||||
], function(
|
||||
Q,
|
||||
superagent
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
// Wrap the ability to read, update, and delete logs using the JobLogsAPI
|
||||
var JobLogsClient = function(params) {
|
||||
params = params || {};
|
||||
|
||||
this.logger = params.logger.fork('JobLogsClient');
|
||||
|
||||
// Get the server url
|
||||
this.token = params.token;
|
||||
this.origin = this._getServerUrl(params);
|
||||
this.relativeUrl = '/execution/logs';
|
||||
this.url = this.origin + this.relativeUrl;
|
||||
|
||||
this.logger.debug(`Setting url to ${this.url}`);
|
||||
|
||||
// Get the project, branch name
|
||||
if (!(params.branchName && params.projectId)) {
|
||||
throw Error('"branchName" and "projectId" required');
|
||||
}
|
||||
this.branch = params.branchName;
|
||||
this.project = params.projectId;
|
||||
this._modifiedJobs = [];
|
||||
|
||||
this.logger.debug(`Using <project>:<branch>: "${this.project}"/"${this.branch}"`);
|
||||
this.logger.info('ctor finished');
|
||||
};
|
||||
|
||||
JobLogsClient.prototype._getServerUrl = function(params) {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.location.origin;
|
||||
}
|
||||
|
||||
// If not in browser, set using the params
|
||||
var server = params.server || '127.0.0.1',
|
||||
port = params.port || '80',
|
||||
protocol = params.httpsecure ? 'https' : 'http'; // default is http
|
||||
|
||||
return params.origin || `${protocol}://${server}:${port}`;
|
||||
};
|
||||
|
||||
// This method could be optimized - it could make a log of requests
|
||||
JobLogsClient.prototype.fork = function(forkName) {
|
||||
var jobIds = this._modifiedJobs,
|
||||
deferred = Q.defer(),
|
||||
url = [
|
||||
this.url,
|
||||
'migrate',
|
||||
encodeURIComponent(this.project),
|
||||
encodeURIComponent(this.branch),
|
||||
encodeURIComponent(forkName)
|
||||
].join('/'),
|
||||
req = superagent.post(url);
|
||||
|
||||
this.logger.info(`migrating ${jobIds.length} jobs from ${this.branch} to ${forkName} in ${this.project}`);
|
||||
if (this.token) {
|
||||
req.set('Authorization', 'Bearer ' + this.token);
|
||||
}
|
||||
|
||||
req.send({jobs: jobIds})
|
||||
.end((err, res) => {
|
||||
if (err || res.status > 399) {
|
||||
return deferred.reject(err || res.status);
|
||||
}
|
||||
|
||||
return deferred.resolve(res);
|
||||
});
|
||||
|
||||
this.branch = forkName;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
JobLogsClient.prototype.getUrl = function(jobId) {
|
||||
return [
|
||||
this.url,
|
||||
encodeURIComponent(this.project),
|
||||
encodeURIComponent(this.branch),
|
||||
encodeURIComponent(jobId)
|
||||
].join('/');
|
||||
};
|
||||
|
||||
JobLogsClient.prototype._logRequest = function(method, jobId, content) {
|
||||
var deferred = Q.defer(),
|
||||
req = superagent[method](this.getUrl(jobId));
|
||||
|
||||
this.logger.info(`sending ${method} request to ${this.getUrl(jobId)}`);
|
||||
if (this.token) {
|
||||
req.set('Authorization', 'Bearer ' + this.token);
|
||||
}
|
||||
|
||||
if (content) {
|
||||
req = req.send(content);
|
||||
}
|
||||
|
||||
req.end((err, res) => {
|
||||
if (err || res.status > 399) {
|
||||
return deferred.reject(err || res.status);
|
||||
}
|
||||
|
||||
return deferred.resolve(res);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
JobLogsClient.prototype.appendTo = function(jobId, text) {
|
||||
this._modifiedJobs.push(jobId);
|
||||
this.logger.info(`Appending logs to ${jobId}`);
|
||||
return this._logRequest('patch', jobId, {patch: text});
|
||||
};
|
||||
|
||||
JobLogsClient.prototype.getLog = function(jobId) {
|
||||
this.logger.info(`Getting logs for ${jobId}`);
|
||||
return this._logRequest('get', jobId)
|
||||
.then(res => res.text);
|
||||
};
|
||||
|
||||
JobLogsClient.prototype.deleteLog = function(jobId) {
|
||||
this.logger.info(`Deleting logs for ${jobId}`);
|
||||
return this._logRequest('delete', jobId);
|
||||
};
|
||||
|
||||
return JobLogsClient;
|
||||
});
|
||||
@@ -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:
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
// This is an 'executor' containing the implementations of all local operations
|
||||
// These are all primitives in DeepForge
|
||||
define([
|
||||
'deepforge/Constants'
|
||||
], function(
|
||||
CONSTANTS
|
||||
) {
|
||||
'use strict';
|
||||
var LocalExecutor = function() {
|
||||
};
|
||||
|
||||
// Should these be in lua?
|
||||
LocalExecutor.prototype.ArtifactLoader = function(node) {
|
||||
LocalExecutor.prototype[CONSTANTS.OP.INPUT] = function(node) {
|
||||
// Get the hash from the output node
|
||||
var hash;
|
||||
return this.core.loadChildren(node)
|
||||
@@ -18,13 +20,13 @@ define([
|
||||
var output = cntrs
|
||||
.find(cntr => {
|
||||
var metaNode = this.core.getMetaType(cntr),
|
||||
metaName = this.core.getAttribute(metaNode, 'name');
|
||||
metaName = this.getAttribute(metaNode, 'name');
|
||||
return metaName === 'Outputs';
|
||||
});
|
||||
return this.core.loadChildren(output);
|
||||
})
|
||||
.then(dataNodes => {
|
||||
hash = this.core.getAttribute(dataNodes[0], 'data');
|
||||
hash = this.getAttribute(dataNodes[0], 'data');
|
||||
return this.getOutputs(node);
|
||||
})
|
||||
.then(outputTuples => {
|
||||
@@ -46,7 +48,7 @@ define([
|
||||
var hash,
|
||||
typeId = this.core.getPointerPath(node, 'type'),
|
||||
type,
|
||||
artifactName = this.core.getAttribute(node, 'artifactName');
|
||||
artifactName = this.getAttribute(node, 'artifactName');
|
||||
|
||||
return this.core.loadByPath(this.rootNode, typeId)
|
||||
.then(_type => {
|
||||
@@ -56,25 +58,20 @@ define([
|
||||
.then(saveDir => this.core.loadChildren(saveDir))
|
||||
.then(artifacts => {
|
||||
return artifacts.find(artifact =>
|
||||
this.core.getAttribute(artifact, 'name') === artifactName &&
|
||||
this.getAttribute(artifact, 'name') === artifactName &&
|
||||
this.isMetaTypeOf(artifact, type));
|
||||
})
|
||||
.then(matchingArtifact => {
|
||||
hash = matchingArtifact && this.core.getAttribute(matchingArtifact, 'data');
|
||||
hash = matchingArtifact && this.getAttribute(matchingArtifact, 'data');
|
||||
// If no hash, just continue (the subsequent ops will receive 'nil')
|
||||
if (!hash) {
|
||||
return this.onOperationComplete(node);
|
||||
} else {
|
||||
return this.getOutputs(node)
|
||||
.then(outputPairs => {
|
||||
var outputs = outputPairs.map(pair => pair[2]),
|
||||
paths;
|
||||
|
||||
paths = outputs.map(output => this.core.getPath(output));
|
||||
var outputs = outputPairs.map(pair => pair[2]);
|
||||
// Get the 'data' hash and store it in the output data ports
|
||||
this.logger.info(`Loading blob data (${hash}) to ${paths.map(p => `"${p}"`)}`);
|
||||
|
||||
outputs.forEach(output => this.core.setAttribute(output, 'data', hash));
|
||||
outputs.forEach(output => this.setAttribute(output, 'data', hash));
|
||||
|
||||
this.onOperationComplete(node);
|
||||
});
|
||||
@@ -97,7 +94,7 @@ define([
|
||||
|
||||
if (containers.length > 1) {
|
||||
saveDir = containers.find(c =>
|
||||
this.core.getAttribute(c, 'name').toLowerCase().indexOf('artifacts') > -1
|
||||
this.getAttribute(c, 'name').toLowerCase().indexOf('artifacts') > -1
|
||||
) || containers[0];
|
||||
}
|
||||
|
||||
@@ -105,22 +102,31 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
LocalExecutor.prototype.Save = function(node) {
|
||||
var nodeId = this.core.getPath(node),
|
||||
parentNode;
|
||||
LocalExecutor.prototype[CONSTANTS.OP.OUTPUT] = function(node) {
|
||||
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.getAttribute(node, 'name'),
|
||||
this.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,20 +135,33 @@ 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.getAttribute(dataNode, 'data'),
|
||||
name = this.core.getOwnAttribute(node, 'saveName') ||
|
||||
this.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) {
|
||||
newNodes.forEach(node =>
|
||||
this.core.setAttribute(node, 'name', newName)
|
||||
this.setAttribute(node, 'name', newName)
|
||||
);
|
||||
}
|
||||
var hashes = dataNodes.map(n => this.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;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Audiowide';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Audiowide'), local('Audiowide-Regular'), url(https://fonts.gstatic.com/s/audiowide/v4/7pSgz2MbVvTCvvm7vukSHxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Audiowide';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Audiowide'), local('Audiowide-Regular'), url(https://fonts.gstatic.com/s/audiowide/v4/8XtYtNKEyyZh481XVWfVOltXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
li.deepforge-logo {
|
||||
background-image: url(img/deepforge-logo.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 100px;
|
||||
background-size: 95px;
|
||||
}
|
||||
|
||||
.deepforge-logo .item-label {
|
||||
font-family: 'Audiowide', cursive;
|
||||
li.deepforge-logo span {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
i.gme-icon {
|
||||
background-image: url(img/deepforge-icon.png);
|
||||
background-size: 15.20px 18px;
|
||||
}
|
||||
|
||||
.create-node text {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.job-canceled {
|
||||
background-color: #ffe0b2;
|
||||
}
|
||||
|
||||
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 2.0 KiB |
Arquivo binário não exibido.
|
Depois Largura: | Altura: | Tamanho: 3.3 KiB |
@@ -0,0 +1,93 @@
|
||||
/* globals define*/
|
||||
(function(root, factory){
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define([], function(){
|
||||
return (root.utils = factory());
|
||||
});
|
||||
} else if(typeof module === 'object' && module.exports) {
|
||||
module.exports = (root.utils = factory());
|
||||
}
|
||||
}(this, 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);
|
||||
}
|
||||
};
|
||||
|
||||
// Resolving stdout
|
||||
var resolveCarriageReturns = function(text) {
|
||||
// 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('');
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
getSetterSchema: getSetterSchema,
|
||||
resolveCarriageReturns: resolveCarriageReturns,
|
||||
abbr: abbr
|
||||
};
|
||||
}));
|
||||
@@ -0,0 +1,191 @@
|
||||
/* globals define, WebGMEGlobal */
|
||||
// Mixin for executing jobs and pipelines
|
||||
define([
|
||||
'q',
|
||||
'executor/ExecutorClient',
|
||||
'panel/FloatingActionButton/styles/Materialize'
|
||||
], function(
|
||||
Q,
|
||||
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';
|
||||
|
||||
if (method === 'runServerPlugin' &&
|
||||
this.client.getBranchStatus() !== this.client.CONSTANTS.BRANCH_STATUS.SYNC) {
|
||||
|
||||
Materialize.toast('Cannot execute operations when client is out-of-sync', 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
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 && result.messages.length) {
|
||||
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.silentStopJob = function(job) {
|
||||
var jobHash,
|
||||
secret;
|
||||
|
||||
job = job || this.client.getNode(this._currentNodeId);
|
||||
jobHash = job.getAttribute('jobId');
|
||||
secret = job.getAttribute('secret');
|
||||
if (!jobHash || !secret) {
|
||||
this.logger.error('Cannot stop job. Missing jobHash or secret');
|
||||
return;
|
||||
}
|
||||
|
||||
return this._executor.cancelJob(jobHash, secret)
|
||||
.then(() => this.logger.info(`${jobHash} has been cancelled!`))
|
||||
.fail(err => this.logger.error(`Job cancel failed: ${err}`));
|
||||
};
|
||||
|
||||
Execute.prototype.stopJob = function(job, silent) {
|
||||
var jobId;
|
||||
|
||||
job = job || this.client.getNode(this._currentNodeId);
|
||||
jobId = job.getId();
|
||||
|
||||
this.silentStopJob(job);
|
||||
|
||||
if (!silent) {
|
||||
this.client.startTransaction(`Stopping "${name}" job`);
|
||||
}
|
||||
|
||||
this.client.delAttributes(jobId, 'jobId');
|
||||
this.client.delAttributes(jobId, 'secret');
|
||||
this.client.setAttributes(jobId, 'status', 'canceled');
|
||||
|
||||
if (!silent) {
|
||||
this.client.completeTransaction();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Execute.prototype.loadChildren = function(id) {
|
||||
var deferred = Q.defer(),
|
||||
execNode = this.client.getNode(id || this._currentNodeId),
|
||||
jobIds = execNode.getChildrenIds(),
|
||||
jobsLoaded = !jobIds.length || this.client.getNode(jobIds[0]);
|
||||
|
||||
// May need to load the jobs...
|
||||
if (!jobsLoaded) {
|
||||
// Create a territory and load the nodes
|
||||
var territory = {},
|
||||
ui;
|
||||
|
||||
territory[id] = {children: 1};
|
||||
ui = this.client.addUI(this, () => {
|
||||
this.client.removeUI(ui);
|
||||
deferred.resolve();
|
||||
});
|
||||
this.client.updateTerritory(ui, territory);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
Execute.prototype.stopExecution = function(id, inTransaction) {
|
||||
var execNode = this.client.getNode(id || this._currentNodeId);
|
||||
|
||||
return this.loadChildren(id)
|
||||
.then(() => this._stopExecution(execNode, inTransaction));
|
||||
};
|
||||
|
||||
Execute.prototype.silentStopExecution = function(id) {
|
||||
var execNode = this.client.getNode(id || this._currentNodeId);
|
||||
|
||||
// Stop the execution w/o setting any attributes
|
||||
return this.loadChildren(id)
|
||||
.then(() => this._silentStopExecution(execNode));
|
||||
};
|
||||
|
||||
Execute.prototype._stopExecution = function(execNode, inTransaction) {
|
||||
var msg = `Canceling ${execNode.getAttribute('name')} execution`;
|
||||
|
||||
if (!inTransaction) {
|
||||
this.client.startTransaction(msg);
|
||||
}
|
||||
|
||||
this._silentStopExecution(execNode);
|
||||
this.client.setAttributes(execNode.getId(), 'status', 'canceled');
|
||||
|
||||
if (!inTransaction) {
|
||||
this.client.completeTransaction();
|
||||
}
|
||||
};
|
||||
|
||||
Execute.prototype._silentStopExecution = function(execNode) {
|
||||
var jobIds = execNode.getChildrenIds();
|
||||
|
||||
jobIds.map(id => this.client.getNode(id))
|
||||
.filter(job => this.isRunning(job)) // get running jobs
|
||||
.forEach(job => this.silentStopJob(job)); // stop them
|
||||
};
|
||||
|
||||
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'
|
||||
}
|
||||
});
|
||||
@@ -1,12 +1,8 @@
|
||||
/*globals define, _*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
/**
|
||||
* @author brollb / https://github.com/brollb
|
||||
*/
|
||||
|
||||
define([
|
||||
'js/Constants',
|
||||
'deepforge/Constants',
|
||||
'decorators/DcOpDecorator/EasyDAG/DcOpDecorator.EasyDAGWidget',
|
||||
'css!./ArtifactOpDecorator.EasyDAGWidget.css'
|
||||
], function (
|
||||
@@ -19,16 +15,17 @@ define([
|
||||
var ArtifactOpDecorator,
|
||||
DECORATOR_ID = 'ArtifactOpDecorator',
|
||||
CAST_OPTS = {
|
||||
ArtifactLoader: {
|
||||
ptr: 'artifact',
|
||||
metaTgt: false
|
||||
},
|
||||
ArtifactFinder: {
|
||||
ptr: 'type',
|
||||
metaTgt: true
|
||||
}
|
||||
};
|
||||
|
||||
CAST_OPTS[CONSTANTS.OP.INPUT] = {
|
||||
ptr: 'artifact',
|
||||
metaTgt: false
|
||||
};
|
||||
|
||||
// ArtifactOp nodes need to be able to...
|
||||
// - dynamically change their outputs (downcast)
|
||||
ArtifactOpDecorator = function (options) {
|
||||
@@ -74,7 +71,7 @@ define([
|
||||
};
|
||||
|
||||
ArtifactOpDecorator.prototype.getDisplayName = function() {
|
||||
var ptrName = this._node.baseName === 'ArtifactLoader' ? 'artifact' : 'type',
|
||||
var ptrName = this._node.baseName === CONSTANTS.OP.INPUT ? 'artifact' : 'type',
|
||||
id = this._node.pointers[ptrName],
|
||||
name = this.nameFor[id] || this._node.name;
|
||||
return name;
|
||||
@@ -91,7 +88,7 @@ define([
|
||||
ArtifactOpDecorator.prototype.updateTargetName = function(id, name) {
|
||||
DecoratorBase.prototype.updateTargetName.apply(this, arguments);
|
||||
// Update name
|
||||
var ptrName = this._node.baseName === 'ArtifactLoader' ? 'artifact' : 'type';
|
||||
var ptrName = this._node.baseName === CONSTANTS.OP.INPUT ? 'artifact' : 'type';
|
||||
if (this._node.pointers[ptrName] === id) {
|
||||
this._name = name;
|
||||
this.onResize();
|
||||
|
||||
@@ -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,17 @@
|
||||
/*globals define, _*/
|
||||
/*jshint browser: true, camelcase: false*/
|
||||
|
||||
/**
|
||||
* @author brollb / https://github.com/brollb
|
||||
*/
|
||||
|
||||
define([
|
||||
'deepforge/Constants',
|
||||
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
|
||||
'./PointerField.RO',
|
||||
'./AttributeField.RO',
|
||||
'css!./JobDecorator.EasyDAGWidget.css'
|
||||
], function (
|
||||
EllipseDecorator
|
||||
CONSTANTS,
|
||||
EllipseDecorator,
|
||||
PointerField,
|
||||
AttributeField
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
@@ -20,6 +22,7 @@ define([
|
||||
pending: '#9e9e9e',
|
||||
queued: '#cfd8dc',
|
||||
running: '#fff59d',
|
||||
canceled: '#ffcc80',
|
||||
success: '#66bb6a',
|
||||
fail: '#e57373'
|
||||
};
|
||||
@@ -35,6 +38,8 @@ define([
|
||||
status: true,
|
||||
execFiles: true,
|
||||
stdout: true,
|
||||
secret: true,
|
||||
jobId: true,
|
||||
debug: true
|
||||
};
|
||||
EllipseDecorator.call(this, options);
|
||||
@@ -43,18 +48,46 @@ define([
|
||||
_.extend(JobDecorator.prototype, EllipseDecorator.prototype);
|
||||
|
||||
JobDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
|
||||
JobDecorator.prototype.AttributeField = AttributeField;
|
||||
JobDecorator.prototype.PointerField = PointerField;
|
||||
|
||||
JobDecorator.prototype.isInputOperation = function() {
|
||||
return this._node.name === CONSTANTS.OP.INPUT;
|
||||
};
|
||||
|
||||
JobDecorator.prototype.getDisplayName = function() {
|
||||
if (this.isInputOperation()) {
|
||||
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*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*globals define*/
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
define([
|
||||
'text!./metadata.json',
|
||||
'module',
|
||||
'path',
|
||||
'fs',
|
||||
'q',
|
||||
'plugin/PluginBase'
|
||||
], function (
|
||||
pluginMetadata,
|
||||
module,
|
||||
path,
|
||||
fs,
|
||||
Q,
|
||||
PluginBase
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
pluginMetadata = JSON.parse(pluginMetadata);
|
||||
var __dirname = path.dirname(module.uri),
|
||||
SEEDS_DIR = path.join(__dirname, '..', '..', 'seeds');
|
||||
|
||||
/**
|
||||
* Initializes a new instance of CheckLibraries.
|
||||
* @class
|
||||
* @augments {PluginBase}
|
||||
* @classdesc This class represents the plugin CheckLibraries.
|
||||
* @constructor
|
||||
*/
|
||||
var CheckLibraries = function () {
|
||||
// Call base class' constructor.
|
||||
PluginBase.call(this);
|
||||
this.pluginMetadata = pluginMetadata;
|
||||
this.libraries = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
|
||||
* This is also available at the instance at this.pluginMetadata.
|
||||
* @type {object}
|
||||
*/
|
||||
CheckLibraries.metadata = pluginMetadata;
|
||||
|
||||
// Prototypical inheritance from PluginBase.
|
||||
CheckLibraries.prototype = Object.create(PluginBase.prototype);
|
||||
CheckLibraries.prototype.constructor = CheckLibraries;
|
||||
|
||||
/**
|
||||
* Main function for the plugin to execute. This will perform the execution.
|
||||
* Notes:
|
||||
* - Always log with the provided logger.[error,warning,info,debug].
|
||||
* - Do NOT put any user interaction logic UI, etc. inside this method.
|
||||
* - callback always has to be called even if error happened.
|
||||
*
|
||||
* @param {function(string, plugin.PluginResult)} callback - the result callback
|
||||
*/
|
||||
CheckLibraries.prototype.main = function (callback) {
|
||||
var tuples;
|
||||
|
||||
return this.getAllLibraries()
|
||||
.then(libs => {
|
||||
tuples = libs.map(lib => { // map to [name, version, dir]
|
||||
var version,
|
||||
hash,
|
||||
data,
|
||||
versionPath = this.getSeedVersionPath(lib);
|
||||
|
||||
try {
|
||||
this.logger.info(`Checking for version info at ${versionPath}`);
|
||||
version = fs.readFileSync(versionPath, 'utf8');
|
||||
this.logger.debug(`${lib} version is ${version}`);
|
||||
data = fs.readFileSync(this.getSeedHashPath(lib), 'utf8').split(' ');
|
||||
if (data[1] === version) {
|
||||
hash = data[0];
|
||||
this.logger.debug(`${lib} hash is ${hash}`);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!version) {
|
||||
this.logger.warn(`Could not find library version for ${lib}`);
|
||||
} else {
|
||||
this.logger.warn(`Could not find library hash for ${lib}`);
|
||||
}
|
||||
}
|
||||
|
||||
return [lib, version, hash];
|
||||
})
|
||||
.filter(tuple => {
|
||||
var projVersion = this.getLoadedVersion(tuple[0]),
|
||||
latest = tuple[1].replace(/\s+/g, '');
|
||||
|
||||
this.logger.info(`${tuple[0]} version info:\n${projVersion} ` +
|
||||
`(project)\n${latest} (latest)`);
|
||||
return latest !== projVersion;
|
||||
});
|
||||
|
||||
return Q.all(tuples.map(tuple => this.uploadSeed.apply(this, tuple)));
|
||||
})
|
||||
.then(hashes => {
|
||||
var name;
|
||||
|
||||
for (var i = hashes.length; i--;) {
|
||||
name = tuples[i][0];
|
||||
this.createMessage(this.libraries[name], `${name} ${hashes[i]}`);
|
||||
}
|
||||
|
||||
this.logger.info(`Found ${hashes.length} out of date libraries`);
|
||||
this.result.setSuccess(true);
|
||||
callback(null, this.result);
|
||||
})
|
||||
.fail(err => {
|
||||
this.logger.error(`Could not check the libraries: ${err}`);
|
||||
callback(err, this.result);
|
||||
});
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getSeedDir = function (name) {
|
||||
return path.join(SEEDS_DIR, name);
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getSeedDataPath = function (name) {
|
||||
return path.join(this.getSeedDir(name), name + '.webgmex');
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getSeedHashPath = function (name) {
|
||||
return path.join(this.getSeedDir(name), 'hash.txt');
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getSeedVersionPath = function (name) {
|
||||
return path.join(this.getSeedDir(name), 'version.txt');
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.uploadSeed = function (name, version, hash) {
|
||||
if (!hash) { // Upload the seed
|
||||
// Get the data
|
||||
return Q.nfcall(fs.readFile, this.getSeedDataPath(name))
|
||||
.then(data => {
|
||||
this.logger.info(`Uploading new version of ${name} (${version})`);
|
||||
return this.blobClient.putFile(`${name}.webgmex`, data);
|
||||
})
|
||||
.then(newHash => { // Store the new hash
|
||||
this.logger.info(`Upload of ${name} finished!`);
|
||||
hash = newHash;
|
||||
return Q.nfcall(
|
||||
fs.writeFile,
|
||||
this.getSeedHashPath(name),
|
||||
`${hash} ${version}`
|
||||
);
|
||||
}).then(() => hash);
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getAllLibraries = function () {
|
||||
var name,
|
||||
names = [];
|
||||
|
||||
return this.core.loadChildren(this.rootNode)
|
||||
.then(children => {
|
||||
for (var i = children.length; i--;) {
|
||||
if (this.core.isLibraryRoot(children[i])) {
|
||||
name = this.core.getAttribute(children[i], 'name');
|
||||
this.libraries[name] = children[i];
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
if (names.length) {
|
||||
this.logger.debug(`Found libraries: ${names.join(', ')}`);
|
||||
} else {
|
||||
this.logger.debug('Found no libraries!');
|
||||
}
|
||||
return names;
|
||||
});
|
||||
};
|
||||
|
||||
CheckLibraries.prototype.getLoadedVersion = function (libName) {
|
||||
var node = this.libraries[libName],
|
||||
version = this.core.getAttribute(node, 'version'); // using library root hash
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
return CheckLibraries;
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "CheckLibraries",
|
||||
"name": "CheckLibraries",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"icon": {
|
||||
"class": "glyphicon glyphicon-cog",
|
||||
"src": ""
|
||||
},
|
||||
"disableServerSideExecution": false,
|
||||
"disableBrowserSideExecution": true,
|
||||
"writeAccessRequired": false,
|
||||
"configStructure": []
|
||||
}
|
||||
@@ -79,48 +79,58 @@ 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
|
||||
// - Wrap the operations in "Job" boxes which contain running info
|
||||
// - eg,
|
||||
// - 'debug' the given run (download all execution files)
|
||||
// - '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
|
||||
});
|
||||
this.logger.debug(`New execution created w/ id: ${this.core.getPath(tgtNode)}`);
|
||||
|
||||
// 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 +138,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 +149,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,45 +157,57 @@ 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();
|
||||
})
|
||||
.then(execDir => {
|
||||
var cIds = this.core.getChildrenPaths(execDir);
|
||||
this.logger.debug(`Current executions are ${cIds.join(', ')}`);
|
||||
return Q.all(cIds.map(id => this.core.loadByPath(this.rootNode, id)));
|
||||
})
|
||||
.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 +222,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);
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -1,6 +1,13 @@
|
||||
-- Instantiate the deepforge object
|
||||
deepforge = {}
|
||||
|
||||
function deepforge.initialize()
|
||||
require 'nn'
|
||||
require 'rnn'
|
||||
require './classes/init'
|
||||
require './custom-layers'
|
||||
end
|
||||
|
||||
function deepforge.id()
|
||||
if __deepforge_id == nil then
|
||||
__deepforge_id = 0
|
||||
@@ -16,9 +23,10 @@ function deepforge._cmd(...)
|
||||
for i=1,n do
|
||||
cmd = cmd .. ' ' .. tostring(arg[i])
|
||||
end
|
||||
print(cmd)
|
||||
print(cmd .. ' ') -- guarantee ends w/ space
|
||||
end
|
||||
|
||||
-- Graph support
|
||||
Graph = torch.class('deepforge.Graph')
|
||||
|
||||
function Graph:__init(name)
|
||||
@@ -36,6 +44,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 +52,46 @@ function Graph:line(name, opts)
|
||||
return deepforge._Line(self.id, name, opts)
|
||||
end
|
||||
|
||||
-- Image support
|
||||
local function saveImage(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)
|
||||
end
|
||||
|
||||
function deepforge.image(name, tensor)
|
||||
saveImage(name, tensor)
|
||||
deepforge._cmd("<%= IMAGE.BASIC %>", deepforge.id(), name)
|
||||
end
|
||||
|
||||
Image = torch.class('deepforge.Image')
|
||||
function Image:__init(name, tensor)
|
||||
self.id = deepforge.id()
|
||||
self.name = name
|
||||
|
||||
if tensor ~= nil then
|
||||
saveImage(name, tensor)
|
||||
deepforge._cmd('<%= IMAGE.CREATE %>', self.id, self.name)
|
||||
end
|
||||
end
|
||||
|
||||
function Image:update(tensor)
|
||||
saveImage(self.name, tensor)
|
||||
deepforge._cmd('<%= IMAGE.UPDATE %>', self.id, self.name)
|
||||
end
|
||||
|
||||
function Image:title(name)
|
||||
self.name = name
|
||||
deepforge._cmd('<%= IMAGE.NAME %>', self.id, self.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,
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
-- load custom layers
|
||||
require './custom-layers'
|
||||
|
||||
-- load custom class definitions
|
||||
require './classes'
|
||||
-- load custom layers and classes
|
||||
deepforge.initialize()
|
||||
|
||||
-- input data<% inputs.forEach(function(pair) { var input = pair[0], isNil = pair[1];%>
|
||||
<%= isNil ? 'local ' : ''%><%= input %> = <% if (isNil) { %>nil<% } else { %>require './inputs/<%= input %>'<%}}); %>
|
||||
local <%= input %> = <% if (isNil) { %>nil<% } else { %>require './inputs/<%= input %>'<%}}); %>
|
||||
|
||||
-- load references<% pointers.forEach(function(pair) { var pointer = pair[0], isNil = pair[1];%>
|
||||
<%= isNil ? 'local ' : ''%><%= pointer %> = <% if (isNil) { %>nil<% } else { %>require './pointers/<%= pointer %>'<%}}); %>
|
||||
attributes = require './attributes'
|
||||
local <%= pointer %> = <% if (isNil) { %>nil<% } else { %>require './pointers/<%= pointer %>'<%}}); %>
|
||||
local attributes = require './attributes'
|
||||
|
||||
-- main operation code for <%= name %>
|
||||
<%= code %>
|
||||
|
||||
@@ -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.PREFIX %>',
|
||||
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(3).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);
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@
|
||||
define([
|
||||
'plugin/CreateExecution/CreateExecution/CreateExecution',
|
||||
'plugin/ExecuteJob/ExecuteJob/ExecuteJob',
|
||||
'deepforge/JobLogsClient',
|
||||
'common/storage/constants',
|
||||
'common/core/constants',
|
||||
'q',
|
||||
@@ -12,6 +13,7 @@ define([
|
||||
], function (
|
||||
CreateExecution,
|
||||
ExecuteJob,
|
||||
JobLogsClient,
|
||||
STORAGE_CONSTANTS,
|
||||
CONSTANTS,
|
||||
Q,
|
||||
@@ -34,6 +36,11 @@ define([
|
||||
this.pluginMetadata = pluginMetadata;
|
||||
|
||||
this._currentSave = Q();
|
||||
this.changes = {};
|
||||
this.currentChanges = {}; // read-only changes being applied
|
||||
this.creations = {};
|
||||
this.deletions = [];
|
||||
this.createIdToMetadataId = {};
|
||||
this.initRun();
|
||||
};
|
||||
|
||||
@@ -74,6 +81,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
|
||||
@@ -93,27 +101,32 @@ define([
|
||||
* @param {function(string, plugin.PluginResult)} callback - the result callback
|
||||
*/
|
||||
ExecutePipeline.prototype.main = function (callback) {
|
||||
// This will probably need to execute the operations, too, because the
|
||||
// inputs for the next operation cannot be created until the inputs have
|
||||
// been generated
|
||||
var startPromise;
|
||||
|
||||
this.initRun();
|
||||
var startPromise;
|
||||
if (this.core.isTypeOf(this.activeNode, this.META.Pipeline)) {
|
||||
// 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.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;
|
||||
// Get the gmeConfig...
|
||||
this.logManager = new JobLogsClient({
|
||||
logger: this.logger,
|
||||
port: this.gmeConfig.server.port,
|
||||
branchName: this.branchName,
|
||||
projectId: this.projectId
|
||||
});
|
||||
this._callback = callback;
|
||||
this.currentForkName = null;
|
||||
|
||||
startPromise
|
||||
.then(() => this.core.loadSubTree(this.activeNode))
|
||||
@@ -121,50 +134,65 @@ define([
|
||||
var children = subtree
|
||||
.filter(n => this.core.getParent(n) === this.activeNode);
|
||||
|
||||
this.pipelineName = this.core.getAttribute(this.activeNode, 'name');
|
||||
this.pipelineName = this.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(() => this.applyModelChanges())
|
||||
.then(() => CreateExecution.prototype.save.call(this, msg))
|
||||
.then(result => {
|
||||
var msg;
|
||||
if (result.status === STORAGE_CONSTANTS.FORKED) {
|
||||
this.currentForkName = result.forkName;
|
||||
this.logManager.fork(result.forkName);
|
||||
msg = `"${this.pipelineName}" execution has forked to "${result.forkName}"`;
|
||||
this.sendNotification(msg);
|
||||
} else if (result.status === STORAGE_CONSTANTS.MERGED) {
|
||||
this.logger.debug('Merged changes. About to update plugin nodes');
|
||||
return this.updateNodes();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return this._currentSave;
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.updateNodes = function (hash) {
|
||||
var result = ExecuteJob.prototype.updateNodes.call(this, hash);
|
||||
return result.then(() => this.updateCache());
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.updateCache = function () {
|
||||
var nodeIds = Object.keys(this.nodes),
|
||||
nodes = nodeIds.map(id => this.core.loadByPath(this.rootNode, id));
|
||||
|
||||
this.logger.debug(`updating node cache (${nodeIds.length} nodes)`);
|
||||
return Q.all(nodes).then(nodes => {
|
||||
for (var i = nodeIds.length; i--;) {
|
||||
this.nodes[nodeIds[i]] = nodes[i];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.isExecutionCanceled = function () {
|
||||
return this.getAttribute(this.activeNode, 'status') === 'canceled';
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.isInputData = function (node) {
|
||||
var prnt = this.core.getParent(node);
|
||||
return this.core.isTypeOf(prnt, this.META.Inputs);
|
||||
@@ -184,13 +212,15 @@ define([
|
||||
nodes.filter(node => this.core.isTypeOf(node, this.META.Job))
|
||||
.forEach(node => {
|
||||
this.recordOldMetadata(node);
|
||||
this.core.setAttribute(node, 'status', 'pending');
|
||||
this.setAttribute(node, 'status', 'pending');
|
||||
});
|
||||
|
||||
// Set the status of the execution to 'running'
|
||||
this.core.setAttribute(this.activeNode, 'status', 'running');
|
||||
this.setAttribute(this.activeNode, 'status', 'running');
|
||||
this.logger.info('Setting all jobs status to "pending"');
|
||||
this.logger.debug(`Making a commit from ${this.currentHash}`);
|
||||
this.setAttribute(this.activeNode, 'startTime', Date.now());
|
||||
this.core.delAttribute(this.activeNode, 'endTime');
|
||||
return this.save(`Initializing ${this.pipelineName} for execution`);
|
||||
};
|
||||
|
||||
@@ -281,16 +311,25 @@ define([
|
||||
ExecutePipeline.prototype.onOperationFail = function(node, err) {
|
||||
var job = this.core.getParent(node),
|
||||
id = this.core.getPath(node),
|
||||
name = this.core.getAttribute(node, 'name');
|
||||
name = this.getAttribute(node, 'name');
|
||||
|
||||
this.logger.debug(`Operation ${name} (${id}) failed: ${err}`);
|
||||
this.core.setAttribute(job, 'status', 'fail');
|
||||
this.setAttribute(job, 'status', 'fail');
|
||||
this.clearOldMetadata(job);
|
||||
this.onPipelineComplete(err);
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onOperationCanceled = function(op) {
|
||||
var job = this.core.getParent(op);
|
||||
this.setAttribute(job, 'status', 'canceled');
|
||||
this.runningJobs--;
|
||||
this.logger.debug(`${this.getAttribute(job, 'name')} has been canceled`);
|
||||
this.onPipelineComplete();
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onPipelineComplete = function(err) {
|
||||
var name = this.core.getAttribute(this.activeNode, 'name');
|
||||
var name = this.getAttribute(this.activeNode, 'name'),
|
||||
msg = `"${this.pipelineName}" `;
|
||||
|
||||
if (err) {
|
||||
this.runningJobs--;
|
||||
@@ -298,23 +337,77 @@ 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;
|
||||
}
|
||||
|
||||
this.logger.debug(`Pipeline "${name}" complete!`);
|
||||
this.core.setAttribute(this.activeNode, 'status',
|
||||
(!this.pipelineError ? 'success' : 'failed'));
|
||||
if (this.currentForkName) {
|
||||
// notify client that the job has completed
|
||||
this.sendNotification(`"${this.pipelineName}" execution completed on branch "${this.currentForkName}"`);
|
||||
}
|
||||
|
||||
this._finished = true;
|
||||
this.save('Pipeline execution finished')
|
||||
.then(() => {
|
||||
if (this.pipelineError) {
|
||||
msg += 'failed!';
|
||||
} else if (this.canceled) {
|
||||
msg += 'canceled!';
|
||||
} else {
|
||||
msg += 'finished!';
|
||||
}
|
||||
|
||||
this.isDeleted().then(isDeleted => {
|
||||
if (!isDeleted) {
|
||||
|
||||
this.logger.debug(`Pipeline "${name}" complete!`);
|
||||
this.setAttribute(this.activeNode, 'endTime', Date.now());
|
||||
this.setAttribute(this.activeNode, 'status',
|
||||
(this.pipelineError ? 'failed' :
|
||||
(this.canceled ? 'canceled' : 'success')
|
||||
)
|
||||
);
|
||||
|
||||
this._finished = true;
|
||||
this.resultMsg(msg);
|
||||
this.save('Pipeline execution finished')
|
||||
.then(() => {
|
||||
this.result.setSuccess(!this.pipelineError);
|
||||
this._callback(this.pipelineError || null, this.result);
|
||||
})
|
||||
.fail(e => this.logger.error(e));
|
||||
} else { // deleted!
|
||||
this.logger.debug('Execution has been deleted!');
|
||||
this.result.setSuccess(!this.pipelineError);
|
||||
this._callback(this.pipelineError || null, this.result);
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.isDeleted = function () {
|
||||
var activeId = this.core.getPath(this.activeNode);
|
||||
|
||||
// Check if the current execution has been deleted
|
||||
return this.project.getBranchHash(this.branchName)
|
||||
.then(hash => this.updateNodes(hash))
|
||||
.then(() => this.core.loadByPath(this.rootNode, activeId))
|
||||
.then(node => {
|
||||
var deleted = node === null,
|
||||
msg = `Verified that execution is ${deleted ? '' : 'not '}deleted`;
|
||||
|
||||
this.logger.debug(msg);
|
||||
return deleted;
|
||||
})
|
||||
.fail(e => this.logger.error(e));
|
||||
.fail(err => this.logger.error(err));
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onPipelineDeleted = function () {
|
||||
var msg = `${this.pipelineName} has been deleted`;
|
||||
this.resultMsg(msg);
|
||||
this.result.setSuccess(true);
|
||||
this._callback(null, this.result);
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.executeReadyOperations = function () {
|
||||
@@ -325,7 +418,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();
|
||||
}
|
||||
@@ -347,7 +440,7 @@ define([
|
||||
};
|
||||
|
||||
ExecutePipeline.prototype.onOperationComplete = function (opNode) {
|
||||
var name = this.core.getAttribute(opNode, 'name'),
|
||||
var name = this.getAttribute(opNode, 'name'),
|
||||
nextPortIds = this.getOperationOutputIds(opNode),
|
||||
jNode = this.core.getParent(opNode),
|
||||
resultPorts,
|
||||
@@ -357,7 +450,7 @@ define([
|
||||
// Set the operation to 'success'!
|
||||
this.clearOldMetadata(jNode);
|
||||
this.runningJobs--;
|
||||
this.core.setAttribute(jNode, 'status', 'success');
|
||||
this.setAttribute(jNode, 'status', 'success');
|
||||
this.logger.info(`Setting ${jobId} status to "success"`);
|
||||
this.logger.info(`There are now ${this.runningJobs} running jobs`);
|
||||
this.logger.debug(`Making a commit from ${this.currentHash}`);
|
||||
@@ -376,11 +469,11 @@ define([
|
||||
.forEach(pair => { // [ resultPort, nextPort ]
|
||||
var result = pair[0],
|
||||
next = pair[1],
|
||||
hash = this.core.getAttribute(result, 'data');
|
||||
hash = this.getAttribute(result, 'data');
|
||||
|
||||
this.logger.info(`forwarding data (${hash}) from ${this.core.getPath(result)} ` +
|
||||
`to ${this.core.getPath(next)}`);
|
||||
this.core.setAttribute(next, 'data', hash);
|
||||
this.setAttribute(next, 'data', hash);
|
||||
this.logger.info(`Setting ${jobId} data to ${hash}`);
|
||||
});
|
||||
|
||||
|
||||
@@ -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 = {net: true};
|
||||
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,75 @@ 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])
|
||||
.filter(GenerateArchitecture.isSet)
|
||||
.join(', ') + ')';
|
||||
var setters = this.LayerDict[layer.name].setters,
|
||||
setterNames = Object.keys(this.LayerDict[layer.name].setters),
|
||||
base = layer[Constants.BASE],
|
||||
desc,
|
||||
fn,
|
||||
layerCode,
|
||||
args,
|
||||
i;
|
||||
|
||||
this.logger.debug(`Creating arg string for ${layer.name}`);
|
||||
args = this.LayerDict[layer.name].args
|
||||
.map(arg => this.getValue(arg.name, layer));
|
||||
|
||||
for (i = args.length; i--;) {
|
||||
if (GenerateArchitecture.isSet(args[i])) {
|
||||
break;
|
||||
}
|
||||
args.pop();
|
||||
}
|
||||
|
||||
layerCode = '(' + args.map(arg => GenerateArchitecture.isSet(arg) ? arg : 'nil')
|
||||
.join(', ') + ')';
|
||||
|
||||
// Add any setters
|
||||
// For each setter, check if it has been changed (and needs to be set)
|
||||
for (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--;) {
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*globals define*/
|
||||
/*jshint node:true, browser:true*/
|
||||
|
||||
define([
|
||||
'text!./metadata.json',
|
||||
'child_process',
|
||||
'path',
|
||||
'q',
|
||||
'fs',
|
||||
'module',
|
||||
'plugin/PluginBase'
|
||||
], function (
|
||||
pluginMetadata,
|
||||
childProcess,
|
||||
path,
|
||||
Q,
|
||||
fs,
|
||||
module,
|
||||
PluginBase
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
pluginMetadata = JSON.parse(pluginMetadata);
|
||||
var SEEDS_DIR = path.join(path.dirname(module.uri), '..', '..', 'seeds');
|
||||
|
||||
/**
|
||||
* Initializes a new instance of UpdateLibrarySeed.
|
||||
* @class
|
||||
* @augments {PluginBase}
|
||||
* @classdesc This class represents the plugin UpdateLibrarySeed.
|
||||
* @constructor
|
||||
*/
|
||||
var UpdateLibrarySeed = function () {
|
||||
// Call base class' constructor.
|
||||
PluginBase.call(this);
|
||||
this.pluginMetadata = pluginMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
|
||||
* This is also available at the instance at this.pluginMetadata.
|
||||
* @type {object}
|
||||
*/
|
||||
UpdateLibrarySeed.metadata = pluginMetadata;
|
||||
|
||||
// Prototypical inheritance from PluginBase.
|
||||
UpdateLibrarySeed.prototype = Object.create(PluginBase.prototype);
|
||||
UpdateLibrarySeed.prototype.constructor = UpdateLibrarySeed;
|
||||
|
||||
/**
|
||||
* Main function for the plugin to execute. This will perform the execution.
|
||||
* Notes:
|
||||
* - Always log with the provided logger.[error,warning,info,debug].
|
||||
* - Do NOT put any user interaction logic UI, etc. inside this method.
|
||||
* - callback always has to be called even if error happened.
|
||||
*
|
||||
* @param {function(string, plugin.PluginResult)} callback - the result callback
|
||||
*/
|
||||
UpdateLibrarySeed.prototype.main = function (callback) {
|
||||
// get the root hash
|
||||
var name = this.projectName,
|
||||
version;
|
||||
|
||||
// get the name and validate
|
||||
return this.getLibraryVersion()
|
||||
.then(vers => {
|
||||
version = vers;
|
||||
return this.checkForLibName(name);
|
||||
})
|
||||
.then(valid => {
|
||||
if (!valid) {
|
||||
var err = `Invalid library name "${name}"`;
|
||||
this.logger.error(err);
|
||||
return callback(err, this.result);
|
||||
}
|
||||
return this.updateSeed(name);
|
||||
})
|
||||
.then(() => this.recordVersion(name, version))
|
||||
.then(() => {
|
||||
this.logger.info(`Finished updating library seed for ${name}`);
|
||||
this.result.setSuccess(true);
|
||||
callback(null, this.result);
|
||||
})
|
||||
.fail(err => callback(err, this.result));
|
||||
};
|
||||
|
||||
UpdateLibrarySeed.prototype.getLibraryVersion = function () {
|
||||
var version,
|
||||
config = this.getCurrentConfig(),
|
||||
vnames = ['major', 'minor', 'patch'],
|
||||
bumpIndex,
|
||||
newVersion;
|
||||
|
||||
version = (this.core.getAttribute(this.rootNode, 'version') || '0.0.0')
|
||||
.split('.').map(num => parseInt(num));
|
||||
bumpIndex = vnames.indexOf(config.releaseType);
|
||||
version[bumpIndex]++;
|
||||
|
||||
newVersion = version.join('.');
|
||||
this.core.setAttribute(this.rootNode, 'version', newVersion);
|
||||
return this.save(`Bumped version to ${newVersion}`).then(() => newVersion);
|
||||
};
|
||||
|
||||
UpdateLibrarySeed.prototype.checkForLibName = function (name) {
|
||||
// check for the library name from the fs
|
||||
return Q.nfcall(fs.readdir, SEEDS_DIR).then(seeds => seeds.indexOf(name) !== -1);
|
||||
};
|
||||
|
||||
UpdateLibrarySeed.prototype.updateSeed = function (seedName) {
|
||||
var deferred = Q.defer(),
|
||||
err,
|
||||
job = childProcess.spawn('webgme', ['new', 'seed', seedName], {
|
||||
cwd: path.dirname(module.uri)
|
||||
});
|
||||
|
||||
this.logger.info(`Updating ${seedName} seed`);
|
||||
job.on('error', _err => {
|
||||
err = _err;
|
||||
});
|
||||
|
||||
job.on('exit', code => {
|
||||
if (!code) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(err || code);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
UpdateLibrarySeed.prototype.recordVersion = function (seed, version) {
|
||||
var versionPath = path.join(SEEDS_DIR, seed, 'version.txt');
|
||||
this.logger.info(`Updating ${seed} version (${version})`);
|
||||
return Q.nfcall(fs.writeFile, versionPath, version);
|
||||
};
|
||||
|
||||
return UpdateLibrarySeed;
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"id": "UpdateLibrarySeed",
|
||||
"name": "UpdateLibrarySeed",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"icon": {
|
||||
"class": "glyphicon glyphicon-cog",
|
||||
"src": ""
|
||||
},
|
||||
"disableServerSideExecution": false,
|
||||
"disableBrowserSideExecution": true,
|
||||
"writeAccessRequired": false,
|
||||
"configStructure": [
|
||||
{
|
||||
"name": "releaseType",
|
||||
"displayName": "Release Type",
|
||||
"description": "Specify major, minor or patch release",
|
||||
"value": "minor",
|
||||
"valueItems": [
|
||||
"major",
|
||||
"minor",
|
||||
"patch"
|
||||
],
|
||||
"valueType": "string",
|
||||
"readOnly": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
var path = require('path'),
|
||||
Q = require('q'),
|
||||
fs = require('fs'),
|
||||
exists = require('exists-file'),
|
||||
utils = require('../../common/utils'),
|
||||
NO_LOG_FOUND = '';
|
||||
|
||||
var JobLogManager = function(logger, config) {
|
||||
this.rootDir = path.join(config.blob.fsDir, 'log-storage');
|
||||
this.logger = logger.fork('JobLogManager');
|
||||
this._onCopyFinished = {};
|
||||
};
|
||||
|
||||
JobLogManager.prototype._getFilePath = function(jInfo) {
|
||||
this.logger.debug(`getting file path for ${jInfo.job} in ${jInfo.project} on ${jInfo.branch}`);
|
||||
var jobId = jInfo.job.replace(/\//g, '_'),
|
||||
filename = `${jobId}.txt`;
|
||||
|
||||
return path.join(this.rootDir, jInfo.project, jInfo.branch, filename);
|
||||
};
|
||||
|
||||
JobLogManager.prototype.exists = function(jobInfo) {
|
||||
var filename = this._getFilePath(jobInfo);
|
||||
return Q.nfcall(exists, filename);
|
||||
};
|
||||
|
||||
JobLogManager.prototype.mkdirIfNeeded = function(dir) {
|
||||
return Q.nfcall(exists, dir).then(exist => {
|
||||
if (!exist) {
|
||||
this.logger.debug('making dir:', dir);
|
||||
return Q.nfcall(fs.mkdir, dir)
|
||||
.catch(() => this.logger.debug(`dir already created: ${dir}`));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
JobLogManager.prototype._copyFile = function(src, dst) {
|
||||
return Q.nfcall(exists, src).then(exists => {
|
||||
if (!exists) {
|
||||
this.logger.warn(`Cannot copy file from ${src}. File doesn't exist!`);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.mkdirIfNeeded(path.dirname(dst)).then(() => {
|
||||
var deferred = Q.defer(),
|
||||
stream = fs.createReadStream(src).pipe(fs.createWriteStream(dst));
|
||||
|
||||
stream.on('error', deferred.reject);
|
||||
stream.on('finish', deferred.resolve);
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Copy one branch info to the next
|
||||
// Could optimize this to symlink until data appended...
|
||||
JobLogManager.prototype.migrate = function(migrationInfo, jobIds) {
|
||||
// Recursively copy the srcBranch dir to the dstBranch dir
|
||||
// Should probably use streams...
|
||||
// Need to block appends to the given files so they are not written
|
||||
// to until they have finished copying...
|
||||
// TODO
|
||||
var jobs,
|
||||
src,
|
||||
dst,
|
||||
i;
|
||||
|
||||
for (i = jobIds.length; i--;) {
|
||||
this._onCopyFinished[jobIds[i]] = [];
|
||||
}
|
||||
|
||||
// Copy the job files and evaluate each of the finish functions
|
||||
this.logger.info('migrating from ' + migrationInfo.srcBranch + ' to '+ migrationInfo.dstBranch);
|
||||
return Q.all(jobIds.map(jobId => {
|
||||
src = this._getFilePath({
|
||||
project: migrationInfo.project,
|
||||
branch: migrationInfo.srcBranch,
|
||||
job: jobId
|
||||
});
|
||||
dst = this._getFilePath({
|
||||
project: migrationInfo.project,
|
||||
branch: migrationInfo.dstBranch,
|
||||
job: jobId
|
||||
});
|
||||
return this._copyFile(src, dst).then(() => {
|
||||
jobs = this._onCopyFinished[jobId];
|
||||
for (var j = jobs.length; j--;) {
|
||||
jobs[j]();
|
||||
}
|
||||
});
|
||||
}));
|
||||
};
|
||||
|
||||
JobLogManager.prototype._appendTo = function(filename, logs) {
|
||||
return Q.nfcall(exists, filename).then(exists => {
|
||||
var promise = Q().then(() => '');
|
||||
if (exists) {
|
||||
promise = Q.nfcall(fs.readFile, filename, 'utf8');
|
||||
}
|
||||
|
||||
return promise.then(content => {
|
||||
// This could be optimized to not re-read/write the whole file each time...
|
||||
var lines = utils.resolveCarriageReturns(content + logs);
|
||||
return Q.nfcall(fs.writeFile, filename, lines.join('\n'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
JobLogManager.prototype.appendTo = function(jobInfo, logs) {
|
||||
var filename = this._getFilePath(jobInfo),
|
||||
branchDirname = path.dirname(filename),
|
||||
projDirname = path.dirname(branchDirname);
|
||||
|
||||
this.logger.info(`Appending content to ${filename}`);
|
||||
// Make directory if needed
|
||||
return this.mkdirIfNeeded(this.rootDir)
|
||||
.then(() => this.mkdirIfNeeded(projDirname))
|
||||
.then(() => this.mkdirIfNeeded(branchDirname))
|
||||
.then(() => this._appendTo(filename, logs));
|
||||
};
|
||||
|
||||
JobLogManager.prototype.getLog = function(jobInfo) {
|
||||
var filename = this._getFilePath(jobInfo);
|
||||
|
||||
this.logger.info(`Getting log content from ${filename}`);
|
||||
return this.exists(jobInfo)
|
||||
.then(exists => {
|
||||
if (exists) {
|
||||
return Q.nfcall(fs.readFile, filename);
|
||||
}
|
||||
return NO_LOG_FOUND;
|
||||
});
|
||||
};
|
||||
|
||||
JobLogManager.prototype.delete = function(jobInfo) {
|
||||
var filename = this._getFilePath(jobInfo);
|
||||
|
||||
return this.exists(jobInfo)
|
||||
.then(exists => {
|
||||
if (exists) {
|
||||
this.logger.debug(`Removing file ${filename}`);
|
||||
return Q.nfcall(fs.unlink, filename);
|
||||
}
|
||||
this.logger.info(`${filename} doesn't exist. No need to delete...`);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = JobLogManager;
|
||||
@@ -0,0 +1,93 @@
|
||||
/*jshint node:true*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var express = require('express'),
|
||||
JobLogManager = require('./JobLogManager'),
|
||||
router = express.Router();
|
||||
|
||||
/**
|
||||
* Called when the server is created but before it starts to listening to incoming requests.
|
||||
* N.B. gmeAuth, safeStorage and workerManager are not ready to use until the start function is called.
|
||||
* (However inside an incoming request they are all ensured to have been initialized.)
|
||||
*
|
||||
* @param {object} middlewareOpts - Passed by the webgme server.
|
||||
* @param {GmeConfig} middlewareOpts.gmeConfig - GME config parameters.
|
||||
* @param {GmeLogger} middlewareOpts.logger - logger
|
||||
* @param {function} middlewareOpts.ensureAuthenticated - Ensures the user is authenticated.
|
||||
* @param {function} middlewareOpts.getUserId - If authenticated retrieves the userId from the request.
|
||||
* @param {object} middlewareOpts.gmeAuth - Authorization module.
|
||||
* @param {object} middlewareOpts.safeStorage - Accesses the storage and emits events (PROJECT_CREATED, COMMIT..).
|
||||
* @param {object} middlewareOpts.workerManager - Spawns and keeps track of "worker" sub-processes.
|
||||
*/
|
||||
function initialize(middlewareOpts) {
|
||||
var logger = middlewareOpts.logger.fork('JobLogsAPI'),
|
||||
ensureAuthenticated = middlewareOpts.ensureAuthenticated,
|
||||
gmeConfig = middlewareOpts.gmeConfig,
|
||||
logManager = new JobLogManager(logger, gmeConfig);
|
||||
|
||||
logger.debug('initializing ...');
|
||||
|
||||
// Ensure authenticated can be used only after this rule.
|
||||
router.use('*', function (req, res, next) {
|
||||
// This header ensures that any failures with authentication won't redirect.
|
||||
res.setHeader('X-WebGME-Media-Type', 'webgme.v1');
|
||||
next();
|
||||
});
|
||||
|
||||
// Use ensureAuthenticated if the routes require authentication. (Can be set explicitly for each route.)
|
||||
router.use('*', ensureAuthenticated);
|
||||
|
||||
router.get('/:project/:branch/:job', function (req, res/*, next*/) {
|
||||
// Retrieve the job logs for the given job
|
||||
logManager.getLog(req.params).then(log => {
|
||||
res.set('Content-Type', 'text/plain');
|
||||
res.send(log);
|
||||
});
|
||||
});
|
||||
|
||||
router.patch('/:project/:branch/:job', function (req, res/*, next*/) {
|
||||
var logs = req.body.patch;
|
||||
logger.info(`Received append request for ${req.params.job} in ${req.params.project}`);
|
||||
logManager.appendTo(req.params, logs)
|
||||
.then(() => res.send('Append successful'))
|
||||
.catch(err => logger.error(`Append failed: ${err}`));
|
||||
});
|
||||
|
||||
router.delete('/:project/:branch/:job', function (req, res/*, next*/) {
|
||||
logManager.delete(req.params).then(() => res.send('delete successful'));
|
||||
});
|
||||
|
||||
router.post('/migrate/:project/:srcBranch/:dstBranch', function (req, res/*, next*/) {
|
||||
var jobs = req.body.jobs;
|
||||
logManager.migrate(req.params, jobs)
|
||||
.then(() => res.send('migration successful'))
|
||||
.fail(err => logger.error(err));
|
||||
});
|
||||
|
||||
logger.debug('ready');
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the server starts listening.
|
||||
* @param {function} callback
|
||||
*/
|
||||
function start(callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the server stopped listening.
|
||||
* @param {function} callback
|
||||
*/
|
||||
function stop(callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
initialize: initialize,
|
||||
router: router,
|
||||
start: start,
|
||||
stop: stop
|
||||
};
|
||||
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.
@@ -0,0 +1 @@
|
||||
0.2.0
|
||||
Arquivo binário não exibido.
@@ -0,0 +1 @@
|
||||
0.3.0
|
||||
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);
|
||||
}
|
||||
TextEditorControl.prototype.saveTextFor.call(this, id, text);
|
||||
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, true);
|
||||
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,380 @@
|
||||
/*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))
|
||||
.filter(line => !!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!
|
||||
if (desc.originId) {
|
||||
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);
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/* globals define */
|
||||
// A notification widget which filters out stdout update notifications
|
||||
define([
|
||||
'deepforge/Constants',
|
||||
'js/Widgets/Notification/NotificationWidget'
|
||||
], function(
|
||||
CONSTANTS,
|
||||
GmeNotificationWidget
|
||||
) {
|
||||
var NotificationWidget = function() {
|
||||
GmeNotificationWidget.apply(this, arguments);
|
||||
};
|
||||
|
||||
NotificationWidget.prototype = Object.create(GmeNotificationWidget.prototype);
|
||||
|
||||
NotificationWidget.prototype.isUserNotication = function(data) {
|
||||
return data.message.indexOf(CONSTANTS.STDOUT_UPDATE) === -1;
|
||||
};
|
||||
|
||||
NotificationWidget.prototype._refreshNotifications = function(eventData) {
|
||||
|
||||
if (this.isUserNotication(eventData)) {
|
||||
GmeNotificationWidget.prototype._refreshNotifications.call(this, eventData);
|
||||
}
|
||||
};
|
||||
|
||||
return NotificationWidget;
|
||||
});
|
||||
@@ -1,8 +1,5 @@
|
||||
/*globals define, _, WebGMEGlobal, $ */
|
||||
/*jshint browser: true*/
|
||||
/**
|
||||
* @author rkereskenyi / https://github.com/rkereskenyi
|
||||
*/
|
||||
|
||||
define([
|
||||
'js/PanelBase/PanelBase',
|
||||
@@ -10,13 +7,15 @@ define([
|
||||
'js/Widgets/BranchStatus/BranchStatusWidget',
|
||||
'js/Widgets/BranchSelector/BranchSelectorWidget',
|
||||
'js/Widgets/KeyboardManager/KeyboardManagerWidget',
|
||||
'js/Widgets/Notification/NotificationWidget'
|
||||
], function (PanelBase,
|
||||
NetworkStatusWidget,
|
||||
BranchStatusWidget,
|
||||
BranchSelectorWidget,
|
||||
KeyboardManagerWidget,
|
||||
NotificationWidget) {
|
||||
'./FilteredNotificationWidget'
|
||||
], function (
|
||||
PanelBase,
|
||||
NetworkStatusWidget,
|
||||
BranchStatusWidget,
|
||||
BranchSelectorWidget,
|
||||
KeyboardManagerWidget,
|
||||
NotificationWidget
|
||||
) {
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -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,36 @@ 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() {
|
||||
this.stopExecution();
|
||||
}
|
||||
}
|
||||
],
|
||||
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,12 +7,12 @@ define([
|
||||
'panel/FloatingActionButton/FloatingActionButton',
|
||||
'deepforge/viz/PipelineControl',
|
||||
'deepforge/viz/NodePrompter',
|
||||
'deepforge/viz/Execute',
|
||||
'./Actions',
|
||||
'widgets/EasyDAG/AddNodeDialog',
|
||||
'js/RegistryKeys',
|
||||
'js/Panels/MetaEditor/MetaEditorConstants',
|
||||
'q',
|
||||
'text!./PluginConfig.json',
|
||||
'deepforge/globals'
|
||||
], function (
|
||||
BlobClient,
|
||||
@@ -20,25 +20,27 @@ define([
|
||||
PluginButton,
|
||||
PipelineControl,
|
||||
NodePrompter,
|
||||
Execute,
|
||||
ACTIONS,
|
||||
AddNodeDialog,
|
||||
REGISTRY_KEYS,
|
||||
META_CONSTANTS,
|
||||
Q,
|
||||
PluginConfig
|
||||
DeepForge
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var NEW_OPERATION_ID = '__NEW_OPERATION__';
|
||||
var ForgeActionButton= function (layoutManager, params) {
|
||||
PluginButton.call(this, layoutManager, params);
|
||||
this._pluginConfig = JSON.parse(PluginConfig);
|
||||
this._client = this.client;
|
||||
this._actions = [];
|
||||
this._blobClient = new BlobClient({
|
||||
logger: this.logger.fork('BlobClient')
|
||||
});
|
||||
|
||||
Execute.call(this, this.client, this.logger);
|
||||
this.initializeKeyListener();
|
||||
this.logger.debug('ctor finished');
|
||||
};
|
||||
|
||||
@@ -46,9 +48,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 +99,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 +108,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 +360,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,18 +0,0 @@
|
||||
{
|
||||
"GenerateArchitecture": {
|
||||
"icon": "description",
|
||||
"priority": -1
|
||||
},
|
||||
"ExecutePipeline": {
|
||||
"icon": "play_arrow",
|
||||
"priority": 1
|
||||
},
|
||||
"ImportTorch": {
|
||||
"icon": "import_export",
|
||||
"priority": -1
|
||||
},
|
||||
"GenerateExecFile": {
|
||||
"icon": "play_for_work",
|
||||
"priority": -1
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
@@ -26,6 +32,8 @@ define([
|
||||
LayerEditorControl.prototype._getObjectDescriptor = function (nodeId) {
|
||||
var desc = TextEditorControl.prototype._getObjectDescriptor.call(this, nodeId),
|
||||
node = this._client.getNode(nodeId),
|
||||
baseId = node.getBaseId(),
|
||||
base = this._client.getNode(baseId),
|
||||
hasCode = node.getValidAttributeNames().indexOf('code') > -1,
|
||||
template;
|
||||
|
||||
@@ -44,68 +52,135 @@ define([
|
||||
}
|
||||
|
||||
if (template) {
|
||||
desc.text = _.template(template)(desc);
|
||||
var baseTorchType = 'nn.Module';
|
||||
// If the base type is 'Criterion', set the base type to nn.Criterion
|
||||
if (base.getAttribute('name') === 'Criterion') {
|
||||
baseTorchType = 'nn.Criterion';
|
||||
}
|
||||
|
||||
desc.text = _.template(template)({
|
||||
name: desc.name,
|
||||
baseTorchType: baseTorchType
|
||||
});
|
||||
}
|
||||
return desc;
|
||||
};
|
||||
|
||||
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);
|
||||
TextEditorControl.prototype.saveTextFor.call(this, id, text, true);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,18 @@
|
||||
/*jshint browser: true*/
|
||||
|
||||
// This is a read-only view of the 'stdout' attribute for a Job node
|
||||
// if the job is running, get the logs from the log-storage
|
||||
define([
|
||||
'q',
|
||||
'deepforge/JobLogsClient',
|
||||
'js/Constants',
|
||||
'deepforge/Constants',
|
||||
'panels/TextEditor/TextEditorControl'
|
||||
], function (
|
||||
Q,
|
||||
JobLogsClient,
|
||||
GME_CONSTANTS,
|
||||
CONSTANTS,
|
||||
TextEditorControl
|
||||
) {
|
||||
|
||||
@@ -19,11 +28,68 @@ define([
|
||||
|
||||
_.extend(LogViewerControl.prototype, TextEditorControl.prototype);
|
||||
|
||||
LogViewerControl.prototype.getFullDescriptor = function (id) {
|
||||
var desc = LogViewerControl.prototype._getObjectDescriptor.call(this, id);
|
||||
|
||||
return this._getRunningLogs(id).then(text => {
|
||||
// Use attribute or running log if none
|
||||
desc.text = desc.text || text;
|
||||
return desc;
|
||||
});
|
||||
};
|
||||
|
||||
LogViewerControl.prototype.getUpdatedJobId = function (msg) {
|
||||
// verify that it is the given notification type
|
||||
if (msg.indexOf(CONSTANTS.STDOUT_UPDATE) !== -1) {
|
||||
return msg.replace(/^[^\/]*\//, '');
|
||||
}
|
||||
};
|
||||
|
||||
LogViewerControl.prototype.selectedObjectChanged = function (id) {
|
||||
TextEditorControl.prototype.selectedObjectChanged.call(this, id);
|
||||
// Listen for notifications about updated logs
|
||||
this.removeNotificationHandler();
|
||||
this.notificationHandler = (sender, data) => {
|
||||
var nodeId = this.getUpdatedJobId(data.message);
|
||||
if (nodeId === id) {
|
||||
this._onUpdate(id);
|
||||
}
|
||||
};
|
||||
this._client.addEventListener(GME_CONSTANTS.CLIENT.NOTIFICATION, this.notificationHandler);
|
||||
};
|
||||
|
||||
LogViewerControl.prototype.removeNotificationHandler = function () {
|
||||
// Remove the notifications listener
|
||||
if (this.notificationHandler) {
|
||||
this._client.removeEventListener();
|
||||
this.notificationHandler = null;
|
||||
}
|
||||
};
|
||||
|
||||
LogViewerControl.prototype.destroy = function () {
|
||||
TextEditorControl.prototype.destroy.call(this);
|
||||
this.removeNotificationHandler();
|
||||
};
|
||||
|
||||
LogViewerControl.prototype._onLoad = function (id) {
|
||||
this.getFullDescriptor(id).then(desc => this._widget.addNode(desc));
|
||||
};
|
||||
|
||||
LogViewerControl.prototype._onUpdate = function (id) {
|
||||
if (id === this._currentNodeId) {
|
||||
TextEditorControl.prototype._onUpdate.call(this, id);
|
||||
this.getFullDescriptor(id).then(desc => this._widget.updateNode(desc));
|
||||
}
|
||||
};
|
||||
|
||||
LogViewerControl.prototype._getRunningLogs = function (id) {
|
||||
var logManager = new JobLogsClient({
|
||||
logger: this._logger,
|
||||
projectId: this._client.getActiveProjectId(),
|
||||
branchName: this._client.getActiveBranchName()
|
||||
});
|
||||
|
||||
return logManager.getLog(id);
|
||||
};
|
||||
|
||||
return LogViewerControl;
|
||||
});
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
define([
|
||||
'blob/BlobClient',
|
||||
'js/Constants',
|
||||
'js/Utils/GMEConcepts',
|
||||
'js/NodePropertyNames',
|
||||
'q',
|
||||
'deepforge/globals'
|
||||
], function (
|
||||
BlobClient,
|
||||
CONSTANTS,
|
||||
GMEConcepts,
|
||||
nodePropertyNames,
|
||||
Q,
|
||||
DeepForge
|
||||
) {
|
||||
|
||||
@@ -22,15 +20,11 @@ define([
|
||||
MainViewControl = function (options) {
|
||||
|
||||
this._logger = options.logger.fork('Control');
|
||||
|
||||
this._client = options.client;
|
||||
|
||||
// Initialize core collections and variables
|
||||
this._widget = options.widget;
|
||||
|
||||
this._currentNodeId = null;
|
||||
this._embedded = options.embedded;
|
||||
|
||||
this.territory = {};
|
||||
this.ui = {};
|
||||
this._blobClient = new BlobClient({
|
||||
@@ -65,12 +59,35 @@ define([
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this._widget.toggleEmbeddedPanel = () => this.toggleEmbeddedPanel();
|
||||
this._widget.updateLibraries = this.updateLibraries.bind(this);
|
||||
this._widget.checkLibUpdates = this.checkLibUpdates.bind(this);
|
||||
this._widget.getProjectName = this.getProjectName.bind(this);
|
||||
};
|
||||
|
||||
MainViewControl.prototype.getProjectName = function () {
|
||||
return this._client.getActiveProjectId().split('+')[1];
|
||||
};
|
||||
|
||||
MainViewControl.prototype.checkLibUpdates = function () {
|
||||
var pluginId = 'CheckLibraries',
|
||||
context = this._client.getCurrentPluginContext(pluginId);
|
||||
|
||||
return Q.ninvoke(this._client, 'runServerPlugin', pluginId, context)
|
||||
.then(res => {
|
||||
return res.messages.map(msg => msg.message.split(' '));
|
||||
});
|
||||
};
|
||||
|
||||
MainViewControl.prototype.updateLibraries = function (libraries) {
|
||||
var promises = libraries
|
||||
.map(lib => Q.ninvoke(this._client, 'updateLibrary', lib[0], lib[1]));
|
||||
|
||||
return Q.all(promises);
|
||||
};
|
||||
|
||||
/* * * * * * * * 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).
|
||||
MainViewControl.prototype.selectedObjectChanged = function (nodeId) {
|
||||
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
|
||||
|
||||
@@ -92,9 +109,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"
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
/*jshint browser: true*/
|
||||
|
||||
define([
|
||||
'deepforge/Constants',
|
||||
'js/Constants',
|
||||
'panels/EasyDAG/EasyDAGControl',
|
||||
'deepforge/viz/PipelineControl',
|
||||
'deepforge/viz/Execute',
|
||||
'deepforge/globals',
|
||||
'common/core/coreQ',
|
||||
'common/storage/constants',
|
||||
@@ -12,8 +14,10 @@ define([
|
||||
'underscore'
|
||||
], function (
|
||||
CONSTANTS,
|
||||
GME_CONSTANTS,
|
||||
EasyDAGControl,
|
||||
PipelineControl,
|
||||
Execute,
|
||||
DeepForge,
|
||||
Core,
|
||||
STORAGE_CONSTANTS,
|
||||
@@ -29,26 +33,28 @@ define([
|
||||
DST: 'dst'
|
||||
},
|
||||
DECORATORS = {
|
||||
ArtifactLoader: 'ArtifactOpDecorator',
|
||||
ArtifactFinder: 'ArtifactOpDecorator'
|
||||
},
|
||||
WIDGET_NAME = 'EasyDAG';
|
||||
|
||||
DECORATORS[CONSTANTS.OP.INPUT] = 'ArtifactOpDecorator';
|
||||
|
||||
PipelineEditorControl = function (options) {
|
||||
EasyDAGControl.call(this, options);
|
||||
Execute.call(this, this._client, this._logger);
|
||||
this.addedIds = {};
|
||||
this.executionTerritory = {};
|
||||
this.executionUI = null;
|
||||
this.invalidated = {};
|
||||
this._widget.deleteNode = id => {
|
||||
this._deleteNode(id);
|
||||
};
|
||||
this._widget.deleteExecution = this.deleteExecution.bind(this);
|
||||
this._widget.isArchitecturePtr = this.isArchitecturePtr.bind(this);
|
||||
};
|
||||
|
||||
_.extend(
|
||||
PipelineEditorControl.prototype,
|
||||
EasyDAGControl.prototype,
|
||||
PipelineControl.prototype
|
||||
PipelineControl.prototype,
|
||||
Execute.prototype
|
||||
);
|
||||
|
||||
PipelineEditorControl.prototype._getValidInitialNodes =
|
||||
@@ -126,7 +132,7 @@ define([
|
||||
// Add arch/artifact dir to the territory
|
||||
// loading more than necessary.... can restrict it in the future
|
||||
// if perf is a problem
|
||||
this._territories[CONSTANTS.PROJECT_ROOT_ID] = {children: 2};
|
||||
this._territories[GME_CONSTANTS.PROJECT_ROOT_ID] = {children: 2};
|
||||
|
||||
this._client.updateTerritory(this._territoryId, this._territories);
|
||||
};
|
||||
@@ -498,7 +504,7 @@ define([
|
||||
|
||||
PipelineEditorControl.prototype._getTargetDirs = function (typeIds) {
|
||||
// Find the directories containing these types
|
||||
return this._client.getNode(CONSTANTS.PROJECT_ROOT_ID).getChildrenIds()
|
||||
return this._client.getNode(GME_CONSTANTS.PROJECT_ROOT_ID).getChildrenIds()
|
||||
// No referencing data meta types
|
||||
.filter(id => {
|
||||
var cMeta = this._client.getChildrenMeta(id),
|
||||
@@ -543,11 +549,11 @@ define([
|
||||
// Handle events related to the associated executions
|
||||
for (var i = events.length; i--;) {
|
||||
event = events[i];
|
||||
if (event.etype === CONSTANTS.TERRITORY_EVENT_LOAD) {
|
||||
if (event.etype === GME_CONSTANTS.TERRITORY_EVENT_LOAD) {
|
||||
this.onExecLoad(event.eid);
|
||||
} else if (event.etype === CONSTANTS.TERRITORY_EVENT_UPDATE) {
|
||||
} else if (event.etype === GME_CONSTANTS.TERRITORY_EVENT_UPDATE) {
|
||||
this.onExecUpdate(event.eid);
|
||||
} else if (event.etype === CONSTANTS.TERRITORY_EVENT_UNLOAD) {
|
||||
} else if (event.etype === GME_CONSTANTS.TERRITORY_EVENT_UNLOAD) {
|
||||
this.onExecUnload(event.eid);
|
||||
}
|
||||
}
|
||||
@@ -595,6 +601,42 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
PipelineEditorControl.prototype._deleteTag = function (tagName) {
|
||||
// Check if the tag exists and delete it if so!
|
||||
var projectId = this._client.getActiveProjectId();
|
||||
|
||||
this._client.deleteTag(projectId, tagName, err => {
|
||||
if (err) {
|
||||
this.logger.error(`Tag deletion failed: ${err}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
PipelineEditorControl.prototype.deleteExecution = function (id) {
|
||||
var node = this._client.getNode(id),
|
||||
name = '',
|
||||
msg;
|
||||
|
||||
if (node) {
|
||||
name = node && node.getAttribute('name');
|
||||
}
|
||||
|
||||
msg = `Deleted ${name} (${id}) execution`;
|
||||
|
||||
// Stop the execution w/o setting any attributes on the execution
|
||||
this._client.startTransaction(msg);
|
||||
this._deleteTag(name); // Remove execution tag
|
||||
if (this.isRunning(node)) {
|
||||
this.silentStopExecution(id, true).then(() => {
|
||||
this._client.delMoreNodes([id]);
|
||||
this._client.completeTransaction();
|
||||
});
|
||||
} else {
|
||||
this._client.delMoreNodes([id]);
|
||||
this._client.completeTransaction();
|
||||
}
|
||||
};
|
||||
|
||||
PipelineEditorControl.prototype.updateThumbnail = function (svg) {
|
||||
var node = this._client.getNode(this._currentNodeId),
|
||||
name,
|
||||
@@ -641,7 +683,19 @@ define([
|
||||
} else {
|
||||
return EasyDAGControl.prototype._getValidTargetsFor.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
PipelineEditorControl.prototype.isArchitecturePtr = function (id, ptr) {
|
||||
var ptrMeta = this._client.getPointerMeta(id, ptr),
|
||||
targets;
|
||||
|
||||
// Check if ptr of the given id is referencing an architecture
|
||||
if (ptrMeta.items) {
|
||||
targets = ptrMeta.items.map(item => this._client.getNode(item.id));
|
||||
return !!targets.find(node => node.getAttribute('name') === 'Architecture');
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
return PipelineEditorControl;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/*globals define, $, _, WebGMEGlobal*/
|
||||
/*jshint browser: true*/
|
||||
/**
|
||||
* Generated by VisualizerGenerator 1.7.0 from webgme on Thu May 19 2016 14:04:47 GMT-0500 (CDT).
|
||||
*/
|
||||
|
||||
define(['js/PanelBase/PanelBaseWithHeader',
|
||||
define([
|
||||
'js/PanelBase/PanelBaseWithHeader',
|
||||
'js/PanelManager/IActivePanel',
|
||||
'widgets/PipelineEditor/PipelineEditorWidget',
|
||||
'./PipelineEditorControl'
|
||||
], function (PanelBaseWithHeader,
|
||||
IActivePanel,
|
||||
PipelineEditorWidget,
|
||||
PipelineEditorControl) {
|
||||
], function (
|
||||
PanelBaseWithHeader,
|
||||
IActivePanel,
|
||||
PipelineEditorWidget,
|
||||
PipelineEditorControl
|
||||
) {
|
||||
'use strict';
|
||||
|
||||
var PipelineEditorPanel;
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
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