Enable self-host build on K drive in CB (#1183)

- Provide accurate info when checking journal availability
- Adding directory translation into engine tests to fix rough behavior of some unit tests that tries to access final paths.
This commit is contained in:
Iman Narasamdya 2019-11-08 10:29:33 -08:00 коммит произвёл Michael Pysson
Родитель 84dc115b3c
Коммит 9ae347e917
3 изменённых файлов: 46 добавлений и 7 удалений

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

@ -2409,12 +2409,16 @@ namespace BuildXL.Engine
{ {
Contract.Requires(path.IsValid); Contract.Requires(path.IsValid);
var translatedPath = m_translator?.Translate(Context.PathTable, path) ?? path; bool possiblyEnabled = IsJournalPossiblyAvailableForPath(Context.PathTable, path, out AbsolutePath finalPath);
bool possiblyEnabled = IsJournalPossiblyAvailableForPath(Context.PathTable, translatedPath);
if (!possiblyEnabled) if (!possiblyEnabled)
{ {
var drive = translatedPath.GetRoot(Context.PathTable).ToString(Context.PathTable).TrimEnd('\\'); var drive = finalPath.GetRoot(Context.PathTable).ToString(Context.PathTable).TrimEnd('\\');
Logger.Log.JournalRequiredOnVolumeError(loggingContext, drive, GetConfigureJournalCommand(drive)); Logger.Log.JournalRequiredOnVolumeError(
loggingContext,
drive,
path.ToString(Context.PathTable),
finalPath.IsValid ? finalPath.ToString(Context.PathTable) : string.Empty,
GetConfigureJournalCommand(drive));
} }
return possiblyEnabled; return possiblyEnabled;
@ -2433,15 +2437,21 @@ namespace BuildXL.Engine
/// Low-risk check if a path is definitely on a volume with a disabled change journal. In some configurations, the journal is /// Low-risk check if a path is definitely on a volume with a disabled change journal. In some configurations, the journal is
/// required and so we want to fail early if misconfiguration is apparent. /// required and so we want to fail early if misconfiguration is apparent.
/// </summary> /// </summary>
private static bool IsJournalPossiblyAvailableForPath(PathTable pathTable, AbsolutePath path) private static bool IsJournalPossiblyAvailableForPath(PathTable pathTable, AbsolutePath path, out AbsolutePath finalPath)
{ {
Contract.Requires(pathTable != null); Contract.Requires(pathTable != null);
Contract.Requires(path.IsValid); Contract.Requires(path.IsValid);
finalPath = path;
// We open the path without reparse point flag. This will returns the handle to the final path, if the original
// path is a junction or symlink. This means that we will check the journal availability of the volume where the final path
// resides.
OpenFileResult result = FileUtilities.TryOpenDirectory( OpenFileResult result = FileUtilities.TryOpenDirectory(
path.ToString(pathTable), path.ToString(pathTable),
FileShare.Delete | FileShare.ReadWrite, FileShare.Delete | FileShare.ReadWrite,
out SafeFileHandle handle); out SafeFileHandle handle);
using (handle) using (handle)
{ {
if (result.Succeeded) if (result.Succeeded)
@ -2452,6 +2462,19 @@ namespace BuildXL.Engine
if (!possibleIdentity.Succeeded && if (!possibleIdentity.Succeeded &&
possibleIdentity.Failure.Content == VersionedFileIdentity.IdentityUnavailabilityReason.NotSupported) possibleIdentity.Failure.Content == VersionedFileIdentity.IdentityUnavailabilityReason.NotSupported)
{ {
try
{
// For correct reporting, we try to get the final path, so that we know precisely which volume
// that does not have the journal capability.
string finalPathStr = FileUtilities.GetFinalPathNameByHandle(handle);
finalPath = AbsolutePath.Create(pathTable, finalPathStr);
}
catch (NativeWin32Exception)
{
// GetFinalPathNameByHandle currently only throws NativeWin32Exception.
finalPath = path;
}
return false; return false;
} }
} }

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

@ -2414,8 +2414,8 @@ If you can't update and need this feature after July 2018 please reach out to th
EventLevel = Level.Error, EventLevel = Level.Error,
Keywords = (int)(Keywords.UserMessage | Keywords.UserError), Keywords = (int)(Keywords.UserMessage | Keywords.UserError),
EventTask = (int)Tasks.Engine, EventTask = (int)Tasks.Engine,
Message = "The volume, '{drive}' does not have an enabled change journal. Change journaling is required for volumes containing sources, build outputs, and the build cache. Please open an elevated command prompt and run:\n {command}")] Message = "The volume, '{drive}' (checked path: '{checkedPath}', final path: '{finalPath}') does not have an enabled change journal. Change journaling is required for volumes containing sources, build outputs, and the build cache. Please open an elevated command prompt and run:\n {command}")]
public abstract void JournalRequiredOnVolumeError(LoggingContext context, string drive, string command); public abstract void JournalRequiredOnVolumeError(LoggingContext context, string drive, string checkedPath, string finalPath, string command);
[GeneratedEvent( [GeneratedEvent(
(int)EventId.StartEngineRun, (int)EventId.StartEngineRun,

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

@ -145,6 +145,22 @@ namespace Test.BuildXL.Engine
} }
}; };
if (TryGetSubstSourceAndTarget(out string substSource, out string substTarget))
{
// Directory translation is needed here particularly when the test temporary directory
// is inside a directory that is actually a junction to another place.
// For example, the temporary directory is D:\src\BuildXL\Out\Object\abc\t_1, but
// the path D:\src\BuildXL\Out or D:\src\BuildXL\Out\Object is a junction to K:\Out.
// Some tool, like cmd, can access the path in K:\Out, and thus the test will have a DFA
// if there's no directory translation.
// This problem does not occur when only substs are involved, but no junctions. The method
// TryGetSubstSourceAndTarget works to get translations due to substs or junctions.
AbsolutePath substSourcePath = AbsolutePath.Create(Context.PathTable, substSource);
AbsolutePath substTargetPath = AbsolutePath.Create(Context.PathTable, substTarget);
Configuration.Engine.DirectoriesToTranslate.Add(
new TranslateDirectoryData(I($"{substSource}<{substTarget}"), substSourcePath, substTargetPath));
}
AbsolutePath Combine(AbsolutePath parent, string name) AbsolutePath Combine(AbsolutePath parent, string name)
{ {
return parent.Combine(Context.PathTable, PathAtom.Create(Context.StringTable, name)); return parent.Combine(Context.PathTable, PathAtom.Create(Context.StringTable, name));