Beispiel #1
0
        /// <summary>
        /// Helper function to build a simple project based on a particular change wave being set.
        /// Call SetChangeWave on your TestEnvironment before calling this function.
        /// </summary>
        /// <param name="testEnvironment">The TestEnvironment being used for this test.</param>
        /// <param name="versionToCheckAgainstCurrentChangeWave">The version to compare to the current set Change Wave.</param>
        /// <param name="currentChangeWaveShouldUltimatelyResolveTo">What the project property for the environment variable MSBuildDisableFeaturesFromVersion ultimately resolves to.</param>
        /// <param name="warningCodesLogShouldContain">An array of warning codes that should exist in the resulting log. Ex: "MSB4271".</param>
        private void buildSimpleProjectAndValidateChangeWave(TestEnvironment testEnvironment, Version versionToCheckAgainstCurrentChangeWave, Version currentChangeWaveShouldUltimatelyResolveTo, params string[] warningCodesLogShouldContain)
        {
            bool isThisWaveEnabled = versionToCheckAgainstCurrentChangeWave < currentChangeWaveShouldUltimatelyResolveTo || currentChangeWaveShouldUltimatelyResolveTo == ChangeWaves.EnableAllFeatures;

            ChangeWaves.AreFeaturesEnabled(versionToCheckAgainstCurrentChangeWave).ShouldBe(isThisWaveEnabled);

            string projectFile = $"" +
                                 $"<Project>" +
                                 $"<Target Name='HelloWorld' Condition=\"$([MSBuild]::AreFeaturesEnabled('{versionToCheckAgainstCurrentChangeWave}')) and '$(MSBUILDDISABLEFEATURESFROMVERSION)' == '{currentChangeWaveShouldUltimatelyResolveTo}'\">" +
                                 $"<Message Text='Hello World!'/>" +
                                 $"</Target>" +
                                 $"</Project>";

            TransientTestFile file = testEnvironment.CreateFile("proj.csproj", projectFile);

            ProjectCollection collection = new ProjectCollection();
            MockLogger        log        = new MockLogger(_output);

            collection.RegisterLogger(log);

            Project p = collection.LoadProject(file.Path);

            p.Build().ShouldBeTrue();

            log.FullLog.Contains("Hello World!").ShouldBe(isThisWaveEnabled);

            if (warningCodesLogShouldContain != null)
            {
                log.WarningCount.ShouldBe(warningCodesLogShouldContain.Length);
                log.AssertLogContains(warningCodesLogShouldContain);
            }

            ChangeWaves.ResetStateForTests();
        }
Beispiel #2
0
        public void VersionTooHighClampsToHighestVersionInRotation(string disableFromWave)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                env.SetChangeWave(disableFromWave);
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                // all waves but the highest should pass
                for (int i = 0; i < ChangeWaves.AllWaves.Length - 1; i++)
                {
                    ChangeWaves.ResetStateForTests();
                    string projectFile = $"" +
                                         $"<Project>" +
                                         $"<Target Name='HelloWorld' Condition=\"'$(MSBUILDDISABLEFEATURESFROMVERSION)' == '{ChangeWaves.HighestWave}' and $([MSBuild]::AreFeaturesEnabled('{ChangeWaves.AllWaves[i]}'))\">" +
                                         $"<Message Text='Hello World!'/>" +
                                         $"</Target>" +
                                         $"</Project>";

                    TransientTestFile file = env.CreateFile("proj.csproj", projectFile);

                    ProjectCollection collection = new ProjectCollection();
                    MockLogger        log        = new MockLogger();
                    collection.RegisterLogger(log);

                    Project p = collection.LoadProject(file.Path);
                    p.Build().ShouldBeTrue();

                    BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                    log.WarningCount.ShouldBe(1);
                    log.AssertLogContains("out of rotation");
                    log.AssertLogContains("Hello World!");
                }
            }
        }
Beispiel #3
0
        public void TargetPathAlreadySet_DisabledUnderChangeWave16_10(string targetPath)
        {
            using TestEnvironment env = TestEnvironment.Create();
            string link = "c:/some/path";

            ChangeWaves.ResetStateForTests();
            env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave16_10.ToString());
            BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

            AssignTargetPath t = new AssignTargetPath();

            t.BuildEngine = new MockEngine();
            Dictionary <string, string> metaData = new Dictionary <string, string>();

            metaData.Add("TargetPath", targetPath);
            metaData.Add("Link", link);
            t.Files = new ITaskItem[]
            {
                new TaskItem(
                    itemSpec: NativeMethodsShared.IsWindows ? @"c:\f1\f2\file.txt" : "/f1/f2/file.txt",
                    itemMetadata: metaData)
            };
            t.RootFolder = NativeMethodsShared.IsWindows ? @"c:\f1\f2" : "/f1/f2";

            t.Execute().ShouldBeTrue();
            t.AssignedFiles.Length.ShouldBe(1);
            t.AssignedFiles[0].GetMetadata("TargetPath").ShouldBe(link);
            ChangeWaves.ResetStateForTests();
        }
