Created dotnet2.0 Builder Image and Added /v2/specialized Endpoint to dotnet2.0 Envrionment (#1001)
This commit is contained in:
committed by
Ta-Ching Chen
parent
56fa8fe766
commit
4632269314
@@ -16,3 +16,7 @@ environments/php7/vendor/
|
||||
.DS_Store
|
||||
vendor/
|
||||
local/
|
||||
environments/dotnet20/Builder/.vs/
|
||||
environments/dotnet20/.vs/
|
||||
environments/dotnet20/obj/
|
||||
environments/dotnet20/bin/
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
builder
|
||||
@@ -4,11 +4,16 @@ using System.Collections.Generic;
|
||||
using Nancy;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Nancy.IO;
|
||||
using Fission.DotNetCore.Utilty;
|
||||
using Fission.DotNetCore.Model;
|
||||
using Nancy.Extensions;
|
||||
|
||||
namespace Fission.DotNetCore
|
||||
{
|
||||
public class ExecutorModule : NancyModule
|
||||
{
|
||||
private static string PackagePath = string.Empty;
|
||||
#if DEBUG
|
||||
private const string CODE_PATH = "/tmp/func.cs";
|
||||
#else
|
||||
@@ -20,6 +25,7 @@ namespace Fission.DotNetCore
|
||||
public ExecutorModule()
|
||||
{
|
||||
Post("/specialize", args => Specialize());
|
||||
Post("/v2/specialize", args => Specializev2());
|
||||
Get("/", _ => Run());
|
||||
Post("/", _ => Run());
|
||||
Put("/", _ => Run());
|
||||
@@ -28,6 +34,94 @@ namespace Fission.DotNetCore
|
||||
Delete("/", _ => Run());
|
||||
}
|
||||
|
||||
private object Specializev2()
|
||||
{
|
||||
Console.WriteLine("Call Reached at /v2/specialize");
|
||||
|
||||
try
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var oinfo = new List<string>();
|
||||
var _request = Request;
|
||||
var _body = Request.Body;
|
||||
// Request.Body.Position = 0; use it only if requst has already been read before that
|
||||
var _requestBodystring = RequestStream.FromStream(Request.Body).AsString();
|
||||
Console.WriteLine($"Request received by endpoint from builder : {_requestBodystring}");
|
||||
BuilderRequest builderRequest = EnvironmentHelper.Instance.GetBuilderRequest(_requestBodystring);
|
||||
if (builderRequest == null)
|
||||
{
|
||||
Console.WriteLine("Error : Unbale to parse builder request!!");
|
||||
throw new Exception("Error : Unbale to parse builder request!!");
|
||||
}
|
||||
|
||||
string functionPath = string.Empty;
|
||||
// functionPath = Path.Combine(builderRequest.filepath, $"{builderRequest.functionName}.cs");
|
||||
|
||||
PackagePath = builderRequest.filepath;
|
||||
//following will enable us to skip --entrypoint flag during function creation
|
||||
if (!string.IsNullOrWhiteSpace(builderRequest.functionName))
|
||||
{
|
||||
functionPath = Path.Combine(builderRequest.filepath, $"{builderRequest.functionName}.cs");
|
||||
}
|
||||
else
|
||||
{
|
||||
functionPath = Path.Combine(builderRequest.filepath, EnvironmentHelper.Instance.environmentSettings.functionBodyFileName);
|
||||
}
|
||||
|
||||
Console.WriteLine($"Going to read function body from path : {functionPath}");
|
||||
|
||||
if (File.Exists(functionPath))
|
||||
{
|
||||
var code = File.ReadAllText(functionPath);
|
||||
try
|
||||
{
|
||||
FissionCompiler fissionCompiler = new FissionCompiler(builderRequest.filepath);
|
||||
_userFunc = fissionCompiler.Compilev2(code, out errors, out oinfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error getting _userFunc :{ex.Message} , Trace : {ex.StackTrace}");
|
||||
}
|
||||
if (_userFunc == null)
|
||||
{
|
||||
var errstr = string.Join(Environment.NewLine, errors);
|
||||
_logger.WriteError(errstr);
|
||||
Console.WriteLine($"Error _userFunc is null :{errstr}");
|
||||
var response = (Response)errstr;
|
||||
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||
return response;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//try to retrun few details
|
||||
var infostr = string.Join(Environment.NewLine, oinfo);
|
||||
_logger.WriteInfo(infostr);
|
||||
var response = (Response)infostr;
|
||||
response.StatusCode = HttpStatusCode.OK;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var errstr = $"Unable to locate code at '{functionPath}'";
|
||||
_logger.WriteError(errstr);
|
||||
var response = (Response)errstr;
|
||||
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Exception occured {ex.Message} | {ex.StackTrace}");
|
||||
var errstr = $"Exception occured {ex.Message} | {ex.StackTrace}";
|
||||
_logger.WriteError(errstr);
|
||||
var response = (Response)errstr;
|
||||
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private object Specialize()
|
||||
{
|
||||
var errors = new List<string>();
|
||||
@@ -67,7 +161,10 @@ namespace Fission.DotNetCore
|
||||
|
||||
try
|
||||
{
|
||||
return _userFunc.Invoke(FissionContext.Build(Request, new Logger()));
|
||||
var context = FissionContext.Build(Request, new Logger());
|
||||
//set the package path ,as that will be required to get appsetting files from package
|
||||
context.PackagePath = PackagePath;
|
||||
return _userFunc.Invoke(context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Fission.DotNetCore.Model;
|
||||
using Fission.DotNetCore.Utilty;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
@@ -12,6 +15,12 @@ namespace Fission.DotNetCore.Compiler
|
||||
//adapted from this article http://www.tugberkugurlu.com/archive/compiling-c-sharp-code-into-memory-and-executing-it-with-roslyn
|
||||
class FissionCompiler
|
||||
{
|
||||
string packagepath = string.Empty;
|
||||
FunctionSpecification functionSpecification = null;
|
||||
public FissionCompiler(string _packagePath)
|
||||
{
|
||||
this.packagepath = _packagePath;
|
||||
}
|
||||
public static Function Compile(string code, out List<string> errors)
|
||||
{
|
||||
errors = new List<string>();
|
||||
@@ -64,12 +73,158 @@ namespace Fission.DotNetCore.Compiler
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
|
||||
var type = assembly.GetType("FissionFunction");
|
||||
//support for Namespace , as well as backward compatibility for existing functions
|
||||
var type = assembly.GetTypes().FirstOrDefault(x => x.Name.EndsWith("FissionFunction"));
|
||||
var info = type.GetMember("Execute").First() as MethodInfo;
|
||||
return new Function(assembly, type, info);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Function Compilev2(string code, out List<string> errors, out List<string> oinfo)
|
||||
{
|
||||
errors = new List<string>();
|
||||
oinfo = new List<string>();
|
||||
|
||||
#region syntext tree and default refrence build
|
||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||||
|
||||
string assemblyName = Path.GetRandomFileName();
|
||||
|
||||
var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
|
||||
|
||||
Console.WriteLine("Adding core refrences !!");
|
||||
List<MetadataReference> references = new List<MetadataReference>
|
||||
{
|
||||
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
|
||||
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "netstandard.dll"),
|
||||
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
|
||||
MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location),
|
||||
MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location)
|
||||
};
|
||||
|
||||
Console.WriteLine("Adding parent assembaly based refrences !!");
|
||||
foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies())
|
||||
{
|
||||
var assembly = Assembly.Load(referencedAssembly);
|
||||
references.Add(MetadataReference.CreateFromFile(assembly.Location));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region load function specs based dlls
|
||||
|
||||
Console.WriteLine($"going to get function specification...");
|
||||
//load all available dlls from deployment folder in dllinfo object
|
||||
functionSpecification = EnvironmentHelper.Instance.GetFunctionSpecs(packagepath);
|
||||
|
||||
Console.WriteLine($"going to get package dlls...");
|
||||
//iterate and all all libraries mentioned
|
||||
foreach (var library in functionSpecification.libraries)
|
||||
{
|
||||
string dllCompletePath = Path.Combine(packagepath, library.path).GetrelevantPathAsPerOS();
|
||||
references.Add(MetadataReference.CreateFromFile(dllCompletePath));
|
||||
Console.WriteLine($"refered folder based dll : {dllCompletePath} from package {library.nugetPackage}");
|
||||
}
|
||||
Console.WriteLine($"refered all available dlls!!");
|
||||
oinfo.Add("refered all available dlls!!");
|
||||
|
||||
#endregion
|
||||
|
||||
#region dynamic resolve handeler registration
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
|
||||
#endregion
|
||||
|
||||
#region function compile
|
||||
|
||||
Console.WriteLine($"Trying to Compile");
|
||||
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
syntaxTrees: new[] { syntaxTree },
|
||||
references: references,
|
||||
options: new CSharpCompilationOptions(
|
||||
OutputKind.DynamicallyLinkedLibrary,
|
||||
optimizationLevel: OptimizationLevel.Release));
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
EmitResult result = compilation.Emit(ms);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
Console.WriteLine($"Compile Failed , see pod logs for more details");
|
||||
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
|
||||
diagnostic.IsWarningAsError ||
|
||||
diagnostic.Severity == DiagnosticSeverity.Error).ToList();
|
||||
|
||||
foreach (Diagnostic diagnostic in failures)
|
||||
{
|
||||
errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
|
||||
Console.WriteLine($"COMPILE ERROR :{diagnostic.Id}: {diagnostic.GetMessage()}", "ERROR");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oinfo.Add("COMPILE SUCCESS!!");
|
||||
Console.WriteLine($"COMPILE SUCCESS!!");
|
||||
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
|
||||
//var type = assembly.GetType("FissionFunction");
|
||||
//support for Namespace , as well as backward compatibility for existing functions
|
||||
var type = assembly.GetTypes().FirstOrDefault(x => x.Name.EndsWith("FissionFunction"));
|
||||
//assembly.GetTypes().Where(x=>x.Name.ToLower().EndsWith("FissionFunction".ToLower())).FirstOrDefault();
|
||||
var info = type.GetMember("Execute").First() as MethodInfo;
|
||||
return new Function(assembly, type, info);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
|
||||
|
||||
Console.WriteLine($"Dynamically trying to load dll {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} in parent assembaly");
|
||||
|
||||
//Retrieve the list of referenced assemblies in an array of AssemblyName.
|
||||
Assembly MyAssembly = null, objExecutingAssemblies;
|
||||
string strTempAssmbPath_relative = "", strTempAssmbPath_absolute = "";
|
||||
|
||||
objExecutingAssemblies = Assembly.GetExecutingAssembly();
|
||||
AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();
|
||||
|
||||
////Loop through the array of referenced assembly names.
|
||||
|
||||
//load all available dlls from deployment folder in dllinfo object
|
||||
if (functionSpecification.libraries.Any(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()))
|
||||
{
|
||||
strTempAssmbPath_relative = functionSpecification.libraries.Where(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()).FirstOrDefault().path;
|
||||
strTempAssmbPath_absolute = Path.Combine(packagepath, strTempAssmbPath_relative);
|
||||
Console.WriteLine($"loading dll in parent assembaly :{strTempAssmbPath_absolute.GetrelevantPathAsPerOS()}");
|
||||
//Load the assembly from the specified path.
|
||||
MyAssembly = Assembly.LoadFile(strTempAssmbPath_absolute.GetrelevantPathAsPerOS());
|
||||
Console.WriteLine($"Load success for :{strTempAssmbPath_absolute.GetrelevantPathAsPerOS()}");
|
||||
}
|
||||
|
||||
if (MyAssembly == null)
|
||||
{
|
||||
Console.WriteLine($"WARNING !!! unabel to locate dll :{(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} ", "WARNING");
|
||||
}
|
||||
//Return the loaded assembly.
|
||||
return MyAssembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using Nancy;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace Fission.DotNetCore.Api
|
||||
{
|
||||
public class FissionContext
|
||||
{
|
||||
public string PackagePath { get; set; }
|
||||
public FissionContext(Dictionary<string, object> args, Logger logger, FissionHttpRequest request)
|
||||
{
|
||||
if (args == null) throw new ArgumentNullException(nameof(args));
|
||||
@@ -31,6 +34,20 @@ namespace Fission.DotNetCore.Api
|
||||
logger,
|
||||
new FissionHttpRequest(request));
|
||||
}
|
||||
//this is to support aditional setting file read from source/deployment package via function
|
||||
public T GetSettings<T>(string relativePath)
|
||||
{
|
||||
var filePath = Path.Combine(this.PackagePath, relativePath);
|
||||
Console.WriteLine($"Going to Get Setting from :{filePath}");
|
||||
string json = GetSettingsJson(filePath);
|
||||
return JsonConvert.DeserializeObject<T>(json);
|
||||
}
|
||||
|
||||
private string GetSettingsJson(string relativePath)
|
||||
{
|
||||
return File.ReadAllText(Path.Combine(this.PackagePath, relativePath));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Logger
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Model
|
||||
{
|
||||
public class BuilderRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// this is folder path of deployment package which contains all deployment content copied to env
|
||||
/// </summary>
|
||||
public string filepath { get; set; }
|
||||
public string functionName { get; set; }
|
||||
public string url { get; set; }
|
||||
public FunctionMetadata FunctionMetadata { get; set; }
|
||||
}
|
||||
public class FunctionMetadata
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string @namespace { get; set; }
|
||||
public string selfLink { get; set; }
|
||||
public string uid { get; set; }
|
||||
public string resourceVersion { get; set; }
|
||||
public int generation { get; set; }
|
||||
public DateTime creationTimestamp { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Model
|
||||
{
|
||||
public class DllInfo
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string rootPackage { get; set; }
|
||||
public string framework { get; set; }
|
||||
|
||||
public string processor { get; set; }
|
||||
public string path { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Model
|
||||
{
|
||||
public class EnvironmentSettings
|
||||
{
|
||||
public string LogDirectory { get; set; }
|
||||
|
||||
public string DllDirectory { get; set; }
|
||||
public string functionBodyFileName { get; set; }
|
||||
public string functionSpecFileName { get; set; }
|
||||
public bool RunningOnwindows { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Fission.DotNetCore.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Model
|
||||
{
|
||||
public class FunctionSpecification
|
||||
{
|
||||
public FunctionSpecification()
|
||||
{
|
||||
this.libraries = new List<Library>();
|
||||
}
|
||||
public string functionName { get; set; }
|
||||
public List<Library> libraries { get; set; }
|
||||
public string hash { get; set; }
|
||||
public string certificatePath { get; set; }
|
||||
}
|
||||
public class Library
|
||||
{
|
||||
public Library()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Library(DllInfo dllInfo)
|
||||
{
|
||||
this.name = dllInfo.name;
|
||||
this.nugetPackage = dllInfo.rootPackage;
|
||||
this.path = dllInfo.path;
|
||||
}
|
||||
public string name { get; set; }
|
||||
//public string version { get; set; }
|
||||
public string path { get; set; }
|
||||
public string nugetPackage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -268,3 +268,97 @@ $ curl -XPOST http://localhost:8888/specialize
|
||||
```
|
||||
$ curl -XGET http://localhost:8888
|
||||
```
|
||||
|
||||
## Few Aditional Features
|
||||
|
||||
**1. NameSpace support :**
|
||||
|
||||
Now , You can use namespace for Fission function class and have many other classes in same namespace , this is also backward compatible , however main execution class would always be *FissionFunction* and its method *Execute*
|
||||
|
||||
```
|
||||
using System;
|
||||
using Fission.DotNetCore.Api;
|
||||
|
||||
|
||||
public class FissionFunction
|
||||
{
|
||||
public string Execute(FissionContext context){
|
||||
//orignal logic
|
||||
}
|
||||
public string AnotherClass(string myval){
|
||||
//do something
|
||||
}
|
||||
}
|
||||
```
|
||||
**2. Aditional **setting/configuration file** support :**
|
||||
|
||||
Now , with Fission V2 end point with builder , in source package you can have aditional setting
|
||||
files which can be read by fission function .
|
||||
Lets say you are writing a function and you need some configurable option and setting to be available in function and thus you want to use some additional configuration file , then you can also achieve the same by having a JSON based configuration file and a corresponding POCO Class for the same.
|
||||
|
||||
Please use https://csharp2json.io/ & http://json2csharp.com/ to create correct POCO class for you JSON configuration file.
|
||||
|
||||
Here is an example of a such file which we want to use in function , lets say your package.zip contains :
|
||||
|
||||
```
|
||||
Source Package zip :
|
||||
--soruce.zip
|
||||
|--Func.cs
|
||||
|--nuget.txt
|
||||
|--exclude.txt
|
||||
|--mysetting.json
|
||||
|--....MiscFiles(optional)
|
||||
|--....MiscFiles(optional)
|
||||
```
|
||||
|
||||
here is what ***mysetting.json*** looks like :
|
||||
|
||||
```
|
||||
{
|
||||
"name": "Alpha",
|
||||
"sendGridEndPoints":
|
||||
[
|
||||
{ "port": 1002 },
|
||||
{ "port": 3004 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
here is what ***func.cs*** looks like :
|
||||
|
||||
```
|
||||
using System;
|
||||
using Fission.DotNetCore.Api;
|
||||
|
||||
namespace FuncNameSpace
|
||||
{
|
||||
public class FissionFunction
|
||||
{
|
||||
public string Execute(FissionContext context){
|
||||
string respo="initial value";
|
||||
context.Logger.WriteInfo("Staring..... ");
|
||||
var settings =context.GetSettings<SendGridSettings>("mysetting.json");
|
||||
context.Logger.WriteInfo($"SendGridEndPoint port : {settings.SendGridEndPoints[0].port} ..... ");
|
||||
respo=settings.SendGridEndPoints[0].port;
|
||||
context.Logger.WriteInfo("Done!!");
|
||||
return respo;
|
||||
}
|
||||
}
|
||||
|
||||
public class SendGridSettings
|
||||
{
|
||||
public string name { get; set; }
|
||||
public System.Collections.Generic.List<SendGridEndPoint> SendGridEndPoints { get; set; }
|
||||
}
|
||||
|
||||
public class SendGridEndPoint
|
||||
{
|
||||
public string port { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
**3. Nuget support :**
|
||||
|
||||
with use of fission builder we can now add various compatible nugets with our deployment package so that it can be leverage via our function code. Please go through detailed documentation of [fission builder for dotnet 2.0 environment](https://github.com/fission/fission/tree/master/environments/dotnet20/builder).
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Utilty
|
||||
{
|
||||
public static class EnvironmentExtension
|
||||
{
|
||||
|
||||
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
|
||||
this IEnumerable<TSource> source,
|
||||
Func<TSource, TKey> keySelector)
|
||||
{
|
||||
var knownKeys = new HashSet<TKey>();
|
||||
return source.Where(element => knownKeys.Add(keySelector(element)));
|
||||
}
|
||||
public static string GetrelevantPathAsPerOS(this string curruntPath)
|
||||
{
|
||||
if (EnvironmentHelper.Instance.environmentSettings.RunningOnwindows && curruntPath.Contains("\\"))
|
||||
{
|
||||
return curruntPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return curruntPath.Replace("\\", "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using Fission.DotNetCore.Api;
|
||||
using Fission.DotNetCore.Model;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Utilty
|
||||
{
|
||||
public sealed class EnvironmentHelper
|
||||
{
|
||||
private static readonly Lazy<EnvironmentHelper> lazy =
|
||||
new Lazy<EnvironmentHelper>(() => new EnvironmentHelper());
|
||||
|
||||
public static EnvironmentHelper Instance { get { return lazy.Value; } }
|
||||
|
||||
public EnvironmentSettings environmentSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_envSettings == null)
|
||||
{
|
||||
string watcherSettingsjson = GetEnvironmentSettingsJson();
|
||||
_envSettings = ObjectConverter.Instance.GetWatcherSettingsFromJson(watcherSettingsjson);
|
||||
}
|
||||
return _envSettings;
|
||||
}
|
||||
set
|
||||
{
|
||||
_envSettings = value;
|
||||
}
|
||||
}
|
||||
|
||||
private EnvironmentSettings _envSettings;
|
||||
|
||||
|
||||
static EnvironmentHelper()
|
||||
{
|
||||
}
|
||||
private EnvironmentHelper()
|
||||
{
|
||||
}
|
||||
|
||||
public void writeToFile(string msg)
|
||||
{
|
||||
|
||||
using (StreamWriter sw = new StreamWriter("main.log",true))
|
||||
{
|
||||
sw.AutoFlush = true;
|
||||
sw.WriteLine($"{DateTime.Now} : {msg}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetEnvironmentSettingsJson()
|
||||
{
|
||||
var baselocation = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var FileLocation = baselocation + "envsettings.json";
|
||||
|
||||
return File.ReadAllText(FileLocation);
|
||||
}
|
||||
|
||||
public BuilderRequest GetBuilderRequest(string json)
|
||||
{
|
||||
BuilderRequest builderRequest = new BuilderRequest();
|
||||
try
|
||||
{
|
||||
builderRequest = JsonConvert.DeserializeObject<BuilderRequest>(json);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error : Unable to intersept request json " + ex.Message + ex.StackTrace);
|
||||
}
|
||||
|
||||
return builderRequest;
|
||||
}
|
||||
|
||||
public List<DllInfo> GetDllInfoFromDirectory(string directorypath)
|
||||
{
|
||||
List<DllInfo> dllInfos = new List<DllInfo>();
|
||||
|
||||
Console.WriteLine($"finding dll in folder {directorypath}");
|
||||
DirectoryInfo d = new DirectoryInfo(directorypath);//Assuming packagepath is your Folder
|
||||
var files = d.GetFiles("*.dll"); //Getting dll files
|
||||
foreach(var file in files)
|
||||
{
|
||||
Console.WriteLine($"found dll {file.Name.ToLower()} at {Path.Combine(directorypath, file.Name)}");
|
||||
dllInfos.Add(new DllInfo() {
|
||||
name = file.Name.ToLower(),
|
||||
path = Path.Combine(directorypath, file.Name)
|
||||
});
|
||||
}
|
||||
|
||||
return dllInfos;
|
||||
}
|
||||
|
||||
public FunctionSpecification GetFunctionSpecs(string directorypath)
|
||||
{
|
||||
|
||||
string functionSpecsFilePath = Path.Combine(directorypath, this.environmentSettings.functionSpecFileName);
|
||||
if (File.Exists(functionSpecsFilePath))
|
||||
{
|
||||
string specsJson = File.ReadAllText(functionSpecsFilePath);
|
||||
return ObjectConverter.Instance.GetFunctionSpecificationFromJson(specsJson);
|
||||
}
|
||||
else
|
||||
throw new Exception($"Function Specification file not found at {functionSpecsFilePath}");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Fission.DotNetCore.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Fission.DotNetCore.Utilty
|
||||
{
|
||||
public sealed class ObjectConverter
|
||||
{
|
||||
|
||||
private static readonly Lazy<ObjectConverter> lazy =
|
||||
new Lazy<ObjectConverter>(() => new ObjectConverter());
|
||||
|
||||
public static ObjectConverter Instance { get { return lazy.Value; } }
|
||||
|
||||
private ObjectConverter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public EnvironmentSettings GetWatcherSettingsFromJson(string json)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<EnvironmentSettings>(json);
|
||||
}
|
||||
|
||||
public FunctionSpecification GetFunctionSpecificationFromJson(string json)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<FunctionSpecification>(json);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using Builder.Utility;
|
||||
using NugetWorker;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Builder.Engine;
|
||||
|
||||
namespace Builder
|
||||
{
|
||||
class Builder
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Builder Task Begins!");
|
||||
//create log file name for this session
|
||||
var logFileName = $"{DateTime.Now.ToString("yyyy_MM_dd")}_{Guid.NewGuid().ToString()}.log";
|
||||
Console.WriteLine($"going to create logger!!");
|
||||
|
||||
try
|
||||
{
|
||||
string _logdirectory = BuilderHelper.Instance.builderSettings.BuildLogDirectory;
|
||||
BuilderHelper.Instance._logFileName = Path.Combine(_logdirectory, logFileName);
|
||||
BuilderHelper.Instance.logger = new Utility.Logger(
|
||||
BuilderHelper.Instance._logFileName);
|
||||
|
||||
//set the same for nuget engine dll
|
||||
NugetHelper.Instance.logger = new NugetWorker.Logger(BuilderHelper.Instance._logFileName);
|
||||
|
||||
Console.WriteLine($"detailed logs for this build will be at : {Path.Combine(_logdirectory, logFileName)}!!");
|
||||
|
||||
|
||||
BuilderEngine builderEngine = new BuilderEngine();
|
||||
builderEngine.BuildPackage().Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string detailedException = string.Empty;
|
||||
try
|
||||
{
|
||||
detailedException= BuilderHelper.Instance.DeepException(ex);
|
||||
Console.WriteLine($"Exception During Build : {Environment.NewLine} {ex.Message} | {ex.StackTrace} | {Environment.NewLine} {detailedException}");
|
||||
}
|
||||
catch(Exception childEx)
|
||||
{
|
||||
//do nothing , just log orignal exception
|
||||
Console.WriteLine($"{Environment.NewLine} Exception During Build :{ex.Message} |{Environment.NewLine} {ex.StackTrace} {Environment.NewLine} ");
|
||||
}
|
||||
|
||||
//now throw back exception so that build gets failed via builder
|
||||
throw;
|
||||
}
|
||||
|
||||
Console.WriteLine("Builder Task Ends!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nancy" Version="2.0.0-clinteastwood" />
|
||||
<PackageReference Include="nugetdownloader" Version="2.0.0" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
<HintPath>System</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="build.sh">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="builder">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="builderSettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="log4net.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="nugetSettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27906.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder", "Builder.csproj", "{D479FF57-44A0-483D-B5B0-B6C475D12292}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D479FF57-44A0-483D-B5B0-B6C475D12292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D479FF57-44A0-483D-B5B0-B6C475D12292}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D479FF57-44A0-483D-B5B0-B6C475D12292}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D479FF57-44A0-483D-B5B0-B6C475D12292}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {AA20D0B8-E5D5-4BA1-9E29-FC5132A4DD00}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,306 @@
|
||||
using Builder.Model;
|
||||
using Builder.Utility;
|
||||
using NugetWorker;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using NuGet.Packaging;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.Reflection;
|
||||
using Microsoft.CodeAnalysis.Emit;
|
||||
using System.Runtime.Loader;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Builder.Engine
|
||||
{
|
||||
public class BuilderEngine
|
||||
{
|
||||
public string SRC_PKG = string.Empty;
|
||||
public string DEPLOY_PKG = string.Empty;
|
||||
|
||||
List<DllInfo> dllInfos = new List<DllInfo>();
|
||||
List<ExcludeDll> excludeDlls = new List<ExcludeDll>();
|
||||
List<IncludeNuget> includeNugets = new List<IncludeNuget>();
|
||||
List<string> compile_errors = new List<string>();
|
||||
List<string> compile_info = new List<string>();
|
||||
|
||||
public BuilderEngine()
|
||||
{
|
||||
SRC_PKG = Environment.GetEnvironmentVariable("SRC_PKG");
|
||||
DEPLOY_PKG = Environment.GetEnvironmentVariable("DEPLOY_PKG");
|
||||
}
|
||||
|
||||
|
||||
public async Task BuildPackage()
|
||||
{
|
||||
await BuildDllInfo();
|
||||
|
||||
Console.WriteLine("DLL Info Gathered!!");
|
||||
// try to compile the function and if compilation succedd ,then create func spec file
|
||||
//this enables us to find compilation issues during package creation itself thus saving time
|
||||
// however this feature impose that the function file name should be func.cs
|
||||
//if we dont want it , we can comment the TryCompile() logic
|
||||
Console.WriteLine("Trying to compile it during build itslef !!");
|
||||
bool compiled =await TryCompile();
|
||||
Console.WriteLine($"Compilation result Gathered as : {compiled}!!");
|
||||
if (compiled)
|
||||
{
|
||||
|
||||
//nowwhatever has been done so far and all files which are generated are in /app folder where dll resides
|
||||
//thus copy relavant thing in SRC_PKG as it is ,but lest skip it here , we shall do it in build.sh
|
||||
CopyToSourceDir();
|
||||
Console.WriteLine($"Copy to Source Done!!");
|
||||
//build the function specs
|
||||
await BuildSpecs();
|
||||
Console.WriteLine("BuildSpecs Done!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Compilation failed , throwing exception !!");
|
||||
foreach(var error in compile_errors)
|
||||
{
|
||||
Console.WriteLine($"COMPILATION ERROR : {error}");
|
||||
}
|
||||
throw new Exception($"COMPILATION FAILED !! , See builder logs for details , total Errors : {compile_errors.Count}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void CopyToSourceDir()
|
||||
{
|
||||
//to create folder if it doesnt already exists
|
||||
string destinationFile=Path.Combine(SRC_PKG, BuilderHelper.Instance.builderSettings.DllDirectory, "dummy.txt");
|
||||
new FileInfo(destinationFile).Directory.Create();
|
||||
|
||||
|
||||
//copy all dlls
|
||||
foreach (var dllinfo in dllInfos)
|
||||
{
|
||||
string filename = Path.GetFileName(dllinfo.path);
|
||||
destinationFile = Path.Combine(SRC_PKG, BuilderHelper.Instance.builderSettings.DllDirectory, filename);
|
||||
File.Copy(dllinfo.path, destinationFile,true);
|
||||
}
|
||||
|
||||
|
||||
//copy logs , well there is not point as logs are still being generated
|
||||
|
||||
//create dir if not exist
|
||||
//new FileInfo(Path.Combine(SRC_PKG, BuilderHelper.Instance._logFileName)).Directory.Create();
|
||||
|
||||
//File.Copy(BuilderHelper.Instance._logFileName, Path.Combine(SRC_PKG, BuilderHelper.Instance._logFileName));
|
||||
//BuilderHelper.Instance.logger.Log($"All Required Files copied to {SRC_PKG}");
|
||||
}
|
||||
|
||||
public async Task<bool> TryCompile()
|
||||
{
|
||||
bool issuccess = false;
|
||||
|
||||
string CODE_PATH = Path.Combine(SRC_PKG, BuilderHelper.Instance.builderSettings.functionBodyFileName);
|
||||
if (!File.Exists(CODE_PATH))
|
||||
{
|
||||
Console.WriteLine($"Source Code not found at : {CODE_PATH} !" +
|
||||
$" to use TryCompile() in Builder, make sure , your main function file name is " +
|
||||
$"{BuilderHelper.Instance.builderSettings.functionBodyFileName} and " +
|
||||
$"it is located at root of zip!!" );
|
||||
return issuccess;
|
||||
}
|
||||
|
||||
var code = File.ReadAllText(CODE_PATH);
|
||||
issuccess = await Compile(code);
|
||||
|
||||
return issuccess;
|
||||
}
|
||||
|
||||
public async Task<bool> Compile(string code)
|
||||
{
|
||||
bool issuccess = false;
|
||||
|
||||
#region assymbaly init and parent dll refrences
|
||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||||
string assemblyName = Path.GetRandomFileName();
|
||||
|
||||
var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
|
||||
|
||||
List<MetadataReference> references = new List<MetadataReference>
|
||||
{
|
||||
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
|
||||
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "netstandard.dll"),
|
||||
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
|
||||
MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location),
|
||||
MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location)
|
||||
};
|
||||
|
||||
foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies())
|
||||
{
|
||||
var assembly = Assembly.Load(referencedAssembly);
|
||||
references.Add(MetadataReference.CreateFromFile(assembly.Location));
|
||||
BuilderHelper.Instance.logger.Log($"Refering assembaly based dls : {assembly.Location}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region handler registration for runtime resolution
|
||||
//now add handeler for missing dlls for parent app domain as same assembalies should be needed
|
||||
//for parent , thus refering from https://support.microsoft.com/en-in/help/837908/how-to-load-an-assembly-at-runtime-that-is-located-in-a-folder-that-is
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
|
||||
#endregion
|
||||
|
||||
BuilderHelper.Instance.logger.Log($"dynamic handlar registered!!");
|
||||
#region nuget dll refrence add
|
||||
//now add those dll refrence
|
||||
foreach (var dll in dllInfos)
|
||||
{
|
||||
BuilderHelper.Instance.logger.Log($"refering nuget based dll : {dll.path}");
|
||||
references.Add(MetadataReference.CreateFromFile(dll.path));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region compilation
|
||||
|
||||
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
syntaxTrees: new[] { syntaxTree },
|
||||
references: references,
|
||||
options: new CSharpCompilationOptions(
|
||||
OutputKind.DynamicallyLinkedLibrary,
|
||||
optimizationLevel: OptimizationLevel.Release));
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
EmitResult result = compilation.Emit(ms);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
BuilderHelper.Instance.logger.Log($"Compile Failed!!!!",true);
|
||||
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
|
||||
diagnostic.IsWarningAsError ||
|
||||
diagnostic.Severity == DiagnosticSeverity.Error).ToList();
|
||||
|
||||
foreach (Diagnostic diagnostic in failures)
|
||||
{
|
||||
compile_errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
|
||||
BuilderHelper.Instance.logger.Log($"COMPILE ERROR :{diagnostic.Id}: {diagnostic.GetMessage()}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BuilderHelper.Instance.logger.Log("Compile Success!!",true);
|
||||
issuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
return issuccess;
|
||||
|
||||
}
|
||||
|
||||
public async Task BuildSpecs()
|
||||
{
|
||||
//create function specs C# object
|
||||
FunctionSpecification functionSpecification = new FunctionSpecification();
|
||||
|
||||
functionSpecification.functionName = BuilderHelper.Instance.builderSettings.functionBodyFileName;
|
||||
|
||||
foreach (var dllinfo in dllInfos)
|
||||
{
|
||||
//here is the tweak , as this path is based on execution directoy , thus choose the relative path
|
||||
string destinationFile = Path.Combine(BuilderHelper.Instance.builderSettings.DllDirectory, Path.GetFileName(dllinfo.path)).GetrelevantPathAsPerOS();
|
||||
|
||||
Library library = new Library()
|
||||
{
|
||||
name=dllinfo.name,
|
||||
nugetPackage=dllinfo.rootPackage,
|
||||
path = destinationFile
|
||||
};
|
||||
functionSpecification.libraries.Add(library);
|
||||
}
|
||||
|
||||
//serilize that object to save it in json file
|
||||
string funcMetaJson= JsonConvert.SerializeObject(functionSpecification);
|
||||
|
||||
string funcMetaFile = Path.Combine(this.SRC_PKG, BuilderHelper.Instance.builderSettings.functionSpecFileName);
|
||||
BuilderHelper.Instance.WriteTofile(funcMetaFile, funcMetaJson);
|
||||
|
||||
}
|
||||
|
||||
public async Task BuildDllInfo()
|
||||
{
|
||||
//read the nuget file and download nuget packages
|
||||
includeNugets = BuilderHelper.Instance.GetNugettoInclude(SRC_PKG);
|
||||
//set the nuget logger to same logger
|
||||
|
||||
|
||||
foreach (var nuget in includeNugets)
|
||||
{
|
||||
NugetEngine nugetEngine = new NugetEngine();
|
||||
await nugetEngine.GetPackage(nuget.packageName, nuget.version);
|
||||
|
||||
//add the list of dlls received via this package in master list
|
||||
dllInfos.AddRange(nugetEngine.dllInfos);
|
||||
}
|
||||
|
||||
//now do a distinct of all dlls paths as multiple packaed might have added same dll
|
||||
dllInfos = dllInfos.DistinctBy(x => x.path).ToList();
|
||||
|
||||
#if DEBUG
|
||||
dllInfos.LogDllPathstoCSV("preFilter.CSV");
|
||||
#endif
|
||||
|
||||
//exclude the dlls from exclude file
|
||||
excludeDlls = BuilderHelper.Instance.GetDllstoExclude(SRC_PKG);
|
||||
foreach (var excludedll in excludeDlls)
|
||||
{
|
||||
BuilderHelper.Instance.logger.Log($"trying to remove , if available : {excludedll.dllName} from package {excludedll.packageName}");
|
||||
dllInfos.RemoveAll(x => x.rootPackage.ToLower() == excludedll.packageName.ToLower() && x.name.ToLower() == excludedll.dllName.ToLower());
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
//log dlls in debug mode
|
||||
dllInfos.LogDllPathstoCSV("PostFilter.CSV");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//This handler is called only when the common language runtime tries to bind to the assembly and fails.
|
||||
|
||||
BuilderHelper.Instance.logger.Log($"Dynamically trying to load dll {(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} in parent assembaly");
|
||||
|
||||
//Retrieve the list of referenced assemblies in an array of AssemblyName.
|
||||
Assembly MyAssembly = null, objExecutingAssemblies;
|
||||
string strTempAssmbPath = "";
|
||||
|
||||
objExecutingAssemblies = Assembly.GetExecutingAssembly();
|
||||
AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();
|
||||
|
||||
////Loop through the array of referenced assembly names.
|
||||
|
||||
if (dllInfos.Any(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()))
|
||||
{
|
||||
strTempAssmbPath = dllInfos.Where(x => x.name.ToLower() == (args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()).FirstOrDefault().path;
|
||||
|
||||
BuilderHelper.Instance.logger.Log($"loading dll in parent :{strTempAssmbPath}");
|
||||
|
||||
//Load the assembly from the specified path.
|
||||
MyAssembly = Assembly.LoadFile(strTempAssmbPath);
|
||||
}
|
||||
|
||||
if (MyAssembly == null)
|
||||
{
|
||||
BuilderHelper.Instance.logger.Log($"WARNING !!! unabel to locate dll :{(args.Name.Substring(0, args.Name.IndexOf(",")).ToString() + ".dll").ToLower()} ", true);
|
||||
}
|
||||
//Return the loaded assembly.
|
||||
return MyAssembly;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
ARG BUILDER_IMAGE=fission/builder
|
||||
FROM ${BUILDER_IMAGE} AS fission-builder
|
||||
|
||||
|
||||
FROM microsoft/dotnet:2.0.0-sdk AS builderimage
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy csproj and restore as distinct layers
|
||||
COPY *.csproj ./
|
||||
RUN dotnet restore
|
||||
|
||||
# Copy everything else and build
|
||||
COPY . ./
|
||||
RUN dotnet publish -c Release -o out
|
||||
|
||||
|
||||
# Build runtime image
|
||||
FROM microsoft/dotnet:aspnetcore-runtime
|
||||
WORKDIR /app
|
||||
COPY --from=builderimage /app/out .
|
||||
|
||||
#this builder is actually compilation from : https://github.com/fission/fission/tree/master/builder/cmd and renamed cmd.exe to builder
|
||||
# make sure to compile it in linux only else you will get exec execute error as binary was compiled in windows and running on linux
|
||||
|
||||
COPY --from=fission-builder /builder /builder
|
||||
|
||||
#ADD builder /builder
|
||||
|
||||
ADD build.sh /usr/local/bin/build
|
||||
RUN chmod +x /usr/local/bin/build
|
||||
|
||||
ADD build.sh /bin/build
|
||||
RUN chmod +x /bin/build
|
||||
|
||||
EXPOSE 8001
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Model
|
||||
{
|
||||
public class BuilderSettings
|
||||
{
|
||||
public string NugetSpecsFile { get; set; }
|
||||
public string DllExcludeFile { get; set; }
|
||||
public string BuildLogDirectory { get; set; }
|
||||
public string NugetPackageRegEx { get; set; }
|
||||
public string ExcludeDllRegEx { get; set; }
|
||||
public bool RunningOnwindows { get; set; }
|
||||
public string functionBodyFileName { get; set; }
|
||||
public string functionSpecFileName { get; set; }
|
||||
public string DllDirectory { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Model
|
||||
{
|
||||
public class ExcludeDll
|
||||
{
|
||||
public string dllName { get; set; }
|
||||
public string packageName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using Nancy;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace Fission.DotNetCore.Api
|
||||
{
|
||||
public class FissionContext
|
||||
{
|
||||
public FissionContext(Dictionary<string, object> args, Logger logger, FissionHttpRequest request)
|
||||
{
|
||||
if (args == null) throw new ArgumentNullException(nameof(args));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
Arguments = args;
|
||||
Logger = logger;
|
||||
Request = request;
|
||||
}
|
||||
|
||||
public Dictionary<string, object> Arguments { get; private set; }
|
||||
|
||||
public FissionHttpRequest Request { get; private set; }
|
||||
|
||||
public Logger Logger { get; private set; }
|
||||
|
||||
public static FissionContext Build(Request request, Logger logger)
|
||||
{
|
||||
return new FissionContext(((DynamicDictionary)request.Query).ToDictionary(),
|
||||
logger,
|
||||
new FissionHttpRequest(request));
|
||||
}
|
||||
|
||||
//this are curruntly dummy , not being implemented, just to pass compilation
|
||||
//actual execution is written in environment to use the app settings as there we need it
|
||||
public T GetSettings<T>(string relativePath)
|
||||
{
|
||||
//intentionaly doing it as these are just dummy methods not being called
|
||||
//but if tomorrow if we decide to give implementation for execution in build then we
|
||||
//need to implement it
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
//this are curruntly dummy , not being implemented, just to pass compilation
|
||||
//actual execution is written in environment to use the app settings as there we need it
|
||||
private string GetSettingsJson(string relativePath)
|
||||
{
|
||||
//intentionaly doing it as these are just dummy methods not being called
|
||||
//but if tomorrow if we decide to give implementation for execution in build then we
|
||||
//need to implement it
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Logger
|
||||
{
|
||||
public void Write(Severity severity, string format, params object[] args)
|
||||
{
|
||||
Console.WriteLine($"{DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz")} {severity}: " + format, args);
|
||||
}
|
||||
|
||||
public void WriteInfo(string format, params object[] args)
|
||||
{
|
||||
Write(Severity.Info, format, args);
|
||||
}
|
||||
|
||||
public void WriteWarning(string format, params object[] args)
|
||||
{
|
||||
Write(Severity.Warning, format, args);
|
||||
}
|
||||
|
||||
public void WriteError(string format, params object[] args)
|
||||
{
|
||||
Write(Severity.Error, format, args);
|
||||
}
|
||||
|
||||
public void WriteCritical(string format, params object[] args)
|
||||
{
|
||||
Write(Severity.Critical, format, args);
|
||||
}
|
||||
|
||||
public void WriteVerbose(string format, params object[] args)
|
||||
{
|
||||
Write(Severity.Verbose, format, args);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Severity
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Critical,
|
||||
Verbose
|
||||
}
|
||||
|
||||
public class FissionHttpRequest
|
||||
{
|
||||
private readonly Request _request;
|
||||
internal FissionHttpRequest(Request request)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
_request = request;
|
||||
}
|
||||
|
||||
public Stream Body { get { return _request.Body; } }
|
||||
|
||||
public string BodyAsString()
|
||||
{
|
||||
int length = (int)_request.Body.Length;
|
||||
byte[] data = new byte[length];
|
||||
_request.Body.Read(data, 0, length);
|
||||
return Encoding.UTF8.GetString(data);
|
||||
}
|
||||
|
||||
public Dictionary<string, IEnumerable<string>> Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
var headers = new Dictionary<string, IEnumerable<string>>();
|
||||
foreach (var kv in _request.Headers)
|
||||
{
|
||||
headers.Add(kv.Key, kv.Value);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
public X509Certificate Certificate { get { return _request.ClientCertificate; } }
|
||||
public string Url { get { return _request.Url.ToString(); } }
|
||||
public string Method { get { return _request.Method; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using NugetWorker;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Model
|
||||
{
|
||||
public class FunctionSpecification
|
||||
{
|
||||
public FunctionSpecification()
|
||||
{
|
||||
this.libraries = new List<Library>();
|
||||
}
|
||||
public string functionName { get; set; }
|
||||
public List<Library> libraries { get; set; }
|
||||
public string hash { get; set; }
|
||||
public string certificatePath { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class Library
|
||||
{
|
||||
public Library()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Library(DllInfo dllInfo)
|
||||
{
|
||||
this.name = dllInfo.name;
|
||||
this.nugetPackage = dllInfo.rootPackage;
|
||||
this.path = dllInfo.path;
|
||||
}
|
||||
public string name { get; set; }
|
||||
//public string version { get; set; }
|
||||
public string path { get; set; }
|
||||
public string nugetPackage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Model
|
||||
{
|
||||
public class IncludeNuget
|
||||
{
|
||||
public string packageName { get; set; }
|
||||
public string version { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
# Fission: dotnet 2.0 C# Environment Builder
|
||||
|
||||
This is a simple dotnet core 2.0 C# environment builder for Fission.
|
||||
|
||||
It's a docker image containing the dotnet 2.0.0 (core) run-time builder. This image read the source package and uses
|
||||
*roslyn* to compile the source package code and creates deployment package out of it.
|
||||
This enables using nuget packages as part of function and thus user can use extended functionality in fission functions via nuget.
|
||||
|
||||
During build , builder also does a pre-compile to prevent any compilation issues during function environment pod specialization.
|
||||
Thus we get the function compilation issues during builder phase in package info's build logs itself.
|
||||
|
||||
**Note** : In future we can further enhance the compiled assembly to be saved as physical file in deployment package ,
|
||||
as this will save cold start time for function.
|
||||
|
||||
Now , once after the build is finished, the output package (deploy archive) will be uploaded to storagesvc to store.
|
||||
Then, during the specialization, the fetcher inside function pod will fetch the package from storagesvc for function loading
|
||||
and will call on the **/v2/specialized** endpoint of fission environment with required parameters.
|
||||
|
||||
There further environment will compile it and execute the function.
|
||||
|
||||
|
||||
Example of simplest possible class to be executed:
|
||||
|
||||
The source package structure in zip file :
|
||||
|
||||
```
|
||||
Source Package zip :
|
||||
--soruce.zip
|
||||
|--func.cs
|
||||
|--nuget.txt
|
||||
|--exclude.txt
|
||||
|--....MiscFiles(optional)
|
||||
|--....MiscFiles(optional)
|
||||
```
|
||||
|
||||
**func.cs** --> This contains original function body with Executing method name as : Execute
|
||||
|
||||
|
||||
**nuget.txt**--> this file contains list of nuget packages required by your function , in this file put one line per nuget with nugetpackage name:version(optional) format, for example :
|
||||
|
||||
```
|
||||
RestSharp
|
||||
CsvHelper
|
||||
Newtonsoft.json:10.2.1.0
|
||||
```
|
||||
|
||||
|
||||
this should match the following regex as mentioned in builderSetting.json
|
||||
```
|
||||
"NugetPackageRegEx": "\\:?\\s*(?<package>[^:\\n]*)(?:\\:)?(?<version>.*)?"
|
||||
```
|
||||
|
||||
|
||||
**exclude.txt**--> as nuget.txt will download original package and their dependent packages , thus sometime dependent packages might not be
|
||||
that useful and can break compilation , thus this file contains list of dlls of specific nuget packages which doesn't need to be added during compilation if they break compilation .Put one line per nuget with dllname:nugetpackagename formate ,for example :
|
||||
|
||||
```
|
||||
Newtonsoft.json:Newtonsoft.json.dll
|
||||
```
|
||||
this should match the following regex as mentions in builderSetting.json
|
||||
|
||||
|
||||
```
|
||||
"ExcludeDllRegEx": "\\:?\\s*(?<package>[^:\\n]*)(?:\\:)?(?<dll>.*)?",
|
||||
```
|
||||
From above , builder will create a deployment package with all dlls in a folder and one functionspecification file :
|
||||
Deployement Package zip :
|
||||
|
||||
```
|
||||
--Deploye.zip
|
||||
|--func.cs
|
||||
|--nuget.txt
|
||||
|--exclude.txt
|
||||
|--dll()
|
||||
|--newtonsoft.json.dll
|
||||
|--restsharp.dll
|
||||
|--csvhelper.dll
|
||||
|--logs()
|
||||
|-->logFileName
|
||||
|--func.meta.json // this is the functionspecific file
|
||||
|--....MiscFiles(optional)
|
||||
|--....MiscFiles(optional)
|
||||
```
|
||||
Here are commands and detailed example for the same .
|
||||
|
||||
lets say my source package zip name is *funccsv.zip* :
|
||||
|
||||
**Content of func.cs:**
|
||||
```
|
||||
using System;
|
||||
using Fission.DotNetCore.Api;
|
||||
|
||||
public class FissionFunction
|
||||
{
|
||||
public string Execute(FissionContext context){
|
||||
string respo="initial value";
|
||||
try
|
||||
{
|
||||
context.Logger.WriteInfo("Staring..... ");
|
||||
respo=$" sample object by getting Enum of CsvHelper nuget dll: { CsvHelper.Caches.NamedIndex.ToString()}";
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
context.Logger.WriteError(ex.Message);
|
||||
respo = ex.Message;
|
||||
}
|
||||
context.Logger.WriteInfo("Done!");
|
||||
return respo;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Content of *nuget.txt***
|
||||
```
|
||||
CsvHelper
|
||||
```
|
||||
**Content of exclude.txt**
|
||||
|
||||
As we dont want to exclude any specific dll thus we shall leave it as empty.
|
||||
|
||||
Now check name of existing environments & functions as we want to create a unique environment for this dotnetcore if not already present
|
||||
|
||||
```
|
||||
fission env list
|
||||
fission fn list
|
||||
```
|
||||
Create Environment with builder (choose a unique which doesn't exist , here we have chosen : dotnetcorewithnuget )
|
||||
also suppose the builder image name is fissiondotnet20-builder and hosted on dockerhub as fission/dotnet20-builder
|
||||
```
|
||||
fission environment create --name dotnetcorewithnuget --image fission/dotnet20-env --builder fission/dotnet20-builder
|
||||
```
|
||||
Verify fission-builder and fission-function namespace for new pods (pods name beginning with env name which we have given like *dotnetcorewithnuget-xxx-xxx*)
|
||||
```
|
||||
kubectl get pods -n fission-builder
|
||||
kubectl get pods -n fission-function
|
||||
```
|
||||
Create Package from source zip using this environment name , this will output some package name created..
|
||||
```
|
||||
fission package create --src funccsv.zip --env dotnetcorewithnuget
|
||||
```
|
||||
Note down output package name lets say it is *funccsv-zip-xyz* now check its status using package info command , this will give the status
|
||||
on what happened with builder and test compilation in builder.
|
||||
|
||||
```
|
||||
fission package info --name funccsv-zip-xyz
|
||||
```
|
||||
|
||||
#Status of package should be f*ailed / running / succeeded* .
|
||||
Wait if the status is running , until it fails or succeeded. For detailed build logs, you can shell into builder pod in fission-builder namespace and verify log location mentioned in above command's result output.
|
||||
|
||||
**Note** : Even If the result is succeeded , please have a look at detailed build logs to see compilation success and builder job done.
|
||||
|
||||
Now If the result is succeeded , then go ahead and create function using this package.
|
||||
|
||||
*--entrypoint* flag is optional if your function body file name is func.cs (which it should be as builder need that), else put the filename (without extension )
|
||||
```
|
||||
fission fn create --name dotnetcsvtest --pkg funccsv-zip-xyz --env dotnetcorewithnuget --entrypoint "func"
|
||||
```
|
||||
Test the function execution :
|
||||
|
||||
```
|
||||
fission fn test --name dotnetcsvtest
|
||||
```
|
||||
above would execute the function and will output the enum value as written in dll.
|
||||
rest of the feature are same as normal fission environment.
|
||||
|
||||
**Benefit of using builder** :
|
||||
|
||||
1. Ability to use various nuget packages.
|
||||
2. Ability to use many additional files and functions as part of deployment package.
|
||||
3. Ability to know the compilation issue in advance via package logs , instead of environment giving compilation issue.
|
||||
4. Reusability of same deployment package.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Utility
|
||||
{
|
||||
public static class BuilderExtensions
|
||||
{
|
||||
public static string GetrelevantPathAsPerOS(this string curruntPath)
|
||||
{
|
||||
if (BuilderHelper.Instance.builderSettings.RunningOnwindows)
|
||||
{
|
||||
return curruntPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return curruntPath.Replace("\\","/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using Builder.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Builder.Utility
|
||||
{
|
||||
|
||||
public sealed class BuilderHelper
|
||||
{
|
||||
|
||||
private static readonly Lazy<BuilderHelper> lazy =
|
||||
new Lazy<BuilderHelper>(() => new BuilderHelper());
|
||||
|
||||
public string _logFileName = string.Empty;
|
||||
public static BuilderHelper Instance { get { return lazy.Value; } }
|
||||
|
||||
private static Logger _logger = new Logger("Initial.log");
|
||||
|
||||
private BuilderSettings _builderSettings = null;
|
||||
|
||||
public BuilderSettings builderSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_builderSettings == null)
|
||||
{
|
||||
string builderSettingsjson = GetBuilderSettingsJson();
|
||||
_builderSettings = ObjectConverter.Instance.GetBuilderSettingsFromJson(builderSettingsjson);
|
||||
}
|
||||
return _builderSettings;
|
||||
}
|
||||
set
|
||||
{
|
||||
builderSettings = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Logger logger
|
||||
{
|
||||
get
|
||||
{
|
||||
return _logger;
|
||||
}
|
||||
set
|
||||
{
|
||||
_logger = value;
|
||||
}
|
||||
}
|
||||
|
||||
static BuilderHelper()
|
||||
{
|
||||
}
|
||||
private BuilderHelper()
|
||||
{
|
||||
}
|
||||
|
||||
private string GetBuilderSettingsJson()
|
||||
{
|
||||
var baselocation = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var FileLocation = baselocation + "builderSettings.json";
|
||||
|
||||
return File.ReadAllText(FileLocation);
|
||||
}
|
||||
|
||||
|
||||
public List<IncludeNuget> GetNugettoInclude(string directoryPath)
|
||||
{
|
||||
List<IncludeNuget> includeNugets = new List<IncludeNuget>();
|
||||
string includeNugetsFilePath = Path.Combine(directoryPath, this.builderSettings.NugetSpecsFile);
|
||||
if (File.Exists(includeNugetsFilePath))
|
||||
{
|
||||
Regex _pkgName = new Regex(this.builderSettings.NugetPackageRegEx,
|
||||
RegexOptions.Compiled);
|
||||
|
||||
string filetext = File.ReadAllText(includeNugetsFilePath);
|
||||
var _pkgMatchCollection = _pkgName.Matches(filetext);
|
||||
|
||||
foreach (Match match in _pkgMatchCollection)
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(match.Value))
|
||||
{
|
||||
string package = match.Groups["package"]?.Value?.Trim();
|
||||
string version = match.Groups["version"]?.Value?.Trim();
|
||||
this.logger.Log($"adding {package} | {version} to includeNugets collection");
|
||||
|
||||
includeNugets.Add(
|
||||
new IncludeNuget()
|
||||
{
|
||||
packageName = package,
|
||||
version = version
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return includeNugets;
|
||||
}
|
||||
public List<ExcludeDll> GetDllstoExclude(string directoryPath)
|
||||
{
|
||||
List<ExcludeDll> excludeDlls = new List<ExcludeDll>();
|
||||
string excludeDllsFilePath = Path.Combine(directoryPath, this.builderSettings.DllExcludeFile);
|
||||
if (File.Exists(excludeDllsFilePath))
|
||||
{
|
||||
//xyzPackage:abc.dll
|
||||
Regex _exclude = new Regex(this.builderSettings.ExcludeDllRegEx,
|
||||
RegexOptions.Compiled);
|
||||
|
||||
string filetext = File.ReadAllText(excludeDllsFilePath);
|
||||
var _excludeMatchCollection = _exclude.Matches(filetext);
|
||||
|
||||
foreach (Match match in _excludeMatchCollection)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(match.Value))
|
||||
{
|
||||
string _package = match.Groups["package"]?.Value?.Trim();
|
||||
string _dllName = match.Groups["dll"]?.Value?.Trim();
|
||||
this.logger.Log($"adding {_package} | {_dllName} to excludeDlls collection");
|
||||
|
||||
excludeDlls.Add(
|
||||
new ExcludeDll()
|
||||
{
|
||||
packageName = _package,
|
||||
dllName = _dllName
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return excludeDlls;
|
||||
}
|
||||
|
||||
public string DeepException(Exception ex)
|
||||
{
|
||||
string responce = string.Empty;
|
||||
|
||||
responce = " Exception : LEVEL 1: " + Environment.NewLine + ex.Message;
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
responce = responce + Environment.NewLine + "LEVEL 2:" + Environment.NewLine + ex.InnerException.Message;
|
||||
if (ex.InnerException.InnerException != null)
|
||||
{
|
||||
responce =responce + Environment.NewLine + "LEVEL 3:" + Environment.NewLine + ex.InnerException.InnerException.Message;
|
||||
|
||||
if (ex.InnerException.InnerException.InnerException != null)
|
||||
{
|
||||
responce = responce + Environment.NewLine + "LEVEL 4:" + Environment.NewLine + ex.InnerException.InnerException.InnerException.Message;
|
||||
if (ex.InnerException.InnerException.InnerException.InnerException != null)
|
||||
{
|
||||
responce = responce + Environment.NewLine + "LEVEL 5:" + Environment.NewLine + ex.InnerException.InnerException.InnerException.InnerException.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ex.StackTrace!=null)
|
||||
{
|
||||
responce = responce + "|| STACK :"+ ex.StackTrace;
|
||||
}
|
||||
return responce;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void WriteTofile(string filenameWithPath , string content)
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter(filenameWithPath, false))
|
||||
{
|
||||
sw.AutoFlush = true;
|
||||
sw.Write(content);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using log4net;
|
||||
using NuGet.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace Builder.Utility
|
||||
{
|
||||
public class Logger : NuGet.Common.ILogger
|
||||
{
|
||||
private ILog _ILog { get; set; }
|
||||
public Logger(string logpath)
|
||||
{
|
||||
|
||||
//read the log4net config and create logger instance form log4net
|
||||
XmlDocument ConfigLoader = new XmlDocument();
|
||||
ConfigLoader.Load(File.OpenRead("log4net.config"));
|
||||
var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(),
|
||||
typeof(log4net.Repository.Hierarchy.Hierarchy));
|
||||
log4net.Config.XmlConfigurator.Configure(repo, ConfigLoader["log4net"]);
|
||||
|
||||
var appender = ((log4net.Appender.FileAppender)repo.GetAppenders().Where(x => x.Name == "RollingLogFileAppender").FirstOrDefault());
|
||||
appender.File = logpath;// $"directoryPath/{DateTime.Now.ToString("yyyy_MM_dd")}_{Guid.NewGuid().ToString()}_.log";
|
||||
|
||||
appender.ActivateOptions();
|
||||
_ILog = LogManager.GetLogger(typeof(Logger));
|
||||
}
|
||||
|
||||
public void Log(string message,bool logToConsoleAsWell=false)
|
||||
{
|
||||
if(logToConsoleAsWell)
|
||||
Console.WriteLine(message);
|
||||
|
||||
_ILog.Info(message);
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Info(data);
|
||||
}
|
||||
|
||||
public void Log(ILogMessage message)
|
||||
{
|
||||
//Console.WriteLine(message);
|
||||
_ILog.Info(message.Message);
|
||||
}
|
||||
|
||||
public Task LogAsync(LogLevel level, string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Info(data);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task LogAsync(ILogMessage message)
|
||||
{
|
||||
//Console.WriteLine(message);
|
||||
_ILog.Info(message.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LogDebug(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Debug(data);
|
||||
|
||||
}
|
||||
|
||||
public void LogError(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Error(data);
|
||||
}
|
||||
|
||||
public void LogInformation(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Info(data);
|
||||
}
|
||||
|
||||
public void LogInformationSummary(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Info(data);
|
||||
}
|
||||
|
||||
public void LogMinimal(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Info(data);
|
||||
}
|
||||
|
||||
public void LogVerbose(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Debug(data);
|
||||
}
|
||||
|
||||
public void LogWarning(string data)
|
||||
{
|
||||
//Console.WriteLine(data);
|
||||
_ILog.Warn(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Builder.Model;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Builder.Utility
|
||||
{
|
||||
public sealed class ObjectConverter
|
||||
{
|
||||
|
||||
private static readonly Lazy<ObjectConverter> lazy =
|
||||
new Lazy<ObjectConverter>(() => new ObjectConverter());
|
||||
|
||||
public static ObjectConverter Instance { get { return lazy.Value; } }
|
||||
|
||||
private ObjectConverter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public BuilderSettings GetBuilderSettingsFromJson(string json)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<BuilderSettings>(json);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
cd ${SRC_PKG}
|
||||
#now start execution of custom logic dll in such a way that it should copy everything in ${SRC_PKG}
|
||||
#first lets try putting sample file which will prove that this worked
|
||||
echo src : ${SRC_PKG} ,dest: ${DEPLOY_PKG} >builderpaths.txt
|
||||
|
||||
#now run actual dll for custom builder logic
|
||||
# please note as this need to be executed from app folder so that all dependent files are avilable
|
||||
# else you will end up getting File not found error
|
||||
cd /app
|
||||
|
||||
#now execute dll
|
||||
dotnet Builder.dll
|
||||
|
||||
#copy entire content to deployment package
|
||||
cp -r ${SRC_PKG} ${DEPLOY_PKG}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"NugetSpecsFile": "nuget.txt",
|
||||
"DllExcludeFile": "exclude.txt",
|
||||
"BuildLogDirectory": "logs",
|
||||
"DllDirectory": "Dlls",
|
||||
"NugetPackageRegEx": "\\s*(?<package>[^:\\n]*)(?:\\:)?(?<version>.*)?",
|
||||
"ExcludeDllRegEx": "\\:?\\s*(?<package>[^:\\n]*)(?:\\:)?(?<dll>.*)?",
|
||||
"RunningOnwindows": false,
|
||||
"functionBodyFileName": "func.cs",
|
||||
"functionSpecFileName": "func.meta.json"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<log4net>
|
||||
<appender name="Console" type="log4net.Appender.ConsoleAppender">
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date %-5level: %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
|
||||
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
|
||||
<File value=""/>
|
||||
<appendToFile value="true" />
|
||||
<rollingStyle value="Size" />
|
||||
<!--<datePattern value="yyyyMMdd-HHmm" />-->
|
||||
<maxSizeRollBackups value="6" />
|
||||
<preserveLogFileNameExtension value="true"/>
|
||||
<staticLogFileName value="false" />
|
||||
<maxSizeRollBackups value="100"/>
|
||||
<maximumFileSize value="1MB"/>
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date [%thread] %-5level : %message %newline %newline"/>
|
||||
</layout>
|
||||
</appender>
|
||||
<root>
|
||||
<level value="ALL"/>
|
||||
<!--<appender-ref ref="Console" />-->
|
||||
<appender-ref ref="RollingLogFileAppender"/>
|
||||
</root>
|
||||
</log4net>
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"NugetFolder": "Nugetdownload",
|
||||
"DisableCache": false,
|
||||
"CSVDirectory": "logs",
|
||||
"RunningOnwindows": false,
|
||||
"NugetRepositories": [
|
||||
{
|
||||
"Order": 1,
|
||||
"IsPrivate": false,
|
||||
"Name": "local",
|
||||
"Source": "Nugetdownload", //in case of local , relative path to folder
|
||||
"IsPasswordClearText": false,
|
||||
"Username": "",
|
||||
"Password": ""
|
||||
},
|
||||
{
|
||||
"Order": 2,
|
||||
"IsPrivate": false,
|
||||
"Name": "NugetV3",
|
||||
"Source": "https://api.nuget.org/v3/index.json",
|
||||
"IsPasswordClearText": false,
|
||||
"Username": "",
|
||||
"Password": ""
|
||||
}
|
||||
//,
|
||||
//{
|
||||
// "Order": 3,
|
||||
// "IsPrivate": true,
|
||||
// "Name": "myPrivateRepository", //in case of private repo , if not using, then just remove this section No 3
|
||||
// "Source": "https://URL-FOR-myPrivateRepository/api/nuget/nugetcore/COMPLETE-END-POINT",
|
||||
// "IsPasswordClearText": true,
|
||||
// "Username": "johndeo@myorg.com",
|
||||
// "Password": "AlPH24GAMAc49fDELTA"
|
||||
//}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fission-dotnet20", "dotnet20\fission-dotnet20.csproj", "{3F044DE1-74E5-48F7-8D23-233C24AAA45C}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fission-dotnet20", "fission-dotnet20.csproj", "{3F044DE1-74E5-48F7-8D23-233C24AAA45C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"LogDirectory": "logs",
|
||||
"RunningOnwindows": false,
|
||||
"DllDirectory": "Dlls",
|
||||
"functionBodyFileName": "func.cs",
|
||||
"functionSpecFileName": "func.meta.json"
|
||||
}
|
||||
@@ -1,10 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Builder\**" />
|
||||
<EmbeddedResource Remove="Builder\**" />
|
||||
<None Remove="Builder\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.0.0" />
|
||||
@@ -14,4 +21,14 @@
|
||||
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Model\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="envsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user