示例#1
0
        /// <summary>
        /// Creates an IpcPip from a single string representing IPC operation payload.
        ///
        /// The standard output property of the created pip is set to <paramref name="workingDir"/>\stdout.txt
        /// </summary>
        internal static IpcPip CreateFromStringPayload(
            PipExecutionContext context,
            AbsolutePath workingDir,
            IpcClientInfo ipcInfo,
            string operationPayload,
            PipProvenance provenance,
            FileArtifact outputFile = default(FileArtifact),
            IEnumerable <PipId> servicePipDependencies            = null,
            IEnumerable <FileArtifact> fileDependencies           = null,
            IEnumerable <DirectoryArtifact> directoryDependencies = null,
            IEnumerable <StringId> tags = null,
            bool isServiceFinalization  = false,
            bool mustRunOnMaster        = false)
        {
            var stdoutPath = workingDir.Combine(context.PathTable, PathAtom.Create(context.StringTable, "stdout.txt"));
            var stdoutFile = outputFile.IsValid ? outputFile : FileArtifact.CreateOutputFile(stdoutPath);

            var pipDataBuilder = new PipDataBuilder(context.StringTable);

            pipDataBuilder.Add(operationPayload);

            return(new IpcPip(
                       ipcInfo,
                       arguments: pipDataBuilder.ToPipData(" ", PipDataFragmentEscaping.NoEscaping),
                       outputFile: stdoutFile,
                       servicePipDependencies: ToReadOnlyArray(servicePipDependencies),
                       fileDependencies: ToReadOnlyArray(fileDependencies),
                       directoryDependencies: ToReadOnlyArray(directoryDependencies),
                       skipMaterializationFor: ReadOnlyArray <FileOrDirectoryArtifact> .Empty,
                       tags: ToReadOnlyArray(tags),
                       isServiceFinalization: isServiceFinalization,
                       mustRunOnMaster: mustRunOnMaster,
                       provenance: provenance));
        }
示例#2
0
 /// <summary>
 /// Clone and override select properties.
 /// </summary>
 public IpcPip Override(
     IpcClientInfo ipcInfo   = null,
     PipData?messageBody     = null,
     FileArtifact?outputFile = null,
     ReadOnlyArray <PipId>?servicePipDependencies            = null,
     ReadOnlyArray <FileArtifact>?fileDependencies           = null,
     ReadOnlyArray <DirectoryArtifact>?directoryDependencies = null,
     ReadOnlyArray <FileOrDirectoryArtifact>?lazilyMaterializedDependencies = null,
     ReadOnlyArray <StringId>?tags = null,
     bool?isServiceFinalization    = null,
     bool?mustRunOnMaster          = null,
     PipProvenance provenance      = null)
 {
     return(new IpcPip(
                ipcInfo ?? IpcInfo,
                messageBody ?? MessageBody,
                outputFile ?? OutputFile,
                servicePipDependencies ?? ServicePipDependencies,
                fileDependencies ?? FileDependencies,
                directoryDependencies ?? DirectoryDependencies,
                lazilyMaterializedDependencies ?? LazilyMaterializedDependencies,
                tags ?? Tags,
                isServiceFinalization ?? IsServiceFinalization,
                mustRunOnMaster ?? MustRunOnMaster,
                provenance ?? Provenance));
 }
示例#3
0
        /// <summary>
        /// Creates a pip representing the hashing of the given source artifact.
        /// </summary>
        public SealDirectory(
            AbsolutePath directoryRoot,
            SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> contents,
            SortedReadOnlyArray <DirectoryArtifact, OrdinalDirectoryArtifactComparer> outputDirectoryContents,
            SealDirectoryKind kind,
            PipProvenance provenance,
            ReadOnlyArray <StringId> tags,
            ReadOnlyArray <StringId> patterns,
            bool scrub = false)
        {
            Contract.Requires(directoryRoot.IsValid);
            Contract.Requires(contents.IsValid);
            Contract.Requires(outputDirectoryContents.IsValid);
            Contract.Requires(tags.IsValid);
            Contract.Requires(provenance != null);
            Contract.Requires(!(patterns.IsValid && patterns.Length != 0) || kind.IsSourceSeal(), "If patterns are provided, it must be a source seal directory");
            Contract.Requires(!scrub || kind.IsFull(), "Only scrub fully seal directory");
            Contract.Requires(outputDirectoryContents.Length == 0 || kind.IsFull(), "Output directory content is only available for fully sealed directories");

            Provenance              = provenance;
            DirectoryRoot           = directoryRoot;
            Contents                = contents;
            OutputDirectoryContents = outputDirectoryContents;
            Kind  = kind;
            Tags  = tags;
            Scrub = scrub;

            Patterns = patterns;

            // Initialization required before this pip is usable or serializable.
            m_partialSealId = null;
        }
        /// <nodoc/>
        public CompositeSharedOpaqueSealDirectory(
            AbsolutePath directoryRoot,
            IReadOnlyList <DirectoryArtifact> composedDirectories,
            PipProvenance provenance,
            ReadOnlyArray <StringId> tags,
            SealDirectoryContentFilter?contentFilter,
            SealDirectoryCompositionActionKind compositionAction)
            : base(
                directoryRoot,
                CollectionUtilities.EmptySortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer>(OrdinalFileArtifactComparer.Instance),
                CollectionUtilities.EmptySortedReadOnlyArray <DirectoryArtifact, OrdinalDirectoryArtifactComparer>(OrdinalDirectoryArtifactComparer.Instance),
                SealDirectoryKind.SharedOpaque,
                provenance,
                tags,
                CollectionUtilities.EmptyArray <StringId>().ToReadOnlyArray())
        {
            Contract.Requires(composedDirectories != null);
            Contract.Requires(compositionAction != SealDirectoryCompositionActionKind.None);

            Contract.Assert(compositionAction != SealDirectoryCompositionActionKind.NarrowDirectoryCone || (composedDirectories.Count == 1), "When action is NarrowDirectoryCone, exactly one directory must be provided.");

            ComposedDirectories   = composedDirectories;
            CompositionActionKind = compositionAction;
            m_contentFilter       = contentFilter;
        }
示例#5
0
        public virtual PipProvenance ReadPipProvenance()
        {
            Start <PipProvenance>();
            PipProvenance value = PipProvenance.Deserialize(this);

            End();
            return(value);
        }
示例#6
0
        public virtual PipProvenance ReadPipProvenance()
        {
            Contract.Ensures(Contract.Result <PipProvenance>() != null);
            Start <PipProvenance>();
            PipProvenance value = PipProvenance.Deserialize(this);

            End();
            return(value);
        }
示例#7
0
 /// <nodoc />
 public static Xldb.Proto.PipProvenance ToPipProvenance(this PipProvenance provenance, PathTable pathTable)
 {
     return(provenance == null ? null : new Xldb.Proto.PipProvenance()
     {
         Usage = provenance.Usage.IsValid ? provenance.Usage.ToString(pathTable) : "",
         ModuleId = provenance.ModuleId.Value.ToString(pathTable),
         ModuleName = provenance.ModuleName.ToString(pathTable),
         SemiStableHash = provenance.SemiStableHash
     });
 }
示例#8
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="source">Path to copy from.</param>
        /// <param name="destination">Path to copy to.</param>
        /// <param name="tags">An optional array of tags to apply to the pip</param>
        /// <param name="provenance">Provenance of copy-file pip</param>
        /// <param name="options">Options for the copied file</param>
        public CopyFile(FileArtifact source, FileArtifact destination, ReadOnlyArray <StringId> tags, PipProvenance provenance, Options options = default(Options))
        {
            Contract.Requires(source.IsValid);
            Contract.Requires(destination.IsValid);
            Contract.Requires(tags.IsValid);
            Contract.Requires(provenance != null);

            Tags        = tags;
            Provenance  = provenance;
            Source      = source;
            Destination = destination;
            m_options   = options;
        }
        /// <nodoc/>
        public CompositeSharedOpaqueSealDirectory(
            AbsolutePath directoryRoot,
            IReadOnlyList <DirectoryArtifact> composedDirectories,
            PipProvenance provenance,
            ReadOnlyArray <StringId> tags)
            : base(
                directoryRoot,
                CollectionUtilities.EmptySortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer>(OrdinalFileArtifactComparer.Instance),
                SealDirectoryKind.SharedOpaque,
                provenance,
                tags,
                CollectionUtilities.EmptyArray <StringId>().ToReadOnlyArray())
        {
            Contract.Requires(composedDirectories != null);

            ComposedDirectories = composedDirectories;
        }
示例#10
0
        /// <summary>
        /// Constructs a WriteFile
        /// </summary>
        public WriteFile(
            FileArtifact destination,
            PipData contents,
            WriteFileEncoding encoding,
            ReadOnlyArray <StringId> tags,
            PipProvenance provenance)
        {
            Contract.Requires(destination.IsValid);
            Contract.Requires(contents.IsValid);
            Contract.Requires(tags.IsValid);
            Contract.Requires(provenance != null);

            Provenance  = provenance;
            Tags        = tags;
            Destination = destination;
            Contents    = contents;
            Encoding    = encoding;
        }
示例#11
0
        /// <nodoc />
        public IpcPip(
            IpcClientInfo ipcInfo,
            PipData arguments,
            FileArtifact outputFile,
            ReadOnlyArray <PipId> servicePipDependencies,
            ReadOnlyArray <FileArtifact> fileDependencies,
            ReadOnlyArray <DirectoryArtifact> directoryDependencies,
            ReadOnlyArray <FileOrDirectoryArtifact> skipMaterializationFor,
            ReadOnlyArray <StringId> tags,
            bool isServiceFinalization,
            bool mustRunOnMaster,
            PipProvenance provenance)
        {
            Contract.Requires(ipcInfo != null);
            Contract.Requires(arguments.IsValid);
            Contract.Requires(outputFile.IsValid);
            Contract.Requires(servicePipDependencies.IsValid);
            Contract.Requires(fileDependencies.IsValid);
            Contract.Requires(directoryDependencies.IsValid);
            Contract.Requires(skipMaterializationFor.IsValid);
            Contract.RequiresForAll(servicePipDependencies, dependency => dependency.IsValid);
            Contract.RequiresForAll(fileDependencies, dependency => dependency.IsValid);
            Contract.RequiresForAll(directoryDependencies, dependency => dependency.IsValid);

            IpcInfo                        = ipcInfo;
            MessageBody                    = arguments;
            OutputFile                     = outputFile;
            ServicePipDependencies         = servicePipDependencies;
            FileDependencies               = fileDependencies;
            LazilyMaterializedDependencies = skipMaterializationFor;
            Tags = tags;
            IsServiceFinalization = isServiceFinalization;
            MustRunOnMaster       = mustRunOnMaster;
            Provenance            = provenance;
            DirectoryDependencies = directoryDependencies;
        }