Beispiel #4
0
        public void NoChangeWaveSetMeansAllChangeWavesAreEnabled(string featureWave)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                ChangeWaves.ResetStateForTests();
                ChangeWaves.AreFeaturesEnabled(featureWave).ShouldBe(true);

                string projectFile = $"" +
                                     $"<Project>" +
                                     $"<Target Name='HelloWorld' Condition=\"'$(MSBUILDDISABLEFEATURESFROMVERSION)' == '{ChangeWaves.EnableAllFeatures}' and $([MSBuild]::AreFeaturesEnabled('{featureWave}'))\">" +
                                     $"<Message Text='Hello World!'/>" +
                                     $"</Target>" +
                                     $"</Project>";

                TransientTestFile file = env.CreateFile("proj.csproj", projectFile);

                ProjectCollection collection = new ProjectCollection();
                MockLogger        log        = new MockLogger();
                collection.RegisterLogger(log);

                collection.LoadProject(file.Path).Build().ShouldBeTrue();
                log.AssertLogContains("Hello World!");
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
            }
        }
Beispiel #5
0
        public void CorrectlyDetermineDisabledFeatures()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                env.SetChangeWave(ChangeWaves.LowestWave);
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                foreach (string wave in ChangeWaves.AllWaves)
                {
                    ChangeWaves.AreFeaturesEnabled(wave).ShouldBeFalse();

                    string projectFile = $"" +
                                         $"<Project>" +
                                         $"<Target Name='HelloWorld' Condition=\"$([MSBuild]::AreFeaturesEnabled('{wave}')) == false\">" +
                                         $"<Message Text='Hello World!'/>" +
                                         $"</Target>" +
                                         $"</Project>";

                    TransientTestFile file = env.CreateFile("proj.csproj", projectFile);

                    ProjectCollection collection = new ProjectCollection();
                    MockLogger        log        = new MockLogger();
                    collection.RegisterLogger(log);

                    Project p = collection.LoadProject(file.Path);
                    p.Build().ShouldBeTrue();

                    log.AssertLogContains("Hello World!");
                }
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
            }
        }
Beispiel #6
0
        internal void InitializeForTests(SdkResolverLoader resolverLoader = null, IList <SdkResolver> resolvers = null)
        {
            if (resolverLoader != null)
            {
                _sdkResolverLoader = resolverLoader;
            }

            _specificResolversManifestsRegistry = null;
            _generalResolversManifestsRegistry  = null;
            _manifestToResolvers = null;
            _resolversList       = null;

            if (resolvers != null)
            {
                if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
                {
                    _specificResolversManifestsRegistry = new List <SdkResolverManifest>();
                    _generalResolversManifestsRegistry  = new List <SdkResolverManifest>();
                    _manifestToResolvers = new Dictionary <SdkResolverManifest, IList <SdkResolver> >();

                    SdkResolverManifest sdkResolverManifest = new SdkResolverManifest(DisplayName: "TestResolversManifest", Path: null, ResolvableSdkRegex: null);
                    _generalResolversManifestsRegistry.Add(sdkResolverManifest);
                    _manifestToResolvers[sdkResolverManifest] = resolvers;
                }
                else
                {
                    _resolversList = resolvers;
                }
            }
        }
Beispiel #7
0
        public void WildcardDriveEnumerationTaskItemLogsError(string itemSpec)
        {
            using (var env = TestEnvironment.Create())
            {
                Helpers.ResetStateForDriveEnumeratingWildcardTests(env, "1");

                try
                {
                    MockEngine engine = new MockEngine();
                    CreateItem t      = new CreateItem()
                    {
                        BuildEngine = engine,
                        Include     = new ITaskItem[] { new TaskItem(itemSpec) },
                    };

                    t.Execute().ShouldBeFalse();
                    engine.Errors.ShouldBe(1);
                    engine.AssertLogContains("MSB5029");
                }
                finally
                {
                    ChangeWaves.ResetStateForTests();
                }
            }
        }
Beispiel #8
0
        private static void VerifyDriveEnumerationWarningLoggedUponCreateItemExecution(string itemSpec)
        {
            using (var env = TestEnvironment.Create())
            {
                Helpers.ResetStateForDriveEnumeratingWildcardTests(env, "0");

                try
                {
                    MockEngine engine = new MockEngine();
                    CreateItem t      = new CreateItem()
                    {
                        BuildEngine = engine,
                        Include     = new ITaskItem[] { new TaskItem(itemSpec) },
                    };

                    t.Execute().ShouldBeTrue();
                    engine.Warnings.ShouldBe(1);
                    engine.AssertLogContains("MSB5029");
                }
                finally
                {
                    ChangeWaves.ResetStateForTests();
                }
            }
        }
Beispiel #9
0
 public void InvalidCallerForIsFeatureEnabledThrows(string waveToCheck)
 {
     using (TestEnvironment env = TestEnvironment.Create())
     {
         env.SetChangeWave("16.8");
         BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
         Shouldly.Should.Throw <InternalErrorException>(() => ChangeWaves.AreFeaturesEnabled(waveToCheck));
     }
 }
Beispiel #10
0
 /// <summary>
 /// Reads the application configuration file.
 /// NOTE: this is abstracted into a method to support unit testing GetToolsetDataFromConfiguration().
 /// Unit tests wish to avoid reading (nunit.exe) application configuration file.
 /// </summary>
 private static Configuration ReadApplicationConfiguration()
 {
     if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0))
     {
         return(s_configurationCache.Value);
     }
     else
     {
         return(ReadOpenMappedExeConfiguration());
     }
 }
Beispiel #11
0
 public virtual SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive, bool isRunningInVisualStudio)
 {
     if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
     {
         return(ResolveSdkUsingResolversWithPatternsFirst(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive, isRunningInVisualStudio));
     }
     else
     {
         return(ResolveSdkUsingAllResolvers(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive, isRunningInVisualStudio));
     }
 }
Beispiel #12
0
        public void EndToEndMultilineExec_EscapeSpecialCharacters_DisabledUnderChangeWave16_10()
        {
            using (var env = TestEnvironment.Create(_output))
            {
                ChangeWaves.ResetStateForTests();
                env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave16_10.ToString());
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                var testProject = env.CreateTestProjectWithFiles(@"<Project>
<Target Name=""ExecCommand"">
  <Exec Command=""echo Hello, World!"" />
   </Target>
</Project>");

                // Ensure path has subfolders
                var    newTempPath = env.CreateNewTempPathWithSubfolder("hello()wo(rld)").TempPath;
                string tempPath    = Path.GetTempPath();
                Assert.StartsWith(newTempPath, tempPath);

                using (var buildManager = new BuildManager())
                {
                    MockLogger logger = new MockLogger(_output, profileEvaluation: false, printEventsToStdout: false);

                    var parameters = new BuildParameters()
                    {
                        Loggers = new[] { logger },
                    };

                    var collection = new ProjectCollection(
                        new Dictionary <string, string>(),
                        new[] { logger },
                        remoteLoggers: null,
                        ToolsetDefinitionLocations.Default,
                        maxNodeCount: 1,
                        onlyLogCriticalEvents: false,
                        loadProjectsReadOnly: true);

                    var project = collection.LoadProject(testProject.ProjectFile).CreateProjectInstance();

                    var request = new BuildRequestData(
                        project,
                        targetsToBuild: new[] { "ExecCommand" },
                        hostServices: null);

                    var result = buildManager.Build(parameters, request);

                    logger.AssertLogContains("Hello, World!");

                    result.OverallResult.ShouldBe(BuildResultCode.Failure);
                }
                ChangeWaves.ResetStateForTests();
            }
        }
Beispiel #13
0
        private static XmlReader GetXmlReader(string file, StreamReader input, bool loadAsReadOnly, out Encoding encoding)
        {
            string uri = new UriBuilder(Uri.UriSchemeFile, string.Empty)
            {
                Path = file
            }.ToString();

            XmlReader reader = null;

            if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10) && loadAsReadOnly && !_disableReadOnlyLoad)
            {
                // Create an XML reader with IgnoreComments and IgnoreWhitespace set if we know that we won't be asked
                // to write the DOM back to a file. This is a performance optimization.
                XmlReaderSettings settings = new XmlReaderSettings
                {
                    DtdProcessing    = DtdProcessing.Ignore,
                    IgnoreComments   = true,
                    IgnoreWhitespace = true,
                };
                reader = XmlReader.Create(input, settings, uri);

                // Try to set Normalization to false. We do this to remain compatible with earlier versions of MSBuild
                // where we constructed the reader with 'new XmlTextReader()' which has normalization enabled by default.
                PropertyInfo normalizationPropertyInfo = GetNormalizationPropertyInfo(reader.GetType());
                if (normalizationPropertyInfo != null)
                {
                    normalizationPropertyInfo.SetValue(reader, false);
                }
                else
                {
                    // Fall back to using XmlTextReader if the prop could not be bound.
                    Debug.Fail("Could not set Normalization to false on the result of XmlReader.Create");
                    _disableReadOnlyLoad = true;

                    reader.Dispose();
                    reader = null;
                }
            }

            if (reader == null)
            {
                reader = new XmlTextReader(uri, input)
                {
                    DtdProcessing = DtdProcessing.Ignore
                };
            }

            reader.Read();
            encoding = input.CurrentEncoding;

            return(reader);
        }
Beispiel #14
0
        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
        {
            if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
            {
                string?libraryPath = _resolver?.ResolveUnmanagedDllToPath(unmanagedDllName);
                if (libraryPath != null)
                {
                    return(LoadUnmanagedDllFromPath(libraryPath));
                }
            }

            return(base.LoadUnmanagedDll(unmanagedDllName));
        }
Beispiel #15
0
        internal static object GetRegistryValue(string keyName, string valueName, object defaultValue)
        {
#if RUNTIME_TYPE_NETCORE
            // .NET Core MSBuild used to always return empty, so match that behavior
            // on non-Windows (no registry), and with a changewave (in case someone
            // had a registry property and it breaks when it lights up).
            if (!NativeMethodsShared.IsWindows || !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
            {
                return(defaultValue);
            }
#endif
            return(Registry.GetValue(keyName, valueName, defaultValue));
        }
Beispiel #16
0
        private void SetResolverState(int submissionId, SdkResolver resolver, object state)
        {
            // Do not set state for resolution requests that are not associated with a valid build submission ID
            if (submissionId != BuildEventContext.InvalidSubmissionId)
            {
                ConcurrentDictionary <SdkResolver, object> resolverState = _resolverStateBySubmission.GetOrAdd(
                    submissionId,
                    _ => new ConcurrentDictionary <SdkResolver, object>(
                        NativeMethodsShared.GetLogicalCoreCount(),
                        ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4) ? _specificResolversManifestsRegistry.Count + _generalResolversManifestsRegistry.Count : _resolversList.Count));

                resolverState.AddOrUpdate(resolver, state, (sdkResolver, obj) => state);
            }
        }
Beispiel #17
0
        public void NoChangeWaveSetMeansAllChangeWavesAreEnabled(string featureVersion)
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                // Reset static ChangeWave
                SetChangeWave(string.Empty, env);
                Version featureAsVersion = Version.Parse(featureVersion);
                ChangeWaves.AreFeaturesEnabled(featureAsVersion).ShouldBe(true);

                buildSimpleProjectAndValidateChangeWave(testEnvironment: env,
                                                        versionToCheckAgainstCurrentChangeWave: featureAsVersion,
                                                        currentChangeWaveShouldUltimatelyResolveTo: ChangeWaves.EnableAllFeatures,
                                                        warningCodesLogShouldContain: null);
            }
        }
Beispiel #18
0
        /// <summary>
        /// Gets the location of the directory used for diagnostic log files.
        /// </summary>
        /// <returns></returns>
        private static string GetDebugDumpPath()
        {
            string debugPath =
// Cannot access change wave logic from these assemblies (https://github.com/dotnet/msbuild/issues/6707)
#if CLR2COMPATIBILITY || MICROSOFT_BUILD_ENGINE_OM_UNITTESTS
                Environment.GetEnvironmentVariable("MSBUILDDEBUGPATH");
#else
                ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0)
                    ? DebugUtils.DebugPath
                    : Environment.GetEnvironmentVariable("MSBUILDDEBUGPATH");
#endif

            return(!string.IsNullOrEmpty(debugPath)
                    ? debugPath
                    : Path.GetTempPath());
        }
Beispiel #19
0
        public void SpacePropertyOptOutWave16_10()
        {
            using TestEnvironment env = TestEnvironment.Create();
            ChangeWaves.ResetStateForTests();
            env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave16_10.ToString());
            BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

            Scanner lexer = new Scanner("$(x )", ParserOptions.AllowProperties);

            AdvanceToScannerError(lexer);
            Assert.Null(lexer.UnexpectedlyFound);

            lexer = new Scanner("$( x)", ParserOptions.AllowProperties);
            AdvanceToScannerError(lexer);
            Assert.Null(lexer.UnexpectedlyFound);
            ChangeWaves.ResetStateForTests();
        }
Beispiel #20
0
        /// <summary>
        /// Scan for the end of the property expression
        /// </summary>
        /// <param name="expression">property expression to parse</param>
        /// <param name="index">current index to start from</param>
        /// <param name="indexResult">If successful, the index corresponds to the end of the property expression.
        /// In case of scan failure, it is the error position index.</param>
        /// <returns>result indicating whether or not the scan was successful.</returns>
        private static bool ScanForPropertyExpressionEnd(string expression, int index, out int indexResult)
        {
            int  nestLevel       = 0;
            bool whitespaceCheck = false;

            unsafe
            {
                fixed(char *pchar = expression)
                {
                    while (index < expression.Length)
                    {
                        char character = pchar[index];
                        if (character == '(')
                        {
                            nestLevel++;
                            whitespaceCheck = true;
                        }
                        else if (character == ')')
                        {
                            nestLevel--;
                            whitespaceCheck = false;
                        }
                        else if (whitespaceCheck && char.IsWhiteSpace(character) && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10))
                        {
                            indexResult = index;
                            return(false);
                        }

                        // We have reached the end of the parenthesis nesting
                        // this should be the end of the property expression
                        // If it is not then the calling code will determine that
                        if (nestLevel == 0)
                        {
                            indexResult = index;
                            return(true);
                        }
                        else
                        {
                            index++;
                        }
                    }
                }
            }
            indexResult = index;
            return(true);
        }
Beispiel #21
0
        internal static object GetRegistryValueFromView(string keyName, string valueName, object defaultValue, params object[] views)
        {
#if RUNTIME_TYPE_NETCORE
            // .NET Core MSBuild used to always return empty, so match that behavior
            // on non-Windows (no registry), and with a changewave (in case someone
            // had a registry property and it breaks when it lights up).
            if (!NativeMethodsShared.IsWindows || !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
            {
                return(defaultValue);
            }
#endif

            if (views == null || views.Length == 0)
            {
                views = DefaultRegistryViews;
            }

            return(GetRegistryValueFromView(keyName, valueName, defaultValue, new ArraySegment <object>(views)));
        }
Beispiel #22
0
        public void EscapeSpecifiedCharactersInPathToGeneratedBatchFile_DisabledUnderChangeWave16_10()
        {
            using (var testEnvironment = TestEnvironment.Create())
            {
                ChangeWaves.ResetStateForTests();
                testEnvironment.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave16_10.ToString());
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                var newTempPath = testEnvironment.CreateNewTempPathWithSubfolder("hello()w]o(rld)").TempPath;

                string tempPath = Path.GetTempPath();
                Assert.StartsWith(newTempPath, tempPath);

                // Now run the Exec task on a simple command.
                Exec exec = PrepareExec("echo Hello World!");
                exec.Execute().ShouldBeFalse();

                ChangeWaves.ResetStateForTests();
            }
        }
Beispiel #23
0
        public void AssertFirstResolverWithPatternCantResolveChangeWave17_4()
        {
            using (TestEnvironment env = TestEnvironment.Create())
            {
                ChangeWaves.ResetStateForTests();
                env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave17_4.ToString());
                BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();

                SdkResolverService.Instance.InitializeForTests(new MockLoaderStrategy(includeResolversWithPatterns: true));

                SdkReference sdk = new SdkReference("1sdkName", "referencedVersion", "minimumVersion");

                var result = SdkResolverService.Instance.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false, isRunningInVisualStudio: false);

                result.Path.ShouldBe("resolverpath1");
                _logger.BuildMessageEvents.Select(i => i.Message).ShouldContain("MockSdkResolver1 running");
                _logger.BuildMessageEvents.Select(i => i.Message).ShouldNotContain("MockSdkResolverWithResolvableSdkPattern1 running");
                ChangeWaves.ResetStateForTests();
            }
        }
Beispiel #24
0
        private static string GetLockedFileMessage(string file)
        {
            string message = string.Empty;

            try
            {
                if (NativeMethodsShared.IsWindows && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_4))
                {
                    var processes = LockCheck.GetProcessesLockingFile(file);
                    message = !string.IsNullOrEmpty(processes)
                        ? ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("Copy.FileLocked", processes)
                        : String.Empty;
                }
            }
            catch (Exception)
            {
                // Never throw if we can't get the processes locking the file.
            }

            return(message);
        }
Beispiel #25
0
        /// <summary>
        ///     Parse the given <paramref name="fileSpec" /> into a <see cref="MSBuildGlob" /> using a given
        ///     <paramref name="globRoot" />.
        /// </summary>
        /// <param name="globRoot">
        ///     The root of the glob.
        ///     The fixed directory part of the glob and the match arguments (<see cref="IsMatch" /> and <see cref="MatchInfo" />)
        ///     will get normalized against this root.
        ///     If empty, the current working directory is used.
        ///     Cannot be null, and cannot contain invalid path arguments.
        /// </param>
        /// <param name="fileSpec">The string to parse</param>
        /// <returns></returns>
        public static MSBuildGlob Parse(string globRoot, string fileSpec)
        {
            ErrorUtilities.VerifyThrowArgumentNull(globRoot, nameof(globRoot));
            ErrorUtilities.VerifyThrowArgumentNull(fileSpec, nameof(fileSpec));
            ErrorUtilities.VerifyThrowArgumentInvalidPath(globRoot, nameof(globRoot));

            if (string.IsNullOrEmpty(globRoot))
            {
                globRoot = Directory.GetCurrentDirectory();
            }

            globRoot = Strings.WeakIntern(FileUtilities.NormalizePath(globRoot).WithTrailingSlash());

            var lazyState = new Lazy <GlobState>(() =>
            {
                FileMatcher.Default.GetFileSpecInfo(
                    fileSpec,
                    out string fixedDirectoryPart,
                    out string wildcardDirectoryPart,
                    out string filenamePart,
                    out bool needsRecursion,
                    out bool isLegalFileSpec,
                    (fixedDirPart, wildcardDirPart, filePart) =>
                {
                    var normalizedFixedPart = NormalizeTheFixedDirectoryPartAgainstTheGlobRoot(fixedDirPart, globRoot);

                    return(normalizedFixedPart, wildcardDirPart, filePart);
                });

                Regex regex = null;
                if (isLegalFileSpec)
                {
                    string matchFileExpression = FileMatcher.RegularExpressionFromFileSpec(fixedDirectoryPart, wildcardDirectoryPart, filenamePart);

                    lock (s_regexCache)
                    {
                        s_regexCache.TryGetValue(matchFileExpression, out regex);
                    }

                    if (regex == null)
                    {
                        RegexOptions regexOptions = FileMatcher.DefaultRegexOptions;
                        // compile the regex since it's expected to be used multiple times
                        // For the kind of regexes used here, compilation on .NET Framework tends to be expensive and not worth the small
                        // run-time boost so it's enabled only on .NET Core by default.
#if RUNTIME_TYPE_NETCORE
                        bool compileRegex = true;
#else
                        bool compileRegex = !ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0);
#endif
                        if (compileRegex)
                        {
                            regexOptions |= RegexOptions.Compiled;
                        }
                        Regex newRegex = new Regex(matchFileExpression, regexOptions);
                        lock (s_regexCache)
                        {
                            if (!s_regexCache.TryGetValue(matchFileExpression, out regex))
                            {
                                s_regexCache[matchFileExpression] = newRegex;
                            }
                        }
                        regex ??= newRegex;
                    }
                }
                return(new GlobState(globRoot, fileSpec, isLegalFileSpec, fixedDirectoryPart, wildcardDirectoryPart, filenamePart, needsRecursion, regex));
            },
            protected override ImmutableList <I> SelectItems(ImmutableList <ItemData> .Builder listBuilder, ImmutableHashSet <string> globsToIgnore)
            {
                var itemsToAdd = ImmutableList.CreateBuilder <I>();

                Lazy <Func <string, bool> > excludeTester = null;

                ImmutableList <string> .Builder excludePatterns = ImmutableList.CreateBuilder <string>();
                if (_excludes != null)
                {
                    // STEP 4: Evaluate, split, expand and subtract any Exclude
                    foreach (string exclude in _excludes)
                    {
                        string excludeExpanded = _expander.ExpandIntoStringLeaveEscaped(exclude, ExpanderOptions.ExpandPropertiesAndItems, _itemElement.ExcludeLocation);
                        var    excludeSplits   = ExpressionShredder.SplitSemiColonSeparatedList(excludeExpanded);
                        excludePatterns.AddRange(excludeSplits);
                    }

                    if (excludePatterns.Count > 0)
                    {
                        excludeTester = new Lazy <Func <string, bool> >(() => EngineFileUtilities.GetFileSpecMatchTester(excludePatterns, _rootDirectory));
                    }
                }

                ISet <string> excludePatternsForGlobs = null;

                foreach (var fragment in _itemSpec.Fragments)
                {
                    if (fragment is ItemSpec <P, I> .ItemExpressionFragment itemReferenceFragment)
                    {
                        // STEP 3: If expression is "@(x)" copy specified list with its metadata, otherwise just treat as string
                        var itemsFromExpression = _expander.ExpandExpressionCaptureIntoItems(
                            itemReferenceFragment.Capture,
                            _evaluatorData,
                            _itemFactory,
                            ExpanderOptions.ExpandItems,
                            includeNullEntries: false,
                            isTransformExpression: out _,
                            elementLocation: _itemElement.IncludeLocation);

                        itemsToAdd.AddRange(
                            excludeTester != null
                                ? itemsFromExpression.Where(item => !excludeTester.Value(item.EvaluatedInclude))
                                : itemsFromExpression);
                    }
                    else if (fragment is ValueFragment valueFragment)
                    {
                        string value = valueFragment.TextFragment;

                        if (excludeTester?.Value(EscapingUtilities.UnescapeAll(value)) != true)
                        {
                            var item = _itemFactory.CreateItem(value, value, _itemElement.ContainingProject.FullPath);
                            itemsToAdd.Add(item);
                        }
                    }
                    else if (fragment is GlobFragment globFragment)
                    {
                        // If this item is behind a false condition and represents a full drive/filesystem scan, expanding it is
                        // almost certainly undesired. It should be skipped to avoid evaluation taking an excessive amount of time.
                        bool skipGlob = !_conditionResult && globFragment.IsFullFileSystemScan && !Traits.Instance.EscapeHatches.AlwaysEvaluateDangerousGlobs && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_8);
                        if (!skipGlob)
                        {
                            string glob = globFragment.TextFragment;

                            if (excludePatternsForGlobs == null)
                            {
                                excludePatternsForGlobs = BuildExcludePatternsForGlobs(globsToIgnore, excludePatterns);
                            }

                            string[] includeSplitFilesEscaped;
                            if (MSBuildEventSource.Log.IsEnabled())
                            {
                                MSBuildEventSource.Log.ExpandGlobStart(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs));
                            }
                            using (_lazyEvaluator._evaluationProfiler.TrackGlob(_rootDirectory, glob, excludePatternsForGlobs))
                            {
                                includeSplitFilesEscaped = EngineFileUtilities.GetFileListEscaped(
                                    _rootDirectory,
                                    glob,
                                    excludePatternsForGlobs
                                    );
                            }
                            if (MSBuildEventSource.Log.IsEnabled())
                            {
                                MSBuildEventSource.Log.ExpandGlobStop(_rootDirectory, glob, string.Join(", ", excludePatternsForGlobs));
                            }

                            foreach (string includeSplitFileEscaped in includeSplitFilesEscaped)
                            {
                                itemsToAdd.Add(_itemFactory.CreateItem(includeSplitFileEscaped, glob, _itemElement.ContainingProject.FullPath));
                            }
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException(fragment.GetType().ToString());
                    }
                }

                return(itemsToAdd.ToImmutable());
            }
