598 lines
No EOL
28 KiB
C#
598 lines
No EOL
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using JetBrains.Annotations;
|
|
using TeaBox.Extensions.IsIn;
|
|
using TeaBox.Macros;
|
|
using TeaBox.NuGet;
|
|
using TeaBox.NUnit;
|
|
using TeaBox.UAF;
|
|
|
|
using Ubisoft.FileUtils;
|
|
|
|
using MacroAttribute = TeaBox.Macros.MacroAttribute;
|
|
using Path = System.IO.Path;
|
|
|
|
namespace TeaBox.Code
|
|
{
|
|
[Module(Icon = "build")]
|
|
[AvailableOn(TeaBoxFlavor.Code)]
|
|
[DisplayName("Build (Code)")]
|
|
public static partial class BuildMacros
|
|
{
|
|
private const string nugetOfficialServer = "https://api.nuget.org/v3/index.json";
|
|
[DisplayName("Generate solutions (sharpmake)")]
|
|
[Macro(ThreadAffinity.ExecuteAsync, Icon = "visualstudio.png")]
|
|
public static void Generate_solutions(IExecutionContext context,
|
|
[DefaultValue(true)] bool closeRunningSolution = true,
|
|
[DefaultValue(ToolsSolutionOptions.None)] ToolsSolutionOptions toolsSolutionOptions = ToolsSolutionOptions.None,
|
|
[DefaultValue(false), Description("Generates a Visual Studio solution to edit/debug sharpmake scripts.")] bool generateSharpmakeDebugSolution = false
|
|
)
|
|
{
|
|
using (closeRunningSolution ? CloseAndOpenSolutions(context) : null)
|
|
{
|
|
var sourceFile = Path.Combine(RootFolder.Value, @"build\sharpmake\main.cs");
|
|
|
|
// Sharpmake has threading issues ... retry a second time when it fails.
|
|
var sharpmakeCommand = new SharpMakeCommand(sourceFile)
|
|
{
|
|
ToolsSolutionOptions = toolsSolutionOptions,
|
|
GenerateDebugSolution = generateSharpmakeDebugSolution
|
|
};
|
|
|
|
using (context.ExecuteStep("Generating solution files"))
|
|
{
|
|
sharpmakeCommand.ExecuteAndRetry(context, retryCount: 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// During the scope of the IDisposable, the engine solution will be closed, it will be restored when finished.
|
|
/// </summary>
|
|
/// <remarks>Allows more than one solution to be open ... this may not happen often, </remarks>
|
|
private static IDisposable CloseAndOpenSolutions(IExecutionContext context)
|
|
{
|
|
return VisualStudioUtilities.CloseAndOpenSolutions(context, IsAGeneratedSolution);
|
|
}
|
|
|
|
private static bool IsAGeneratedSolution(string solutionPath)
|
|
{
|
|
return !string.IsNullOrEmpty(solutionPath) &&
|
|
FileUtility.IsSubPath(solutionPath, RootFolder.Value) &&
|
|
(solutionPath.EndsWith("2010.sln") || solutionPath.EndsWith("2012.sln") || solutionPath.EndsWith("2015.sln") || solutionPath.EndsWith("2017.sln"));
|
|
}
|
|
|
|
public enum BuildAccelerators
|
|
{
|
|
UseDefault,
|
|
ForceToSndbs,
|
|
Disable
|
|
}
|
|
|
|
[DisplayName("Build engine solution")]
|
|
[Macro(ThreadAffinity.ExecuteAsync, Icon = "build.png")]
|
|
public static void Build_engine_solution(IExecutionContext context, [DefaultValue(DevEnvBuildVariant.Release)] DevEnvBuildVariant buildVariants,
|
|
[DefaultValue(Platform.win64)] Platform platforms, [DefaultValue(false)] bool rebuild = false,
|
|
[DefaultValue(true)] BuildAccelerators buildAccelerators = BuildAccelerators.UseDefault)
|
|
{
|
|
if (!InstallMacros.ValidateHasReferencedDirectX(context, autoInstall: true))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!ValidateHasRightSdk(context, platforms))
|
|
{
|
|
return;
|
|
}
|
|
|
|
using (var steps = context.ExecuteSteps())
|
|
{
|
|
foreach (var platform in platforms.FlagsDefined())
|
|
{
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
var alternateBuildVariantName = $"{buildVariant}|{platform.ToDevenvString()}";
|
|
|
|
steps.AddStep($"Building engine on {alternateBuildVariantName}", stepcontext =>
|
|
{
|
|
VisualStudioVersion visualStudioVersion = VisualStudioVersion.vs2012;
|
|
|
|
if (platform == Platform.NX
|
|
|| platform == Platform.win32
|
|
|| platform == Platform.PC
|
|
|| platform == Platform.Durango
|
|
|| platform == Platform.Orbis
|
|
|| platform == Platform.Cafe
|
|
|| platform == Platform.win64
|
|
|| platform == Platform.GGP
|
|
|| platform == Platform.Prospero
|
|
|| platform == Platform.Scarlett)
|
|
{
|
|
visualStudioVersion = VisualStudioVersion.vs2017;
|
|
}
|
|
|
|
|
|
|
|
// This removes the copy to the XBox after the compilation.
|
|
if (platform == Platform.x360)
|
|
{
|
|
Environment.SetEnvironmentVariable("XBECOPY_SUPPRESS_COPY", "1");
|
|
}
|
|
|
|
var solutionFile = UAFConstants.GetEngineSolutionFile(visualStudioVersion);
|
|
var command = new VisualStudioCommand(solutionFile)
|
|
{
|
|
Timeout = TimeSpan.FromMinutes(50),
|
|
Version = visualStudioVersion,
|
|
BuildVariant = alternateBuildVariantName,
|
|
Action = rebuild ? VisualStudioAction.Rebuild : VisualStudioAction.Build
|
|
};
|
|
|
|
// During the transition to sn dbs, we force the robots to use it, we
|
|
// do not use the parameter so that the command stays the same for all branches.
|
|
|
|
/*if (UAFConstants.IsOnRobot && command.SnDbsExtensionIsInstalled)
|
|
{
|
|
buildAccelerators = BuildAccelerators.ForceToSndbs;
|
|
}*/
|
|
|
|
if (buildAccelerators != BuildAccelerators.Disable && platform != Platform.wii)
|
|
{
|
|
if (platform.IsIn(Platform.Orbis, Platform.Prospero))
|
|
{
|
|
command.UseSnDbs = true;
|
|
}
|
|
else if (platform.IsIn(Platform.PS3) || buildAccelerators == BuildAccelerators.ForceToSndbs)
|
|
{
|
|
command.UseSnDbs = true;
|
|
}
|
|
else if (platform.IsIn(Platform.win32, Platform.PC, Platform.win64, Platform.GGP, Platform.GGP_Validation, Platform.NX))
|
|
{
|
|
command.UseSnDbs = true;
|
|
}
|
|
else if (platform.IsIn(Platform.Cafe, Platform.x360, Platform.Scarlett, Platform.Durango))
|
|
{
|
|
command.UseIncredibuild = true;
|
|
}
|
|
}
|
|
|
|
|
|
// The build is not really reliable so we improve the stats by automatically retrying on a failed build.
|
|
int retryCount = UAFConstants.IsOnRobot ? 1 : 0;
|
|
if (platform == Platform.Cafe)
|
|
{
|
|
retryCount = UAFConstants.IsOnRobot ? 2 : 0;
|
|
}
|
|
int retryIndex = 0;
|
|
AutoRetry.ExecuteAndRetry(retryContext =>
|
|
{
|
|
if (retryIndex > 0)
|
|
{
|
|
var cleanCommand = new VisualStudioCommand(solutionFile)
|
|
{
|
|
Version = visualStudioVersion,
|
|
BuildVariant = alternateBuildVariantName,
|
|
Action = VisualStudioAction.Clean
|
|
};
|
|
cleanCommand.Execute(retryContext);
|
|
}
|
|
command.Execute(retryContext);
|
|
retryIndex++;
|
|
},
|
|
stepcontext,
|
|
retryCount);
|
|
|
|
KillOrphanProcesses(stepcontext);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool ValidateHasRightSdk(IExecutionContext context, Platform platform)
|
|
{
|
|
switch (platform)
|
|
{
|
|
case Platform.Durango:
|
|
return ValidateXoneSdk(context);
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static bool ValidateXoneSdk(IExecutionContext context)
|
|
{
|
|
string file = Environment.ExpandEnvironmentVariables(@"%XboxOneXDKLatest%\xdk\include\shared\xdk.h");
|
|
if (file.StartsWith("%"))
|
|
{
|
|
context.LogError(new FileLocation(file), "XBoxOne XDK is not installed please install it before compilation");
|
|
return false;
|
|
}
|
|
|
|
if (!System.IO.File.Exists(file))
|
|
{
|
|
context.LogError("XDK file {0} was not found.", file);
|
|
return false;
|
|
}
|
|
|
|
string searchPattern = "#define _XDK_EDITION";
|
|
string xdkEdition = System.IO.File.ReadAllLines(file).FirstOrDefault(line => line.Contains(searchPattern));
|
|
|
|
if (xdkEdition == null)
|
|
{
|
|
context.LogError($"{searchPattern} not found in {file}");
|
|
return false;
|
|
}
|
|
|
|
if (!xdkEdition.Contains(UAFConstants.CurrentXBoxOneXdkVersion))
|
|
{
|
|
xdkEdition = xdkEdition.Replace(searchPattern, "").Trim();
|
|
|
|
context.LogError($"XBoxOne XDK version mismatch");
|
|
context.LogError($"UAFConstants='{UAFConstants.CurrentXBoxOneXdkVersion}' > if this doesn't match the expected version, update UAFConstants.cs");
|
|
context.LogError($"xdk.h='{xdkEdition}' > if this doesn't match the expected version, make sure the expected version of XDK is installed, check the system environment variable, restart QB Agent");
|
|
context.LogError($"Environment XboxOneXDKLatest='{Environment.GetEnvironmentVariable("XboxOneXDKLatest")}' > if this doesn't match the system environment variable, QB Agent needs to be restarted");
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[DisplayName("Build tools solution")]
|
|
[Macro(ThreadAffinity.ExecuteAsync, Icon = "build.png")]
|
|
public static void Build_tools_solution(IExecutionContext context,
|
|
[DefaultValue(Platform.win64)]Platform platform = Platform.win64,
|
|
[DefaultValue(DevEnvBuildVariant.Release)] DevEnvBuildVariant buildVariants = DevEnvBuildVariant.Release,
|
|
[DefaultValue(false)] bool rebuild = false,
|
|
[DefaultValue(false)] bool runUnitTests = false)
|
|
{
|
|
if (Environment.UserName == "jd4-robot")
|
|
{
|
|
LaunchMacros.KillUAFTools(context);
|
|
}
|
|
|
|
using (var steps = context.ExecuteSteps(continueOnErroneousStep: false))
|
|
{
|
|
var solutionFile = UAFConstants.GetToolsSolution(UAFConstants.ToolsVisualStudioVersion);
|
|
steps.AddStep($"Cleaning temp files (project.json, project.assets.json...) for {solutionFile}", stepcontext =>
|
|
{
|
|
var fileTypesToDelete = new[] {"project.assets.json", "project.json", "*.csproj.nuget.*"};
|
|
var filesToDelete = new List<string>();
|
|
foreach (var fileTypeToDelete in fileTypesToDelete)
|
|
{
|
|
filesToDelete.AddRange(System.IO.Directory.EnumerateFiles(UAFConstants.ToolsFolder, fileTypeToDelete, SearchOption.AllDirectories));
|
|
}
|
|
foreach (var tempFile in filesToDelete)
|
|
{
|
|
File.SafeDelete(tempFile, true);
|
|
}
|
|
stepcontext.LogMessage($"{filesToDelete.Count} files deleted.");
|
|
});
|
|
steps.AddStep($"Restoring NuGet packages for {solutionFile}", stepcontext =>
|
|
{
|
|
RestoreNugetPackages(stepcontext, solutionFile);
|
|
});
|
|
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
steps.AddStep($"Building tools on {buildVariant}", stepcontext =>
|
|
{
|
|
var platformString = platform == Platform.win64 ? "x64" : "Any CPU";
|
|
var completeBuildVariantName = $"{buildVariant}|{platformString}";
|
|
BuildSolution(stepcontext, solutionFile, completeBuildVariantName, rebuild, visualStudioVersion: UAFConstants.ToolsVisualStudioVersion);
|
|
});
|
|
}
|
|
}
|
|
|
|
using (var steps = context.ExecuteSteps())
|
|
{
|
|
if (runUnitTests)
|
|
{
|
|
steps.AddStep("Run tools unit tests", step => NUnitMacros.RunToolsUnitTests(step, buildVariants));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void RestoreNugetPackages(IExecutionContext context, string solutionFile)
|
|
{
|
|
var restoreCommand = new NugetRestoreCommand(
|
|
solutionFile,
|
|
$"source {NuGetConfiguration.NuGetApi};https://artifactory.ubisoft.org/api/nuget/nuget-snapshot;https://www.nuget.org/api/v2",
|
|
"noninteractive",
|
|
"verbosity detailed");
|
|
|
|
restoreCommand.Execute(context);
|
|
}
|
|
|
|
private static void CopyScoringUtilitiesToOutputFolder(IExecutionContext context, string buildVariant)
|
|
{
|
|
try
|
|
{
|
|
// copying the lib folder
|
|
var utilityLibFolder = Path.Combine(UAFConstants.ToolsFolder, "extern", "scoringutilities", "lib", "tools");
|
|
var destinationLibFolder = Path.Combine(RootFolder.Value, "output", "lib", "tools");
|
|
Robocopy.CopyDirectory(utilityLibFolder, destinationLibFolder, RobocopyOptions.ForceOverwrite | RobocopyOptions.Recursive);
|
|
|
|
// copy the exes
|
|
var utilityFolder = Path.Combine(UAFConstants.ToolsFolder, "extern", "scoringutilities", "bin", buildVariant, "tools", "scoringtools");
|
|
var destinationFolder = Path.Combine(RootFolder.Value, "output", "bin", buildVariant, "tools", "scoringtools");
|
|
Robocopy.CopyDirectory(utilityFolder, destinationFolder, RobocopyOptions.ForceOverwrite | RobocopyOptions.Recursive);
|
|
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
context.LogMessage("Problem with copying the Utilities for scoring tools : ", exception.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Builds solution for all scoring tools.
|
|
/// </summary>
|
|
[DisplayName(@"Build scoring tools solution")]
|
|
[Macro(ThreadAffinity.ExecuteAsync, Icon = "build.png")]
|
|
public static void Build_scoring_tools_solution(IExecutionContext context,
|
|
[DefaultValue(DevEnvBuildVariant.Release)] DevEnvBuildVariant buildVariants = DevEnvBuildVariant.Release,
|
|
[DefaultValue(false)] bool buildScoringUtilities = false,
|
|
[DefaultValue(false)] bool rebuild = false)
|
|
{
|
|
using (var steps = context.ExecuteSteps())
|
|
{
|
|
if (buildScoringUtilities)
|
|
{
|
|
steps.AddStep("Build Scoring Utilities Solution", step => BuildScoringUtilitiesSolution(step, buildVariants, rebuild));
|
|
|
|
// TODO : check if we need this function to create and compile the solution of Gesture Comparer as this project is
|
|
// divided into the soln for xone and ps4 + these projects are part of Managed Scoring tools
|
|
|
|
//steps.AddStep("Build GestureComparer tool", step => BuildGestureComparerStandalone(step, buildVariants, rebuild));
|
|
}
|
|
else if (buildVariants != DevEnvBuildVariant.Final)
|
|
{
|
|
steps.AddStep("Copying the ScoringUtilities to Output Folder", step => CopyScoringUtilitiesToOutputFolder(context, buildVariants.ToString()));
|
|
|
|
steps.AddStep($"Restoring NuGet packages for Scoring Tools Solution", stepcontext =>
|
|
{
|
|
RestoreNugetPackages(stepcontext, UAFConstants.GetManagedScoringTools());
|
|
});
|
|
|
|
steps.AddStep("Build Scoring Tools Solution", step => BuildScoringToolsSolution(step, buildVariants, rebuild));
|
|
steps.AddStep("Build JoyConCapturer Solution", step => BuildJoyConCapturerSolution(step, buildVariants, rebuild));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void BuildJoyConCapturerSolution(IExecutionContext context, DevEnvBuildVariant buildVariants, bool rebuild = true)
|
|
{
|
|
var visualStudioVersion = UAFConstants.ToolsVisualStudioVersion;
|
|
var solutionFile = UAFConstants.GetJoyConCapturerSolution(visualStudioVersion);
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
BuildSolution(context, solutionFile, buildVariant.ToString(), rebuild, visualStudioVersion: visualStudioVersion);
|
|
}
|
|
}
|
|
|
|
//TODO: Going further this function will be handling the code related to building all C# based scoring pipeline tools
|
|
// for now the ManagedScoringTools.sln only contains MARS related C# based applications
|
|
public static void BuildManagedScoringTools(IExecutionContext context, DevEnvBuildVariant buildVariants, bool rebuild = true)
|
|
{
|
|
var visualStudioVersion = UAFConstants.ToolsVisualStudioVersion;
|
|
var solutionFile = UAFConstants.GetManagedScoringTools();
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
BuildSolution(context, solutionFile, buildVariant.ToString(), rebuild, visualStudioVersion: visualStudioVersion);
|
|
}
|
|
}
|
|
|
|
private static void BuildScoringToolsSolution(IExecutionContext context, DevEnvBuildVariant buildVariants, bool rebuild = true)
|
|
{
|
|
var visualStudioVersion = UAFConstants.ToolsVisualStudioVersion;
|
|
|
|
var solutionFile = UAFConstants.GetManagedScoringTools();
|
|
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
BuildSolution(context, solutionFile, buildVariant.ToString(), rebuild, visualStudioVersion: visualStudioVersion);
|
|
}
|
|
}
|
|
|
|
private static void BuildScoringUtilitiesSolution(IExecutionContext context, DevEnvBuildVariant buildVariants, bool rebuild = true)
|
|
{
|
|
var solutionFile = UAFConstants.GetScoringUtilitiesSolution(VisualStudioVersion.vs2012);
|
|
foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
{
|
|
var buildVariantName = buildVariant.ToString();
|
|
BuildSolution(context, solutionFile, buildVariantName + "|Win64", rebuild);
|
|
BuildSolution(context, solutionFile, buildVariantName + "_PS4|Win64", rebuild);
|
|
BuildSolution(context, solutionFile, buildVariantName + "_XOne|Win64", rebuild);
|
|
}
|
|
}
|
|
|
|
private static void BuildSolution(IExecutionContext context, string solutionPath, string buildVariant, bool rebuild, int retryCount = 0,
|
|
VisualStudioVersion visualStudioVersion = VisualStudioVersion.vs2012)
|
|
{
|
|
var buildSolution = new VisualStudioCommand(solutionPath)
|
|
{
|
|
Version = visualStudioVersion,
|
|
BuildVariant = buildVariant,
|
|
Action = (rebuild ? VisualStudioAction.Rebuild : VisualStudioAction.Build)
|
|
};
|
|
|
|
buildSolution.ExecuteAndRetry(context, retryCount);
|
|
}
|
|
|
|
///// <summary>
|
|
///// Builds KinectGestureTrainerWrapper Solution containing GestureComparer tool for PS4. XOne, X360
|
|
///// </summary>
|
|
//private static void BuildGestureComparerStandalone(IExecutionContext context, DevEnvBuildVariant buildVariants, bool rebuild = true)
|
|
//{
|
|
// var solutionPath = Path.Combine(UAFConstants.ToolsFolder, @"legacy\ScoringTools\src\GestureComparer\GestureComparer.vs2012.csproj");
|
|
|
|
// foreach (var buildVariant in buildVariants.FlagsDefined())
|
|
// {
|
|
// // Auto retrying since the scoring tools compilation randomly
|
|
// // fails on a null reference exception.
|
|
// var buildVariantName = buildVariant.ToString();
|
|
// BuildSolution(context, solutionPath, buildVariantName + "Ps4", rebuild, retryCount: 2);
|
|
// BuildSolution(context, solutionPath, buildVariantName + "XOne", rebuild, retryCount: 2);
|
|
// }
|
|
//}
|
|
|
|
[DisplayName("Clean output")]
|
|
[Macro(ThreadAffinity.ExecuteAsync, Icon = "trash.png")]
|
|
public static void Clean_Output(IExecutionContext context, [Description("By default tools are not cleaned since their incremental build is working fine, force will make sure everything is cleaned.")] bool forceAll)
|
|
{
|
|
var outputDir = Path.Combine(RootFolder.Value, @"output");
|
|
FileSystemCommand.CleanFolder(context, outputDir, folder => forceAll || !folder.Contains("Tools"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// There is a bug with Incredibuild that leaves sleeping processes on the machine.
|
|
/// This makes the compilation time out.
|
|
/// We know that these processes do not have any parent while they are supposed to,
|
|
/// => Track and kill
|
|
/// </summary>
|
|
public static void KillOrphanProcesses(IStep stepcontext)
|
|
{
|
|
foreach (var process in Process.GetProcesses())
|
|
{
|
|
var parent = process.GetParentProcess();
|
|
if (parent == null && process.ProcessName.ToLower().IsIn("cl", "ccppc", "ecomppc", "link", "tracker", "xgwait", "ax", "vs11build"))
|
|
{
|
|
try
|
|
{
|
|
stepcontext.LogWarning("The ghost process {0} was still alive, killing it", process.ProcessName);
|
|
process.Kill();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
stepcontext.LogMessage(e.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the parent process of the current process.
|
|
/// </summary>
|
|
/// <returns>An instance of the Process class.</returns>
|
|
public static Process GetParentProcess(this Process process)
|
|
{
|
|
try
|
|
{
|
|
return ParentProcessUtilities.GetParentProcess(process.Id);
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
[CanBeNull]
|
|
public static string GetLatestVersionInDirectory(ILogger logger, string envDirectoryPath, Region region,
|
|
DevEnvBuildVariant target, string filePattern)
|
|
{
|
|
string package = null;
|
|
|
|
if (String.IsNullOrEmpty(envDirectoryPath))
|
|
{
|
|
logger.LogError("Versions directory path is empty.");
|
|
}
|
|
else if (!System.IO.Directory.Exists(envDirectoryPath))
|
|
{
|
|
logger.LogError("Directory {0} does not exist.", envDirectoryPath);
|
|
}
|
|
else
|
|
{
|
|
var latestVersionDirectory = System.IO.Directory.EnumerateDirectories(envDirectoryPath)
|
|
.OrderByDescending(System.IO.Directory.GetCreationTime)
|
|
.FirstOrDefault();
|
|
if (latestVersionDirectory == null)
|
|
{
|
|
logger.LogError("No directory found under {0}.", envDirectoryPath);
|
|
}
|
|
else
|
|
{
|
|
latestVersionDirectory = Path.Combine(latestVersionDirectory, region.ToString(), target.ToString());
|
|
var validFiles =
|
|
System.IO.Directory.EnumerateFiles(latestVersionDirectory, filePattern, SearchOption.AllDirectories)
|
|
.OrderByDescending(file => new System.IO.FileInfo(file).Length)
|
|
.ToList();
|
|
package = validFiles.FirstOrDefault();
|
|
|
|
if (validFiles.Count > 1)
|
|
{
|
|
logger.LogWarning("More than one {0} file found under {1}, selecting the first one : {2}.",
|
|
filePattern, latestVersionDirectory, package);
|
|
}
|
|
else if (package == null)
|
|
{
|
|
logger.LogError("No suitable package file under latest version folder {0}", latestVersionDirectory);
|
|
}
|
|
}
|
|
}
|
|
|
|
return package;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A utility class to determine a process parent.
|
|
/// </summary>
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct ParentProcessUtilities
|
|
{
|
|
// These members must match PROCESS_BASIC_INFORMATION
|
|
internal IntPtr Reserved1;
|
|
internal IntPtr PebBaseAddress;
|
|
internal IntPtr Reserved2_0;
|
|
internal IntPtr Reserved2_1;
|
|
internal IntPtr UniqueProcessId;
|
|
internal IntPtr InheritedFromUniqueProcessId;
|
|
|
|
[DllImport("ntdll.dll")]
|
|
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
|
|
|
|
/// <summary>
|
|
/// Gets the parent process of specified process.
|
|
/// </summary>
|
|
/// <param name="id">The process id.</param>
|
|
/// <returns>An instance of the Process class.</returns>
|
|
public static Process GetParentProcess(int id)
|
|
{
|
|
Process process = Process.GetProcessById(id);
|
|
return GetParentProcess(process.Handle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the parent process of a specified process.
|
|
/// </summary>
|
|
/// <param name="handle">The process handle.</param>
|
|
/// <returns>An instance of the Process class.</returns>
|
|
public static Process GetParentProcess(IntPtr handle)
|
|
{
|
|
ParentProcessUtilities pbi = new ParentProcessUtilities();
|
|
int returnLength;
|
|
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
|
|
if (status != 0)
|
|
{
|
|
throw new Win32Exception(status);
|
|
}
|
|
|
|
try
|
|
{
|
|
return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
// not found
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |