예제 #1
0
        /// <summary>
        /// Returns all projects that the actual selector in the discriminating union specifies
        /// </summary>
        public bool TryGetMatches(DiscriminatingUnion <string, IJavaScriptProjectSimpleSelector, IJavaScriptProjectRegexSelector> selector, out IReadOnlyCollection <JavaScriptProject> matches, out string failure)
        {
            failure = string.Empty;
            switch (selector.GetValue())
            {
            case string s:
                matches = GetMatches(s);
                return(true);

            case IJavaScriptProjectSimpleSelector simpleSelector:
                matches = GetMatches(simpleSelector);
                return(true);

            case IJavaScriptProjectRegexSelector regexSelector:
                try
                {
                    matches = GetMatches(regexSelector);
                }
                catch (ArgumentException e)
                {
                    matches = CollectionUtilities.EmptyArray <JavaScriptProject>();
                    failure = e.Message;
                    return(false);
                }

                return(true);

            default:
                Contract.Assert(false, $"Unexpected type {selector.GetValue().GetType()}");
                matches = CollectionUtilities.EmptyArray <JavaScriptProject>();
                return(false);
            }
        }
예제 #2
0
        private static DiscriminatingUnion <AbsolutePath, IInlineModuleDefinition> RemapModule(
            DiscriminatingUnion <AbsolutePath, IInlineModuleDefinition> fileOrInlineModule,
            PathRemapper pathRemapper)
        {
            var fileOrInlineModuleValue = fileOrInlineModule?.GetValue();

            if (fileOrInlineModuleValue == null)
            {
                return(null);
            }

            if (fileOrInlineModuleValue is AbsolutePath path)
            {
                return(new DiscriminatingUnion <AbsolutePath, IInlineModuleDefinition>(pathRemapper.Remap(path)));
            }

            var inlineModuleDefinition = (IInlineModuleDefinition)fileOrInlineModuleValue;

            var remappedInlineModuleDefinition = new InlineModuleDefinition
            {
                ModuleName = inlineModuleDefinition.ModuleName,
                Projects   = inlineModuleDefinition.Projects?.Select(project => pathRemapper.Remap(project)).ToList()
            };

            return(new DiscriminatingUnion <AbsolutePath, IInlineModuleDefinition>(remappedInlineModuleDefinition));
        }
예제 #3
0
        private bool ValidateProjectSelector(DiscriminatingUnion <string, IJavaScriptProjectSimpleSelector, IJavaScriptProjectRegexSelector> selector, string pathToFile, string provenance)
        {
            object projectValue = selector.GetValue();

            switch (projectValue)
            {
            case string packageName:
            {
                if (string.IsNullOrEmpty(packageName))
                {
                    Tracing.Logger.Log.InvalidResolverSettings(Context.LoggingContext, Location.FromFile(pathToFile), $"Package name for {provenance} must be defined.");
                    return(false);
                }

                break;
            }

            case IJavaScriptProjectSimpleSelector simpleSelector:
            {
                if (string.IsNullOrEmpty(simpleSelector.PackageName))
                {
                    Tracing.Logger.Log.InvalidResolverSettings(Context.LoggingContext, Location.FromFile(pathToFile), $"Package name for {provenance} must be defined.");
                    return(false);
                }

                if (simpleSelector.Commands == null)
                {
                    Tracing.Logger.Log.InvalidResolverSettings(Context.LoggingContext, Location.FromFile(pathToFile), $"Commands for {provenance} must be defined.");
                    return(false);
                }

                foreach (var command in simpleSelector.Commands)
                {
                    if (string.IsNullOrEmpty(command))
                    {
                        Tracing.Logger.Log.InvalidResolverSettings(Context.LoggingContext, Location.FromFile(pathToFile), $"Command name for {provenance} must be defined.");
                        return(false);
                    }
                }
                break;
            }

            case IJavaScriptProjectRegexSelector regexSelector:
            {
                if (string.IsNullOrEmpty(regexSelector.PackageNameRegex))
                {
                    Tracing.Logger.Log.InvalidResolverSettings(Context.LoggingContext, Location.FromFile(pathToFile), $"Package name regular expression for {provenance} must be defined.");
                    return(false);
                }

                break;
            }
            }

            return(true);
        }
예제 #4
0
        private static DirectoryArtifact ResolveAbsoluteOrRelativeDirectory(PathTable pathTable, DiscriminatingUnion <DirectoryArtifact, RelativePath> absoluteOrRelativeUnion, AbsolutePath root)
        {
            var absoluteOrRelative = absoluteOrRelativeUnion.GetValue();

            if (absoluteOrRelative is DirectoryArtifact directory)
            {
                return(directory);
            }

            var relative = (RelativePath)absoluteOrRelative;

            if (!relative.IsValid)
            {
                return(DirectoryArtifact.Invalid);
            }

            return(DirectoryArtifact.CreateWithZeroPartialSealId(root.Combine(pathTable, relative)));
        }
        /// <nodoc />
        public void Serialize(BuildXLWriter writer)
        {
            Contract.Requires(writer != null);

            WriteState(writer);
            object executableValue = Executable.GetValue();

            if (executableValue is AbsolutePath absolutePath)
            {
                writer.Write(true);
                writer.Write(absolutePath);
            }
            else if (executableValue is PathAtom pathAtom)
            {
                writer.Write(false);
                writer.Write(pathAtom);
            }
        }
예제 #6
0
        /// <nodoc />
        public DiscriminatingUnion <FileArtifact, IReadOnlyList <DirectoryArtifact> > Remap(DiscriminatingUnion <FileArtifact, IReadOnlyList <DirectoryArtifact> > fileUnion)
        {
            DiscriminatingUnion <FileArtifact, IReadOnlyList <DirectoryArtifact> > remappedPath = null;

            if (fileUnion != null)
            {
                var fileValue = fileUnion.GetValue();
                remappedPath = new DiscriminatingUnion <FileArtifact, IReadOnlyList <DirectoryArtifact> >();

                if (fileValue is FileArtifact file)
                {
                    remappedPath.SetValue(Remap(file));
                }
                else if (fileValue is IReadOnlyList <DirectoryArtifact> searchDirectories)
                {
                    remappedPath.SetValue(Remap(searchDirectories));
                }
            }

            return(remappedPath);
        }
