Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update tf.exe #4955

Merged
merged 10 commits into from
Sep 3, 2024
11 changes: 8 additions & 3 deletions src/Agent.Plugins/TFCliManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using Microsoft.VisualStudio.Services.Agent.Util;
using Agent.Sdk.Knob;

namespace Agent.Plugins.Repository
{
Expand All @@ -37,11 +38,15 @@ public override TfsVCFeatures Features

public static readonly int RetriesOnFailure = 3;

public string FilePath => Path.Combine(ExecutionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf", "tf.exe");
private string TfPath => AgentKnobs.InstallLegacyTfExe.GetValue(ExecutionContext).AsBoolean()
? Path.Combine(ExecutionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf-legacy")
: Path.Combine(ExecutionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf");

private string AppConfigFile => Path.Combine(ExecutionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf", "tf.exe.config");
public string FilePath => Path.Combine(TfPath, "tf.exe");

private string AppConfigRestoreFile => Path.Combine(ExecutionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf", "tf.exe.config.restore");
private string AppConfigFile => Path.Combine(TfPath, "tf.exe.config");

private string AppConfigRestoreFile => Path.Combine(TfPath, "tf.exe.config.restore");

// TODO: Remove AddAsync after last-saved-checkin-metadata problem is fixed properly.
public async Task AddAsync(string localPath)
Expand Down
3 changes: 2 additions & 1 deletion src/Agent.Plugins/TfsVCSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ public async Task GetSourceAsync(
if (PlatformUtil.RunningOnWindows)
{
// Set TFVC_BUILDAGENT_POLICYPATH
string policyDllPath = Path.Combine(executionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf", "Microsoft.TeamFoundation.VersionControl.Controls.dll");
string tfDirectoryName = AgentKnobs.InstallLegacyTfExe.GetValue(executionContext).AsBoolean() ? "tf-legacy" : "tf";
string policyDllPath = Path.Combine(executionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", tfDirectoryName, "Microsoft.TeamFoundation.VersionControl.Controls.dll");
ArgUtil.File(policyDllPath, nameof(policyDllPath));
const string policyPathEnvKey = "TFVC_BUILDAGENT_POLICYPATH";
executionContext.Output(StringUtil.Loc("SetEnvVar", policyPathEnvKey));
Expand Down
7 changes: 7 additions & 0 deletions src/Agent.Sdk/Knob/AgentKnobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -758,5 +758,12 @@ public class AgentKnobs
"Use PowerShell script wrapper to handle PowerShell ConstrainedLanguage mode.",
new PipelineFeatureSource("UsePSScriptWrapper"),
new BuiltInDefaultKnobSource("false"));

public static readonly Knob InstallLegacyTfExe = new Knob(
nameof(InstallLegacyTfExe),
"If true, agent will install the previous version of TF.exe in the tf-legacy and vstsom-legacy directories",
new RuntimeKnobSource("AGENT_INSTALL_LEGACY_TF_EXE"),
new EnvironmentKnobSource("AGENT_INSTALL_LEGACY_TF_EXE"),
new BuiltInDefaultKnobSource("false"));
}
}
11 changes: 8 additions & 3 deletions src/Agent.Worker/Build/TFCommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Text;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using Agent.Sdk.Knob;

namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
Expand All @@ -34,11 +35,15 @@ public override TfsVCFeatures Features

protected override string Switch => "/";

public override string FilePath => Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Tf), "tf.exe");
private string TfPath => AgentKnobs.InstallLegacyTfExe.GetValue(ExecutionContext).AsBoolean()
? HostContext.GetDirectory(WellKnownDirectory.TfLegacy)
: HostContext.GetDirectory(WellKnownDirectory.Tf);

private string AppConfigFile => Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Tf), "tf.exe.config");
public override string FilePath => Path.Combine(TfPath, "tf.exe");

private string AppConfigRestoreFile => Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Tf), "tf.exe.config.restore");
private string AppConfigFile => Path.Combine(TfPath, "tf.exe.config");

private string AppConfigRestoreFile => Path.Combine(TfPath, "tf.exe.config.restore");

// TODO: Remove AddAsync after last-saved-checkin-metadata problem is fixed properly.
public async Task AddAsync(string localPath)
Expand Down
7 changes: 6 additions & 1 deletion src/Agent.Worker/Build/TfsVCSourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Agent.Sdk.Knob;

namespace Microsoft.VisualStudio.Services.Agent.Worker.Build
{
Expand Down Expand Up @@ -88,7 +89,11 @@ public async Task GetSourceAsync(
if (PlatformUtil.RunningOnWindows)
{
// Set TFVC_BUILDAGENT_POLICYPATH
string policyDllPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.ServerOM), "Microsoft.TeamFoundation.VersionControl.Controls.dll");
string vstsomPath = AgentKnobs.InstallLegacyTfExe.GetValue(executionContext).AsBoolean()
? HostContext.GetDirectory(WellKnownDirectory.ServerOMLegacy)
: HostContext.GetDirectory(WellKnownDirectory.ServerOM);

string policyDllPath = Path.Combine(vstsomPath, "Microsoft.TeamFoundation.VersionControl.Controls.dll");
ArgUtil.File(policyDllPath, nameof(policyDllPath));
const string policyPathEnvKey = "TFVC_BUILDAGENT_POLICYPATH";
executionContext.Output(StringUtil.Loc("SetEnvVar", policyPathEnvKey));
Expand Down
8 changes: 7 additions & 1 deletion src/Agent.Worker/Handlers/LegacyPowerShellHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.VisualStudio.Services.WebApi;
using System.Xml;
using Microsoft.TeamFoundation.DistributedTask.Pipelines;
using Agent.Sdk.Knob;

namespace Microsoft.VisualStudio.Services.Agent.Worker.Handlers
{
Expand Down Expand Up @@ -205,8 +206,13 @@ public async Task RunAsync()

// Copy the OM binaries into the legacy host folder.
ExecutionContext.Output(StringUtil.Loc("PrepareTaskExecutionHandler"));

string sourceDirectory = AgentKnobs.InstallLegacyTfExe.GetValue(ExecutionContext).AsBoolean()
? HostContext.GetDirectory(WellKnownDirectory.ServerOMLegacy)
: HostContext.GetDirectory(WellKnownDirectory.ServerOM);

IOUtil.CopyDirectory(
source: HostContext.GetDirectory(WellKnownDirectory.ServerOM),
source: sourceDirectory,
target: HostContext.GetDirectory(WellKnownDirectory.LegacyPSHost),
cancellationToken: ExecutionContext.CancellationToken);
Trace.Info("Finished copying files.");
Expand Down
5 changes: 5 additions & 0 deletions src/Agent.Worker/JobExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ public async Task<List<IStep>> InitializeJob(IExecutionContext jobContext, Pipel
}
}

if (AgentKnobs.InstallLegacyTfExe.GetValue(jobContext).AsBoolean())
{
await TfUtil.DownloadTfLegacyAsync(context);
}

// build up 3 lists of steps, pre-job, job, post-job
Stack<IStep> postJobStepsBuilder = new Stack<IStep>();
Dictionary<Guid, Variables> taskVariablesMapping = new Dictionary<Guid, Variables>();
Expand Down
6 changes: 5 additions & 1 deletion src/Agent.Worker/JobRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,11 @@ public async Task<TaskResult> RunAsync(Pipelines.AgentJobRequestMessage message,
jobContext.SetVariable(Constants.Variables.Agent.RootDirectory, HostContext.GetDirectory(WellKnownDirectory.Work), isFilePath: true);
if (PlatformUtil.RunningOnWindows)
{
jobContext.SetVariable(Constants.Variables.Agent.ServerOMDirectory, HostContext.GetDirectory(WellKnownDirectory.ServerOM), isFilePath: true);
string serverOMDirectoryVariable = AgentKnobs.InstallLegacyTfExe.GetValue(jobContext).AsBoolean()
? HostContext.GetDirectory(WellKnownDirectory.ServerOMLegacy)
: HostContext.GetDirectory(WellKnownDirectory.ServerOM);

jobContext.SetVariable(Constants.Variables.Agent.ServerOMDirectory, serverOMDirectoryVariable, isFilePath: true);
}
if (!PlatformUtil.RunningOnWindows)
{
Expand Down
5 changes: 5 additions & 0 deletions src/Agent.Worker/Release/ReleaseJobExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ private async Task DownloadArtifacts(IExecutionContext executionContext,
await teeUtil.DownloadTeeIfAbsent();
}

if (AgentKnobs.InstallLegacyTfExe.GetValue(executionContext).AsBoolean())
{
await TfUtil.DownloadTfLegacyAsync(executionContext);
}

try
{
foreach (AgentArtifactDefinition agentArtifactDefinition in agentArtifactDefinitions)
Expand Down
131 changes: 131 additions & 0 deletions src/Agent.Worker/TfManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using Microsoft.VisualStudio.Services.Agent.Util;
using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.VisualStudio.Services.Agent.Worker
{
public static class TfUtil
{
public static async Task DownloadTfLegacyAsync(IExecutionContext executionContext)
{
ArgUtil.NotNull(executionContext, nameof(executionContext));
string externalsPath = Path.Combine(executionContext.GetVariableValueOrDefault("Agent.HomeDirectory"), Constants.Path.ExternalsDirectory);
ArgUtil.NotNull(externalsPath, nameof(externalsPath));

string tfLegacyExternalsPath = Path.Combine(externalsPath, "tf-legacy");

if (!Directory.Exists(tfLegacyExternalsPath))
DergachevE marked this conversation as resolved.
Show resolved Hide resolved
{
const string tfDownloadUrl = "https://vstsagenttools.blob.core.windows.net/tools/vstsom/m153_47c0856d/vstsom.zip";

string tempTfDirectory = Path.Combine(externalsPath, "tf_download_temp");
Directory.CreateDirectory(tempTfDirectory);
string downloadTfPath = Path.ChangeExtension(Path.Combine(tempTfDirectory, "tfdownload"), ".completed");

if (!File.Exists(downloadTfPath))
{
await DownloadAsync(downloadTfPath, tfDownloadUrl, executionContext);
}
else
{
executionContext.Debug($"tf is already downloaded to {downloadTfPath}.");
}

try
{
ZipFile.ExtractToDirectory(downloadTfPath, tfLegacyExternalsPath);
File.WriteAllText(downloadTfPath, DateTime.UtcNow.ToString());
executionContext.Debug("tf-legacy has been extracted and cleaned up");
}
catch (Exception ex)
{
executionContext.Error(ex);
}
}
else
{
executionContext.Debug($"tf-legacy download already exists at {tfLegacyExternalsPath}.");
}

string vstsomLegacyExternalsPath = Path.Combine(externalsPath, "vstsom-legacy");

if (!Directory.Exists(vstsomLegacyExternalsPath))
{
const string vstsomDownloadUrl = "https://vstsagenttools.blob.core.windows.net/tools/vstsom/m122_887c6659/vstsom.zip";

string tempVstsomDirectory = Path.Combine(externalsPath, "vstsom_download_temp");
Directory.CreateDirectory(tempVstsomDirectory);
string downloadVstsomPath = Path.ChangeExtension(Path.Combine(tempVstsomDirectory, "vstsomdownload"), ".completed");

if (!File.Exists(downloadVstsomPath))
{
await DownloadAsync(downloadVstsomPath, vstsomDownloadUrl, executionContext);
}
else
{
executionContext.Debug($"vstsom is already downloaded to {downloadVstsomPath}.");
}

try
{
ZipFile.ExtractToDirectory(downloadVstsomPath, vstsomLegacyExternalsPath);
File.WriteAllText(downloadVstsomPath, DateTime.UtcNow.ToString());
executionContext.Debug("vstsom-legacy has been extracted and cleaned up");
}
catch (Exception ex)
{
executionContext.Error(ex);
}
}
else
{
executionContext.Debug($"vstsom-legacy download already exists at {vstsomLegacyExternalsPath}.");
}
}

private static async Task DownloadAsync(string downloadPath, string blobUrl, IExecutionContext executionContext)
{
int retryCount = 0;
const int retryLimit = 3;
const int timeout = 180;
const int defaultFileStreamBufferSize = 4096;
const int retryDelay = 10000;

while (retryCount < retryLimit)
kirill-ivlev marked this conversation as resolved.
Show resolved Hide resolved
{
using CancellationTokenSource downloadCts = new(TimeSpan.FromSeconds(timeout));
using CancellationTokenSource linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(downloadCts.Token, executionContext.CancellationToken);
CancellationToken cancellationToken = linkedTokenSource.Token;

try
{
using HttpClient httpClient = new();
using Stream stream = await httpClient.GetStreamAsync(blobUrl, cancellationToken);
using FileStream fs = new(downloadPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: defaultFileStreamBufferSize, useAsync: true);
kirill-ivlev marked this conversation as resolved.
Show resolved Hide resolved

await stream.CopyToAsync(fs, cancellationToken);
executionContext.Debug("Finished downloading tool.");
await fs.FlushAsync(cancellationToken);
fs.Close();
break;
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
executionContext.Debug("Tool download has been cancelled.");
throw;
}
catch (Exception)
{
retryCount++;
executionContext.Debug("Failed to download tool");
executionContext.Debug("Retry tool download in 10 seconds.");
await Task.Delay(retryDelay, cancellationToken);
}
}
}
}
}
4 changes: 4 additions & 0 deletions src/Microsoft.VisualStudio.Services.Agent/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public enum WellKnownDirectory
Tools,
Update,
Work,
TfLegacy,
ServerOMLegacy
}

public enum WellKnownConfigFile
Expand Down Expand Up @@ -313,9 +315,11 @@ public static class Path
public static readonly string ExternalsDirectory = "externals";
public static readonly string LegacyPSHostDirectory = "vstshost";
public static readonly string ServerOMDirectory = "vstsom";
public static readonly string ServerOMLegacyDirectory = "vstsom-legacy";
public static readonly string TempDirectory = "_temp";
public static readonly string TeeDirectory = "tee";
public static readonly string TfDirectory = "tf";
public static readonly string TfLegacyDirectory = "tf-legacy";
public static readonly string ToolDirectory = "_tool";
public static readonly string TaskJsonFile = "task.json";
public static readonly string TasksDirectory = "_tasks";
Expand Down
12 changes: 12 additions & 0 deletions src/Microsoft.VisualStudio.Services.Agent/HostContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,24 @@ public virtual string GetDirectory(WellKnownDirectory directory)
Constants.Path.ServerOMDirectory);
break;

case WellKnownDirectory.ServerOMLegacy:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Constants.Path.ServerOMLegacyDirectory);
break;

case WellKnownDirectory.Tf:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Constants.Path.TfDirectory);
break;

case WellKnownDirectory.TfLegacy:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Constants.Path.TfLegacyDirectory);
break;

