Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add c# .net core support #40

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,17 @@ node_modules/
__pycache__/
*.pyc
*.pyo


# .NET Core build assets
tmp/dotnet/
release/dotnet/
[Dd]ebug/
[Dd]ebugPublic/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
1 change: 1 addition & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ see: [100+ Working Service Examples](https://github.com/stackvana/microcule-exam
- coffee-script
- common lisp
- bash
- dotnet (.NET Core)
- lua
- golang
- ocaml
Expand Down
31 changes: 22 additions & 9 deletions bin/microcule
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ config.http.port = argv.p || argv.port || config.http.port;
config.watch = argv.w || argv.watch || config.watch;
config.stream = argv.s || argv.stream || config.stream;

// default to releasing compiled binaries to current working directory of `microcule` binary
// If no config, default to releasing compiled binaries to current working directory of `microcule` binary
config.releaseDir = config.releaseDir || process.cwd();

if (typeof argv.v !== "undefined" || typeof argv.version !== "undefined") {
var pkg = require('../package.json')
console.log(pkg.version)
var pkg = require('../package.json');
console.log(pkg.version);
process.exit();
}

Expand Down Expand Up @@ -48,6 +48,10 @@ var _service;

try {
_service = requireServiceSync({ path: servicePath });

//console.log('#### microcule: requireServiceSync() ######');
//console.dir(_service);

} catch (err) {
if (err.code === 'ENOENT') {
// if we could not find the service, attempt to see if it's a globally available binary
Expand All @@ -71,7 +75,7 @@ if (typeof argv.l !== "undefined" || typeof argv.language !== "undefined") {
}

if (stdin.isTTY) {
// console.log('ignoring will not run in TTY mode')
//console.log('ignoring will not run in TTY mode')
// helps with peformance of STDIN tool
http = require('resource-http');
startServer(_service);
Expand Down Expand Up @@ -109,14 +113,15 @@ function startSTDIN (service) {
mode: 'stream'
};


var Readable = require('stream').Readable;
var Writable = require('stream').Writable;

var input = new Readable;
var output = Writable();

output._write = function (chunk, enc, next) {
// console.log('wirtint out',chunk.toString());
console.log('wirtint out',chunk.toString());
process.stdout.write(chunk);
next();
};
Expand Down Expand Up @@ -145,6 +150,7 @@ function startSTDIN (service) {
bin: service.bin,
argv: service.argv,
code: service.code,
originalCodeFilePath: service.originalCodeFilePath,
schema: service.schema,
view: service.view,
presenter: service.presenter,
Expand All @@ -153,7 +159,7 @@ function startSTDIN (service) {
config: config,
log: console.log
})(stdin, output, function(){
// console.log("COMPLETED STREAMING SERVICE")
console.log("COMPLETED STREAMING SERVICE")
});
} else {
var result = '';
Expand All @@ -164,11 +170,12 @@ function startSTDIN (service) {
STDIN: result
}
};
// console.log('spawning service'.yellow)
console.log('spawning service'.yellow)
microcule.plugins.spawn({
bin: service.bin,
argv: service.argv,
code: service.code,
originalCodeFilePath: service.originalCodeFilePath,
schema: service.schema,
view: service.view,
presenter: service.presenter,
Expand Down Expand Up @@ -208,7 +215,7 @@ function startServer (_service) {
console.log('using presenter for service')
}

console.log(_service.language + ' microcule started at: http://' + addr.address + ":" + addr.port);
console.log(_service.language + ' microcule started at: http://'.blue + addr.address + ":" + addr.port);

// Remark: Will automatically map the process.env `microcule` was spawned in to the service.env of the spawned function
config.env = process.env;
Expand All @@ -233,9 +240,11 @@ function startServer (_service) {
spawnService(__service);
});
*/
console.log('1'.red);
spawnService(requireServiceSync({ path: servicePath }));
} else {
spawnService(_service)
console.log('2'.red);
spawnService(_service);
}

function spawnService (service) {
Expand All @@ -248,10 +257,12 @@ function startServer (_service) {
if (err) {
return next(err);
}
console.log('3'.red);
microcule.plugins.spawn({
bin: service.bin,
argv: service.argv,
code: service.code,
originalCodeFilePath: service.originalCodeFilePath,
schema: service.schema,
view: service.view,
presenter: service.presenter,
Expand All @@ -266,10 +277,12 @@ function startServer (_service) {
});
});
} else {
console.log('4'.red);
microcule.plugins.spawn({
bin: service.bin,
argv: service.argv,
code: service.code,
originalCodeFilePath: service.originalCodeFilePath,
schema: service.schema,
view: service.view,
presenter: service.presenter,
Expand Down
4 changes: 3 additions & 1 deletion config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ module.exports = {
ca: [fs.readFileSync(__dirname + '/ssl/ca-crt.pem').toString()],
sslRequired: true, // redirects all http traffic to https, optional
onlySSL: false // will only start https server with no unprotected http interface, optional

},
SERVICE_MAX_TIMEOUT: 10000,
messages: {
childProcessSpawnError: require('./messages/childProcessSpawnError'),
serviceExecutionTimeout: require('./messages/serviceExecutionTimeout')
}
},
releaseDir: process.cwd() + '/release'
};
2 changes: 1 addition & 1 deletion examples/express-compiled-languages.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var service = {
var spawn = microcule.plugins.spawn(service);

app.use(function(req, res, next){
console.log('attempting to spawn', service)
console.log('[express-compiled-languages.js] attempting to spawn ', service)
spawn(req, res, next);
});

Expand Down
18 changes: 18 additions & 0 deletions examples/services/hello-world/dotnet-hello/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace dotnet_hello
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World from .NET Core!!!");

foreach (var arg in args)
{
Console.WriteLine("param: {0}", arg);
}

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>
155 changes: 155 additions & 0 deletions lib/plugins/compile/compileServiceCode/dotnet/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
var fs = require('fs');
var spawn = require('child_process').spawn;
var crypto = require('crypto');
var path = require('path');
var ncp = require('ncp').ncp;
var shasum = require('shasum');
var path = require('path');

module.exports = function (req, res, cb) {
console.log('compileServiceCode.dotnet(). just executed'.yellow);
var service = req.service;

// TODO: override hash logic here to include the csproj contents.
// by default handled in compile/index.js and only used the code file
var hash = service.sha1;

console.log('inside compileServiceCode.dotnet()'.yellow)
console.dir(service);
/*
Supported Target: .NET Core 1.1
.NET Core 2.0 (untested)
Uasge:
- Standard .NET Core console app created via `dotnet new console -n <app name>`
- To execute run `microcule ./<path to .NET Core app>/Program.cs`
*/

//console.log('buildDir: ' + service.buildDir);
//console.log('releaseDir: ' + service.releaseDir);


// release is explicityly defaulted to the root of the microcule binary. Not sure why given there is a release folder.
// This may will break if the releaseDir default is overriden in config
//service.releaseDir = service.releaseDir + '/release';


// first, we need to write the file to a temporary location on the disk
// it could be possible to bypass writing to the disk entirely here, but it will be easier to debug user-scripts,
// and also interact with various compilers without having to look up special use cases for stdin / argv code parsing


//console.dir(service, { depth: null, colors: true });

var tmpBuildDir = service.buildDir + '/dotnet/' + hash;
var buildOutputDir = service.releaseDir + '/dotnet/' + hash;
//service.sourceCodeFilePath = '/Users/janaka.abeywardhana/code-projects/microcule/examples/services/hello-world/dotnet-hello/Program.cs';
//console.log('codefilepath = '.yellow, service.originalCodeFilePath);



// Create the folders we need. Because put code in a folders based on the hash we need to create folders it code changes.
// Logic for deciding if we needed re-build is in the shared complile logic.
if (!fs.existsSync(buildOutputDir)) {
fs.mkdirSync(buildOutputDir);
if (!fs.existsSync(tmpBuildDir)) {
fs.mkdirSync(tmpBuildDir);
}
}


console.log('Copy from ', service.originalSourceCodeDir, ' to ', tmpBuildDir);


ncp.limit = 5; // concurrent copies

ncp(service.originalSourceCodeDir, tmpBuildDir, function (err) {

if (err) {
return cb(err);
}
console.log('Successfully copied code to temp build dir');
console.log('starting dependency restore', 'dotnet restore');

var restore = spawn('dotnet', ['restore'], {
cwd: tmpBuildDir // ensure binary compiles to target directory
});

var stderr = '', stdout = '';

restore.on('error', function (data) {
console.log('error', data);
cb(data);
});


restore.on('exit', function (data) {
console.log('exit', data);

console.log('starting compiler dotnet', 'dotnet build -c release -v minimal -o ', buildOutputDir);

// command syntax: dotnet build -f 1.1 -c release -o <output dir> -v minimal
var compiler = spawn('dotnet', ['build', '-c', 'release', '-v','minimal', '-o', buildOutputDir], {
cwd: tmpBuildDir // ensure binary compiles to target directory
});

var stderr = '', stdout = '';

compiler.on('error', function (data) {
console.log('error', data)
cb(data);
});

/*
vm.stdin.error
vm.exit
vm.stdout.end
vm.stderr
*/

compiler.on('data', function (data) {
console.log('got data', data)
});

compiler.on('close', function (data) {
console.log('close', data)
//cb(null, 'close')
});

compiler.stdin.on('error', function (data) {
console.log('stdin.error', data);
// cb(null, 'close')
});

compiler.stdout.on('data', function (data) {
console.log('stdout', data);
stdout += data.toString();
//cb(null, 'close')
});

compiler.stderr.on('data', function (data) {
// console.log('stderr', data);
stderr += data.toString();
//cb(null, 'close')
});

compiler.on('exit', function (data) {
console.log('exit', data);
var result = {
tmpSourceFile: tmpBuildDir,
bin: buildOutputDir,
buildDir: tmpBuildDir,
originalCodeFilePath: service.originalCodeFilePath,
dotnetCsproj: service.dotnetCsproj,
stderr: stderr,
stdout: stdout,
exitCode: data
};
cb(null, result);
});

});
});



};
4 changes: 3 additions & 1 deletion lib/plugins/compile/compileServiceMappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ module.exports = {
"gcc": require('./compileServiceCode/gcc'),
"go": require('./compileServiceCode/golang'),
"rust": require('./compileServiceCode/rust'),
"r": require('./compileServiceCode/r')
"r": require('./compileServiceCode/r'),
"dotnet": require('./compileServiceCode/dotnet')

};
Loading