Beispiel #27
0
        private static bool ScanForPropertyExpressionEnd(string expression, int index, out int indexResult)
        {
            int  nestLevel                   = 0;
            bool whitespaceFound             = false;
            bool nonIdentifierCharacterFound = false;

            indexResult = -1;
            unsafe
            {
                fixed(char *pchar = expression)
                {
                    while (index < expression.Length)
                    {
                        char character = pchar[index];
                        if (character == '(')
                        {
                            nestLevel++;
                        }
                        else if (character == ')')
                        {
                            nestLevel--;
                        }
                        else if (char.IsWhiteSpace(character))
                        {
                            whitespaceFound = true;
                            indexResult     = index;
                        }
                        else if (!XmlUtilities.IsValidSubsequentElementNameCharacter(character))
                        {
                            nonIdentifierCharacterFound = true;
                        }

                        if (character == '$' && index < expression.Length - 1 && pchar[index + 1] == '(')
                        {
                            if (!ScanForPropertyExpressionEnd(expression, index + 1, out index))
                            {
                                indexResult = index;
                                return(false);
                            }
                        }

                        // We have reached the end of the parenthesis nesting
                        // this should be the end of the property expression
                        // If it is not then the calling code will determine that
                        if (nestLevel == 0)
                        {
                            if (whitespaceFound && !nonIdentifierCharacterFound && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10))
                            {
                                return(false);
                            }

                            indexResult = index;
                            return(true);
                        }
                        else
                        {
                            index++;
                        }
                    }
                }
            }
            indexResult = index;
            return(true);
        }
