in src/Shared/Modifiers.cs [390:611]
internal static string GetItemSpecModifier(string currentDirectory, string itemSpec, string definingProjectEscaped, string modifier, ref string fullPath)
{
ErrorUtilities.VerifyThrow(itemSpec != null, "Need item-spec to modify.");
ErrorUtilities.VerifyThrow(modifier != null, "Need modifier to apply to item-spec.");
string modifiedItemSpec = null;
try
{
if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.FullPath, StringComparison.OrdinalIgnoreCase) == 0)
{
if (fullPath != null)
{
return fullPath;
}
if (currentDirectory == null)
{
currentDirectory = String.Empty;
}
modifiedItemSpec = GetFullPath(itemSpec, currentDirectory);
fullPath = modifiedItemSpec;
ThrowForUrl(modifiedItemSpec, itemSpec, currentDirectory);
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RootDir, StringComparison.OrdinalIgnoreCase) == 0)
{
GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);
modifiedItemSpec = Path.GetPathRoot(fullPath);
if (!EndsWithSlash(modifiedItemSpec))
{
ErrorUtilities.VerifyThrow(FileUtilitiesRegex.UNCPattern.IsMatch(modifiedItemSpec),
"Only UNC shares should be missing trailing slashes.");
// restore/append trailing slash if Path.GetPathRoot() has either removed it, or failed to add it
// (this happens with UNC shares)
modifiedItemSpec += Path.DirectorySeparatorChar;
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Filename, StringComparison.OrdinalIgnoreCase) == 0)
{
// if the item-spec is a root directory, it can have no filename
if (Path.GetDirectoryName(itemSpec) == null)
{
// NOTE: this is to prevent Path.GetFileNameWithoutExtension() from treating server and share elements
// in a UNC file-spec as filenames e.g. \\server, \\server\share
modifiedItemSpec = String.Empty;
}
else
{
modifiedItemSpec = Path.GetFileNameWithoutExtension(itemSpec);
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Extension, StringComparison.OrdinalIgnoreCase) == 0)
{
// if the item-spec is a root directory, it can have no extension
if (Path.GetDirectoryName(itemSpec) == null)
{
// NOTE: this is to prevent Path.GetExtension() from treating server and share elements in a UNC
// file-spec as filenames e.g. \\server.ext, \\server\share.ext
modifiedItemSpec = String.Empty;
}
else
{
modifiedItemSpec = Path.GetExtension(itemSpec);
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RelativeDir, StringComparison.OrdinalIgnoreCase) == 0)
{
modifiedItemSpec = GetDirectory(itemSpec);
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Directory, StringComparison.OrdinalIgnoreCase) == 0)
{
GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);
modifiedItemSpec = GetDirectory(fullPath);
if (NativeMethodsShared.IsWindows)
{
Match root = FileUtilitiesRegex.DrivePattern.Match(modifiedItemSpec);
if (!root.Success)
{
root = FileUtilitiesRegex.UNCPattern.Match(modifiedItemSpec);
}
if (root.Success)
{
ErrorUtilities.VerifyThrow((modifiedItemSpec.Length > root.Length) && IsSlash(modifiedItemSpec[root.Length]),
"Root directory must have a trailing slash.");
modifiedItemSpec = modifiedItemSpec.Substring(root.Length + 1);
}
}
else
{
ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(modifiedItemSpec) && IsSlash(modifiedItemSpec[0]),
"Expected a full non-windows path rooted at '/'.");
// A full unix path is always rooted at
// `/`, and a root-relative path is the
// rest of the string.
modifiedItemSpec = modifiedItemSpec.Substring(1);
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RecursiveDir, StringComparison.OrdinalIgnoreCase) == 0)
{
// only the BuildItem class can compute this modifier -- so leave empty
modifiedItemSpec = String.Empty;
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Identity, StringComparison.OrdinalIgnoreCase) == 0)
{
modifiedItemSpec = itemSpec;
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.ModifiedTime, StringComparison.OrdinalIgnoreCase) == 0)
{
// About to go out to the filesystem. This means data is leaving the engine, so need
// to unescape first.
string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);
FileInfo info = FileUtilities.GetFileInfoNoThrow(unescapedItemSpec);
if (info != null)
{
modifiedItemSpec = info.LastWriteTime.ToString(FileTimeFormat, null);
}
else
{
// File does not exist, or path is a directory
modifiedItemSpec = String.Empty;
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.CreatedTime, StringComparison.OrdinalIgnoreCase) == 0)
{
// About to go out to the filesystem. This means data is leaving the engine, so need
// to unescape first.
string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);
if (File.Exists(unescapedItemSpec))
{
modifiedItemSpec = File.GetCreationTime(unescapedItemSpec).ToString(FileTimeFormat, null);
}
else
{
// File does not exist, or path is a directory
modifiedItemSpec = String.Empty;
}
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.AccessedTime, StringComparison.OrdinalIgnoreCase) == 0)
{
// About to go out to the filesystem. This means data is leaving the engine, so need
// to unescape first.
string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);
if (File.Exists(unescapedItemSpec))
{
modifiedItemSpec = File.GetLastAccessTime(unescapedItemSpec).ToString(FileTimeFormat, null);
}
else
{
// File does not exist, or path is a directory
modifiedItemSpec = String.Empty;
}
}
else if (IsDefiningProjectModifier(modifier))
{
if (String.IsNullOrEmpty(definingProjectEscaped))
{
// We have nothing to work with, but that's sometimes OK -- so just return String.Empty
modifiedItemSpec = String.Empty;
}
else
{
if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectDirectory, StringComparison.OrdinalIgnoreCase) == 0)
{
// ItemSpecModifiers.Directory does not contain the root directory
modifiedItemSpec = Path.Combine
(
GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.RootDir),
GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.Directory)
);
}
else
{
string additionalModifier = null;
if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectFullPath, StringComparison.OrdinalIgnoreCase) == 0)
{
additionalModifier = ItemSpecModifiers.FullPath;
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectName, StringComparison.OrdinalIgnoreCase) == 0)
{
additionalModifier = ItemSpecModifiers.Filename;
}
else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectExtension, StringComparison.OrdinalIgnoreCase) == 0)
{
additionalModifier = ItemSpecModifiers.Extension;
}
else
{
ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
}
modifiedItemSpec = GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, additionalModifier);
}
}
}
else
{
ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
}
}
catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
{
ErrorUtilities.VerifyThrowInvalidOperation(false, "Shared.InvalidFilespecForTransform", modifier, itemSpec, e.Message);
}
return modifiedItemSpec;
}