示例#12
0
 /// <summary>
 /// Clone and override select properties.
 /// </summary>
 public Process Override(
     FileArtifact?executable       = null,
     AbsolutePath?workingDirectory = null,
     PipData?arguments             = null,
     FileArtifact?responseFile     = null,
     PipData?responseFileData      = null,
     ReadOnlyArray <EnvironmentVariable>?environmentVariables = null,
     StandardInput?standardInput    = null,
     FileArtifact?standardOutput    = null,
     FileArtifact?standardError     = null,
     AbsolutePath?standardDirectory = null,
     TimeSpan?warningTimeout        = null,
     TimeSpan?timeout = null,
     ReadOnlyArray <FileArtifact>?dependencies = null,
     ReadOnlyArray <FileArtifactWithAttributes>?fileOutputs  = null,
     ReadOnlyArray <DirectoryArtifact>?directoryDependencies = null,
     ReadOnlyArray <DirectoryArtifact>?directoryOutputs      = null,
     ReadOnlyArray <PipId>?orderDependencies      = null,
     ReadOnlyArray <AbsolutePath>?untrackedPaths  = null,
     ReadOnlyArray <AbsolutePath>?untrackedScopes = null,
     ReadOnlyArray <StringId>?tags                   = null,
     ReadOnlyArray <int>?successExitCodes            = null,
     ReadOnlyArray <ProcessSemaphoreInfo>?semaphores = null,
     PipProvenance provenance = null,
     StringId?toolDescription = null,
     ReadOnlyArray <AbsolutePath>?additionalTempDirectories = null,
     RegexDescriptor?warningRegex         = null,
     RegexDescriptor?errorRegex           = null,
     AbsolutePath?uniqueOutputDirectory   = null,
     AbsolutePath?redirectedDirectoryRoot = null,
     AbsolutePath?tempDirectory           = null,
     Options?options                    = null,
     bool?testRetries                   = null,
     ServiceInfo serviceInfo            = null,
     ReadOnlyArray <int>?retryExitCodes = null,
     ReadOnlyArray <PathAtom>?allowedSurvivingChildProcessNames = null,
     TimeSpan?nestedProcessTerminationTimeout = null,
     AbsentPathProbeInUndeclaredOpaquesMode absentPathProbeMode = AbsentPathProbeInUndeclaredOpaquesMode.Unsafe,
     DoubleWritePolicy doubleWritePolicy             = DoubleWritePolicy.DoubleWritesAreErrors,
     ContainerIsolationLevel containerIsolationLevel = ContainerIsolationLevel.None)
 {
     return(new Process(
                executable ?? Executable,
                workingDirectory ?? WorkingDirectory,
                arguments ?? Arguments,
                responseFile ?? ResponseFile,
                responseFileData ?? ResponseFileData,
                environmentVariables ?? EnvironmentVariables,
                standardInput ?? StandardInput,
                standardOutput ?? StandardOutput,
                standardError ?? StandardError,
                standardDirectory ?? StandardDirectory,
                warningTimeout ?? WarningTimeout,
                timeout ?? Timeout,
                dependencies ?? Dependencies,
                fileOutputs ?? FileOutputs,
                directoryDependencies ?? DirectoryDependencies,
                directoryOutputs ?? DirectoryOutputs,
                orderDependencies ?? OrderDependencies,
                untrackedPaths ?? UntrackedPaths,
                untrackedScopes ?? UntrackedScopes,
                tags ?? Tags,
                successExitCodes ?? SuccessExitCodes,
                semaphores ?? Semaphores,
                provenance ?? Provenance,
                toolDescription ?? ToolDescription,
                additionalTempDirectories ?? AdditionalTempDirectories,
                warningRegex ?? WarningRegex,
                errorRegex ?? ErrorRegex,
                uniqueOutputDirectory ?? UniqueOutputDirectory,
                redirectedDirectoryRoot ?? UniqueRedirectedDirectoryRoot,
                tempDirectory ?? TempDirectory,
                options ?? ProcessOptions,
                testRetries ?? TestRetries,
                serviceInfo ?? ServiceInfo,
                retryExitCodes ?? RetryExitCodes,
                allowedSurvivingChildProcessNames,
                nestedProcessTerminationTimeout,
                absentPathProbeMode,
                doubleWritePolicy,
                containerIsolationLevel));
 }