예제 #7
0
        /// <nodoc />
        public DiscriminatingUnion <FileArtifact, PathAtom> Remap(DiscriminatingUnion <FileArtifact, PathAtom> fileUnion)
        {
            DiscriminatingUnion <FileArtifact, PathAtom> remappedPath = null;

            if (fileUnion != null)
            {
                var fileValue = fileUnion.GetValue();
                remappedPath = new DiscriminatingUnion <FileArtifact, PathAtom>();

                if (fileValue is FileArtifact file)
                {
                    remappedPath.SetValue(Remap(file));
                }
                else if (fileValue is PathAtom pathAtom)
                {
                    remappedPath.SetValue(Remap(pathAtom));
                }
            }

            return(remappedPath);
        }
        public async Task TestSerialization()
        {
            var context = BuildXLContext.CreateInstanceForTesting();

            var pathTable   = context.PathTable;
            var stringTable = context.StringTable;
            var symbolTable = new SymbolTable(pathTable.StringTable);
            var allowlist   = new FileAccessAllowlist(context);

            //Allowlist with full paths
            var path1            = new DiscriminatingUnion <AbsolutePath, PathAtom>(AbsolutePath.Create(pathTable, @"\\fakePath\foo.txt"));
            var path2            = new DiscriminatingUnion <AbsolutePath, PathAtom>(AbsolutePath.Create(pathTable, @"\\fakePath\bar.txt"));
            var regex1           = new SerializableRegex(@"dir\foo.txt");
            var executableEntry1 = new ExecutablePathAllowlistEntry(
                path1, regex1, true, "entry1");
            var executableEntry2 = new ExecutablePathAllowlistEntry(
                path2, new SerializableRegex("bar"), false, "entry2");

            allowlist.Add(executableEntry1);
            allowlist.Add(executableEntry2);

            // Allowlist with executable names only
            var path3            = new DiscriminatingUnion <AbsolutePath, PathAtom>(PathAtom.Create(stringTable, "alice.txt"));
            var path4            = new DiscriminatingUnion <AbsolutePath, PathAtom>(PathAtom.Create(stringTable, "bob.txt"));
            var regex3           = new SerializableRegex(@"dir\alice.txt");
            var executableEntry3 = new ExecutablePathAllowlistEntry(
                path3, regex3, true, "entry5");
            var executableEntry4 = new ExecutablePathAllowlistEntry(
                path4, new SerializableRegex("bob"), false, "entry6");

            allowlist.Add(executableEntry3);
            allowlist.Add(executableEntry4);

            var symbol1    = FullSymbol.Create(symbolTable, "symbol1");
            var valueEntry = new ValuePathFileAccessAllowlistEntry(
                symbol1, new SerializableRegex("symbol1"), false, null);

            var symbol2     = FullSymbol.Create(symbolTable, "symbol2");
            var valueEntry2 = new ValuePathFileAccessAllowlistEntry(
                symbol2, new SerializableRegex("symbol2"), false, "entry4");

            allowlist.Add(valueEntry);
            allowlist.Add(valueEntry2);

            XAssert.AreEqual(4, allowlist.UncacheableEntryCount);
            XAssert.AreEqual(2, allowlist.CacheableEntryCount);
            XAssert.AreEqual("Unnamed", valueEntry.Name);

            using (var ms = new MemoryStream())
            {
                BuildXLWriter writer = new BuildXLWriter(true, ms, true, true);
                allowlist.Serialize(writer);

                ms.Position = 0;
                BuildXLReader reader       = new BuildXLReader(true, ms, true);
                var           deserialized = await FileAccessAllowlist.DeserializeAsync(reader, Task.FromResult <PipExecutionContext>(context));

                var path1Absolute = (AbsolutePath)path1.GetValue();
                var path2Absolute = (AbsolutePath)path2.GetValue();
                var path3Atom     = ((PathAtom)path3.GetValue()).StringId;
                var path4Atom     = ((PathAtom)path4.GetValue()).StringId;

                XAssert.AreEqual(2, deserialized.ExecutablePathEntries.Count);
                XAssert.AreEqual(1, deserialized.ExecutablePathEntries[path1Absolute].Count);
                XAssert.AreEqual(true, deserialized.ExecutablePathEntries[path1Absolute][0].AllowsCaching);
                XAssert.AreEqual(regex1.ToString(), deserialized.ExecutablePathEntries[path1Absolute][0].PathRegex.ToString());
                XAssert.AreEqual(executableEntry1.Name, deserialized.ExecutablePathEntries[path1Absolute][0].Name);
                XAssert.AreEqual(executableEntry2.Name, deserialized.ExecutablePathEntries[path2Absolute][0].Name);

                XAssert.AreEqual(2, deserialized.ToolExecutableNameEntries.Count);
                XAssert.AreEqual(1, deserialized.ToolExecutableNameEntries[path3Atom].Count);
                XAssert.AreEqual(true, deserialized.ToolExecutableNameEntries[path3Atom][0].AllowsCaching);
                XAssert.AreEqual(regex3.ToString(), deserialized.ToolExecutableNameEntries[path3Atom][0].PathRegex.ToString());
                XAssert.AreEqual(executableEntry3.Name, deserialized.ToolExecutableNameEntries[path3Atom][0].Name);
                XAssert.AreEqual(executableEntry4.Name, deserialized.ToolExecutableNameEntries[path4Atom][0].Name);

                XAssert.AreEqual(2, deserialized.ValuePathEntries.Count);
                XAssert.AreEqual(1, deserialized.ValuePathEntries[symbol1].Count);
                XAssert.AreEqual(false, deserialized.ValuePathEntries[symbol1][0].AllowsCaching);
                XAssert.AreEqual(valueEntry.Name, deserialized.ValuePathEntries[symbol1][0].Name);
                XAssert.AreEqual(valueEntry2.Name, deserialized.ValuePathEntries[symbol2][0].Name);

                XAssert.AreEqual(4, deserialized.UncacheableEntryCount);
                XAssert.AreEqual(2, deserialized.CacheableEntryCount);
            }
        }
예제 #9
0
        private static bool ComputeCommands(
            LoggingContext context,
            Location location,
            IReadOnlyList<DiscriminatingUnion<string, IJavaScriptCommand>> commands,
            out IReadOnlyDictionary<string, IReadOnlyList<IJavaScriptCommandDependency>> resultingCommands)
        {
            if (commands == null)
            {
                // If not defined, the default is ["build"]
                commands = new[] { new DiscriminatingUnion<string, IJavaScriptCommand>("build") };
            }

            var computedCommands = new Dictionary<string, IReadOnlyList<IJavaScriptCommandDependency>>(commands.Count);
            resultingCommands = computedCommands;

            for (int i = 0; i < commands.Count; i++)
            {
                DiscriminatingUnion<string, IJavaScriptCommand> command = commands[i];
                string commandName = command.GetCommandName();

                if (string.IsNullOrEmpty(commandName))
                {
                    Tracing.Logger.Log.JavaScriptCommandIsEmpty(context, location);
                    return false;
                }

                if (computedCommands.ContainsKey(commandName))
                {
                    Tracing.Logger.Log.JavaScriptCommandIsDuplicated(context, location, commandName);
                    return false;
                }

                if (command.GetValue() is string simpleCommand)
                {
                    // A simple string command first on the list means depending on the same command of all its dependencies.
                    // Canonical example: 'build'
                    if (i == 0)
                    {
                        computedCommands.Add(
                            simpleCommand,
                            new[] { new JavaScriptCommandDependency { Command = simpleCommand, Kind = JavaScriptCommandDependency.Package } });
                    }
                    else
                    {
                        // A simple string command that is not first in the list means depending on the immediate predecesor in the list
                        // Canonical example: 'build', 'test'
                        computedCommands.Add(
                            simpleCommand,
                            new[] { new JavaScriptCommandDependency { Command = commands[i - 1].GetCommandName(), Kind = JavaScriptCommandDependency.Local } });
                    }
                }
                else
                {
                    // Otherwise if a full fledge command is specified, then we honor it as is
                    var javaScriptCommand = (IJavaScriptCommand)command.GetValue();
                    computedCommands.Add(commandName, javaScriptCommand.DependsOn);
                }
            }

            return true;
        }