Beispiel #28
0
 public void SetChangeWave(string wave)
 {
     ChangeWaves.ResetStateForTests();
     SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", wave);
 }
Beispiel #29
0
        /// <summary>
        /// Execute the task.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            AssignedFiles = new ITaskItem[Files.Length];

            if (Files.Length > 0)
            {
                // Compose a file in the root folder.
                // NOTE: at this point fullRootPath may or may not have a trailing
                // slash because Path.GetFullPath() does not add or remove it
                string fullRootPath = Path.GetFullPath(RootFolder);

                // Ensure trailing slash otherwise c:\bin appears to match part of c:\bin2\foo
                fullRootPath = FileUtilities.EnsureTrailingSlash(fullRootPath);

                string currentDirectory = Directory.GetCurrentDirectory();

                // check if the root folder is the same as the current directory
                // NOTE: the path returned from Directory.GetCurrentDirectory()
                // does not have a trailing slash, but fullRootPath does
                bool isRootFolderSameAsCurrentDirectory =
                    ((fullRootPath.Length - 1 /* exclude trailing slash */) == currentDirectory.Length)
                    &&
                    (String.Compare(
                         fullRootPath, 0,
                         currentDirectory, 0,
                         fullRootPath.Length - 1 /* don't compare trailing slash */,
                         StringComparison.OrdinalIgnoreCase) == 0);

                for (int i = 0; i < Files.Length; ++i)
                {
                    AssignedFiles[i] = new TaskItem(Files[i]);

                    // If TargetPath is already set, it takes priority.
                    // https://github.com/dotnet/msbuild/issues/2795
                    string targetPath = ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave16_10) ? Files[i].GetMetadata(ItemMetadataNames.targetPath) : null;

                    // If TargetPath not already set, fall back to default behavior.
                    if (string.IsNullOrEmpty(targetPath))
                    {
                        targetPath = Files[i].GetMetadata(ItemMetadataNames.link);
                    }

                    if (string.IsNullOrEmpty(targetPath))
                    {
                        if (// if the file path is relative
                            !Path.IsPathRooted(Files[i].ItemSpec) &&
                            // if the file path doesn't contain any relative specifiers
                            !Files[i].ItemSpec.Contains("." + Path.DirectorySeparatorChar) &&
                            // if the file path is already relative to the root folder
                            isRootFolderSameAsCurrentDirectory)
                        {
                            // then just use the file path as-is
                            // PERF NOTE: we do this to avoid calling Path.GetFullPath() below,
                            // because that method consumes a lot of memory, esp. when we have
                            // a lot of items coming through this task
                            targetPath = Files[i].ItemSpec;
                        }
                        else
                        {
                            // PERF WARNING: Path.GetFullPath() is expensive in terms of memory;
                            // we should avoid calling it whenever possible
                            string itemSpecFullFileNamePath = Path.GetFullPath(Files[i].ItemSpec);

                            if (String.Compare(fullRootPath, 0, itemSpecFullFileNamePath, 0, fullRootPath.Length, StringComparison.CurrentCultureIgnoreCase) == 0)
                            {
                                // The item spec file is in the "cone" of the RootFolder. Return the relative path from the cone root.
                                targetPath = itemSpecFullFileNamePath.Substring(fullRootPath.Length);
                            }
                            else
                            {
                                // The item spec file is not in the "cone" of the RootFolder. Return the filename only.
                                targetPath = Path.GetFileName(Files[i].ItemSpec);
                            }
                        }
                    }

                    AssignedFiles[i].SetMetadata(ItemMetadataNames.targetPath, EscapingUtilities.Escape(targetPath));
                }
            }

            return(true);
        }
Beispiel #30
0
 /// <summary>
 /// Performs necessary operations for setting the MSBuildDisableFeaturesFromVersion environment variable.
 /// This is required because Change Waves is static and stale values can be seen between tests in the same assembly.
 /// </summary>
 /// <param name="wave">The version to set as the current Change Wave.</param>
 private void SetChangeWave(string wave, TestEnvironment env)
 {
     ChangeWaves.ResetStateForTests();
     env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", wave);
     BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
 }