//------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// <summary> /// Execute method in Task /// </summary> /// <returns></returns> public override bool Execute() { TaskHelper.DisplayLogo(Log, nameof(MarkupCompilePass2)); // // Create the TaskFileService instance here // _taskFileService = new TaskFileService(this) as ITaskFileService; try { IsSupportedOutputType(OutputType); Log.LogMessageFromResources(MessageImportance.Low, SRID.CurrentDirectory, SourceDir); // If wrong files are set to some properties, the task // should stop here immediatelly. if (_nErrors > 0) { Log.LogErrorWithCodeFromResources(SRID.WrongPropertySetting); } else { bool hasLocalXamlFiles; hasLocalXamlFiles = InitLocalXamlCache(); if (!hasLocalXamlFiles) { // There is no valid input xaml files. // No need to do further work. // stop here. return(true); } // create output directory if (!Directory.Exists(OutputPath)) { Directory.CreateDirectory(OutputPath); } // Call the Markup Compiler to do the real compiling work ArrayList referenceList; FileUnit localApplicationFile; FileUnit[] localXamlPageFileList; // Prepare the appropriate file lists required by MarkupCompiler. PrepareForMarkupCompilation(out localApplicationFile, out localXamlPageFileList, out referenceList); // Do the real Pass2 compilation work here. DoLocalReferenceMarkupCompilation(localApplicationFile, localXamlPageFileList, referenceList); // Generate the required output items. GenerateOutputItems(); Log.LogMessageFromResources(MessageImportance.Low, SRID.CompilationDone); } } #pragma warning disable 6500 catch (Exception e) { string message; string errorId; errorId = Log.ExtractMessageCode(e.Message, out message); if (String.IsNullOrEmpty(errorId)) { errorId = UnknownErrorID; message = SR.Get(SRID.UnknownBuildError, message); } Log.LogError(null, errorId, null, null, 0, 0, 0, 0, message, null); _nErrors++; } catch // Non-CLS compliant errors { Log.LogErrorWithCodeFromResources(SRID.NonClsError); _nErrors++; } #pragma warning restore 6500 if (_nErrors > 0) { // When error counter is changed, the appropriate error message should have // been reported. // // The task should cleanup all the cache files so that all the xaml files will // get chance to recompile next time. // string stateFileName = OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.StateFile : SharedStrings.IntellisenseStateFile); string localTypeCacheFileName = OutputPath + AssemblyName + (TaskFileService.IsRealBuild? SharedStrings.LocalTypeCacheFile : SharedStrings.IntellisenseLocalTypeCacheFile); if (TaskFileService.Exists(stateFileName)) { TaskFileService.Delete(stateFileName); } if (TaskFileService.Exists(localTypeCacheFileName)) { TaskFileService.Delete(localTypeCacheFileName); } return(false); } else { // Mark Pass2 as completed in the cache string stateFileName = OutputPath + AssemblyName + (TaskFileService.IsRealBuild ? SharedStrings.StateFile : SharedStrings.IntellisenseStateFile); if (TaskFileService.Exists(stateFileName)) { CompilerState compilerState = new CompilerState(stateFileName, TaskFileService); compilerState.LoadStateInformation(); if (compilerState.Pass2Required) { compilerState.Pass2Required = false; compilerState.SaveStateInformation(); } } Log.LogMessageFromResources(SRID.CompileSucceed_Pass2); return(true); } }
// // Analyze the input files based on the compiler cache files. // // Put the analyze result in _analyzeResult and other related data fields, // such as RecompileMarkupPages, RecompileApplicationFile, etc. // // If analyze is failed somehow, throw exception. // internal void AnalyzeInputFiles() { // // First: Detect if the entire project requires re-compile. // // // If the compiler state file doesn't exist, recompile all the xaml files. // if (!CompilerState.StateFileExists()) { _analyzeResult = RecompileCategory.All; } else { // Load the compiler state file. CompilerState.LoadStateInformation(); // if PresenationBuildTasks.dll is changed last build, rebuild the entire project for sure. if (IsFileChanged(Assembly.GetExecutingAssembly().Location) || IsFileListChanged(_mcPass1.ExtraBuildControlFiles)) { _analyzeResult = RecompileCategory.All; } else { // // Any one single change in below list would request completely re-compile. // if (IsSettingModified(CompilerState.References, _mcPass1.ReferencesCache) || IsSettingModified(CompilerState.ApplicationFile, _mcPass1.ApplicationFile) || IsSettingModified(CompilerState.RootNamespace, _mcPass1.RootNamespace) || IsSettingModified(CompilerState.AssemblyName, _mcPass1.AssemblyName) || IsSettingModified(CompilerState.AssemblyVersion, _mcPass1.AssemblyVersion) || IsSettingModified(CompilerState.AssemblyPublicKeyToken, _mcPass1.AssemblyPublicKeyToken) || IsSettingModified(CompilerState.OutputType, _mcPass1.OutputType) || IsSettingModified(CompilerState.Language, _mcPass1.Language) || IsSettingModified(CompilerState.LanguageSourceExtension, _mcPass1.LanguageSourceExtension) || IsSettingModified(CompilerState.OutputPath, _mcPass1.OutputPath) || IsSettingModified(CompilerState.LocalizationDirectivesToLocFile, _mcPass1.LocalizationDirectivesToLocFile)) { _analyzeResult = RecompileCategory.All; } else { if (_mcPass1.IsApplicationTarget) { // // When application definition file is modified, it could potentially change the application // class name, it then has impact on all other xaml file compilation, so recompile the entire // project for this case. // if (TaskFileService.Exists(_mcPass1.ApplicationFile) && IsFileChanged(_mcPass1.ApplicationFile)) { _analyzeResult = RecompileCategory.All; } } // // If any one referenced assembly is updated since last build, the entire project needs to recompile. // if (IsFileListChanged(_mcPass1.References)) { _analyzeResult = RecompileCategory.All; } } } } if (_analyzeResult == RecompileCategory.All) { UpdateFileListForCleanbuild(); return; } // // The entire project recompilation should have already been handled when code goes here. // Now, Detect the individual xaml files which require to recompile. // if (_mcPass1.IsApplicationTarget) { if (IsSettingModified(CompilerState.ContentFiles, _mcPass1.ContentFilesCache)) { _analyzeResult |= RecompileCategory.ContentFiles; } // if HostInBrowser setting is changed, it would affect the application file compilation only. if (IsSettingModified(CompilerState.HostInBrowser, _mcPass1.HostInBrowser)) { _analyzeResult |= RecompileCategory.ApplicationFile; } if (IsSettingModified(CompilerState.SplashImage, _mcPass1.SplashImageName)) { _analyzeResult |= RecompileCategory.ApplicationFile; } } // // If code files are changed, or Define flags are changed, it would affect the xaml file with local types. // // If previous build didn't have such local-ref-xaml files, don't bother to do further check for this. // if (CompilerLocalReference.CacheFileExists()) { if (IsSettingModified(CompilerState.DefineConstants, _mcPass1.DefineConstants) || IsSettingModified(CompilerState.SourceCodeFiles, _mcPass1.SourceCodeFilesCache) || IsFileListChanged(_mcPass1.SourceCodeFiles)) { _analyzeResult |= RecompileCategory.PagesWithLocalType; } } List <FileUnit> modifiedXamlFiles = new List <FileUnit>(); // // Detect if any .xaml page is updated since last build // if (ListIsNotEmpty(_mcPass1.PageMarkup)) { // // If the PageMarkup file number or hashcode is changed, it would affect // the xaml files with local types. // // This check is necessary for the senario that a xaml file is removed and the // removed xaml file could be referenced by other xaml files with local types. // if (IsSettingModified(CompilerState.PageMarkup, _mcPass1.PageMarkupCache)) { if (CompilerLocalReference.CacheFileExists()) { _analyzeResult |= RecompileCategory.PagesWithLocalType; } } // Below code detects which invidual xaml files are modified since last build. for (int i = 0; i < _mcPass1.PageMarkup.Length; i++) { ITaskItem taskItem = _mcPass1.PageMarkup[i]; string fileName = taskItem.ItemSpec; string filepath = Path.GetFullPath(fileName); string linkAlias = taskItem.GetMetadata(SharedStrings.Link); string logicalName = taskItem.GetMetadata(SharedStrings.LogicalName); if (IsFileChanged(filepath)) { // add this file to the modified file list. modifiedXamlFiles.Add(new FileUnit(filepath, linkAlias, logicalName)); } else { // A previously generated xaml file (with timestamp earlier than of the cache file) // could be added to the project. This means that the above check for time stamp // will skip compiling the newly added xaml file. We save the name all the xaml // files we previously built to the cache file. Retrieve that list and see if // this xaml file is already in it. If so, we'll skip compiling this xaml file, // else, this xaml file was just added to the project and thus compile it. if (!CompilerState.PageMarkupFileNames.Contains(fileName)) { modifiedXamlFiles.Add(new FileUnit(filepath, linkAlias, logicalName)); } } } if (modifiedXamlFiles.Count > 0) { _analyzeResult |= RecompileCategory.ModifiedPages; if (CompilerLocalReference.CacheFileExists()) { _analyzeResult |= RecompileCategory.PagesWithLocalType; } } } // Check for the case where a required Pass2 wasn't run, e.g. because the build was aborted, // or because the Compile target was run inside VS. // If that happened, let's recompile the local-type pages, which will force Pass2 to run. if (CompilerState.Pass2Required && CompilerLocalReference.CacheFileExists()) { _analyzeResult |= RecompileCategory.PagesWithLocalType; } UpdateFileListForIncrementalBuild(modifiedXamlFiles); }