예제 #10
0
        private static bool ComputeCommands(
            LoggingContext context,
            Location location,
            IReadOnlyList <DiscriminatingUnion <string, IJavaScriptCommand, IJavaScriptCommandGroupWithDependencies, IJavaScriptCommandGroup> > commands,
            out IReadOnlyDictionary <string, IReadOnlyList <IJavaScriptCommandDependency> > resultingCommands,
            out IReadOnlyDictionary <string, IReadOnlyList <string> > resultingCommandGroups)
        {
            if (commands == null)
            {
                // If not defined, the default is ["build"]
                commands = new[] { new DiscriminatingUnion <string, IJavaScriptCommand, IJavaScriptCommandGroupWithDependencies, IJavaScriptCommandGroup>("build") };
            }

            var computedCommands = new Dictionary <string, IReadOnlyList <IJavaScriptCommandDependency> >(commands.Count);

            resultingCommands = computedCommands;
            var commandGroups = new Dictionary <string, IReadOnlyList <string> >();

            resultingCommandGroups = commandGroups;

            for (int i = 0; i < commands.Count; i++)
            {
                DiscriminatingUnion <string, IJavaScriptCommand, IJavaScriptCommandGroupWithDependencies, IJavaScriptCommandGroup> command = commands[i];
                string commandName = command.GetCommandName();

                if (string.IsNullOrEmpty(commandName))
                {
                    Tracing.Logger.Log.JavaScriptCommandIsEmpty(context, location);
                    return(false);
                }

                if (computedCommands.ContainsKey(commandName))
                {
                    Tracing.Logger.Log.JavaScriptCommandIsDuplicated(context, location, commandName);
                    return(false);
                }

                object commandValue = command.GetValue();
                if (commandValue is string simpleCommand)
                {
                    // A simple string command first on the list means depending on the same command of all its dependencies.
                    // Canonical example: 'build'
                    if (i == 0)
                    {
                        computedCommands.Add(
                            simpleCommand,
                            new[] { new JavaScriptCommandDependency {
                                        Command = simpleCommand, Kind = JavaScriptCommandDependency.Package
                                    } });
                    }
                    else
                    {
                        // A simple string command that is not first in the list means depending on the immediate predecesor in the list
                        // Canonical example: 'build', 'test'
                        computedCommands.Add(
                            simpleCommand,
                            new[] { new JavaScriptCommandDependency {
                                        Command = commands[i - 1].GetCommandName(), Kind = JavaScriptCommandDependency.Local
                                    } });
                    }
                }
                else
                {
                    // Otherwise if a full fledge command is specified, we honor it as is

                    // The command may specify dependencies, in which case we add it to the map
                    // of computed commands. Cases like the Lage resolver explicitly don't expose
                    // commands with dependencies since it is Lage the one that defines them
                    if (commandValue is IJavaScriptCommandWithDependencies commandWithDependencies)
                    {
                        computedCommands.Add(commandName, commandWithDependencies.DependsOn);
                    }

                    // Deal with the case of group commands
                    if (commandValue is IJavaScriptCommandGroup commandGroup)
                    {
                        var emptyCommands = commandGroup.Commands.Where(command => string.IsNullOrEmpty(command));
                        if (emptyCommands.Any())
                        {
                            Tracing.Logger.Log.JavaScriptCommandIsEmpty(context, location);
                            return(false);
                        }

                        // Check that command members cannot be groups commands as well
                        var dup = commandGroup.Commands.FirstOrDefault(command => computedCommands.ContainsKey(command));
                        if (dup != default)
                        {
                            Tracing.Logger.Log.JavaScriptCommandGroupCanOnlyContainRegularCommands(context, location, commandGroup.CommandName, dup);
                            return(false);
                        }

                        commandGroups.Add(commandGroup.CommandName, commandGroup.Commands);
                    }
                }
            }

            return(true);
        }