예제 #1
0
        /// <summary>
        /// Some validations and operations require knowledge of whether a mount is nested under another mount.
        /// </summary>
        /// <returns>true if the operations were performed successfully</returns>
        private bool AddAndPerformNestingOperations()
        {
            bool success = true;

            // flip alternative roots -> mount map for easier lookup
            var alternativeRoots = m_alternativeRoots.ToMultiValueDictionary(kvp => kvp.Value, kvp => kvp.Key);

            // Compute the depth of each mount root so parent mounts can be visited first
            List <KeyValuePair <int, IMount> > mountsByRootDepth = new List <KeyValuePair <int, IMount> >();

            foreach (IMount mount in m_mountMapBuilder.Values)
            {
                int          depth = 0;
                AbsolutePath path  = mount.Path;
                while (path.IsValid)
                {
                    path = path.GetParent(m_context.PathTable);
                    depth++;
                }

                mountsByRootDepth.Add(new KeyValuePair <int, IMount>(depth, mount));
            }

            mountsByRootDepth.Sort((depthAndMount1, depthAndMount2) => depthAndMount1.Key.CompareTo(depthAndMount2.Key));

            foreach (var mountEntry in mountsByRootDepth)
            {
                var childMount      = mountEntry.Value;
                var parentMountInfo = MountPathExpander.GetSemanticPathInfo(childMount.Path);
                if (parentMountInfo.IsValid)
                {
                    IMount parentMount;
                    if (!m_mountMapBuilder.TryGetValue(parentMountInfo.Root, out parentMount) && m_parent != null)
                    {
                        parentMount = m_parent.m_mountMapBuilder[parentMountInfo.Root];
                    }

                    if (parentMount.IsScrubbable && !childMount.IsScrubbable)
                    {
                        LogRelatedMountError(
                            Logger.Log.ScrubbableMountsMayOnlyContainScrubbableMounts,
                            childMount: childMount,
                            parentMount: parentMount);
                        success = false;
                    }
                }

                // TODO: Does not adding on success == false change behavior
                if (success)
                {
                    MountPathExpander.Add(m_context.PathTable, childMount);

                    if (alternativeRoots.TryGetValue(childMount, out var additionalRoots))
                    {
                        foreach (var root in additionalRoots)
                        {
                            MountPathExpander.AddWithExistingName(
                                m_context.PathTable,
                                new SemanticPathInfo(childMount.Name, root, childMount.TrackSourceFileChanges, childMount.IsReadable, childMount.IsWritable, childMount.IsSystem, childMount.IsScrubbable, childMount.AllowCreateDirectory));
                        }
                    }
                }
            }

            return(success);
        }
예제 #2
0
        /// <summary>
        /// Some validations and operations require knowledge of whether a mount is nested under another mount.
        /// </summary>
        /// <returns>true if the operations were performed successfully</returns>
        private bool AddAndPerformNestingOperations()
        {
            bool success = true;

            // flip alternative roots -> mount map for easier lookup
            var alternativeRoots = m_alternativeRoots.ToMultiValueDictionary(kvp => kvp.Value, kvp => kvp.Key);

            // Collect here the mount roots of tokenizable mounts. The logic is:
            // * System mounts are tokenizable.
            // * Mounts that are descendants of a system mount are tokenizable
            // Rationale: We don't tokenize all mounts because that can lead to incorrect fingerprinting. E.g. let's say a tool writes
            // a path P in an output file, P is a descendant of a tokenized mount root M and the corresponding pip gets cached.
            // If the pip is looked up on a machine where M is a different root M', then we can get a cache hit, whereas it should have been
            // a miss because the tool would have produced an output file with a written path P'
            // As a compromise solution, system mounts are deemed safe enough to tokenize because they tend to be stable enough and it is unlikely
            // that tools embed system-related paths in produced files. Transitively, any non-system mount that has a
            // system mount above should be equally safe.
            var tokenizableMountRoots = new HashSet <AbsolutePath>();

            // All system mount paths
            var systemMounts = m_mountPathIdentifiersByMount.Keys.Where(mount => mount.IsSystem && mount.Path.IsValid).Select(mount => mount.Path).ToHashSet();

            // Compute the depth of each mount root so parent mounts can be visited first
            // As we go upwards, also verify if there is any parent mount that is a system one
            List <KeyValuePair <int, IMount> > mountsByRootDepth = new List <KeyValuePair <int, IMount> >();

            foreach (IMount mount in m_mountMapBuilder.Values)
            {
                int          depth = 0;
                AbsolutePath path  = mount.Path;

                while (path.IsValid)
                {
                    // if a mount is defined in the same location of a system mount, or has a system mount somewhere above, then it is also tokenizable
                    if (systemMounts.Contains(path))
                    {
                        tokenizableMountRoots.Add(mount.Path);
                    }

                    path = path.GetParent(m_context.PathTable);
                    depth++;
                }

                mountsByRootDepth.Add(new KeyValuePair <int, IMount>(depth, mount));
            }

            mountsByRootDepth.Sort((depthAndMount1, depthAndMount2) => depthAndMount1.Key.CompareTo(depthAndMount2.Key));

            foreach (var mountEntry in mountsByRootDepth)
            {
                var childMount      = mountEntry.Value;
                var parentMountInfo = MountPathExpander.GetSemanticPathInfo(childMount.Path);
                if (parentMountInfo.IsValid)
                {
                    IMount parentMount;
                    if (!m_mountMapBuilder.TryGetValue(parentMountInfo.Root, out parentMount) && m_parent != null)
                    {
                        parentMount = m_parent.m_mountMapBuilder[parentMountInfo.Root];
                    }

                    if (parentMount.IsScrubbable && !childMount.IsScrubbable)
                    {
                        LogRelatedMountError(
                            Logger.Log.ScrubbableMountsMayOnlyContainScrubbableMounts,
                            childMount: childMount,
                            parentMount: parentMount);
                        success = false;
                    }
                }

                // TODO: Does not adding on success == false change behavior
                if (success)
                {
                    MountPathExpander.Add(m_context.PathTable, childMount, isTokenizable: tokenizableMountRoots.Contains(childMount.Path));

                    if (alternativeRoots.TryGetValue(childMount, out var additionalRoots))
                    {
                        foreach (var root in additionalRoots)
                        {
                            MountPathExpander.AddWithExistingName(
                                m_context.PathTable,
                                new SemanticPathInfo(
                                    childMount.Name,
                                    root,
                                    childMount.TrackSourceFileChanges,
                                    childMount.IsReadable,
                                    childMount.IsWritable,
                                    childMount.IsSystem,
                                    childMount.IsStatic,
                                    childMount.IsScrubbable,
                                    childMount.AllowCreateDirectory,
                                    tokenizable: tokenizableMountRoots.Contains(root)));
                        }
                    }
                }
            }

            return(success);
        }