/// <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;
        }
        /// <nodoc/>
        public bool TryComposeSharedOpaqueDirectory(
            AbsolutePath directoryRoot,
            IReadOnlyList <DirectoryArtifact> contents,
            SealDirectoryCompositionActionKind actionKind,
            SealDirectoryContentFilter?contentFilter,
            [CanBeNull] string description,
            [CanBeNull] string[] tags,
            out DirectoryArtifact sharedOpaqueDirectory)
        {
            Contract.Requires(directoryRoot.IsValid);
            Contract.Requires(contents != null);
            Contract.Requires(actionKind.IsComposite());

            if (PipGraph == null)
            {
                sharedOpaqueDirectory = DirectoryArtifact.CreateWithZeroPartialSealId(directoryRoot);
                return(true);
            }

            PipData usage = PipDataBuilder.CreatePipData(Context.StringTable, string.Empty, PipDataFragmentEscaping.NoEscaping, description != null
                ? new PipDataAtom[] { description }
                : generatePipDescription());

            sharedOpaqueDirectory = PipGraph.ReserveSharedOpaqueDirectory(directoryRoot);

            var pip = new CompositeSharedOpaqueSealDirectory(
                directoryRoot,
                contents,
                CreatePipProvenance(usage),
                ToStringIds(tags),
                contentFilter,
                actionKind);

            // The seal directory is ready to be initialized, since the directory artifact has been reserved already
            pip.SetDirectoryArtifact(sharedOpaqueDirectory);

            sharedOpaqueDirectory = PipGraph.AddSealDirectory(pip, GetValuePipId());
            if (!sharedOpaqueDirectory.IsValid)
            {
                return(false);
            }

            return(true);

            PipDataAtom[] generatePipDescription()
            {
                switch (actionKind)
                {
                case SealDirectoryCompositionActionKind.WidenDirectoryCone:
                    return(new PipDataAtom[] {
                        "'", directoryRoot, "' [", contents.Count.ToString(CultureInfo.InvariantCulture), " shared opaque directories, filter: ",
                        contentFilter.HasValue ? $"'{contentFilter.Value.Regex}' (kind: {Enum.GetName(typeof(SealDirectoryContentFilter.ContentFilterKind), contentFilter.Value.Kind)})" : "''",
                        "]"
                    });

                case SealDirectoryCompositionActionKind.NarrowDirectoryCone:
                    return(new PipDataAtom[] {
                        "'", directoryRoot, "' [ subdirectory of a shared opaque '", contents.FirstOrDefault().ToString(), "', filter: ",
                        contentFilter.HasValue ? $"'{contentFilter.Value.Regex}' (kind: {Enum.GetName(typeof(SealDirectoryContentFilter.ContentFilterKind), contentFilter.Value.Kind)})" : "''",
                        "]"
                    });

                default:
                    throw new Exception($"Cannot create description for a CompositeSharedOpaqueSealDirectory with action kind {actionKind}");
                }
            }
        }
 /// <summary>
 /// Whether an action describes a composite shared opaque seal directory
 /// </summary>
 public static bool IsComposite(this SealDirectoryCompositionActionKind actionKind) => actionKind != SealDirectoryCompositionActionKind.None;