/// <nodoc /> public PathAtomLiteral(PathAtom value, LineInfo location) : base(location) { Contract.Requires(value.IsValid); Value = value; }
internal MsbuildFile( Context context, AbsolutePath specFilePath, string projectExtension) { ProjectsByQualifier = new Dictionary <string, Project>(); ProjectReferences = new List <MsbuildFile>(); Context = context; Name = specFilePath.GetName(Context.PathTable).RemoveExtension(Context.StringTable).ToString(Context.StringTable); SpecFilePath = specFilePath; SpecDirectory = SpecFilePath.GetParent(Context.PathTable); // Add '.g' suffix only if the projects files will be in the spec root if (Context.CanWriteToSrc) { projectExtension = ".g" + projectExtension; } // Relative to enlistment root RelativePath = Context.GetRelativePath(SpecFilePath).ChangeExtension(Context.StringTable, PathAtom.Create(Context.StringTable, projectExtension)); Guid = GenerateGuid(RelativePath.ToString(Context.StringTable)); Path = Context.ProjectsRoot.Combine(Context.PathTable, RelativePath); }
/// <summary> /// Helper for tests to create a default configuration object /// </summary> public static CommandLineConfiguration GetDefaultForTesting(PathTable pathTable, AbsolutePath configFile) { var rootPath = configFile.GetParent(pathTable); var outPath = rootPath.Combine(pathTable, PathAtom.Create(pathTable.StringTable, "Out")); var logsPath = outPath.Combine(pathTable, PathAtom.Create(pathTable.StringTable, "Logs")); return(new CommandLineConfiguration { Startup = { ConfigFile = configFile, CurrentHost = new Host(), }, Layout = { PrimaryConfigFile = configFile, SourceDirectory = rootPath, OutputDirectory = outPath, ObjectDirectory = rootPath.Combine(pathTable,PathAtom.Create(pathTable.StringTable, "obj")), CacheDirectory = rootPath.Combine(pathTable,PathAtom.Create(pathTable.StringTable, "cache")), BuildEngineDirectory = rootPath.Combine(pathTable,PathAtom.Create(pathTable.StringTable, "bxl.exe")), EngineCacheDirectory = rootPath.Combine(pathTable,PathAtom.Create(pathTable.StringTable, "cache"), PathAtom.Create(pathTable.StringTable,"engineCache")), }, Logging = { LogsDirectory = logsPath, LogExecution = false, StoreFingerprints = false }, Engine = { MaxRelativeOutputDirectoryLength = 260, TrackBuildsInUserFolder = false, }, Schedule = { MaxIO = 1, MaxProcesses = 1, }, Cache = { CacheSpecs = SpecCachingOption.Disabled, CacheLogFilePath = logsPath.Combine(pathTable,PathAtom.Create(pathTable.StringTable, "cache.log")), }, FrontEnd = { MaxFrontEndConcurrency = 1, }, Sandbox = { FileSystemMode = FileSystemMode.RealAndMinimalPipGraph, }, }); }
/// <summary> /// Creates a <see cref="TrackedFileContentInfo"/> with a hash but no tracking information. /// This is intended for when change tracking is disable or unsupported (due to e.g. a volume having change journaling disabled). /// </summary> public static TrackedFileContentInfo CreateUntracked(FileContentInfo fileContentInfo, PathAtom fileName = default) { Contract.Ensures(!Contract.Result <TrackedFileContentInfo>().IsTracked); return(new TrackedFileContentInfo(fileContentInfo, FileChangeTrackingSubscription.Invalid, fileName)); }
public void PredictedInputsInKnownOutputDirectoriesAreSkipped() { var dependency = CreateProjectWithPredictions(outputs: CreatePath("OutDir")); // We create 4 predicted inputs. 3 of them under predicted output directories. So only the last one should be added as a true input, the rest are assumed to be intermediates var dependent = CreateProjectWithPredictions( outputs: CreatePath("AnotherOutput"), inputs: CreatePath(@"AnotherOutput\input.txt", @"OutDir\input1.txt", @"OutDir\nested\input2.txt", "input3.txt"), references: new[] { dependency }); var processInputs = Start() .Add(dependency) .Add(dependent) .ScheduleAll() .RetrieveSuccessfulProcess(dependent) .Dependencies; // The only source file (besides MSBuild.exe itself) should be input3 var input = processInputs.Single(i => (i.IsSourceFile && i.Path.GetName(PathTable) != PathAtom.Create(StringTable, "MSBuild.exe"))); XAssert.Equals("input3.txt", input.Path.GetName(PathTable).ToString(PathTable.StringTable)); }
/// <summary> /// Gets a relative path for temp files unique for the current call. /// </summary> public DirectoryArtifact GetUniqueTempDirectory() { var relativePath = GetUniqueRelativePath(PathAtom.Create(Context.StringTable, "t")); return(DirectoryArtifact.CreateWithZeroPartialSealId(m_tempRoot.Combine(Context.PathTable, relativePath))); }
/// <summary> /// Construct a new allowlist entry that will match based on tool and full path /// </summary> /// <param name="executableName">The executable name of the tool that does the bad access.</param> /// <param name="pathRegex">The ECMAScript regex pattern that will be used as the basis for the match.</param> /// <param name="allowsCaching"> /// Whether this allowlist rule should be interpreted to allow caching of a pip that matches /// it. /// </param> /// <param name="name">Name of the allowlist entry. Defaults to 'Unnamed' if null/empty.</param> public ExecutablePathAllowlistEntry(PathAtom executableName, SerializableRegex pathRegex, bool allowsCaching, string name) : this(new DiscriminatingUnion <AbsolutePath, PathAtom>(executableName), pathRegex, allowsCaching, name) { Contract.Requires(executableName.IsValid); }
public RelativePath CreateRelativePath(RelativePath original, PathAtom atom1, PathAtom atom2) { Contract.Requires(original.IsValid); Contract.Requires(atom1.IsValid); Contract.Requires(atom2.IsValid); return(original.Combine(atom1, atom2)); }
/// <summary> /// Try to create a PathAtom from a string. /// </summary> /// <remarks> /// The rules for a valid path atom are that the input string may not /// be empty and must only contain characters reported as valid by <see cref="PathAtom.IsValidPathAtomChar" />. /// </remarks> public bool TryCreatePathAtom(string atom, out PathAtom result) { Contract.Requires(!string.IsNullOrEmpty(atom)); return(PathAtom.TryCreate(m_stringTable, atom, out result)); }
/// <summary> /// Creates a new SemanticPathInfo /// </summary> public SemanticPathInfo(PathAtom rootName, AbsolutePath root, SemanticPathFlags flags) { RootName = rootName; Root = root; Flags = flags; }
/// <summary> /// Creates an AbsolutePath by appending path atoms to an existing one. /// </summary> public AbsolutePath CreateAbsolutePath(AbsolutePath original, PathAtom atom1, PathAtom atom2) { Contract.Requires(original.IsValid); Contract.Requires(atom1.IsValid); Contract.Requires(atom2.IsValid); return(original.Combine(m_pathTable, atom1, atom2)); }
/// <inheritdoc/> public override bool Include(PathAtom fileName, string fileNameStr) { return(m_regex.IsMatch(fileNameStr)); }
public void BreakawayProcessCompensatesWithAugmentedAccesses() { string sharedOpaqueDir = Path.Combine(ObjectRoot, "partialDir"); AbsolutePath sharedOpaqueDirPath = AbsolutePath.Create(Context.PathTable, sharedOpaqueDir); FileArtifact outputInSharedOpaque = CreateOutputFileArtifact(sharedOpaqueDir); FileArtifact source = CreateSourceFile(); var builder = CreatePipBuilder(new Operation[] { // We spawn a process, since breakaway happens for child processes only Operation.Spawn(Context.PathTable, waitToFinish: true, // Write a file. This access will not be observed Operation.WriteFile(outputInSharedOpaque, doNotInfer: true)), // Report the augmented accesses (in the root process, which is detoured normally) without actually // performing any IO Operation.AugmentedWrite(outputInSharedOpaque, doNotInfer: true), }); builder.AddOutputDirectory(sharedOpaqueDirPath, kind: SealDirectoryKind.SharedOpaque); builder.AddInputFile(source); // Configure the test process itself to escape the sandbox builder.ChildProcessesToBreakawayFromSandbox = ReadOnlyArray <PathAtom> .FromWithoutCopy(new[] { PathAtom.Create(Context.StringTable, TestProcessToolName) }); var pip = SchedulePipBuilder(builder); RunScheduler().AssertSuccess(); XAssert.IsTrue(File.Exists(ArtifactToString(outputInSharedOpaque))); // Make sure we can replay the file in the opaque directory. This means the write access reached detours via augmentation. File.Delete(ArtifactToString(outputInSharedOpaque)); RunScheduler().AssertCacheHit(pip.Process.PipId); XAssert.IsTrue(File.Exists(ArtifactToString(outputInSharedOpaque))); }
/// <nodoc /> public PathAtomLiteral(DeserializationContext context, LineInfo location) : base(location) { Value = context.Reader.ReadPathAtom(); }
/// <summary> /// Creates a new PipConstructionHelper /// </summary> /// <remarks> /// Ideally this function would take ModuleId, FullSymbol QualifierId and compute uniqueOutputLocation itself. Unfortunately today the data is not yet /// exposed via IPipGraph, therefore the responsibility is on the call site for now. /// </remarks> public static PipConstructionHelper Create( PipExecutionContext context, AbsolutePath objectRoot, AbsolutePath redirectedRoot, AbsolutePath tempRoot, IMutablePipGraph pipGraph, ModuleId moduleId, string moduleName, RelativePath specRelativePath, FullSymbol symbol, LocationData thunkLocation, QualifierId qualifierId) { var stringTable = context.StringTable; var pathTable = context.PathTable; // We have to manually compute the pipPipUniqueString here, Ideally we pass PackageId, SpecFile, FullSymbol and qualiferId and have it computed inside, but the IPipGraph does not allow querying it for now. string hashString; long semiStableHashSeed = 0; using (var builderWrapper = Pools.GetStringBuilder()) { var builder = builderWrapper.Instance; builder.Append(moduleName); builder.Append('/'); semiStableHashSeed = HashCodeHelper.GetOrdinalHashCode64(moduleName); if (specRelativePath.IsValid) { string specPath = specRelativePath.ToString(stringTable); builder.Append(specPath); builder.Append('/'); semiStableHashSeed = HashCodeHelper.Combine(semiStableHashSeed, HashCodeHelper.GetOrdinalHashCode64(specPath)); } var symbolName = symbol.ToStringAsCharArray(context.SymbolTable); builder.Append(symbolName); builder.Append('/'); semiStableHashSeed = HashCodeHelper.Combine(semiStableHashSeed, HashCodeHelper.GetOrdinalHashCode64(symbolName)); var qualifierDisplayValue = context.QualifierTable.GetCanonicalDisplayString(qualifierId); builder.Append(qualifierDisplayValue); semiStableHashSeed = HashCodeHelper.Combine(semiStableHashSeed, HashCodeHelper.GetOrdinalHashCode64(qualifierDisplayValue)); var pipPipUniqueString = builder.ToString(); hashString = Hash(pipPipUniqueString); } var pipRelativePath = RelativePath.Create( PathAtom.Create(stringTable, hashString.Substring(0, 1)), PathAtom.Create(stringTable, hashString.Substring(1, 1)), PathAtom.Create(stringTable, hashString.Substring(2))); var valuePip = new ValuePip(symbol, qualifierId, thunkLocation); return(new PipConstructionHelper( context, objectRoot, redirectedRoot, tempRoot, pipGraph, moduleId, moduleName, valuePip, pipRelativePath, semiStableHashSeed)); }
/// <summary> /// Create a PathAtom from a string and abandons if the string is invalid. /// </summary> /// <remarks> /// The rules for a valid path atom are that the input string may not /// be empty and must only contain characters reported as valid by <see cref="PathAtom.IsValidPathAtomChar" />. /// This is useful for hard-coded literals, don't use with any user input since it will kill the process on bad format. /// </remarks> public PathAtom CreatePathAtom(string atom) { Contract.Requires(!string.IsNullOrEmpty(atom)); return(PathAtom.Create(m_stringTable, atom)); }
/// <summary> /// Gets a directory unique for the current call under the redirected directory root. /// </summary> public DirectoryArtifact GetUniqueRedirectedDirectory(PathAtom name) { var relativePath = GetUniqueRelativePath(name); return(DirectoryArtifact.CreateWithZeroPartialSealId(m_redirectedRoot.Combine(Context.PathTable, relativePath))); }
/// <summary> /// Adds or changes the file extension of an absolute path, returning a new absolute path. /// </summary> /// <param name="path">The original absolute path that may or may not have an extension.</param> /// <param name="extension">The new extension (this string must include a leading .). If this is PathAtom.Invalid then this method is equivalent to calling RemoveExtension instead.</param> public AbsolutePath ChangeExtension(AbsolutePath path, PathAtom extension) { Contract.Requires(path.IsValid); return(path.ChangeExtension(m_pathTable, extension)); }
public void ChangeExtension() { var st = new StringTable(0); // change a single char extension RelativePath rp1 = RelativePath.Create(st, @"a.c"); RelativePath rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"a.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"a.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"a.d", rp2.ToString(st)); // change nothing rp1 = RelativePath.Create(st, @"a"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"a.d", rp2.ToString(st)); // change a single char extension rp1 = RelativePath.Create(st, @"ab.c"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"ab.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"ab.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"ab.d", rp2.ToString(st)); // change nothing rp1 = RelativePath.Create(st, @"ab"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"ab.d", rp2.ToString(st)); // change a single char extension rp1 = RelativePath.Create(st, @"ab.xyz.c"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"ab.xyz.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"ab.xyz.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"ab.xyz.d", rp2.ToString(st)); rp1 = RelativePath.Create(st, @".cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@".d", rp2.ToString(st)); // change a single char extension rp1 = RelativePath.Create(st, @"xyz\a.c"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\a.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"xyz\a.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\a.d", rp2.ToString(st)); // change nothing rp1 = RelativePath.Create(st, @"xyz\a"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\a.d", rp2.ToString(st)); // change a single char extension rp1 = RelativePath.Create(st, @"xyz\ab.c"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\ab.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"xyz\ab.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\ab.d", rp2.ToString(st)); // change nothing rp1 = RelativePath.Create(st, @"xyz\ab"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\ab.d", rp2.ToString(st)); // change a single char extension rp1 = RelativePath.Create(st, @"xyz\ab.xyz.c"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\ab.xyz.d", rp2.ToString(st)); // change a multi char extension rp1 = RelativePath.Create(st, @"xyz\ab.xyz.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\ab.xyz.d", rp2.ToString(st)); rp1 = RelativePath.Create(st, @"xyz\.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".d")); XAssert.AreEqual(@"xyz\.d", rp2.ToString(st)); // nop change rp1 = RelativePath.Create(st, @"xyz\ab.xyz.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Create(st, ".cpp")); XAssert.AreEqual(rp1, rp2); rp1 = RelativePath.Create(st, @"xyz\ab.xyz.cpp"); rp2 = rp1.ChangeExtension(st, PathAtom.Invalid); XAssert.AreEqual(@"xyz\ab.xyz", rp2.ToString(st)); }
/// <summary> /// Adds or changes the file extension of a relative path, returning a new relative path. /// </summary> /// <param name="path">The original relative path that may or may not have an extension.</param> /// <param name="extension">The new extension (this string must include a leading .). If this is PathAtom.Invalid then this method is equivalent to calling RemoveExtension instead.</param> public RelativePath ChangeExtension(RelativePath path, PathAtom extension) { Contract.Requires(path.IsValid); return(path.ChangeExtension(m_stringTable, extension)); }
/// <summary> /// Creates a <see cref="TrackedFileContentInfo"/> with an associated change tracking subscription. /// </summary> public TrackedFileContentInfo(FileContentInfo fileContentInfo, FileChangeTrackingSubscription subscription, PathAtom fileName, ReparsePointInfo?reparsePointInfo = null) { Subscription = subscription; FileContentInfo = fileContentInfo; FileName = fileName; ReparsePointInfo = reparsePointInfo ?? ReparsePointInfo.CreateNoneReparsePoint(); }
/// <summary> /// Adds or changes the file extension of a path atom, returning a new path atom. /// </summary> /// <param name="atom">The original atom that may or may not have an extension.</param> /// <param name="extension">The new extension (this string must include a leading .). If this is PathAtom.Invalid then this method is equivalent to calling RemoveExtension instead.</param> public PathAtom ChangeExtension(PathAtom atom, PathAtom extension) { Contract.Requires(atom.IsValid); return(atom.ChangeExtension(m_stringTable, extension)); }
private bool TryConfigureProcessBuilder( ProcessBuilder processBuilder, PipConstructionHelper pipConstructionHelper, ProjectWithPredictions project, QualifierId qualifierId, out AbsolutePath outputResultCacheFile, out string failureDetail) { outputResultCacheFile = AbsolutePath.Invalid; if (!TrySetBuildToolExecutor(pipConstructionHelper, processBuilder, project)) { failureDetail = "Failed to construct tooldefinition"; return(false); } // Working directory - the directory where the project file lives. processBuilder.WorkingDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(project.FullPath.GetParent(PathTable)); // We allow undeclared inputs to be read processBuilder.Options |= Process.Options.AllowUndeclaredSourceReads; // Run in a container if specified if (m_resolverSettings.RunInContainer) { processBuilder.Options |= Process.Options.NeedsToRunInContainer; processBuilder.ContainerIsolationLevel = ContainerIsolationLevel.IsolateAllOutputs; } // Until we can deal with double writes in a better way, this unsafe option allows the build to progress and // prints warnings processBuilder.DoubleWritePolicy |= DoubleWritePolicy.UnsafeFirstDoubleWriteWins; SetUntrackedFilesAndDirectories(processBuilder); // Add the log directory and its corresponding files var qualifier = m_context.QualifierTable.GetQualifier(qualifierId); AbsolutePath logDirectory = GetLogDirectory(project, qualifier); processBuilder.AddOutputFile(logDirectory.Combine(PathTable, "msbuild.log"), FileExistence.Optional); processBuilder.AddOutputFile(logDirectory.Combine(PathTable, "msbuild.wrn"), FileExistence.Optional); processBuilder.AddOutputFile(logDirectory.Combine(PathTable, "msbuild.err"), FileExistence.Optional); processBuilder.AddOutputFile(logDirectory.Combine(PathTable, "msbuild.prf"), FileExistence.Optional); if (m_resolverSettings.EnableBinLogTracing == true) { processBuilder.AddOutputFile(logDirectory.Combine(PathTable, "msbuild.binlog"), FileExistence.Optional); } // Unless the legacy non-isolated mode is explicitly specified, the project builds in isolation, and therefore // it produces an output cache file. This file is placed on the (unique) object directory for this project if (m_resolverSettings.UseLegacyProjectIsolation != true) { var objectDirectory = pipConstructionHelper.GetUniqueObjectDirectory(project.FullPath.GetName(PathTable)); outputResultCacheFile = objectDirectory.Path.Combine(PathTable, PathAtom.Create(PathTable.StringTable, OutputCacheFileName)); processBuilder.AddOutputFile(outputResultCacheFile, FileExistence.Required); } // Path to the project processBuilder.ArgumentsBuilder.Add(PipDataAtom.FromAbsolutePath(project.FullPath)); // Response file with the rest of the arguments var rspFileSpec = ResponseFileSpecification.Builder() .AllowForRemainingArguments(processBuilder.ArgumentsBuilder.CreateCursor()) .ForceCreation(true) .Prefix("@") .Build(); processBuilder.SetResponseFileSpecification(rspFileSpec); if (!TryAddMsBuildArguments(project, processBuilder.ArgumentsBuilder, logDirectory, outputResultCacheFile, out failureDetail)) { return(false); } // Q_SESSION_GUID is used to provide a unique build GUID to build tools and scripts. // It'll cause full cache misses if we try to hash it as an input, however, so exclude. processBuilder.SetPassthroughEnvironmentVariable(StringId.Create(m_context.StringTable, BuildEnvironmentConstants.QSessionGuidEnvVar)); // mspdbsrv: _MSPDBSRV_ENDPOINT_ sets up one mspdbsrv.exe instance per build target execution. // However this process will live beyond the build.cmd or msbuild.exe call. // Allow the pip job object to clean the process without complaint. // // vctip.exe: On any compile error this telemetry upload exe will be run as a detached process. // Just let it be killed. // TODO: Can we stop it running? https://stackoverflow.microsoft.com/questions/74425/how-to-disable-vctip-exe-in-vc14 // // conhost.exe: This process needs a little bit more time to finish after the main process. We shouldn't be allowing // this one to survive, we just need the timeout to be slightly more than zero. This will also be beneficial to other // arbitrary processeses that need a little bit more time. But, apparently, setting a timeout has a perf impact that is // being investigated. TODO: revisit this once this is fixed. // // All child processes: Don't wait to kill the processes. // CODESYNC: CloudBuild repo TrackerExecutor.cs "info.NestedProcessTerminationTimeout = TimeSpan.Zero" processBuilder.AllowedSurvivingChildProcessNames = ReadOnlyArray <PathAtom> .FromWithoutCopy( PathAtom.Create(m_context.StringTable, "mspdbsrv.exe"), PathAtom.Create(m_context.StringTable, "vctip.exe"), PathAtom.Create(m_context.StringTable, "conhost.exe")); processBuilder.NestedProcessTerminationTimeout = TimeSpan.Zero; SetProcessEnvironmentVariables(CreateEnvironment(logDirectory, project), processBuilder); failureDetail = string.Empty; return(true); }
/// <summary> /// Removes the final extension of a path atom, returning a new atom. /// </summary> /// <remarks> /// This function is a nop if the atom has no extension. /// </remarks> public PathAtom RemoveExtension(PathAtom atom) { Contract.Requires(atom.IsValid); return(atom.RemoveExtension(m_stringTable)); }
public void PredictedInputsUnderUntrackedDirectoriesAreSkipped() { var project = CreateProjectWithPredictions(inputs: CreatePath(@"untracked\input.txt", "input2.txt")); var processInputs = Start(new MsBuildResolverSettings { UntrackedDirectories = CreatePath("untracked").Select(path => DirectoryArtifact.CreateWithZeroPartialSealId(path)).ToList() }) .Add(project) .ScheduleAll() .RetrieveSuccessfulProcess(project) .Dependencies; // The only source file (besides MSBuild.exe itself) should be input2 var input = processInputs.Single(i => (i.IsSourceFile && i.Path.GetName(PathTable) != PathAtom.Create(StringTable, "MSBuild.exe"))); XAssert.Equals("input2.txt", input.Path.GetName(PathTable).ToString(PathTable.StringTable)); }
/// <summary> /// Retrieve a string representation of a path atom. /// </summary> public string Expand(PathAtom atom) { Contract.Requires(atom.IsValid); return(atom.ToString(m_stringTable)); }
/// <summary> /// Indicates whether the given path passes at least one of the filters. /// </summary> public override bool Include(PathAtom fileName, string fileNameStr) { return(m_filter1.Include(fileName, fileNameStr) || m_filter2.Include(fileName, fileNameStr)); }
/// <summary> /// Performs a case insensitive comparison on two PathAtoms /// </summary> public bool CaseInsensitiveEquals(PathAtom atom1, PathAtom atom2) { return(atom1.CaseInsensitiveEquals(m_stringTable, atom2)); }
private void ParseManagedSemantics() { var stringTable = m_context.PathTable.StringTable; var magicNugetMarker = PathAtom.Create(stringTable, "_._"); var dllExtension = PathAtom.Create(stringTable, ".dll"); foreach (var relativePath in PackageOnDisk.Contents.OrderBy(path => path.ToString(stringTable))) { // This is a dll. Check if it is in a lib folder or ref folder. var atoms = relativePath.GetAtoms(); if (atoms.Length == 3) { var libOrRef = atoms[0]; var targetFrameworkFolder = atoms[1]; var fileName = atoms[2]; var isLib = NugetFrameworkMonikers.LibFolderName.CaseInsensitiveEquals(stringTable, libOrRef); var isRef = NugetFrameworkMonikers.RefFolderName.CaseInsensitiveEquals(stringTable, libOrRef); if (isLib || isRef) { if (!TryGetKnownTargetFramework(targetFrameworkFolder, out NugetTargetFramework targetFramework)) { // We skip unknown frameworks, packages are not necessarily well constructed. We log this // as a verbose message (i.e., this is not an error). Logger.Log.NugetUnknownFramework(m_context.LoggingContext, PackageOnDisk.Package.Id, targetFrameworkFolder.ToString(stringTable), relativePath.ToString(stringTable)); continue; } var isManagedEntry = false; var ext = fileName.GetExtension(stringTable); if (dllExtension.CaseInsensitiveEquals(stringTable, ext)) { isManagedEntry = true; if (isRef) { References.Add(targetFramework, relativePath); } if (isLib) { Libraries.Add(targetFramework, relativePath); } } else if (fileName == magicNugetMarker) { isManagedEntry = true; } if (isManagedEntry) { IsManagedPackage = true; if (!TargetFrameworks.Contains(targetFramework.Moniker)) { TargetFrameworks.Add(targetFramework.Moniker); } // The magic marker is there so the framework is declared as supported, but no actual files are listed // So we don't want to add a magic marker as a real artifact that can be referenced. if (fileName != magicNugetMarker) { AssemblyToTargetFramework.Add(fileName, targetFramework); } } } } } if (TargetFrameworks.Count == 0) { var history = ForceFullFrameworkQualifiersOnly ? NugetFrameworkMonikers.FullFrameworkVersionHistory : NugetFrameworkMonikers.WellknownMonikers.ToList(); foreach (var moniker in history) { TargetFrameworks.Add(moniker); } } // For the refs without lib, copy them to refs. foreach (var kv in Libraries) { if (!References.ContainsKey(kv.Key)) { References.Add(kv.Key, kv.Value.ToArray()); } } }
private static bool IsModuleConfigFileName(PathAtom fileName, StringTable stringTable) { return(ExtensionUtilities.IsModuleConfigurationFile(fileName.ToString(stringTable))); }