ln.build/ln.build/CIService.cs

202 lines
7.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using ln.application;
using ln.build.repositories;
using ln.http;
using ln.http.router;
using ln.json;
using ln.logging;
using ln.templates.html;
using ln.templates.http;
using ln.threading;
using ln.type;
using Microsoft.VisualBasic;
namespace ln.build
{
public class CIService
{
[StaticArgument( Option = 'b', LongOption = "base-directory")]
public string BaseDirectory { get; set; }
[StaticArgument( Option = 'u', LongOption = "base-url")]
public string BaseURL { get; set; }
[StaticArgument( Option = 'h', LongOption = "hostname")]
public string HostName { get; set; }
public Pool buildPool;
public string ReportsDirectory { get; set; }
Logger webLogger;
SimpleRouter httpRouter;
SimpleRouter hookRouter;
StaticRouter staticsRouter;
TemplateRouter templateRouter;
HTTPServer httpServer;
List<RepositoryInterface> repositoryInterfaces = new List<RepositoryInterface>();
HashSet<PipeLine> pipelines = new HashSet<PipeLine>();
public IEnumerable<PipeLine> PipeLines => pipelines;
Dictionary<string,string> secrets = new Dictionary<string, string>();
public CIService()
{
buildPool = new Pool(2);
String secretsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),".ln.build.secrets.json");
Logging.Log(LogLevel.INFO, "Trying to load secrets from {0}", secretsPath);
if (File.Exists(secretsPath))
{
JSONObject secretsObject = JSONParser.ParseFile(secretsPath) as JSONObject;
foreach (string key in secretsObject.Keys)
{
secrets.Add(key, secretsObject[key].ToNative().ToString());
}
Logging.Log(LogLevel.INFO, "Secrets loaded from {0}", secretsPath);
}
}
public CIService(string baseDirectory) : this()
{
BaseDirectory = baseDirectory;
ReportsDirectory = Path.Combine(baseDirectory, "builds" );
}
public void Initialize()
{
BaseDirectory ??= AppContext.BaseDirectory;
ReportsDirectory ??= Path.Combine(BaseDirectory, "builds" );
ReportsDirectory = Path.GetFullPath(ReportsDirectory);
Logging.Log(LogLevel.INFO, "Commandline: {0}", Environment.CommandLine);
Logging.Log(LogLevel.INFO, "Working Directory: {0}", Environment.CurrentDirectory);
Logging.Log(LogLevel.INFO, "Base Directory: {0}", BaseDirectory);
Logging.Log(LogLevel.INFO, "Reports Directory: {0}", ReportsDirectory);
Directory.CreateDirectory(ReportsDirectory);
InitializeHttpServer();
}
private void InitializeHttpServer()
{
if (HostName == null)
HostName = FindHostName();
if (BaseURL == null)
BaseURL = string.Format("http://{0}:{1}", HostName, 1888);
Logging.Log(LogLevel.DEBUG, "Hostname: {0}", HostName);
Logging.Log(LogLevel.DEBUG, "BaseURL: {0}", BaseURL);
httpRouter = new SimpleRouter();
httpRouter.AddSimpleRoute("/builds/*", new StaticRouter(ReportsDirectory));
hookRouter = new SimpleRouter();
staticsRouter = new StaticRouter(Path.Combine(BaseDirectory, "html", "static"));
templateRouter = new TemplateRouter(new FileSystemTemplateSource(Path.Combine(BaseDirectory, "html", "documents"), false));
templateRouter.DefaultTemplatePath = "index.html";
templateRouter.OnPrepareRenderContext += (templateRouter, templateDocument, renderContext) => {
renderContext.SetScriptObject("CIService", this);
};
httpRouter.AddSimpleRoute("/hooks/*", hookRouter);
httpRouter.AddSimpleRoute("/builds/:buildid/*", templateRouter);
httpRouter.AddSimpleRoute("/builds/:buildid", templateRouter);
httpRouter.AddSimpleRoute("/*", staticsRouter);
webLogger = new Logger(Logger.ConsoleLogger);
webLogger.Backends.Add(new FileLogger("ln.build.http.log"));
httpServer = new HTTPServer(new LoggingRouter(httpRouter, webLogger));
foreach (IPAddress _ip in Dns.GetHostAddresses(HostName))
{
IPv6 ip6 = _ip;
httpServer.AddEndpoint(new Endpoint(ip6, 1888));
}
}
public string GetJobURL(CIJob job) => string.Format("{0}/builds/{1}", BaseURL, job.JobID);
public string GetSecret(string key) => secrets[key];
public void Start()
{
buildPool.Start();
httpServer.Start();
}
public void AddPipeline(PipeLine pipeLine)
{
pipelines.Add(pipeLine);
}
public void AddRepositoryInterface(RepositoryInterface repositoryInterface)
{
hookRouter.AddSimpleRoute(String.Format("/{0}", repositoryInterface.WebHookName), (HttpRoutingContext context,HttpRequest request) => repositoryInterface.WebHookHandler(this, request));
repositoryInterfaces.Add(repositoryInterface);
}
public void Enqueue(CIJob job)
{
buildPool.Enqueue(job);
}
public void CreateReport(CIJob job)
{
JSONObject report = new JSONObject();
JSONArray steps = new JSONArray();
report["steps"] = steps;
report["state"] = new JSONString(job.BuildState.ToString());
string reportDirectory = Path.Combine(ReportsDirectory, job.JobID);
Directory.CreateDirectory(reportDirectory);
foreach (string logName in job.GetLogStreamNames())
{
string logFileName = Path.Combine(reportDirectory, logName);
using (FileStream fileStream = new FileStream(logFileName, FileMode.CreateNew))
{
job.GetLogStream(logName).Position = 0;
job.GetLogStream(logName).CopyTo(fileStream);
fileStream.Flush();
fileStream.Close();
}
steps.Add(new JSONString(logName));
}
using (StreamWriter writer = new StreamWriter(Path.Combine(reportDirectory, "build.json")))
writer.Write(report.ToString());
}
public string FindHostName()
{
return Dns.GetHostEntry("LocalHost").HostName;
/*
string hostName = IPGlobalProperties.GetIPGlobalProperties().HostName;
string domainName = IPGlobalProperties.GetIPGlobalProperties().DomainName;
if (!hostName.EndsWith(domainName))
{
hostName = string.Format("{0}.{1}", hostName, domainName);
}
return hostName;
*/ }
}
}