示例#13
0
        /// <summary>
        /// Class constructor
        /// </summary>
        public Process(
            FileArtifact executable,
            AbsolutePath workingDirectory,
            PipData arguments,
            FileArtifact responseFile,
            PipData responseFileData,
            ReadOnlyArray <EnvironmentVariable> environmentVariables,
            StandardInput standardInput,
            FileArtifact standardOutput,
            FileArtifact standardError,
            AbsolutePath standardDirectory,
            TimeSpan?warningTimeout,
            TimeSpan?timeout,
            ReadOnlyArray <FileArtifact> dependencies,
            ReadOnlyArray <FileArtifactWithAttributes> outputs,
            ReadOnlyArray <DirectoryArtifact> directoryDependencies,
            ReadOnlyArray <DirectoryArtifact> directoryOutputs,
            ReadOnlyArray <PipId> orderDependencies,
            ReadOnlyArray <AbsolutePath> untrackedPaths,
            ReadOnlyArray <AbsolutePath> untrackedScopes,
            ReadOnlyArray <StringId> tags,
            ReadOnlyArray <int> successExitCodes,
            ReadOnlyArray <ProcessSemaphoreInfo> semaphores,
            PipProvenance provenance,
            StringId toolDescription,
            ReadOnlyArray <AbsolutePath> additionalTempDirectories,
            RegexDescriptor warningRegex               = default,
            RegexDescriptor errorRegex                 = default,
            AbsolutePath uniqueOutputDirectory         = default,
            AbsolutePath uniqueRedirectedDirectoryRoot = default,
            AbsolutePath tempDirectory                 = default,
            Options options                    = default,
            bool testRetries                   = false,
            ServiceInfo serviceInfo            = null,
            ReadOnlyArray <int>?retryExitCodes = null,
            ReadOnlyArray <PathAtom>?allowedSurvivingChildProcessNames = null,
            TimeSpan?nestedProcessTerminationTimeout = null,
            AbsentPathProbeInUndeclaredOpaquesMode absentPathProbeMode = AbsentPathProbeInUndeclaredOpaquesMode.Unsafe,
            DoubleWritePolicy doubleWritePolicy             = DoubleWritePolicy.DoubleWritesAreErrors,
            ContainerIsolationLevel containerIsolationLevel = ContainerIsolationLevel.None)
        {
            Contract.Requires(executable.IsValid);
            Contract.Requires(workingDirectory.IsValid);
            Contract.Requires(arguments.IsValid);
            Contract.RequiresForAll(environmentVariables, environmentVariable => environmentVariable.Name.IsValid);
            Contract.RequiresForAll(environmentVariables, environmentVariable => environmentVariable.Value.IsValid ^ environmentVariable.IsPassThrough);
            Contract.Requires(dependencies.IsValid);
            Contract.RequiresForAll(dependencies, dependency => dependency.IsValid);
            Contract.Requires(directoryDependencies.IsValid);
            Contract.RequiresForAll(directoryDependencies, directoryDependency => directoryDependency.IsValid);
            Contract.Requires(outputs.IsValid);
            Contract.RequiresForAll(outputs, output => output.IsValid);
            Contract.Requires(directoryOutputs.IsValid);
            Contract.RequiresForAll(outputs, output => !output.IsSourceFile);
            Contract.RequiresForAll(directoryOutputs, directoryOutput => directoryOutput.IsValid);
            Contract.Requires(orderDependencies.IsValid);
            Contract.RequiresForAll(orderDependencies, dependency => dependency != PipId.Invalid);
            Contract.Requires(untrackedPaths.IsValid);
            Contract.RequiresForAll(untrackedPaths, path => path.IsValid);
            Contract.Requires(untrackedScopes.IsValid);
            Contract.RequiresForAll(untrackedScopes, scope => scope.IsValid);
            Contract.Requires(!timeout.HasValue || timeout.Value <= MaxTimeout);
            Contract.Requires(standardDirectory.IsValid || (standardOutput.IsValid && standardError.IsValid));
            Contract.Requires(provenance != null);
            Contract.Requires(additionalTempDirectories.IsValid);
            Contract.RequiresForAll(additionalTempDirectories, path => path.IsValid);
            Contract.Requires(tags.IsValid);
            // If the process needs to run in a container, the redirected directory has to be set
            Contract.Requires((options & Options.NeedsToRunInContainer) == Options.None || uniqueRedirectedDirectoryRoot.IsValid);

#if DEBUG   // a little too expensive for release builds
            Contract.Requires(Contract.Exists(dependencies, d => d == executable), "The executable must be declared as a dependency");
            Contract.Requires(
                !standardInput.IsFile || Contract.Exists(dependencies, d => d == standardInput.File),
                "If provided, the standard-input artifact must be declared as a dependency");
            Contract.Requires(
                !standardOutput.IsValid || Contract.Exists(outputs, o => o.ToFileArtifact() == standardOutput),
                "If provided, the standard-error artifact must be declared as an expected output");
            Contract.Requires(
                !standardError.IsValid || Contract.Exists(outputs, o => o.ToFileArtifact() == standardError),
                "If provided, the standard-error artifact must be declared as an expected output");
            Contract.Requires(
                !responseFile.IsValid ^ responseFileData.IsValid,
                "If provided, the response-file artifact must have a corresponding ResponseFileData");

            Contract.Requires(outputs.Length == outputs.Distinct().Count());
            Contract.Requires(directoryOutputs.Length == directoryOutputs.Distinct().Count());
            Contract.Requires(dependencies.Length == dependencies.Distinct().Count());
            Contract.Requires(directoryDependencies.Length == directoryDependencies.Distinct().Count());
            Contract.Requires(untrackedPaths.Length == untrackedPaths.Distinct().Count());
            Contract.Requires(untrackedScopes.Length == untrackedScopes.Distinct().Count());
            Contract.Requires(additionalTempDirectories.Length == additionalTempDirectories.Distinct().Count());
            Contract.RequiresForAll(semaphores, s => s.IsValid);
            Contract.Requires(semaphores.Length == semaphores.Distinct().Count());
#endif

            Provenance        = provenance;
            Tags              = tags;
            Executable        = executable;
            ToolDescription   = toolDescription;
            WorkingDirectory  = workingDirectory;
            Arguments         = arguments;
            ResponseFile      = responseFile;
            ResponseFileData  = responseFileData;
            StandardOutput    = standardOutput;
            StandardError     = standardError;
            StandardInput     = standardInput;
            StandardDirectory = standardDirectory;
            WarningTimeout    = warningTimeout;
            Timeout           = timeout;

            // We allow any IEnumerable for these fields, but perform a copy up-front.
            // See the remarks of RemoveDuplicateFileArtifacts for why it is used on the input / output lists.
            Dependencies                                  = dependencies;
            DirectoryDependencies                         = directoryDependencies;
            FileOutputs                                   = outputs;
            DirectoryOutputs                              = directoryOutputs;
            OrderDependencies                             = orderDependencies;
            UntrackedPaths                                = untrackedPaths;
            UntrackedScopes                               = untrackedScopes;
            EnvironmentVariables                          = environmentVariables;
            SuccessExitCodes                              = successExitCodes;
            RetryExitCodes                                = retryExitCodes ?? ReadOnlyArray <int> .Empty;
            WarningRegex                                  = warningRegex;
            ErrorRegex                                    = errorRegex;
            UniqueOutputDirectory                         = uniqueOutputDirectory;
            UniqueRedirectedDirectoryRoot                 = uniqueRedirectedDirectoryRoot;
            Semaphores                                    = semaphores;
            TempDirectory                                 = tempDirectory;
            TestRetries                                   = testRetries;
            ServiceInfo                                   = serviceInfo;
            ProcessOptions                                = options;
            AdditionalTempDirectories                     = additionalTempDirectories;
            AllowedSurvivingChildProcessNames             = allowedSurvivingChildProcessNames ?? ReadOnlyArray <PathAtom> .Empty;
            NestedProcessTerminationTimeout               = nestedProcessTerminationTimeout;
            ProcessAbsentPathProbeInUndeclaredOpaquesMode = absentPathProbeMode;
            DoubleWritePolicy                             = doubleWritePolicy;
            ContainerIsolationLevel                       = containerIsolationLevel;
        }
