Example #1
0
        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));
        }
Example #2
0
        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));
            }
        }
Example #3
0
        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));
        }
Example #4
0
        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));
        }
Example #6
0
        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));
        }
Example #7
0
        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));
        }
Example #8
0
        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()));
            }
        }