case WellKnownDirectory.Tee:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Expand Down
4 changes: 2 additions & 2 deletions src/Misc/externals.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ if [[ "$PACKAGERUNTIME" == "win-x"* ]]; then

acquireExternalTool "$CONTAINER_URL/azcopy/1/azcopy.zip" azcopy
acquireExternalTool "$CONTAINER_URL/vstshost/m122_887c6659/vstshost.zip" vstshost
acquireExternalTool "$CONTAINER_URL/vstsom/m122_887c6659/vstsom.zip" vstsom
acquireExternalTool "$CONTAINER_URL/vstsom/m153_47c0856d_adhoc/vstsom.zip" vstsom
fi

acquireExternalTool "$CONTAINER_URL/mingit/${MINGIT_VERSION}/MinGit-${MINGIT_VERSION}-${BIT}-bit.zip" git
acquireExternalTool "$CONTAINER_URL/git-lfs/${LFS_VERSION}/x${BIT}/git-lfs.exe" "git/mingw${BIT}/bin"
acquireExternalTool "$CONTAINER_URL/pdbstr/1/pdbstr.zip" pdbstr
acquireExternalTool "$CONTAINER_URL/symstore/1/symstore.zip" symstore
acquireExternalTool "$CONTAINER_URL/vstsom/m153_47c0856d/vstsom.zip" tf
acquireExternalTool "$CONTAINER_URL/vstsom/m153_47c0856d_adhoc/vstsom.zip" tf
acquireExternalTool "$CONTAINER_URL/vswhere/2_8_4/vswhere.zip" vswhere
acquireExternalTool "https://dist.nuget.org/win-x86-commandline/v3.4.4/nuget.exe" nuget

Expand Down
6 changes: 6 additions & 0 deletions src/Test/L0/TestHostContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ public string GetDirectory(WellKnownDirectory directory)
Constants.Path.TfDirectory);
break;

case WellKnownDirectory.TfLegacy:
kirill-ivlev marked this conversation as resolved.
Show resolved Hide resolved
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Constants.Path.TfLegacyDirectory);
break;

case WellKnownDirectory.Tee:
path = Path.Combine(
GetDirectory(WellKnownDirectory.Externals),
Expand Down
Loading