зеркало из
1
0
Форкнуть 0
This commit is contained in:
Ethan Dennis 2022-03-23 16:43:08 -07:00
Родитель e1305cdce5
Коммит e0a0bfbfe7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 6C85E14D00C447F7
6 изменённых файлов: 149 добавлений и 67 удалений

3
.gitignore поставляемый
Просмотреть файл

@ -9,6 +9,9 @@
*.user
*.userosscache
*.sln.docstates
.DS_STORE
output/
dist/
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

Просмотреть файл

@ -41,9 +41,7 @@ public class App
public async Task<int> ExecuteValetAsync(string[] args)
{
Console.WriteLine(string.Join(' ', args));
await _dockerService.ExecuteCommandAsync($"{ValetContainerRegistry}/{ValetImage}:latest", args);
return 1;
var result = await _dockerService.ExecuteCommandAsync($"{ValetContainerRegistry}/{ValetImage}:latest", args);
return result ? 0 : 1;
}
}

Просмотреть файл

@ -0,0 +1,6 @@
namespace Valet.Interfaces;
public interface IProcessService
{
Task<bool> RunAsync(string filename, string arguments, string? cwd = null, IEnumerable<(string, string)>? environmentVariables = null);
}

Просмотреть файл

@ -1,27 +1,43 @@
// See https://aka.ms/new-console-template for more information
using CommandLine;
using CommandLine.Text;
using Valet;
using Valet.Models;
using Valet.Services;
var processService = new ProcessService();
var app = new App(
new DockerService(),
new DockerService(processService),
new AuthenticationService()
);
var parser = new Parser(with => with.HelpWriter = null);
var parserResult = parser.ParseArguments<UpdateOptions, ExecuteOptions>(args);
// TODO: Utilize help menu from Valet itself
await Parser.Default.ParseArguments<UpdateOptions, ExecuteOptions>(args)
.MapResult(
(UpdateOptions opts) =>
{
return app.UpdateValetAsync(opts.Username, opts.Password);
},
(ExecuteOptions opts) =>
{
return Task.FromResult(1);
},
_ =>
{
return app.ExecuteValetAsync(args);
});
await parserResult.WithNotParsedAsync(errs =>
{
return app.ExecuteValetAsync(args);
});
await parserResult.WithParsedAsync<UpdateOptions>(options => app.UpdateValetAsync(options.Username, options.Password));
// (UpdateOptions opts) => app.UpdateValetAsync(opts.Username, opts.Password),
// (ExecuteOptions opts) => Task.FromResult(1),
// _ =>
// {
// var helpText = new HelpText
// {
// Heading = "Tool tool usage",
// AdditionalNewLineAfterOption = false,
// AddDashesToOption = true
// };
//
// Console.Error.WriteLine(helpText);
//
// return app.ExecuteValetAsync(args);
// });

Просмотреть файл

