public async Task LoadGitExecutionInfo(AgentTaskPluginExecutionContext context, bool useBuiltInGit) { // Resolve the location of git. if (useBuiltInGit) { #if OS_WINDOWS string agentHomeDir = context.Variables.GetValueOrDefault("agent.homedirectory")?.Value; ArgUtil.NotNullOrEmpty(agentHomeDir, nameof(agentHomeDir)); gitPath = Path.Combine(agentHomeDir, "externals", "git", "cmd", $"git.exe"); // Prepend the PATH. context.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", "Path", Path.GetFileName(gitPath))); context.PrependPath(Path.GetDirectoryName(gitPath)); context.Debug($"PATH: '{Environment.GetEnvironmentVariable("PATH")}'"); #else // There is no built-in git for OSX/Linux gitPath = null; #endif } else { gitPath = WhichUtil.Which("git", require: true, trace: context); } ArgUtil.File(gitPath, nameof(gitPath)); // Get the Git version. gitVersion = await GitVersion(context); ArgUtil.NotNull(gitVersion, nameof(gitVersion)); context.Debug($"Detect git version: {gitVersion.ToString()}."); // Resolve the location of git-lfs. // This should be best effort since checkout lfs objects is an option. // We will check and ensure git-lfs version later gitLfsPath = WhichUtil.Which("git-lfs", require: false, trace: context); // Get the Git-LFS version if git-lfs exist in %PATH%. if (!string.IsNullOrEmpty(gitLfsPath)) { gitLfsVersion = await GitLfsVersion(context); context.Debug($"Detect git-lfs version: '{gitLfsVersion?.ToString() ?? string.Empty}'."); } // required 2.0, all git operation commandline args need min git version 2.0 Version minRequiredGitVersion = new Version(2, 0); EnsureGitVersion(minRequiredGitVersion, throwOnNotMatch: true); // suggest user upgrade to 2.9 for better git experience Version recommendGitVersion = new Version(2, 9); if (!EnsureGitVersion(recommendGitVersion, throwOnNotMatch: false)) { context.Output(StringUtil.Loc("UpgradeToLatestGit", recommendGitVersion, gitVersion)); } // Set the user agent. gitHttpUserAgentEnv = $"git/{gitVersion.ToString()} (vsts-agent-git/{context.Variables.GetValueOrDefault("agent.version")?.Value ?? "unknown"})"; context.Debug($"Set git useragent to: {gitHttpUserAgentEnv}."); }
/// <summary> /// Git package verification result using the "debsums" utility. /// </summary> /// <returns>String with the "debsums" output</returns> private async Task <string> GetPackageVerificationResult() { var debsums = WhichUtil.Which("debsums"); var stringBuilder = new StringBuilder(); using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs mes) => { stringBuilder.AppendLine(mes.Data); }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs mes) => { stringBuilder.AppendLine(mes.Data); }; await processInvoker.ExecuteAsync( workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Bin), fileName : debsums, arguments : string.Empty, environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, cancellationToken : default(CancellationToken) ); } return(stringBuilder.ToString()); }
public void Check(string name, string fileName = null, string[] filePaths = null) { ArgUtil.NotNullOrEmpty(name, nameof(name)); _cancellationToken.ThrowIfCancellationRequested(); try { // Which the file. string filePath = WhichUtil.Which(fileName ?? name, trace: _trace); if (string.IsNullOrEmpty(filePath)) { // Fallback to the well-known locations. foreach (string candidateFilePath in filePaths ?? new string[0]) { _trace.Info($"Checking file: '{candidateFilePath}'"); if (File.Exists(candidateFilePath)) { filePath = candidateFilePath; break; } } } if (!string.IsNullOrEmpty(filePath)) { _trace.Info($"Adding '{name}': '{filePath}'"); _capabilities.Add(new Capability(name, filePath)); } } catch (Exception ex) { _trace.Error(ex); } }
private void CreateCredentialStoreFile() { File.WriteAllText(_credStoreFile, ""); File.SetAttributes(_credStoreFile, File.GetAttributes(_credStoreFile) | FileAttributes.Hidden); // Try to lock down the .credentials_store file to the owner/group var chmodPath = WhichUtil.Which("chmod", trace: Trace); if (!String.IsNullOrEmpty(chmodPath)) { var arguments = $"600 {new FileInfo(_credStoreFile).FullName}"; using (var invoker = HostContext.CreateService <IProcessInvoker>()) { var exitCode = invoker.ExecuteAsync(HostContext.GetDirectory(WellKnownDirectory.Root), chmodPath, arguments, null, default(CancellationToken)).GetAwaiter().GetResult(); if (exitCode == 0) { Trace.Info("Successfully set permissions for credentials store file {0}", _credStoreFile); } else { Trace.Warning("Unable to successfully set permissions for credentials store file {0}. Received exit code {1} from {2}", _credStoreFile, exitCode, chmodPath); } } } else { Trace.Warning("Unable to locate chmod to set permissions for credentials store file {0}.", _credStoreFile); } }
public async Task ExecAsync(string workingDirectory, string toolName, string argLine) { Trace.Entering(); string toolPath = WhichUtil.Which(toolName, trace: Trace); Trace.Info($"Running {toolPath} {argLine}"); var processInvoker = HostContext.CreateService <IProcessInvoker>(); processInvoker.OutputDataReceived += OnOutputDataReceived; processInvoker.ErrorDataReceived += OnErrorDataReceived; try { using (var cs = new CancellationTokenSource(TimeSpan.FromSeconds(45))) { await processInvoker.ExecuteAsync(workingDirectory, toolPath, argLine, null, true, cs.Token); } } finally { processInvoker.OutputDataReceived -= OnOutputDataReceived; processInvoker.ErrorDataReceived -= OnErrorDataReceived; } }
private void RestartBasedOnUserInput(CommandSettings command) { Trace.Info("Asking the user to restart the machine to launch agent and for autologon settings to take effect."); _terminal.WriteLine(StringUtil.Loc("RestartMessage")); var noRestart = command.GetNoRestart(); if (!noRestart) { var shutdownExePath = WhichUtil.Which("shutdown.exe", trace: Trace); Trace.Info("Restarting the machine in 15 seconds"); _terminal.WriteLine(StringUtil.Loc("RestartIn15SecMessage")); string msg = StringUtil.Loc("ShutdownMessage"); //we are not using ProcessInvoker here as today it is not designed for 'fire and forget' pattern //ExecuteAsync API of ProcessInvoker waits for the process to exit var args = $@"-r -t 15 -c ""{msg}"""; Trace.Info($"Shutdown.exe path: {shutdownExePath}. Arguments: {args}"); Process.Start(shutdownExePath, $@"{args}"); } else { _terminal.WriteLine(StringUtil.Loc("NoRestartSuggestion")); } }
public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveRunner, CancellationToken token) { Busy = true; try { if (!await UpdateNeeded(updateMessage.TargetVersion, token)) { Trace.Info($"Can't find available update package."); return(false); } Trace.Info($"An update is available."); // Print console line that warn user not shutdown runner. await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner."); await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner"); await DownloadLatestRunner(token); Trace.Info($"Download latest runner and unzip into runner root."); // wait till all running job finish await UpdateRunnerUpdateStateAsync("Waiting for current job finish running."); await jobDispatcher.WaitAsync(token); Trace.Info($"All running job has exited."); // delete runner backup DeletePreviousVersionRunnerBackup(token); Trace.Info($"Delete old version runner backup."); // generate update script from template await UpdateRunnerUpdateStateAsync("Generate and execute update script."); string updateScript = GenerateUpdateScript(restartInteractiveRunner); Trace.Info($"Generate update script into: {updateScript}"); // kick off update script Process invokeScript = new Process(); #if OS_WINDOWS invokeScript.StartInfo.FileName = WhichUtil.Which("cmd.exe", trace: Trace); invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\""; #elif (OS_OSX || OS_LINUX) invokeScript.StartInfo.FileName = WhichUtil.Which("bash", trace: Trace); invokeScript.StartInfo.Arguments = $"\"{updateScript}\""; #endif invokeScript.Start(); Trace.Info($"Update script start running"); await UpdateRunnerUpdateStateAsync("Runner will exit shortly for update, should back online within 10 seconds."); return(true); } finally { Busy = false; } }
public override void Initialize(IHostContext hostContext) { ArgUtil.NotNull(hostContext, nameof(hostContext)); base.Initialize(hostContext); DockerPath = WhichUtil.Which("docker", true, Trace); DockerInstanceLabel = IOUtil.GetPathHash(hostContext.GetDirectory(WellKnownDirectory.Root)).Substring(0, 6); }
public async Task LoadGitExecutionInfo(IExecutionContext context, bool useBuiltInGit) { // Resolve the location of git. if (useBuiltInGit) { #if OS_WINDOWS _gitPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "git", "cmd", $"git{IOUtil.ExeExtension}"); // Prepend the PATH. context.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", Constants.PathVariable, Path.GetFileName(_gitPath))); PathUtil.PrependPath(Path.GetDirectoryName(_gitPath)); context.Debug($"{Constants.PathVariable}: '{Environment.GetEnvironmentVariable(Constants.PathVariable)}'"); #else // There is no built-in git for OSX/Linux _gitPath = null; #endif } else { _gitPath = WhichUtil.Which("git", require: true, trace: Trace); } ArgUtil.File(_gitPath, nameof(_gitPath)); // Get the Git version. _gitVersion = await GitVersion(context); ArgUtil.NotNull(_gitVersion, nameof(_gitVersion)); context.Debug($"Detect git version: {_gitVersion.ToString()}."); // Resolve the location of git-lfs. // This should be best effort since checkout lfs objects is an option. // We will check and ensure git-lfs version later _gitLfsPath = WhichUtil.Which("git-lfs", require: false, trace: Trace); // Get the Git-LFS version if git-lfs exist in %PATH%. if (!string.IsNullOrEmpty(_gitLfsPath)) { _gitLfsVersion = await GitLfsVersion(context); context.Debug($"Detect git-lfs version: '{_gitLfsVersion?.ToString() ?? string.Empty}'."); } // required 2.0, all git operation commandline args need min git version 2.0 Version minRequiredGitVersion = new Version(2, 0); EnsureGitVersion(minRequiredGitVersion, throwOnNotMatch: true); // suggest user upgrade to 2.9 for better git experience Version recommendGitVersion = new Version(2, 9); if (!EnsureGitVersion(recommendGitVersion, throwOnNotMatch: false)) { context.Output(StringUtil.Loc("UpgradeToLatestGit", recommendGitVersion, _gitVersion)); } // Set the user agent. _gitHttpUserAgentEnv = $"git/{_gitVersion.ToString()} (vsts-agent-git/{BuildConstants.AgentPackage.Version})"; context.Debug($"Set git useragent to: {_gitHttpUserAgentEnv}."); }
public async Task <bool> SelfUpdate(AgentRefreshMessage updateMessage, IJobDispatcher jobDispatcher, bool restartInteractiveAgent, CancellationToken token) { ArgUtil.NotNull(updateMessage, nameof(updateMessage)); ArgUtil.NotNull(jobDispatcher, nameof(jobDispatcher)); if (!await UpdateNeeded(updateMessage.TargetVersion, token)) { Trace.Info($"Can't find available update package."); return(false); } Trace.Info($"An update is available."); // Print console line that warn user not shutdown agent. await UpdateAgentUpdateStateAsync(StringUtil.Loc("UpdateInProgress")); await UpdateAgentUpdateStateAsync(StringUtil.Loc("DownloadAgent", _targetPackage.Version)); await DownloadLatestAgent(token); Trace.Info($"Download latest agent and unzip into agent root."); // wait till all running job finish await UpdateAgentUpdateStateAsync(StringUtil.Loc("EnsureJobFinished")); await jobDispatcher.WaitAsync(token); Trace.Info($"All running jobs have exited."); // delete agent backup DeletePreviousVersionAgentBackup(token); Trace.Info($"Delete old version agent backup."); // generate update script from template await UpdateAgentUpdateStateAsync(StringUtil.Loc("GenerateAndRunUpdateScript")); string updateScript = GenerateUpdateScript(restartInteractiveAgent); Trace.Info($"Generate update script into: {updateScript}"); // kick off update script Process invokeScript = new Process(); if (PlatformUtil.RunningOnWindows) { invokeScript.StartInfo.FileName = WhichUtil.Which("cmd.exe", trace: Trace); invokeScript.StartInfo.Arguments = $"/c \"{updateScript}\""; } else { invokeScript.StartInfo.FileName = WhichUtil.Which("bash", trace: Trace); invokeScript.StartInfo.Arguments = $"\"{updateScript}\""; } invokeScript.Start(); Trace.Info($"Update script start running"); await UpdateAgentUpdateStateAsync(StringUtil.Loc("AgentExit")); return(true); }
private async Task ExtractRunnerPackage(string archiveFile, string extractDirectory, CancellationToken token) { var stopWatch = Stopwatch.StartNew(); if (archiveFile.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { ZipFile.ExtractToDirectory(archiveFile, extractDirectory); } else if (archiveFile.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase)) { string tar = WhichUtil.Which("tar", trace: Trace); if (string.IsNullOrEmpty(tar)) { throw new NotSupportedException($"tar -xzf"); } // tar -xzf using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += new EventHandler <ProcessDataReceivedEventArgs>((sender, args) => { if (!string.IsNullOrEmpty(args.Data)) { Trace.Info(args.Data); } }); processInvoker.ErrorDataReceived += new EventHandler <ProcessDataReceivedEventArgs>((sender, args) => { if (!string.IsNullOrEmpty(args.Data)) { Trace.Error(args.Data); } }); int exitCode = await processInvoker.ExecuteAsync(extractDirectory, tar, $"-xzf \"{archiveFile}\"", null, token); if (exitCode != 0) { throw new NotSupportedException($"Can't use 'tar -xzf' extract archive file: {archiveFile}. return code: {exitCode}."); } } } else { throw new NotSupportedException($"{archiveFile}"); } stopWatch.Stop(); Trace.Info($"Finished getting latest runner package at: {extractDirectory}."); _updateTrace.Add($"PackageExtractTime: {stopWatch.ElapsedMilliseconds}ms"); }
/// <summary> /// Initializes svn command path and execution environment /// </summary> /// <param name="context">The build commands' execution context</param> /// <param name="endpoint">The Subversion server endpoint providing URL, username/password, and untrasted certs acceptace information</param> /// <param name="cancellationToken">The cancellation token used to stop svn command execution</param> public void Init( AgentTaskPluginExecutionContext context, Pipelines.RepositoryResource repository, CancellationToken cancellationToken) { // Validation. ArgUtil.NotNull(context, nameof(context)); ArgUtil.NotNull(repository, nameof(repository)); ArgUtil.NotNull(cancellationToken, nameof(cancellationToken)); ArgUtil.NotNull(repository.Url, nameof(repository.Url)); ArgUtil.Equal(true, repository.Url.IsAbsoluteUri, nameof(repository.Url.IsAbsoluteUri)); ArgUtil.NotNull(repository.Endpoint, nameof(repository.Endpoint)); ServiceEndpoint endpoint = context.Endpoints.Single( x => (repository.Endpoint.Id != Guid.Empty && x.Id == repository.Endpoint.Id) || (repository.Endpoint.Id == Guid.Empty && string.Equals(x.Name, repository.Endpoint.Name.ToString(), StringComparison.OrdinalIgnoreCase))); ArgUtil.NotNull(endpoint.Data, nameof(endpoint.Data)); ArgUtil.NotNull(endpoint.Authorization, nameof(endpoint.Authorization)); ArgUtil.NotNull(endpoint.Authorization.Parameters, nameof(endpoint.Authorization.Parameters)); ArgUtil.Equal(EndpointAuthorizationSchemes.UsernamePassword, endpoint.Authorization.Scheme, nameof(endpoint.Authorization.Scheme)); _context = context; _repository = repository; _cancellationToken = cancellationToken; // Find svn in %Path% string svnPath = WhichUtil.Which("svn", trace: context); if (string.IsNullOrEmpty(svnPath)) { throw new Exception(StringUtil.Loc("SvnNotInstalled")); } else { _context.Debug($"Found svn installation path: {svnPath}."); _svn = svnPath; } // External providers may need basic auth or tokens endpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.Username, out _username); endpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.Password, out _password); if (endpoint.Data.TryGetValue(EndpointData.AcceptUntrustedCertificates, out string endpointAcceptUntrustedCerts)) { _acceptUntrusted = StringUtil.ConvertToBoolean(endpointAcceptUntrustedCerts); } _acceptUntrusted = _acceptUntrusted || (context.GetCertConfiguration()?.SkipServerCertificateValidation ?? false); }
public void SetupClientCertificate(string clientCert, string clientCertKey, string clientCertArchive, string clientCertPassword) { ExecutionContext.Debug("Convert client certificate from 'pkcs' format to 'jks' format."); string toolPath = WhichUtil.Which("keytool", true, ExecutionContext); string jksFile = Path.Combine(ExecutionContext.Variables.GetValueOrDefault("agent.tempdirectory")?.Value, $"{Guid.NewGuid()}.jks"); string argLine; if (!string.IsNullOrEmpty(clientCertPassword)) { argLine = $"-importkeystore -srckeystore \"{clientCertArchive}\" -srcstoretype pkcs12 -destkeystore \"{jksFile}\" -deststoretype JKS -srcstorepass \"{clientCertPassword}\" -deststorepass \"{clientCertPassword}\""; } else { argLine = $"-importkeystore -srckeystore \"{clientCertArchive}\" -srcstoretype pkcs12 -destkeystore \"{jksFile}\" -deststoretype JKS"; } ExecutionContext.Command($"{toolPath} {argLine}"); using (var processInvoker = new ProcessInvoker(ExecutionContext)) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { if (!string.IsNullOrEmpty(args.Data)) { ExecutionContext.Output(args.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { if (!string.IsNullOrEmpty(args.Data)) { ExecutionContext.Output(args.Data); } }; processInvoker.ExecuteAsync(ExecutionContext.Variables.GetValueOrDefault("system.defaultworkingdirectory")?.Value, toolPath, argLine, null, true, CancellationToken.None).GetAwaiter().GetResult(); if (!string.IsNullOrEmpty(clientCertPassword)) { ExecutionContext.Debug($"Set TF_ADDITIONAL_JAVA_ARGS=-Djavax.net.ssl.keyStore={jksFile} -Djavax.net.ssl.keyStorePassword={clientCertPassword}"); AdditionalEnvironmentVariables["TF_ADDITIONAL_JAVA_ARGS"] = $"-Djavax.net.ssl.keyStore={jksFile} -Djavax.net.ssl.keyStorePassword={clientCertPassword}"; } else { ExecutionContext.Debug($"Set TF_ADDITIONAL_JAVA_ARGS=-Djavax.net.ssl.keyStore={jksFile}"); AdditionalEnvironmentVariables["TF_ADDITIONAL_JAVA_ARGS"] = $"-Djavax.net.ssl.keyStore={jksFile}"; } } }
public Task GetSourceAsync( IExecutionContext executionContext, ServiceEndpoint endpoint, CancellationToken cancellationToken) { Trace.Entering(); ArgUtil.Equal(RunMode.Local, HostContext.RunMode, nameof(HostContext.RunMode)); ArgUtil.Equal(HostTypes.Build, executionContext.Variables.System_HostType, nameof(executionContext.Variables.System_HostType)); ArgUtil.NotNull(executionContext, nameof(executionContext)); ArgUtil.NotNull(endpoint, nameof(endpoint)); bool preferGitFromPath; #if OS_WINDOWS preferGitFromPath = false; #else preferGitFromPath = true; #endif if (!preferGitFromPath) { // Add git to the PATH. string gitPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "git", "cmd", $"git{IOUtil.ExeExtension}"); ArgUtil.File(gitPath, nameof(gitPath)); executionContext.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", Constants.PathVariable, Path.GetFileName(gitPath))); PathUtil.PrependPath(Path.GetDirectoryName(gitPath)); executionContext.Debug($"{Constants.PathVariable}: '{Environment.GetEnvironmentVariable(Constants.PathVariable)}'"); } else { // Validate git is in the PATH. WhichUtil.Which("git", require: true, trace: Trace); } // Override build.sourcesDirectory. // // Technically the value will be out of sync with the tracking file. The tracking file // is created during job initialization (Get Sources is later). That is OK, since the // local-run-sources-directory should not participate in cleanup anyway. string localDirectory = endpoint.Data?["localDirectory"]; ArgUtil.Directory(localDirectory, nameof(localDirectory)); ArgUtil.Directory(Path.Combine(localDirectory, ".git"), "localDotGitDirectory"); executionContext.Variables.Set(Constants.Variables.System.DefaultWorkingDirectory, localDirectory); executionContext.Variables.Set(Constants.Variables.Build.SourcesDirectory, localDirectory); executionContext.Variables.Set(Constants.Variables.Build.RepoLocalPath, localDirectory); // todo: consider support for clean return(Task.CompletedTask); }
public void WhichHandleFullyQualifiedPath() { using (TestHostContext hc = new TestHostContext(this)) { //Arrange Tracing trace = hc.GetTrace(); // Act. var gitPath = WhichUtil.Which("git", require: true, trace: trace); var gitPath2 = WhichUtil.Which(gitPath, require: true, trace: trace); // Assert. Assert.Equal(gitPath, gitPath2); } }
public async Task <Boolean> VerifyAsync(Definition definition, CancellationToken token) { ArgUtil.NotNull(definition, nameof(definition)); // This is used for the Checkout task. // We can consider it verified since it's embedded in the Agent code. if (String.IsNullOrEmpty(definition.ZipPath)) { return(true); } // Find NuGet String nugetPath = WhichUtil.Which("nuget", require: true); var configurationStore = HostContext.GetService <IConfigurationStore>(); AgentSettings settings = configurationStore.GetSettings(); String fingerprint = settings.Fingerprint; String taskZipPath = definition.ZipPath; String taskNugetPath = definition.ZipPath.Replace(".zip", ".nupkg"); // Rename .zip to .nupkg File.Move(taskZipPath, taskNugetPath); String arguments = $"verify -Signatures \"{taskNugetPath}\" -CertificateFingerprint {fingerprint} -Verbosity Detailed"; // Run nuget verify using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { int exitCode = await processInvoker.ExecuteAsync(workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Root), fileName : nugetPath, arguments : arguments, environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, cancellationToken : token); // Rename back to zip File.Move(taskNugetPath, taskZipPath); if (exitCode != 0) { return(false); } } return(true); }
public void WhichReturnsNullWhenNotFound() { using (TestHostContext hc = new TestHostContext(this)) { //Arrange Tracing trace = hc.GetTrace(); // Act. string nosuch = WhichUtil.Which("no-such-file-cf7e351f", trace: trace); trace.Info($"result: {nosuch ?? string.Empty}"); // Assert. Assert.True(string.IsNullOrEmpty(nosuch), "Path should not be resolved"); } }
private async Task CreateRepository(TestHostContext hostConetxt, string path, string url) { Directory.CreateDirectory(path); var gitPath = WhichUtil.Which("git", true); var environment = new Dictionary <string, string>(); using (var processInvoker = new ProcessInvoker(hostConetxt.GetTrace())) { await processInvoker.ExecuteAsync(path, gitPath, "init", environment, CancellationToken.None); } using (var processInvoker = new ProcessInvoker(hostConetxt.GetTrace())) { await processInvoker.ExecuteAsync(path, gitPath, $"remote add origin {url}", environment, CancellationToken.None); } }
public void UseWhichFindGit() { using (TestHostContext hc = new TestHostContext(this)) { //Arrange Tracing trace = hc.GetTrace(); // Act. string gitPath = WhichUtil.Which("git", trace: trace); trace.Info($"Which(\"git\") returns: {gitPath ?? string.Empty}"); // Assert. Assert.True(!string.IsNullOrEmpty(gitPath) && File.Exists(gitPath), $"Unable to find Git through: {nameof(WhichUtil.Which)}"); } }
public async Task CheckToolOutputAsync(string name, string fileName, string arguments) { _trace.Entering(); ArgUtil.NotNullOrEmpty(name, nameof(name)); ArgUtil.NotNullOrEmpty(fileName, nameof(fileName)); try { // Attempt to locate the tool. string filePath = WhichUtil.Which(fileName, trace: _trace); if (string.IsNullOrEmpty(filePath)) { return; } // Invoke the tool and capture the output. var output = new StringBuilder(); using (var processInvoker = _hostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { if (!string.IsNullOrEmpty(args.Data)) { output.Append(args.Data); } }; await processInvoker.ExecuteAsync( workingDirectory : string.Empty, fileName : filePath, arguments : arguments ?? string.Empty, environment : null, cancellationToken : _cancellationToken); } // Add the capability. if (output.Length > 0) { string value = output.ToString(); _trace.Info($"Adding '{name}': '{value}'"); _capabilities.Add(new Capability(name, value)); } } catch (Exception ex) when(!(ex is OperationCanceledException)) { _trace.Error(ex); } }
public RSACryptoServiceProvider CreateKey() { RSACryptoServiceProvider rsa = null; if (!File.Exists(_keyFile)) { Trace.Info("Creating new RSA key using 2048-bit key length"); rsa = new RSACryptoServiceProvider(2048); // Now write the parameters to disk IOUtil.SaveObject(new RSAParametersSerializable(rsa.ExportParameters(true)), _keyFile); Trace.Info("Successfully saved RSA key parameters to file {0}", _keyFile); // Try to lock down the credentials_key file to the owner/group var chmodPath = WhichUtil.Which("chmod", trace: Trace); if (!String.IsNullOrEmpty(chmodPath)) { var arguments = $"600 {new FileInfo(_keyFile).FullName}"; using (var invoker = _context.CreateService <IProcessInvoker>()) { var exitCode = invoker.ExecuteAsync(HostContext.GetDirectory(WellKnownDirectory.Root), chmodPath, arguments, null, default(CancellationToken)).GetAwaiter().GetResult(); if (exitCode == 0) { Trace.Info("Successfully set permissions for RSA key parameters file {0}", _keyFile); } else { Trace.Warning("Unable to succesfully set permissions for RSA key parameters file {0}. Received exit code {1} from {2}", _keyFile, exitCode, chmodPath); } } } else { Trace.Warning("Unable to locate chmod to set permissions for RSA key parameters file {0}.", _keyFile); } } else { Trace.Info("Found existing RSA key parameters file {0}", _keyFile); rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(IOUtil.LoadObject <RSAParametersSerializable>(_keyFile).RSAParameters); } return(rsa); }
public async Task LoadGitExecutionInfo(RunnerActionPluginExecutionContext context) { // Resolve the location of git. gitPath = WhichUtil.Which("git", require: true, trace: context); ArgUtil.File(gitPath, nameof(gitPath)); // Get the Git version. gitVersion = await GitVersion(context); ArgUtil.NotNull(gitVersion, nameof(gitVersion)); context.Debug($"Detect git version: {gitVersion.ToString()}."); // Resolve the location of git-lfs. // This should be best effort since checkout lfs objects is an option. // We will check and ensure git-lfs version later gitLfsPath = WhichUtil.Which("git-lfs", require: false, trace: context); // Get the Git-LFS version if git-lfs exist in %PATH%. if (!string.IsNullOrEmpty(gitLfsPath)) { gitLfsVersion = await GitLfsVersion(context); context.Debug($"Detect git-lfs version: '{gitLfsVersion?.ToString() ?? string.Empty}'."); } // required 2.0, all git operation commandline args need min git version 2.0 Version minRequiredGitVersion = new Version(2, 0); EnsureGitVersion(minRequiredGitVersion, throwOnNotMatch: true); // suggest user upgrade to 2.9 for better git experience Version recommendGitVersion = new Version(2, 9); if (!EnsureGitVersion(recommendGitVersion, throwOnNotMatch: false)) { context.Output($"To get a better Git experience, upgrade your Git to at least version '{recommendGitVersion}'. Your current Git version is '{gitVersion}'."); } // Set the user agent. string gitHttpUserAgentEnv = $"git/{gitVersion.ToString()} (github-actions-runner-git/{BuildConstants.RunnerPackage.Version})"; context.Debug($"Set git useragent to: {gitHttpUserAgentEnv}."); gitEnv["GIT_HTTP_USER_AGENT"] = gitHttpUserAgentEnv; }
/// <summary> /// Dumping cloud-init logs to diag folder of agent if cloud-init is installed on current machine. /// </summary> /// <param name="logsFile">Path to collect cloud-init logs</param> /// <returns>Returns the method execution logs</returns> private async Task <string> DumpCloudInitLogs(string logsFile) { var builder = new StringBuilder(); string cloudInit = WhichUtil.Which("cloud-init", trace: Trace); if (string.IsNullOrEmpty(cloudInit)) { return("Cloud-init isn't found on current machine."); } string arguments = $"collect-logs -t \"{logsFile}\""; try { using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { builder.AppendLine(args.Data); }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { builder.AppendLine(args.Data); }; await processInvoker.ExecuteAsync( workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Bin), fileName : cloudInit, arguments : arguments, environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, cancellationToken : default(CancellationToken)); } } catch (Exception ex) { builder.AppendLine(ex.Message); } return(builder.ToString()); }
public void WhichThrowsWhenRequireAndNotFound() { using (TestHostContext hc = new TestHostContext(this)) { //Arrange Tracing trace = hc.GetTrace(); // Act. try { WhichUtil.Which("no-such-file-cf7e351f", require: true, trace: trace); throw new Exception("which should have thrown"); } catch (FileNotFoundException ex) { Assert.Equal("no-such-file-cf7e351f", ex.FileName); } } }
public void Init( IExecutionContext context, ServiceEndpoint endpoint, CancellationToken cancellationToken) { // Validation. ArgUtil.NotNull(context, nameof(context)); ArgUtil.NotNull(endpoint, nameof(endpoint)); ArgUtil.NotNull(cancellationToken, nameof(cancellationToken)); ArgUtil.NotNull(endpoint.Url, nameof(endpoint.Url)); ArgUtil.Equal(true, endpoint.Url.IsAbsoluteUri, nameof(endpoint.Url.IsAbsoluteUri)); ArgUtil.NotNull(endpoint.Data, nameof(endpoint.Data)); ArgUtil.NotNull(endpoint.Authorization, nameof(endpoint.Authorization)); ArgUtil.NotNull(endpoint.Authorization.Parameters, nameof(endpoint.Authorization.Parameters)); ArgUtil.Equal(EndpointAuthorizationSchemes.UsernamePassword, endpoint.Authorization.Scheme, nameof(endpoint.Authorization.Scheme)); _context = context; _endpoint = endpoint; _cancellationToken = cancellationToken; // Find svn in %Path% string svnPath = WhichUtil.Which("svn", trace: Trace); if (string.IsNullOrEmpty(svnPath)) { throw new Exception(StringUtil.Loc("SvnNotInstalled")); } else { _context.Debug($"Found svn installation path: {svnPath}."); _svn = svnPath; } // External providers may need basic auth or tokens endpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.Username, out _username); endpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.Password, out _password); _acceptUntrusted = endpoint.Data.ContainsKey(EndpointData.SvnAcceptUntrustedCertificates) && StringUtil.ConvertToBoolean(endpoint.Data[EndpointData.SvnAcceptUntrustedCertificates], defaultValue: false); }
private async Task SwitchToUtf8Codepage(IStep step) { if (!PlatformUtil.RunningOnWindows) { return; } try { if (step.ExecutionContext.Variables.Retain_Default_Encoding != true && Console.InputEncoding.CodePage != 65001) { using (var p = HostContext.CreateService <IProcessInvoker>()) { // Use UTF8 code page int exitCode = await p.ExecuteAsync(workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Work), fileName : WhichUtil.Which("chcp", true, Trace), arguments : "65001", environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, redirectStandardIn : null, inheritConsoleHandler : true, cancellationToken : step.ExecutionContext.CancellationToken); if (exitCode == 0) { Trace.Info("Successfully returned to code page 65001 (UTF8)"); } else { Trace.Warning($"'chcp 65001' failed with exit code {exitCode}"); } } } } catch (Exception ex) { Trace.Warning($"'chcp 65001' failed with exception {ex.Message}"); } }
private async Task ConfigurePowerOptions() { var filePath = WhichUtil.Which("powercfg.exe", require: true, trace: Trace); string[] commands = new string[] { "/Change monitor-timeout-ac 0", "/Change monitor-timeout-dc 0" }; foreach (var command in commands) { try { Trace.Info($"Running powercfg.exe with {command}"); using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { Trace.Info(message.Data); }; processInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { Trace.Error(message.Data); _terminal.WriteError(message.Data); }; await processInvoker.ExecuteAsync( workingDirectory : string.Empty, fileName : filePath, arguments : command, environment : null, cancellationToken : CancellationToken.None); } } catch (Exception ex) { //we will not stop the configuration. just show the warning and continue _terminal.WriteError(StringUtil.Loc("PowerOptionsConfigError")); Trace.Error(ex); } } }
public static async Task SetEncoding(IHostContext hostContext, Tracing trace, CancellationToken cancellationToken) { #if OS_WINDOWS try { if (Console.InputEncoding.CodePage != 65001) { using (var p = hostContext.CreateService <IProcessInvoker>()) { // Use UTF8 code page int exitCode = await p.ExecuteAsync(workingDirectory : hostContext.GetDirectory(WellKnownDirectory.Work), fileName : WhichUtil.Which("chcp", true, trace), arguments : "65001", environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, redirectStandardIn : null, inheritConsoleHandler : true, cancellationToken : cancellationToken); if (exitCode == 0) { trace.Info("Successfully returned to code page 65001 (UTF8)"); } else { trace.Warning($"'chcp 65001' failed with exit code {exitCode}"); } } } } catch (Exception ex) { trace.Warning($"'chcp 65001' failed with exception {ex.Message}"); } #endif // Dummy variable to prevent compiler error CS1998: "This async method lacks 'await' operators and will run synchronously..." await Task.CompletedTask; }
/// <summary> /// Get user groups on a non-windows platform using core utility "id". /// </summary> /// <returns>Returns the string with user groups</returns> private async Task <string> GetUserGroupsOnNonWindows() { var idUtil = WhichUtil.Which("id"); var stringBuilder = new StringBuilder(); try { using (var processInvoker = HostContext.CreateService <IProcessInvoker>()) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs mes) => { stringBuilder.AppendLine(mes.Data); }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs mes) => { stringBuilder.AppendLine(mes.Data); }; await processInvoker.ExecuteAsync( workingDirectory : HostContext.GetDirectory(WellKnownDirectory.Bin), fileName : idUtil, arguments : "-nG", environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : false, cancellationToken : default(CancellationToken) ); } } catch (Exception ex) { stringBuilder.AppendLine(ex.Message); } return(stringBuilder.ToString()); }
private async Task <string> GitAsync(string arguments, CancellationToken token) { // Resolve the location of git. if (_gitPath == null) { #if OS_WINDOWS _gitPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "git", "cmd", $"git{IOUtil.ExeExtension}"); ArgUtil.File(_gitPath, nameof(_gitPath)); #else _gitPath = WhichUtil.Which("git", require: true); #endif } // Prepare the environment variables to overlay. var overlayEnvironment = new Dictionary <string, string>(StringComparer.Ordinal); overlayEnvironment["GIT_TERMINAL_PROMPT"] = "0"; // Skip any GIT_TRACE variable since GIT_TRACE will affect ouput from every git command. // This will fail the parse logic for detect git version, remote url, etc. // Ex. // SET GIT_TRACE=true // git version // 11:39:58.295959 git.c:371 trace: built-in: git 'version' // git version 2.11.1.windows.1 IDictionary currentEnvironment = Environment.GetEnvironmentVariables(); foreach (DictionaryEntry entry in currentEnvironment) { string key = entry.Key as string ?? string.Empty; if (string.Equals(key, "GIT_TRACE", StringComparison.OrdinalIgnoreCase) || key.StartsWith("GIT_TRACE_", StringComparison.OrdinalIgnoreCase)) { overlayEnvironment[key] = string.Empty; } } // Run git and return the output from the streams. var output = new StringBuilder(); var processInvoker = HostContext.CreateService <IProcessInvoker>(); Console.WriteLine(); Console.WriteLine($"git {arguments}"); processInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { output.AppendLine(message.Data); Console.WriteLine(message.Data); }; processInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { output.AppendLine(message.Data); Console.WriteLine(message.Data); }; #if OS_WINDOWS Encoding encoding = Encoding.UTF8; #else Encoding encoding = null; #endif await processInvoker.ExecuteAsync( workingDirectory : Directory.GetCurrentDirectory(), fileName : _gitPath, arguments : arguments, environment : overlayEnvironment, requireExitCodeZero : true, outputEncoding : encoding, cancellationToken : token); string result = output.ToString().Trim(); ArgUtil.NotNullOrEmpty(result, nameof(result)); return(result); }