示例#14
0
        /// <summary>
        /// Class constructor
        /// </summary>
        public Process(
            FileArtifact executable,
            AbsolutePath workingDirectory,
            PipData arguments,
            FileArtifact responseFile,
            PipData responseFileData,
            ReadOnlyArray <EnvironmentVariable> environmentVariables,
            StandardInput standardInput,
            FileArtifact standardOutput,
            FileArtifact standardError,
            AbsolutePath standardDirectory,
            TimeSpan?warningTimeout,
            TimeSpan?timeout,
            ReadOnlyArray <FileArtifact> dependencies,
            ReadOnlyArray <FileArtifactWithAttributes> outputs,
            ReadOnlyArray <DirectoryArtifact> directoryDependencies,
            ReadOnlyArray <DirectoryArtifact> directoryOutputs,
            ReadOnlyArray <PipId> orderDependencies,
            ReadOnlyArray <AbsolutePath> untrackedPaths,
            ReadOnlyArray <AbsolutePath> untrackedScopes,
            ReadOnlyArray <StringId> tags,
            ReadOnlyArray <int> successExitCodes,
            ReadOnlyArray <ProcessSemaphoreInfo> semaphores,
            PipProvenance provenance,
            StringId toolDescription,
            ReadOnlyArray <AbsolutePath> additionalTempDirectories,
            RegexDescriptor warningRegex       = default,
            RegexDescriptor errorRegex         = default,
            AbsolutePath uniqueOutputDirectory = default,
            AbsolutePath tempDirectory         = default,
            Options options                    = default,
            UnsafeOptions unsafeOptions        = default,
            bool testRetries                   = false,
            ReadOnlyArray <int>?retryExitCodes = null,
            ReadOnlyArray <PathAtom>?allowedSurvivingChildProcessNames = null,
            TimeSpan?nestedProcessTerminationTimeout = null)
        {
            Contract.Requires(executable.IsValid);
            Contract.Requires(workingDirectory.IsValid);
            Contract.Requires(arguments.IsValid);
            Contract.RequiresForAll(environmentVariables, environmentVariable => environmentVariable.Name.IsValid);
            Contract.RequiresForAll(environmentVariables, environmentVariable => environmentVariable.Value.IsValid ^ environmentVariable.IsPassThrough);
            Contract.Requires(dependencies.IsValid);
            Contract.RequiresForAll(dependencies, dependency => dependency.IsValid);
            Contract.Requires(directoryDependencies.IsValid);
            Contract.RequiresForAll(directoryDependencies, directoryDependency => directoryDependency.IsValid);
            Contract.Requires(outputs.IsValid);
            Contract.RequiresForAll(outputs, output => output.IsValid);
            Contract.Requires(directoryOutputs.IsValid);
            Contract.RequiresForAll(outputs, output => !output.IsSourceFile);
            Contract.RequiresForAll(directoryOutputs, directoryOutput => directoryOutput.IsValid);
            Contract.Requires(orderDependencies.IsValid);
            Contract.RequiresForAll(orderDependencies, dependency => dependency != PipId.Invalid);
            Contract.Requires(untrackedPaths.IsValid);
            Contract.RequiresForAll(untrackedPaths, path => path.IsValid);
            Contract.Requires(untrackedScopes.IsValid);
            Contract.RequiresForAll(untrackedScopes, scope => scope.IsValid);
            Contract.Requires(!timeout.HasValue || timeout.Value <= MaxTimeout);
            Contract.Requires(standardDirectory.IsValid || (standardOutput.IsValid && standardError.IsValid));
            Contract.Requires(provenance != null);
            Contract.Requires(additionalTempDirectories.IsValid);
            Contract.RequiresForAll(additionalTempDirectories, path => path.IsValid);
            Contract.Requires(tags.IsValid);

#if DEBUG   // a little too expensive for release builds
            Contract.Requires(Contract.Exists(dependencies, d => d == executable), "The executable must be declared as a dependency");
            Contract.Requires(
                !standardInput.IsFile || Contract.Exists(dependencies, d => d == standardInput.File),
                "If provided, the standard-input artifact must be declared as a dependency");
            Contract.Requires(
                !standardOutput.IsValid || Contract.Exists(outputs, o => o.ToFileArtifact() == standardOutput),
                "If provided, the standard-error artifact must be declared as an expected output");
            Contract.Requires(
                !standardError.IsValid || Contract.Exists(outputs, o => o.ToFileArtifact() == standardError),
                "If provided, the standard-error artifact must be declared as an expected output");
            Contract.Requires(
                !responseFile.IsValid ^ responseFileData.IsValid,
                "If provided, the response-file artifact must have a corresponding ResponseFileData");

            Contract.Requires(outputs.Length == outputs.Distinct().Count());
            Contract.Requires(directoryOutputs.Length == directoryOutputs.Distinct().Count());
            Contract.Requires(dependencies.Length == dependencies.Distinct().Count());
            Contract.Requires(directoryDependencies.Length == directoryDependencies.Distinct().Count());
            Contract.Requires(untrackedPaths.Length == untrackedPaths.Distinct().Count());
            Contract.Requires(untrackedScopes.Length == untrackedScopes.Distinct().Count());
            Contract.Requires(additionalTempDirectories.Length == additionalTempDirectories.Distinct().Count());
            Contract.RequiresForAll(semaphores, s => s.IsValid);
            Contract.Requires(semaphores.Length == semaphores.Distinct().Count());
#endif

            Provenance        = provenance;
            Tags              = tags;
            Executable        = executable;
            ToolDescription   = toolDescription;
            WorkingDirectory  = workingDirectory;
            Arguments         = arguments;
            ResponseFile      = responseFile;
            ResponseFileData  = responseFileData;
            StandardOutput    = standardOutput;
            StandardError     = standardError;
            StandardInput     = standardInput;
            StandardDirectory = standardDirectory;
            WarningTimeout    = warningTimeout;
            Timeout           = timeout;

            // We allow any IEnumerable for these fields, but perform a copy up-front. Transformer implementations
            // may be calling this constructor, and we should exhaust their computation up front (yield,
            // LINQ, custom collections, etc. are all valid).
            // See the remarks of RemoveDuplicateFileArtifacts for why it is used on the input / output lists.
            Dependencies                      = dependencies;
            DirectoryDependencies             = directoryDependencies;
            FileOutputs                       = outputs;
            DirectoryOutputs                  = directoryOutputs;
            OrderDependencies                 = orderDependencies;
            UntrackedPaths                    = untrackedPaths;
            UntrackedScopes                   = untrackedScopes;
            EnvironmentVariables              = environmentVariables;
            SuccessExitCodes                  = successExitCodes;
            RetryExitCodes                    = retryExitCodes ?? ReadOnlyArray <int> .Empty;
            WarningRegex                      = warningRegex;
            ErrorRegex                        = errorRegex;
            UniqueOutputDirectory             = uniqueOutputDirectory;
            Semaphores                        = semaphores;
            TempDirectory                     = tempDirectory;
            TestRetries                       = testRetries;
            ProcessOptions                    = options;
            ProcessUnsafeOptions              = unsafeOptions;
            AdditionalTempDirectories         = additionalTempDirectories;
            AllowedSurvivingChildProcessNames = allowedSurvivingChildProcessNames ?? ReadOnlyArray <PathAtom> .Empty;
            NestedProcessTerminationTimeout   = nestedProcessTerminationTimeout;
        }