@ -1,3 +1,5 @@
using System.Diagnostics;
using System.Text;
using Docker.DotNet;
using Docker.DotNet.Models;
using Valet.Interfaces;
@ -8,8 +10,10 @@ namespace Valet.Services;
public class DockerService : IDockerService
{
private readonly DockerClient _client;
private readonly IProcessService _processService;
private readonly string[] _valetEnvVars = {
private readonly string[] _valetEnvVars =
{
"GH_ACCESS_TOKEN", "GH_INSTANCE_URL", "GITHUB_ACCESS_TOKEN", "GITHUB_INSTANCE_URL",
"JENKINSFILE_ACCESS_TOKEN", "JENKINS_USERNAME", "JENKINS_ACCESS_TOKEN", "JENKINS_INSTANCE_URL",
"TRAVIS_CI_ACCESS_TOKEN", "TRAVIS_CI_INSTANCE_URL", "TRAVIS_CI_SOURCE_GITHUB_ACCESS_TOKEN", "TRAVIS_CI_SOURCE_GITHUB_INSTANCE_URL", "TRAVIS_CI_ORGANIZATION",
@ -18,9 +22,11 @@ public class DockerService : IDockerService
"AZURE_DEVOPS_ACCESS_TOKEN", "AZURE_DEVOPS_PROJECT", "AZURE_DEVOPS_ORGANIZATION", "AZURE_DEVOPS_INSTANCE_URL",
"YAML_VERBOSITY", "HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "OCTOKIT_PROXY", "OCTOKIT_SSL_VERIFY_MODE",
};
public DockerService()
public DockerService(IProcessService processService)
{
_processService = processService;
// TODO: Raise error if docker daemon not started
_client = new DockerClientConfiguration()
.CreateClient();
@ -47,65 +53,47 @@ public class DockerService : IDockerService
public async Task<bool> ExecuteCommandAsync(string image, params string[] arguments)
{
// MSYS_NO_PATHCONV=1 docker run --rm $dockerArgs --env INSTALLATION_ID="$INSTALLATION_ID" $DOCKER_OPTIONS -v "$VALET_LOCAL_FOLDER"":/data" "$VALET_IMAGE":"$VALET_IMAGE_VERSION" "$@"
var container = await _client.Containers.CreateContainerAsync(
new CreateContainerParameters
{
Image = image,
HostConfig = new HostConfig
{
Binds = new[] { $"{Directory.GetCurrentDirectory()}:/data" },
AutoRemove = true,
},
Env = GetEnvironmentVariables().ToArray()
}
).ConfigureAwait(false);
var valetArguments = new List<string>();
valetArguments.Add("run --rm");
valetArguments.AddRange(GetEnvironmentVariableArguments());
valetArguments.Add($"-v \"{Directory.GetCurrentDirectory()}\":/data");
valetArguments.Add(image);
valetArguments.AddRange(arguments);
await _client.Containers.StartContainerAsync(
container.ID,
new ContainerStartParameters()
Debug.WriteLine(string.Join(' ', valetArguments));
var result = await _processService.RunAsync(
"docker",
string.Join(' ', valetArguments),
Directory.GetCurrentDirectory(),
new[] { ("MSYS_NO_PATHCONV", "1") }
);
return true;
return result;
}
private IEnumerable<string> GetEnvironmentVariables()
private IEnumerable<string> GetEnvironmentVariableArguments()
{
if (File.Exists(".env.local"))
{
foreach (var line in File.ReadAllLines(".env.local"))
{
var parts = line.Split('=', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2)
continue;
yield return $"{parts[0]}={parts[1]}";
}
yield return "--env-file .env.local";
}
var installationId = Environment.GetEnvironmentVariable("INSTALLATION_ID") ?? "get_from_client";
yield return $"--env INSTALLATION_ID={installationId}";
foreach (var env in _valetEnvVars)
{
var value = Environment.GetEnvironmentVariable(env);
if (!string.IsNullOrWhiteSpace(value))
{
var key = env;
// TODO: This can probably be cleaner
if (key.StartsWith("GH_"))
key = key.Replace("GH_", "GITHUB_");
yield return $"{key}={value}";
}
}
if (string.IsNullOrWhiteSpace(value)) continue;
var installationId = Environment.GetEnvironmentVariable("INSTALLATION_ID");
if (installationId == null)
{
installationId = "get_from_client";
}
var key = env;
// TODO: This can probably be cleaner
if (key.StartsWith("GH_"))
key = key.Replace("GH_", "GITHUB_");
yield return $"INSTALLATION_ID={installationId}";
yield return $"--env {key}={value}";
}
}
}

Просмотреть файл

@ -0,0 +1,71 @@
using System.Collections.Specialized;
using Valet.Interfaces;
namespace Valet.Services;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class ProcessService : IProcessService
{
public Task<bool> RunAsync(string filename, string arguments, string? cwd = null, IEnumerable<(string, string)>? environmentVariables = null)
{
var tcs = new TaskCompletionSource<bool>();
var startInfo = new ProcessStartInfo
{
FileName = filename,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
WorkingDirectory = cwd
};
if (environmentVariables != null)
{
foreach (var (key, value) in environmentVariables)
{
startInfo.EnvironmentVariables.Add(key, value);
}
}
var process = new Process
{
StartInfo = startInfo,
EnableRaisingEvents = true
};
void OnProcessExited(object? sender, EventArgs args)
{
process.Exited -= OnProcessExited;
process.OutputDataReceived -= OnOutputDataReceived;
if (process.ExitCode == 0)
{
tcs.TrySetResult(true);
}
else
{
// TODO: Verify works
var error = process.StandardError.ReadToEnd();
tcs.TrySetException(new Exception(error));
}
process.Dispose();
}
void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
process.OutputDataReceived += OnOutputDataReceived;
process.Exited += OnProcessExited;
process.Start();
process.BeginOutputReadLine();
return tcs.Task;
}
}