private static EvaluationResult ReadGraphFragment(Context context, ModuleLiteral env, EvaluationStackFrame args) { var file = Args.AsFile(args, 0); var deps = Args.AsArrayLiteral(args, 1).Values.Select(v => (AbsolutePath)v.Value).ToArray(); var description = Args.AsStringOptional(args, 2) ?? file.Path.ToString(context.PathTable); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed adding pip graph fragment file '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } if (!context.FrontEndContext.FileSystem.Exists(file.Path)) { throw new FileOperationException(new FileNotFoundException(I($"File '{file.Path.ToString(context.PathTable)}' does not exist"))); } // Record the file, so that its content is tracked by input tracker. context.FrontEndHost.Engine.RecordFrontEndFile(file.Path, "DScript"); int id = Interlocked.Increment(ref s_uniqueFragmentId); var readFragmentResult = context.FrontEndHost.PipGraphFragmentManager.AddFragmentFileToGraph(file, description, deps); if (!readFragmentResult) { return(EvaluationResult.Error); } return(EvaluationResult.Create(file.Path)); }
private static EvaluationResult Read(Context context, ModuleLiteral env, EvaluationStackFrame args) { // File that is read here will be tracked by the input tracker in the same way the spec file. var file = Args.AsFile(args, 0); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed reading '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } if (!context.FrontEndHost.Engine.TryGetFrontEndFile(file.Path, "ambient", out Stream stream)) { throw new FileOperationException( new Exception(I($"Failed reading '{file.Path.ToString(context.PathTable)}'"))); } try { var reader = XmlReader.Create(stream, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, }); var xmlContext = new XmlReadingContext(file.Path, context.PathTable, context.StringTable); var doc = ReadDocument(reader, xmlContext); return(EvaluationResult.Create(doc)); } catch (XmlException e) { throw new XmlReadException(file.Path.ToString(context.PathTable), e.LineNumber, e.LinePosition, e.Message, new ErrorContext(pos: 1)); } }
private static EvaluationResult ReadAllText(Context context, ModuleLiteral env, EvaluationStackFrame args) { // File that is read here will be tracked by the input tracker in the same way the spec file. var file = Args.AsFile(args, 0); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed reading '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } // This is a total HACK. // Unfortunately we are forced to use synchronous IO here and blast a hack through to the engine to ensure this file is // tracked for graph caching. The reason is that we use Task.Run to spawn frontend threads and for larger builds we can have // saturated the threadpool. So when during evaluation we perform IO there is no thread available to continue the work once the // OS returns the data. We have a mode where do use an ActionBlock ActionBlock to schedule the work. This can be turned on via `/enableEvaluationThrottling+` // but this was never made the default because measuring at the time resulted in about a 2x slowdown for the office build. // Since AB testing will take a long time since we need to get averages of metabuild duration now that most evaluation happens there. // So to unblock for now we will perform synchronous IO :( // There is also another small problem with this change. It is not using the IFileSystem to access the file because that doesn't have any way to get // file handles, so the memory filesystem of unittests won't function. var possibleContent = context.FrontEndHost.Engine.GetFileContentSynchronous(file.Path); if (possibleContent.Succeeded) { return(EvaluationResult.Create(possibleContent.Result)); } throw new FileOperationException( new Exception(I($"Failed reading '{file.Path.ToString(context.PathTable)}'"), possibleContent.Failure.Exception)); }
private static EvaluationResult Exists(Context context, ModuleLiteral env, EvaluationStackFrame args) { var file = Args.AsFile(args, 0); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed checking existence for '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } bool fileExists = context.FrontEndContext.FileSystem.Exists(file.Path); return(EvaluationResult.Create(fileExists)); }
private static EvaluationResult ReadGraphFragment(Context context, ModuleLiteral env, EvaluationStackFrame args) { var file = Args.AsFile(args, 0); var deps = Args.AsArrayLiteral(args, 1).Values.Select(v => (int)v.Value).ToArray(); var description = Args.AsStringOptional(args, 2) ?? file.Path.ToString(context.PathTable); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed adding pip graph fragment file '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } Contract.Assert(context.FrontEndContext.FileSystem.Exists(file.Path), "Fragment file does not exist"); int id = Interlocked.Increment(ref s_uniqueFragmentId); var readFragmentTask = context.FrontEndHost.PipGraphFragmentManager.AddFragmentFileToGraph(id, file, deps, description); return(EvaluationResult.Create(id)); }
private static EvaluationResult ReadAllText(Context context, ModuleLiteral env, EvaluationStackFrame args) { // File that is read here will be tracked by the input tracker in the same way the spec file. var file = Args.AsFile(args, 0); if (!file.IsSourceFile) { // Do not read output file. throw new FileOperationException( new Exception( I($"Failed reading '{file.Path.ToString(context.PathTable)}' because the file is not a source file"))); } var possibleContent = context.FrontEndHost.Engine.GetFileContentAsync(file.Path).GetAwaiter().GetResult(); if (possibleContent.Succeeded) { return(EvaluationResult.Create(possibleContent.Result.GetContentAsString())); } throw new FileOperationException( new Exception(I($"Failed reading '{file.Path.ToString(context.PathTable)}'"), possibleContent.Failure.Exception)); }
private static EvaluationResult CopyFile(Context context, ModuleLiteral env, EvaluationStackFrame args) { var source = Args.AsFile(args, 0); var destination = Args.AsPath(args, 1); var tags = Args.AsStringArrayOptional(args, 2); var description = Args.AsStringOptional(args, 3); var writable = Args.AsBoolOptional(args, 4); CopyFile.Options options = default; if (writable) { options = BuildXL.Pips.Operations.CopyFile.Options.OutputsMustRemainWritable; } FileArtifact result; if (!context.GetPipConstructionHelper().TryCopyFile(source, destination, options, tags, description, out result)) { // Error has been logged return(EvaluationResult.Error); } return(new EvaluationResult(result)); }
private EvaluationResult GetKeyForm(Context context, ModuleLiteral env, EvaluationStackFrame args) { var keyFormDll = Args.AsFile(args, 0); var arch = Args.AsString(args, 1); var name = Args.AsString(args, 2); var version = Args.AsString(args, 3); var publicKeyToken = Args.AsString(args, 4); var versionScope = Args.AsStringOptional(args, 5); var culture = Args.AsStringOptional(args, 6); var type = Args.AsStringOptional(args, 7); var handler = m_handlers.GetOrAdd( keyFormDll.Path, _ => { var keyFormDllPath = keyFormDll.Path.ToString(context.PathTable); var fileName = Path.GetFileName(keyFormDllPath); if (!string.Equals(KeyFormFileName, fileName, StringComparison.OrdinalIgnoreCase)) { throw new KeyFormDllWrongFileNameException(keyFormDllPath, KeyFormFileName, new ErrorContext(pos: 1)); } if (!File.Exists(keyFormDllPath)) { throw new KeyFormDllNotFoundException(keyFormDllPath, new ErrorContext(pos: 1)); } IntPtr moduleHandle = NativeMethods.LoadLibraryW(keyFormDllPath); if (moduleHandle == IntPtr.Zero) { var lasterror = Marshal.GetLastWin32Error(); var ex = new Win32Exception(lasterror); throw new KeyFormDllLoadException(keyFormDllPath, lasterror, ex.Message, new ErrorContext(pos: 1)); } IntPtr procHandle = NativeMethods.GetProcAddress(moduleHandle, KeyFormFunction); if (procHandle == IntPtr.Zero) { var lasterror = Marshal.GetLastWin32Error(); var ex = new Win32Exception(lasterror); throw new KeyFormDllLoadException(keyFormDllPath, lasterror, ex.Message, new ErrorContext(pos: 1)); } return(Marshal.GetDelegateForFunctionPointer <GetKeyFormHandler>(procHandle)); }); using (var pooledBuilder = m_stringBuilderCache.GetInstance()) { var builder = pooledBuilder.Instance; try { // Since this is native code hardening our process against threading issues // in the native code by ensuring we only access from single thread. // WIP: experimental. Removing locking for key form. // lock (m_keyFormLock) { handler(arch, name, version, publicKeyToken, versionScope, culture, type, builder, (uint)builder.Capacity); } } catch (Exception e) { // I know it is bad to catch all exceptions, but this is going into native code of which we // don't have control and this code doesn't handle weird input properly. var keyFormDllPath = keyFormDll.Path.ToString(context.PathTable); throw new KeyFormNativeFailureException(keyFormDllPath, e, new ErrorContext(pos: 1)); } return(EvaluationResult.Create(builder.ToString())); } }