* WIP #945 Added some structure for the extensions support * WIP #945 Added ext installation using npm * WIP #945 Added some structure for the extensions support * WIP #945 Added ext installation using npm * WIP #945 Restructured export formats * WIP #945 Added ExportFormat:Pipeline installation * WIP #945 Updated extension installer * WIP #945 Fixed format.js format path * WIP #945 Added reinstalling message * WIP #945 Updated the default Basic CLI * WIP Updated deserializers and cli deserializer * WIP #945 Added simple static ext config * WIP #945 Added custom config dialog for exporting pipelines * WIP #945 Added dynamic updating based on config * WIP #945 Added section headers * WIP #945 Renamed to Export:Pipeline * WIP #945 moved cli export to first option * WIP #945 Renamed plugin 'GenerateExecFile' -> 'Export' * WIP #945 Renamed GenExecFile -> Export * WIP #945 Added 'deepforge extension remove X' * WIP #945 Added 'list' command for extensions * WIP #945 fixed minor linting issues * WIP #945 aliased remove/rm, list/ls * WIP #945 Moved gen installation fn to utils/extender * WIP #945 Added ext reinstall script on postinstall * WIP #945 don't prompt if no options * WIP #945 Updated the plugin name in registry * WIP #945 Updated format template * WIP #945 Fixed cli tests * WIP #945 Removed unused main method * WIP #945 Fixed linter issues
Esse commit está contido em:
@@ -447,6 +447,10 @@ program
|
||||
}
|
||||
});
|
||||
|
||||
// extensions
|
||||
program
|
||||
.command('extensions <command>', 'Manage deepforge extensions');
|
||||
|
||||
module.exports = function(cmd) {
|
||||
var cmds = cmd.split(/\s+/).filter(w => !!w);
|
||||
cmds.unshift('./bin/deepforge');
|
||||
|
||||
Arquivo executável
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var Command = require('commander').Command,
|
||||
program = new Command(),
|
||||
extender = require('../utils/extender');
|
||||
|
||||
// Supported commands
|
||||
// - add
|
||||
// - remove
|
||||
// - list
|
||||
// - update
|
||||
program
|
||||
.command('add <project>')
|
||||
.description('Add an extension to deepforge')
|
||||
.option('-n, --name <name>', 'Project name (if different from <project>)')
|
||||
.action(project => {
|
||||
console.log('loading extension from: ' + project);
|
||||
extender.install(project)
|
||||
.then(extConfig =>
|
||||
console.log(`The ${extConfig.name} extension has been added to deepforge.`))
|
||||
.fail(err => {
|
||||
console.error('Could not install extension:\n');
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
||||
program
|
||||
.command('remove <name>').alias('rm')
|
||||
.description('Remove an extension from deepforge')
|
||||
.action(name => {
|
||||
try {
|
||||
extender.uninstall(name);
|
||||
console.log(`${name} has been successfully removed!`);
|
||||
} catch (e) {
|
||||
console.error('Could not remove extension:');
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command('list').alias('ls')
|
||||
.description('List installed deepforge extensions')
|
||||
.action(() => {
|
||||
var allExtConfigs = extender.getExtensionsConfig(),
|
||||
types = Object.keys(allExtConfigs),
|
||||
hasContents = false,
|
||||
names;
|
||||
|
||||
for (var i = types.length; i--;) {
|
||||
names = Object.keys(allExtConfigs[types[i]]);
|
||||
if (names.length) {
|
||||
hasContents = true;
|
||||
console.log(types[i]);
|
||||
for (var j = names.length; j--;) {
|
||||
console.log(` ${names[j]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasContents) {
|
||||
console.log('No installed extensions');
|
||||
}
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
@@ -49,7 +49,7 @@
|
||||
"icon": "import_export",
|
||||
"priority": -1
|
||||
},
|
||||
"GenerateExecFile": {
|
||||
"Export": {
|
||||
"icon": "play_for_work",
|
||||
"priority": -1
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
"postinstall": "node utils/reinstall-extensions.js",
|
||||
"start-dev": "NODE_ENV=dev node app.js",
|
||||
"local": "node ./bin/start-local.js",
|
||||
"worker": "node ./bin/start-worker.js",
|
||||
@@ -21,8 +22,10 @@
|
||||
"graceful-fs": "^4.1.10",
|
||||
"lodash.difference": "^4.1.2",
|
||||
"lodash.merge": "^4.5.1",
|
||||
"lodash.template": "^4.4.0",
|
||||
"mongodb": "^2.2.10",
|
||||
"nodemon": "^1.9.2",
|
||||
"npm": "^4.0.5",
|
||||
"q": "1.4.1",
|
||||
"rimraf": "^2.4.0",
|
||||
"webgme": "^2.7.1",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
define([
|
||||
'text!./metadata.json',
|
||||
'text!./toboolean.lua',
|
||||
'./format',
|
||||
'plugin/PluginBase',
|
||||
'deepforge/plugin/PtrCodeGen',
|
||||
@@ -13,7 +12,6 @@ define([
|
||||
'q'
|
||||
], function (
|
||||
pluginMetadata,
|
||||
TOBOOLEAN,
|
||||
FORMATS,
|
||||
PluginBase,
|
||||
PtrCodeGen,
|
||||
@@ -33,13 +31,13 @@ define([
|
||||
RESERVED = /^(and|break|do|else|elseifend|false|for|function|if|in|local|nil|not|orrepeat|return|then|true|until|while|print)$/;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of GenerateExecFile.
|
||||
* Initializes a new instance of Export.
|
||||
* @class
|
||||
* @augments {PluginBase}
|
||||
* @classdesc This class represents the plugin GenerateExecFile.
|
||||
* @classdesc This class represents the plugin Export.
|
||||
* @constructor
|
||||
*/
|
||||
var GenerateExecFile = function () {
|
||||
var Export = function () {
|
||||
// Call base class' constructor.
|
||||
PluginBase.call(this);
|
||||
this.initRecords();
|
||||
@@ -50,13 +48,13 @@ define([
|
||||
* This is also available at the instance at this.pluginMetadata.
|
||||
* @type {object}
|
||||
*/
|
||||
GenerateExecFile.metadata = pluginMetadata;
|
||||
Export.metadata = pluginMetadata;
|
||||
|
||||
// Prototypical inheritance from PluginBase.
|
||||
GenerateExecFile.prototype = Object.create(PluginBase.prototype);
|
||||
GenerateExecFile.prototype.constructor = GenerateExecFile;
|
||||
Export.prototype = Object.create(PluginBase.prototype);
|
||||
Export.prototype.constructor = Export;
|
||||
|
||||
GenerateExecFile.prototype.initRecords = function() {
|
||||
Export.prototype.initRecords = function() {
|
||||
this.pluginMetadata = pluginMetadata;
|
||||
|
||||
this._srcIdFor = {}; // input path -> output data node path
|
||||
@@ -94,7 +92,7 @@ define([
|
||||
*
|
||||
* @param {function(string, plugin.PluginResult)} callback - the result callback
|
||||
*/
|
||||
GenerateExecFile.prototype.main = function (callback) {
|
||||
Export.prototype.main = function (callback) {
|
||||
this.initRecords();
|
||||
|
||||
// Get all the children and call generate exec file
|
||||
@@ -107,6 +105,7 @@ define([
|
||||
|
||||
return this.core.loadChildren(this.activeNode)
|
||||
.then(nodes => this.generateOutputFiles(nodes))
|
||||
.catch(err => callback(err))
|
||||
.then(hash => {
|
||||
this.result.addArtifact(hash);
|
||||
this.result.setSuccess(true);
|
||||
@@ -115,20 +114,20 @@ define([
|
||||
.fail(err => callback(err));
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getCurrentConfig = function () {
|
||||
Export.prototype.getCurrentConfig = function () {
|
||||
var config = PluginBase.prototype.getCurrentConfig.call(this);
|
||||
config.staticInputs = config.staticInputs || [];
|
||||
return config;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.generateOutputFiles = function (children) {
|
||||
Export.prototype.generateOutputFiles = function (children) {
|
||||
var name = this.core.getAttribute(this.activeNode, 'name');
|
||||
|
||||
return this.createCodeSections(children)
|
||||
.then(sections => {
|
||||
// Get the selected format
|
||||
var config = this.getCurrentConfig(),
|
||||
format = config.format || 'Torch CLI',
|
||||
format = config.format || 'Basic CLI',
|
||||
generate = FORMATS[format],
|
||||
staticInputs,
|
||||
files;
|
||||
@@ -167,7 +166,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.createCodeSections = function (children) {
|
||||
Export.prototype.createCodeSections = function (children) {
|
||||
// Convert opNodes' jobs to the nested operations
|
||||
var opNodes,
|
||||
nodes;
|
||||
@@ -211,7 +210,7 @@ define([
|
||||
.fail(err => this.logger.error(err));
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.unpackJobs = function (nodes) {
|
||||
Export.prototype.unpackJobs = function (nodes) {
|
||||
return Q.all(
|
||||
nodes.map(node => {
|
||||
if (!this.isMetaTypeOf(node, this.META.Job)) {
|
||||
@@ -225,7 +224,7 @@ define([
|
||||
);
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.sortOperations = function (operationDict, opIds) {
|
||||
Export.prototype.sortOperations = function (operationDict, opIds) {
|
||||
var nextIds = [],
|
||||
sorted = opIds,
|
||||
dstIds,
|
||||
@@ -253,7 +252,7 @@ define([
|
||||
.concat(this.sortOperations(operationDict, nextIds));
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.generateCodeSections = function(sortedOps) {
|
||||
Export.prototype.generateCodeSections = function(sortedOps) {
|
||||
// Create the code sections:
|
||||
// - operation definitions
|
||||
// - pipeline definition
|
||||
@@ -286,8 +285,8 @@ define([
|
||||
// Define the serializers/deserializers
|
||||
this.addCodeSerializers(code);
|
||||
|
||||
// Define the main body
|
||||
this.addCodeMain(code);
|
||||
// Define the main input names
|
||||
code.mainInputNames = Object.keys(this.isInputOp).map(id => this._nameFor[id]);
|
||||
|
||||
// Add custom class definitions
|
||||
this.addCustomClasses(code);
|
||||
@@ -299,12 +298,12 @@ define([
|
||||
};
|
||||
|
||||
// expose this utility function to format extensions
|
||||
var indent = GenerateExecFile.prototype.indent = function(text, spaces) {
|
||||
var indent = Export.prototype.indent = function(text, spaces) {
|
||||
spaces = spaces || 3;
|
||||
return text.replace(/^/mg, new Array(spaces+1).join(' '));
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.defineOperationFn = function(operation) {
|
||||
Export.prototype.defineOperationFn = function(operation) {
|
||||
var lines = [],
|
||||
args = operation.inputNames || [];
|
||||
|
||||
@@ -322,7 +321,7 @@ define([
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.definePipelineFn = function(sortedOps, outputOps) {
|
||||
Export.prototype.definePipelineFn = function(sortedOps, outputOps) {
|
||||
var inputArgs = Object.keys(this.isInputOp).map(id => this._nameFor[id]),
|
||||
name = this.core.getAttribute(this.activeNode, 'name'),
|
||||
safename = getUniqueName(name, this._opBaseNames),
|
||||
@@ -348,7 +347,7 @@ define([
|
||||
return result;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getOutputPair = function(operation) {
|
||||
Export.prototype.getOutputPair = function(operation) {
|
||||
var input = operation.inputValues[0].slice(),
|
||||
value;
|
||||
|
||||
@@ -358,11 +357,9 @@ define([
|
||||
return [this._nameFor[operation.id], value];
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.addCodeSerializers = function(sections) {
|
||||
Export.prototype.addCodeSerializers = function(sections) {
|
||||
var loadNodes = {},
|
||||
saveNodes = {},
|
||||
hasBool = false;
|
||||
|
||||
saveNodes = {};
|
||||
|
||||
// Add the serializer fn names for each input
|
||||
sections.serializerFor = {};
|
||||
@@ -376,21 +373,10 @@ define([
|
||||
// Add the serializer definitions
|
||||
Object.keys(this.isInputOp).forEach(id => {
|
||||
var node = this.inputNode[id],
|
||||
base = this.core.getBase(node),
|
||||
type = this.core.getAttribute(base, 'name'),
|
||||
name = this._nameFor[id];
|
||||
|
||||
if (type === 'boolean') {
|
||||
hasBool = true;
|
||||
sections.deserializerFor[name] = 'toboolean';
|
||||
} else if (type === 'number') {
|
||||
sections.deserializerFor[name] = 'tonumber';
|
||||
} else if (type === 'string') {
|
||||
sections.deserializerFor[name] = 'tostring';
|
||||
} else {
|
||||
loadNodes[id] = node;
|
||||
sections.deserializerFor[name] = `__load['${this._nameFor[id]}']`;
|
||||
}
|
||||
loadNodes[id] = node;
|
||||
sections.deserializerFor[name] = `__load['${this._nameFor[id]}']`;
|
||||
});
|
||||
|
||||
sections.deserializers = this.createTorchFnDict(
|
||||
@@ -417,10 +403,6 @@ define([
|
||||
'path, data'
|
||||
);
|
||||
|
||||
if (hasBool) { // add toboolean def
|
||||
sections.deserializers += '\n' + TOBOOLEAN;
|
||||
}
|
||||
|
||||
// Add a saveOutputs method for convenience
|
||||
sections.serializeOutputsDef = [
|
||||
'local function __saveOutputs(data)',
|
||||
@@ -438,18 +420,7 @@ define([
|
||||
sections.serializeOutputs = '__saveOutputs(outputs)';
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.addCodeMain = function(sections) {
|
||||
var pipelineName = Object.keys(sections.pipelines)[0],
|
||||
args;
|
||||
|
||||
// Create some names for the inputs
|
||||
sections.mainInputNames = Object.keys(this.isInputOp).map(id => this._nameFor[id]);
|
||||
args = sections.mainInputNames.map(name => `${sections.deserializerFor[name]}(${name})`);
|
||||
|
||||
sections.main = `local outputs = ${pipelineName}(${args.join(', ')})`;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.createTorchFnDict = function(name, nodeDict, attr, args) {
|
||||
Export.prototype.createTorchFnDict = function(name, nodeDict, attr, args) {
|
||||
return [
|
||||
`local ${name} = {}`,
|
||||
Object.keys(nodeDict).map(id => {
|
||||
@@ -463,7 +434,7 @@ define([
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.addCustomClasses = function(sections) {
|
||||
Export.prototype.addCustomClasses = function(sections) {
|
||||
var metaDict = this.core.getAllMetaNodes(this.rootNode),
|
||||
isClass,
|
||||
metanodes,
|
||||
@@ -528,7 +499,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.addCustomLayers = function(sections) {
|
||||
Export.prototype.addCustomLayers = function(sections) {
|
||||
var metaDict = this.core.getAllMetaNodes(this.rootNode),
|
||||
isCustomLayer,
|
||||
metanodes,
|
||||
@@ -552,7 +523,7 @@ define([
|
||||
};
|
||||
|
||||
|
||||
GenerateExecFile.prototype.getTypeDictFor = function (name, metanodes) {
|
||||
Export.prototype.getTypeDictFor = function (name, metanodes) {
|
||||
var isType = {};
|
||||
// Get all the custom layers
|
||||
for (var i = metanodes.length; i--;) {
|
||||
@@ -570,7 +541,7 @@ define([
|
||||
return `"${attr}"`;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getOpInvocation = function(op) {
|
||||
Export.prototype.getOpInvocation = function(op) {
|
||||
var lines = [],
|
||||
attrs,
|
||||
refInits = [],
|
||||
@@ -603,13 +574,13 @@ define([
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getOutputName = function(node) {
|
||||
Export.prototype.getOutputName = function(node) {
|
||||
var basename = this.core.getAttribute(node, 'saveName');
|
||||
|
||||
return getUniqueName(basename, this._outputNames, true);
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getVariableName = function (/*node*/) {
|
||||
Export.prototype.getVariableName = function (/*node*/) {
|
||||
var c = Object.keys(this.isInputOp).length;
|
||||
|
||||
if (c !== 1) {
|
||||
@@ -619,7 +590,7 @@ define([
|
||||
return 'input';
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.registerNode = function (node) {
|
||||
Export.prototype.registerNode = function (node) {
|
||||
if (this.isMetaTypeOf(node, this.META.Operation)) {
|
||||
return this.registerOperation(node);
|
||||
} else if (this.isMetaTypeOf(node, this.META.Transporter)) {
|
||||
@@ -648,7 +619,7 @@ define([
|
||||
return name;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.registerOperation = function (node) {
|
||||
Export.prototype.registerOperation = function (node) {
|
||||
var name = this.core.getAttribute(node, 'name'),
|
||||
id = this.core.getPath(node),
|
||||
base = this.core.getBase(node),
|
||||
@@ -710,7 +681,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.registerTransporter = function (node) {
|
||||
Export.prototype.registerTransporter = function (node) {
|
||||
var outputData = this.core.getPointerPath(node, 'src'),
|
||||
inputData = this.core.getPointerPath(node, 'dst'),
|
||||
srcOpId = this.getOpIdFor(outputData),
|
||||
@@ -729,7 +700,7 @@ define([
|
||||
this._incomingCnts[dstOpId]++;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.getOpIdFor = function (dataId) {
|
||||
Export.prototype.getOpIdFor = function (dataId) {
|
||||
var ids = dataId.split('/'),
|
||||
depth = ids.length;
|
||||
|
||||
@@ -744,7 +715,7 @@ define([
|
||||
// - add the references
|
||||
// - generate the code
|
||||
// - replace the `return <thing>` w/ `<ref-name> = <thing>`
|
||||
GenerateExecFile.prototype.createOperation = function (node) {
|
||||
Export.prototype.createOperation = function (node) {
|
||||
var id = this.core.getPath(node),
|
||||
baseId = this.core.getPath(this.core.getBase(node)),
|
||||
attrNames = this.core.getValidAttributeNames(node),
|
||||
@@ -819,12 +790,12 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.genPtrSnippet = function (ptrName, pId) {
|
||||
Export.prototype.genPtrSnippet = function (ptrName, pId) {
|
||||
return this.getPtrCodeHash(pId)
|
||||
.then(hash => this.blobClient.getObjectAsString(hash));
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.createHeader = function (title, length) {
|
||||
Export.prototype.createHeader = function (title, length) {
|
||||
var len;
|
||||
title = ` ${title} `;
|
||||
length = length || HEADER_LENGTH;
|
||||
@@ -842,7 +813,7 @@ define([
|
||||
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.genOperationCode = function (operation) {
|
||||
Export.prototype.genOperationCode = function (operation) {
|
||||
var header = this.createHeader(`"${operation.name}" Operation`),
|
||||
codeParts = [],
|
||||
body = [];
|
||||
@@ -869,15 +840,7 @@ define([
|
||||
return operation;
|
||||
};
|
||||
|
||||
GenerateExecFile.prototype.assignResultToVar = function (code, name) {
|
||||
var i = code.lastIndexOf('return');
|
||||
_.extend(Export.prototype, PtrCodeGen.prototype);
|
||||
|
||||
return code.substring(0, i) +
|
||||
code.substring(i)
|
||||
.replace('return', `${name} = `);
|
||||
};
|
||||
|
||||
_.extend(GenerateExecFile.prototype, PtrCodeGen.prototype);
|
||||
|
||||
return GenerateExecFile;
|
||||
return Export;
|
||||
});
|
||||
@@ -1,12 +1,13 @@
|
||||
|
||||
/* globals define*/
|
||||
// The supported export formats and metadata
|
||||
define([
|
||||
'./formats/cli'
|
||||
'./formats/cli/cli'
|
||||
], function(
|
||||
TorchCLI
|
||||
Format0
|
||||
) {
|
||||
|
||||
return {
|
||||
'Torch CLI': TorchCLI
|
||||
'Basic CLI': Format0
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
<% // Add default format
|
||||
formats.unshift({ name: 'cli', main: 'cli.js', displayName: 'Basic CLI' })
|
||||
%>
|
||||
/* globals define*/
|
||||
// The supported export formats and metadata
|
||||
define([
|
||||
<%= formats.map(function(format) {
|
||||
return ' \'./formats/' + format.name + '/' +
|
||||
path.basename(format.main.replace(/\.js$/, '')) + '\''
|
||||
})
|
||||
.join(',\n') %>
|
||||
], function(
|
||||
<%= formats.map(function(f, index) { return ' Format' + index; }).join(',\n') %>
|
||||
) {
|
||||
|
||||
return {
|
||||
<%= formats.map(function(f, index) {
|
||||
return ' \'' + f.displayName + '\': Format' + index;
|
||||
}).join(',\n') %>
|
||||
};
|
||||
});
|
||||
+50
-4
@@ -8,16 +8,46 @@ define([
|
||||
|
||||
var INIT_CLASSES_FN = '__initClasses',
|
||||
INIT_LAYERS_FN = '__initLayers',
|
||||
TOBOOLEAN,
|
||||
DEEPFORGE_CODE; // defined at the bottom (after the embedded template)
|
||||
|
||||
var deserializersFromString = function(sections) {
|
||||
var hasBool = false;
|
||||
|
||||
// Add serializers given cli string input
|
||||
Object.keys(this.isInputOp).forEach(id => {
|
||||
var node = this.inputNode[id],
|
||||
base = this.core.getBase(node),
|
||||
type = this.core.getAttribute(base, 'name'),
|
||||
name = this._nameFor[id];
|
||||
|
||||
if (type === 'boolean') {
|
||||
hasBool = true;
|
||||
sections.deserializerFor[name] = 'toboolean';
|
||||
} else if (type === 'number') {
|
||||
sections.deserializerFor[name] = 'tonumber';
|
||||
} else if (type === 'string') {
|
||||
sections.deserializerFor[name] = 'tostring';
|
||||
}
|
||||
});
|
||||
|
||||
if (hasBool) {
|
||||
sections.deserializers += '\n' + TOBOOLEAN;
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
|
||||
var createExecFile = function (sections, staticInputs) {
|
||||
var classes,
|
||||
initClassFn,
|
||||
initLayerFn,
|
||||
code = [];
|
||||
|
||||
// concat all the sections into a single file
|
||||
// Update deserializers for cli input
|
||||
deserializersFromString.call(this, sections);
|
||||
|
||||
// concat all the sections into a single file
|
||||
// wrap the class/layer initialization in a fn
|
||||
// Add the classes ordered wrt their deps
|
||||
classes = sections.orderedClasses
|
||||
@@ -86,21 +116,28 @@ define([
|
||||
|
||||
return files;
|
||||
} else {
|
||||
var pipelineName = Object.keys(sections.pipelines)[0],
|
||||
main,
|
||||
args;
|
||||
|
||||
// Create some names for the inputs
|
||||
args = sections.mainInputNames.map(name => `${sections.deserializerFor[name]}(${name})`);
|
||||
|
||||
main = `local outputs = ${pipelineName}(${args.join(', ')})`;
|
||||
|
||||
// Grab the args from the cli
|
||||
code.push(sections.mainInputNames.map((name, index) => {
|
||||
return `local ${name} = arg[${index + 1}]`;
|
||||
}).join('\n'));
|
||||
|
||||
// Add the main fn
|
||||
code.push(sections.main);
|
||||
code.push(main);
|
||||
|
||||
// Save outputs to disk
|
||||
code.push(sections.serializeOutputs);
|
||||
|
||||
return code.join('\n\n');
|
||||
}
|
||||
|
||||
return code.join('\n\n');
|
||||
};
|
||||
|
||||
var deepforgeTxt =
|
||||
@@ -152,6 +189,15 @@ function deepforge.Image:title(name)
|
||||
-- nop
|
||||
end`;
|
||||
|
||||
TOBOOLEAN =
|
||||
`local function toboolean(str)
|
||||
if str == 'true' then
|
||||
return true
|
||||
elseif str == 'false' then
|
||||
return false
|
||||
end
|
||||
end`;
|
||||
|
||||
DEEPFORGE_CODE = _.template(deepforgeTxt)({
|
||||
initCode: `${INIT_CLASSES_FN}()\n${' '}${INIT_LAYERS_FN}()`
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "GenerateExecFile",
|
||||
"name": "Generate Execution File",
|
||||
"version": "0.1.0",
|
||||
"id": "Export",
|
||||
"name": "Export",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"icon": {
|
||||
"class": "glyphicon glyphicon-cog",
|
||||
@@ -0,0 +1,5 @@
|
||||
.config-section-header {
|
||||
margin-top: 0;
|
||||
color: #888;
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/* globals define, $*/
|
||||
define([
|
||||
'js/Dialogs/PluginConfig/PluginConfigDialog',
|
||||
'text!js/Dialogs/PluginConfig/templates/PluginConfigDialog.html',
|
||||
'plugin/Export/Export/format',
|
||||
'css!./ConfigDialog.css'
|
||||
], function(
|
||||
PluginConfigDialog,
|
||||
pluginConfigDialogTemplate,
|
||||
ExportFormats
|
||||
) {
|
||||
var SECTION_DATA_KEY = 'section',
|
||||
ATTRIBUTE_DATA_KEY = 'attribute',
|
||||
//jscs:disable maximumLineLength
|
||||
PLUGIN_CONFIG_SECTION_BASE = $('<div><fieldset><form class="form-horizontal" role="form"></form><fieldset></div>'),
|
||||
ENTRY_BASE = $('<div class="form-group"><div class="row"><label class="col-sm-4 control-label">NAME</label><div class="col-sm-8 controls"></div></div><div class="row description"><div class="col-sm-4"></div></div></div>'),
|
||||
//jscs:enable maximumLineLength
|
||||
DESCRIPTION_BASE = $('<div class="desc muted col-sm-8"></div>'),
|
||||
SECTION_HEADER = $('<h6 class="config-section-header">');
|
||||
|
||||
var ConfigDialog = function(client, nodeId) {
|
||||
PluginConfigDialog.call(this, {client: client});
|
||||
this._widgets = {};
|
||||
this._node = this._client.getNode(nodeId);
|
||||
};
|
||||
|
||||
ConfigDialog.prototype = Object.create(PluginConfigDialog.prototype);
|
||||
|
||||
ConfigDialog.prototype.show = function(globalOptions, pluginMetadata, extMetadata, callback) {
|
||||
this._extMetadata = extMetadata;
|
||||
return PluginConfigDialog.prototype.show.call(this, globalOptions, pluginMetadata, {}, callback);
|
||||
};
|
||||
|
||||
ConfigDialog.prototype._initDialog = function() {
|
||||
this._dialog = $(pluginConfigDialogTemplate);
|
||||
|
||||
this._btnSave = this._dialog.find('.btn-save');
|
||||
this._divContainer = this._dialog.find('.modal-body');
|
||||
this._saveConfigurationCb = this._dialog.find('.save-configuration');
|
||||
this._modalHeader = this._dialog.find('.modal-header');
|
||||
|
||||
// Create the header
|
||||
var iconEl = $('<i/>', {
|
||||
class: this._pluginMetadata.icon.class || 'glyphicon glyphicon-cog'
|
||||
});
|
||||
iconEl.addClass('plugin-icon pull-left');
|
||||
this._modalHeader.prepend(iconEl);
|
||||
this._title = this._modalHeader.find('.modal-title');
|
||||
this._title.text(this._pluginMetadata.id + ' ' + 'v' + this._pluginMetadata.version);
|
||||
|
||||
// Generate the config options
|
||||
var formats = Object.keys(ExportFormats),
|
||||
format = formats[0],
|
||||
sectionHeader = SECTION_HEADER.clone();
|
||||
|
||||
sectionHeader.text('Static Artifacts');
|
||||
this._divContainer.append(sectionHeader);
|
||||
this.generateConfigSection(this._pluginMetadata);
|
||||
|
||||
if (formats.length > 1) {
|
||||
this._divContainer.append($('<hr class="extension-config-divider">'));
|
||||
sectionHeader = SECTION_HEADER.clone();
|
||||
sectionHeader.text('Export Options');
|
||||
this._divContainer.append(sectionHeader);
|
||||
|
||||
this.generateConfigSection({
|
||||
id: 'FormatOptions',
|
||||
configStructure: this._globalOptions
|
||||
});
|
||||
this._widgets.FormatOptions.exportFormat.el.find('select').on('change', event => {
|
||||
var format = event.target.value;
|
||||
// Update the ext config
|
||||
this.updateExtConfig(format);
|
||||
});
|
||||
}
|
||||
|
||||
this.updateExtConfig(format);
|
||||
};
|
||||
|
||||
ConfigDialog.prototype.updateExtConfig = function (format) {
|
||||
var extConfig = {
|
||||
class: 'extension-config',
|
||||
configStructure: ExportFormats[format].getConfigStructure ?
|
||||
ExportFormats[format].getConfigStructure(this._client, this._node) : []
|
||||
};
|
||||
this._divContainer.find('.extension-config').remove();
|
||||
|
||||
if (extConfig.configStructure.length) {
|
||||
this.generateConfigSection(extConfig);
|
||||
}
|
||||
};
|
||||
|
||||
ConfigDialog.prototype.generateConfigSection = function (metadata) {
|
||||
var len = metadata.configStructure.length,
|
||||
i,
|
||||
el,
|
||||
pluginConfigEntry,
|
||||
widget,
|
||||
descEl,
|
||||
containerEl,
|
||||
pluginSectionEl = PLUGIN_CONFIG_SECTION_BASE.clone();
|
||||
|
||||
pluginSectionEl.data(SECTION_DATA_KEY, metadata.id);
|
||||
this._divContainer.append(pluginSectionEl);
|
||||
containerEl = pluginSectionEl.find('.form-horizontal');
|
||||
|
||||
if (metadata.class) {
|
||||
pluginSectionEl.addClass(metadata.class);
|
||||
}
|
||||
|
||||
this._widgets[metadata.id] = {};
|
||||
for (i = 0; i < len; i += 1) {
|
||||
pluginConfigEntry = metadata.configStructure[i];
|
||||
descEl = undefined;
|
||||
|
||||
// Make sure not modify the global metadata.
|
||||
pluginConfigEntry = JSON.parse(JSON.stringify(pluginConfigEntry));
|
||||
if (this._client.getProjectAccess().write === false && pluginConfigEntry.writeAccessRequired === true) {
|
||||
pluginConfigEntry.readOnly = true;
|
||||
}
|
||||
|
||||
widget = this._propertyGridWidgetManager.getWidgetForProperty(pluginConfigEntry);
|
||||
this._widgets[metadata.id][pluginConfigEntry.name] = widget;
|
||||
|
||||
el = ENTRY_BASE.clone();
|
||||
el.data(ATTRIBUTE_DATA_KEY, pluginConfigEntry.name);
|
||||
|
||||
el.find('label.control-label').text(pluginConfigEntry.displayName);
|
||||
|
||||
if (pluginConfigEntry.description && pluginConfigEntry.description !== '') {
|
||||
descEl = descEl || DESCRIPTION_BASE.clone();
|
||||
descEl.text(pluginConfigEntry.description);
|
||||
}
|
||||
|
||||
if (pluginConfigEntry.minValue !== undefined &&
|
||||
pluginConfigEntry.minValue !== null &&
|
||||
pluginConfigEntry.minValue !== '') {
|
||||
descEl = descEl || DESCRIPTION_BASE.clone();
|
||||
descEl.append(' The minimum value is: ' + pluginConfigEntry.minValue + '.');
|
||||
}
|
||||
|
||||
if (pluginConfigEntry.maxValue !== undefined &&
|
||||
pluginConfigEntry.maxValue !== null &&
|
||||
pluginConfigEntry.maxValue !== '') {
|
||||
descEl = descEl || DESCRIPTION_BASE.clone();
|
||||
descEl.append(' The maximum value is: ' + pluginConfigEntry.maxValue + '.');
|
||||
}
|
||||
|
||||
el.find('.controls').append(widget.el);
|
||||
if (descEl) {
|
||||
el.find('.description').append(descEl);
|
||||
}
|
||||
|
||||
containerEl.append(el);
|
||||
}
|
||||
};
|
||||
|
||||
return ConfigDialog;
|
||||
});
|
||||
@@ -4,7 +4,7 @@
|
||||
define([
|
||||
'blob/BlobClient',
|
||||
'js/Utils/SaveToDisk',
|
||||
'js/Dialogs/PluginConfig/PluginConfigDialog',
|
||||
'./ConfigDialog',
|
||||
'js/Constants',
|
||||
'panel/FloatingActionButton/FloatingActionButton',
|
||||
'deepforge/viz/PipelineControl',
|
||||
@@ -17,11 +17,11 @@ define([
|
||||
'q',
|
||||
'deepforge/globals',
|
||||
'deepforge/Constants',
|
||||
'plugin/GenerateExecFile/GenerateExecFile/format'
|
||||
'plugin/Export/Export/format'
|
||||
], function (
|
||||
BlobClient,
|
||||
SaveToDisk,
|
||||
PluginConfigDialog,
|
||||
ConfigDialog,
|
||||
GME_CONSTANTS,
|
||||
PluginButton,
|
||||
PipelineControl,
|
||||
@@ -388,7 +388,7 @@ define([
|
||||
/// Export Pipeline Support
|
||||
ForgeActionButton.prototype.exportPipeline = function() {
|
||||
var deferred = Q.defer(),
|
||||
pluginId = 'GenerateExecFile',
|
||||
pluginId = 'Export',
|
||||
metadata = WebGMEGlobal.allPluginsMetadata[pluginId],
|
||||
id = this._currentNodeId,
|
||||
node = this.client.getNode(id),
|
||||
@@ -429,9 +429,16 @@ define([
|
||||
.map(id => this.client.getNode(id))
|
||||
.filter(output => output.getAttribute('data'));
|
||||
|
||||
// get the output data node name
|
||||
// get the name of node referenced from the input op
|
||||
inputNames = inputData
|
||||
.map(node => node.getAttribute('name'))
|
||||
.map(node => {
|
||||
var cntrId = node.getParentId(),
|
||||
opId = this._client.getNode(cntrId).getParentId(),
|
||||
inputOp = this._client.getNode(opId),
|
||||
targetNodeId = inputOp.getPointer('artifact').to;
|
||||
|
||||
return this._client.getNode(targetNodeId).getAttribute('name');
|
||||
})
|
||||
.sort();
|
||||
|
||||
// create config options from inputs
|
||||
@@ -447,18 +454,11 @@ define([
|
||||
});
|
||||
|
||||
var exportFormats = Object.keys(ExportFormatDict),
|
||||
configDialog = new PluginConfigDialog({client: this.client}),
|
||||
configDialog = new ConfigDialog(this.client, this._currentNodeId),
|
||||
inputConfig = _.extend({}, metadata),
|
||||
extOptions = [],
|
||||
globalOpts = [];
|
||||
|
||||
// Hide the divider if missing inputOpts or globalOpts
|
||||
configDialog._initDialog = function() {
|
||||
PluginConfigDialog.prototype._initDialog.apply(this, arguments);
|
||||
if (!globalOpts.length || !inputOpts.length) {
|
||||
this._divContainer.find('.global-and-plugin-divider').remove();
|
||||
}
|
||||
};
|
||||
|
||||
if (exportFormats.length > 1) {
|
||||
globalOpts.push({ // format options
|
||||
name: 'exportFormat',
|
||||
@@ -471,8 +471,9 @@ define([
|
||||
}
|
||||
inputConfig.configStructure = inputOpts;
|
||||
|
||||
if (inputOpts.length || exportFormats.length > 1) {
|
||||
configDialog.show(globalOpts, inputConfig, {}, (formatOpts, inputOpts) => {
|
||||
// Try to get the extension options
|
||||
if (inputOpts.length || exportFormats.length > 1|| extOptions.length) {
|
||||
configDialog.show(globalOpts, inputConfig, (formatOpts, inputOpts) => {
|
||||
var context = this.client.getCurrentPluginContext(pluginId),
|
||||
exportFormat = (globalOpts.length && formatOpts) ? formatOpts.exportFormat : exportFormats[0],
|
||||
staticInputs = Object.keys(inputOpts || {}).filter(input => inputOpts[input]);
|
||||
@@ -508,5 +509,6 @@ define([
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return ForgeActionButton;
|
||||
});
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/*jshint node:true, mocha:true*/
|
||||
|
||||
'use strict';
|
||||
describe('GenerateExecFile', function () {
|
||||
describe('Export', function () {
|
||||
var testFixture = require('../../globals'),
|
||||
lua = require('../../../src/common/lua'),
|
||||
path = testFixture.path,
|
||||
@@ -9,12 +9,12 @@ describe('GenerateExecFile', function () {
|
||||
SEED_DIR = path.join(testFixture.DF_SEED_DIR, 'devProject'),
|
||||
gmeConfig = testFixture.getGmeConfig(),
|
||||
expect = testFixture.expect,
|
||||
logger = testFixture.logger.fork('GenerateExecFile'),
|
||||
logger = testFixture.logger.fork('Export'),
|
||||
PluginCliManager = testFixture.WebGME.PluginCliManager,
|
||||
manager = new PluginCliManager(null, logger, gmeConfig),
|
||||
BlobClient = require('webgme/src/server/middleware/blob/BlobClientWithFSBackend'),
|
||||
projectName = 'testProject',
|
||||
pluginName = 'GenerateExecFile',
|
||||
pluginName = 'Export',
|
||||
project,
|
||||
gmeAuth,
|
||||
storage,
|
||||
@@ -0,0 +1,199 @@
|
||||
// Utility for applying and removing deepforge extensions
|
||||
// This utility is run by the cli when executing:
|
||||
//
|
||||
// deepforge extensions add <project>
|
||||
// deepforge extensions remove <name>
|
||||
//
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
npm = require('npm'),
|
||||
Q = require('q'),
|
||||
rm_rf = require('rimraf'),
|
||||
exists = require('exists-file'),
|
||||
makeTpl = require('lodash.template'),
|
||||
CONFIG_DIR = path.join(process.env.HOME, '.deepforge'),
|
||||
EXT_CONFIG_NAME = 'extension.json',
|
||||
EXTENSION_REGISTRY_NAME = 'extensions.json',
|
||||
extConfigPath = path.join(CONFIG_DIR, EXTENSION_REGISTRY_NAME),
|
||||
allExtConfigs;
|
||||
|
||||
var values = obj => Object.keys(obj).map(key => obj[key]);
|
||||
|
||||
// Create the extensions.json if doesn't exist. Otherwise, load it
|
||||
if (!exists.sync(extConfigPath)) {
|
||||
allExtConfigs = {};
|
||||
} else {
|
||||
try {
|
||||
allExtConfigs = JSON.parse(fs.readFileSync(extConfigPath, 'utf8'));
|
||||
} catch (e) {
|
||||
throw `Invalid config at ${extConfigPath}: ${e.toString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
var persistExtConfig = () => {
|
||||
fs.writeFileSync(extConfigPath, JSON.stringify(allExtConfigs, null, 2));
|
||||
};
|
||||
|
||||
var extender = {};
|
||||
|
||||
extender.EXT_CONFIG_NAME = EXT_CONFIG_NAME;
|
||||
|
||||
extender.isSupportedType = function(type) {
|
||||
return extender.install[type] && extender.uninstall[type];
|
||||
};
|
||||
|
||||
extender.getExtensionsConfig = function() {
|
||||
return allExtConfigs;
|
||||
};
|
||||
|
||||
extender.getInstalledConfig = function(name) {
|
||||
var group = values(allExtConfigs).find(typeGroup => {
|
||||
return !!typeGroup[name];
|
||||
});
|
||||
return group && group[name];
|
||||
};
|
||||
|
||||
extender.install = function(project, isReinstall) {
|
||||
// Install the project
|
||||
return Q.ninvoke(npm, 'load', {})
|
||||
.then(() => Q.ninvoke(npm, 'install', project))
|
||||
.then(results => {
|
||||
var installed = results[0],
|
||||
extProject,
|
||||
extRoot;
|
||||
|
||||
extProject = installed[0][0];
|
||||
extRoot = installed[0][1];
|
||||
|
||||
// Check for the extensions.json in the project (look up type, etc)
|
||||
var extConfigPath = path.join(extRoot, extender.EXT_CONFIG_NAME),
|
||||
extConfig,
|
||||
extType;
|
||||
|
||||
// Check that the extensions file exists
|
||||
if (!exists.sync(extConfigPath)) {
|
||||
throw [
|
||||
`Could not find ${extender.EXT_CONFIG_NAME} for ${project}.`,
|
||||
'',
|
||||
`This is likely an issue w/ the deepforge extension (${project})`
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
try {
|
||||
extConfig = JSON.parse(fs.readFileSync(extConfigPath, 'utf8'));
|
||||
} catch(e) { // Invalid JSON
|
||||
throw `Invalid ${extender.EXT_CONFIG_NAME}: ${e}`;
|
||||
}
|
||||
|
||||
// Try to add the extension to the project (using the extender)
|
||||
extType = extConfig.type;
|
||||
if (!extender.isSupportedType(extType)) {
|
||||
throw `Unrecognized extension type: "${extType}"`;
|
||||
}
|
||||
extender.install[extType](extConfig, {
|
||||
arg: project,
|
||||
root: extRoot,
|
||||
name: extProject
|
||||
}, !!isReinstall);
|
||||
|
||||
return extConfig;
|
||||
});
|
||||
};
|
||||
|
||||
extender.uninstall = function(name) {
|
||||
// Look up the extension in ~/.deepforge/extensions.json
|
||||
var extConfig = extender.getInstalledConfig(name);
|
||||
if (!extConfig) {
|
||||
throw `Extension "${name}" not found`;
|
||||
}
|
||||
|
||||
// Run the uninstaller using the extender
|
||||
var extType = extConfig.type;
|
||||
extender.uninstall[extType](name);
|
||||
};
|
||||
|
||||
var makeInstallFor = function(typeCfg) {
|
||||
var saveExtensions = () => {
|
||||
// regenerate the format.js file from the template
|
||||
var installedExts = values(allExtConfigs[typeCfg.type]),
|
||||
formatTemplate = makeTpl(fs.readFileSync(typeCfg.template, 'utf8')),
|
||||
formatsIndex = formatTemplate({path: path, formats: installedExts}),
|
||||
dstPath = typeCfg.template.replace(/\.ejs$/, '');
|
||||
|
||||
fs.writeFileSync(dstPath, formatsIndex);
|
||||
persistExtConfig();
|
||||
};
|
||||
|
||||
// Given a...
|
||||
// - template file
|
||||
// - extension type
|
||||
// - target path tpl
|
||||
// create the installation/uninstallation functions
|
||||
extender.install[typeCfg.type] = (config, project, isReinstall) => {
|
||||
var dstPath,
|
||||
pkgJsonPath = path.join(project.root, 'package.json'),
|
||||
pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')),
|
||||
content;
|
||||
|
||||
// add the config to the current installed extensions of this type
|
||||
project = project || config.project;
|
||||
config.version = pkgJson.version;
|
||||
config.project = project;
|
||||
|
||||
allExtConfigs[typeCfg.type] = allExtConfigs[typeCfg.type] || {};
|
||||
|
||||
if (allExtConfigs[typeCfg.type][config.name] && !isReinstall) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Extension ${config.name} already installed. Reinstalling...`);
|
||||
}
|
||||
|
||||
allExtConfigs[typeCfg.type][config.name] = config;
|
||||
|
||||
// copy the main script to src/plugins/Export/formats/<name>/<main>
|
||||
dstPath = makeTpl(typeCfg.targetDir)(config);
|
||||
if (!exists.sync(dstPath)) {
|
||||
fs.mkdirSync(dstPath);
|
||||
}
|
||||
|
||||
try {
|
||||
content = fs.readFileSync(path.join(project.root, config.main), 'utf8');
|
||||
} catch (e) {
|
||||
throw 'Could not read the extension\'s main file: ' + e;
|
||||
}
|
||||
dstPath = path.join(dstPath, path.basename(config.main));
|
||||
fs.writeFileSync(dstPath, content);
|
||||
|
||||
saveExtensions();
|
||||
};
|
||||
|
||||
// uninstall
|
||||
extender.uninstall['Export:Pipeline'] = name => {
|
||||
// Remove from config
|
||||
allExtConfigs[typeCfg.type] = allExtConfigs[typeCfg.type] || {};
|
||||
|
||||
if (!allExtConfigs[typeCfg.type][name]) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Extension ${name} not installed`);
|
||||
return;
|
||||
}
|
||||
var config = allExtConfigs[typeCfg.type][name],
|
||||
dstPath = makeTpl(typeCfg.targetDir)(config);
|
||||
|
||||
// Remove the dstPath
|
||||
delete allExtConfigs[typeCfg.type][name];
|
||||
rm_rf.sync(dstPath);
|
||||
|
||||
// Re-generate template file
|
||||
saveExtensions();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
var PLUGIN_ROOT = path.join(__dirname, '..', 'src', 'plugins', 'Export');
|
||||
makeInstallFor({
|
||||
type: 'Export:Pipeline',
|
||||
template: path.join(PLUGIN_ROOT, 'format.js.ejs'),
|
||||
targetDir: path.join(PLUGIN_ROOT, 'formats', '<%=name%>')
|
||||
});
|
||||
|
||||
module.exports = extender;
|
||||
@@ -0,0 +1,30 @@
|
||||
// Re-install all extensions
|
||||
var extender = require('./extender'),
|
||||
Q = require('q'),
|
||||
extConfig = extender.getExtensionsConfig(),
|
||||
types,
|
||||
names,
|
||||
currentInstall = Q(),
|
||||
installCount = 0,
|
||||
config;
|
||||
|
||||
// Read the extensions and reinstall each of them
|
||||
types = Object.keys(extConfig);
|
||||
for (var i = types.length; i--;) {
|
||||
names = Object.keys(extConfig[types[i]]);
|
||||
if (names.length) {
|
||||
installCount += names.length;
|
||||
for (var j = names.length; j--;) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Re-installing ${names[j]} extension...`);
|
||||
config = extConfig[types[i]][names[j]];
|
||||
currentInstall = currentInstall
|
||||
.then(() => extender.install(config.project.arg, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (installCount) {
|
||||
// eslint-disable-next-line no-console
|
||||
currentInstall.then(() => console.log('Extensions reinstalled successfully'));
|
||||
}
|
||||
+3
-3
@@ -29,9 +29,9 @@
|
||||
"src": "src/plugins/CreateExecution",
|
||||
"test": "test/plugins/CreateExecution"
|
||||
},
|
||||
"GenerateExecFile": {
|
||||
"src": "src/plugins/GenerateExecFile",
|
||||
"test": "test/plugins/GenerateExecFile"
|
||||
"Export": {
|
||||
"src": "src/plugins/Export",
|
||||
"test": "test/plugins/Export"
|
||||
},
|
||||
"ImportArtifact": {
|
||||
"src": "src/plugins/ImportArtifact",
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário