Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / BuildTasks / MS / Internal / Tasks / IncrementalCompileAnalyzer.cs / 1305600 / IncrementalCompileAnalyzer.cs
//----------------------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description:
// Analyze the current project inputs, the compiler state file and local reference
// cache, determine which xaml files require to recompile.
//
// History:
//
// 11/21/05: weibz Created
//
//---------------------------------------------------------------------------------------
using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Build.Tasks.Windows;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using MS.Utility;
namespace MS.Internal.Tasks
{
//
// Keep different categories of recompilation.
//
[Flags]
internal enum RecompileCategory : byte
{
NoRecompile = 0x00,
ApplicationFile = 0x01,
ModifiedPages = 0x02,
PagesWithLocalType = 0x04,
ContentFiles = 0x08,
All = 0x0F
}
//
// IncrementalCompileAnalyzer
//
internal class IncrementalCompileAnalyzer
{
//
// ctor of IncrementalCompileAnalyzer
//
internal IncrementalCompileAnalyzer(MarkupCompilePass1 mcPass1)
{
_mcPass1 = mcPass1;
_analyzeResult = RecompileCategory.NoRecompile;
}
#region internal methods
//
// 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;
}
}
ArrayList modifiedXamlFiles = new ArrayList();
//
// 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++)
{
string fileName = _mcPass1.PageMarkup[i].ItemSpec;
string filepath = Path.GetFullPath(fileName);
if (IsFileChanged(filepath))
{
// add this file to the modified file list.
modifiedXamlFiles.Add(filepath);
}
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(filepath);
}
}
}
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);
}
#endregion
#region internal properties
//
// Keep the AnlyzeResult.
//
internal RecompileCategory AnalyzeResult
{
get { return _analyzeResult; }
}
//
// Keep a list of markup pages which require to recompile
//
internal string[] RecompileMarkupPages
{
get { return _recompileMarkupPages; }
}
//
// Application file which requires re-compile.
// If the value is String.Empty, the appdef file is not required
// to recompile.
//
internal string RecompileApplicationFile
{
get { return _recompileApplicationFile; }
}
internal string[] ContentFiles
{
get { return _contentFiles; }
}
#endregion
#region private properties and methods
private CompilerState CompilerState
{
get { return _mcPass1.CompilerState; }
}
private CompilerLocalReference CompilerLocalReference
{
get { return _mcPass1.CompilerLocalReference; }
}
private ITaskFileService TaskFileService
{
get { return _mcPass1.TaskFileService; }
}
private DateTime LastCompileTime
{
get
{
DateTime nonSet = new DateTime(0);
if (_lastCompileTime == nonSet)
{
_lastCompileTime = TaskFileService.GetLastChangeTime(CompilerState.CacheFilePath);
}
return _lastCompileTime;
}
}
//
// Compare two strings.
//
private bool IsSettingModified(string textSource, string textTarget)
{
bool IsSettingModified;
bool isSrcEmpty = String.IsNullOrEmpty(textSource);
bool istgtEmpty = String.IsNullOrEmpty(textTarget);
if (isSrcEmpty != istgtEmpty)
{
IsSettingModified = true;
}
else
{
if (isSrcEmpty) // Both source and target strings are empty.
{
IsSettingModified = false;
}
else // Both source and target strings are not empty.
{
IsSettingModified = String.Compare(textSource, textTarget, StringComparison.OrdinalIgnoreCase) == 0 ? false : true;
}
}
return IsSettingModified;
}
//
// Generate new list of files that require to recompile for incremental build based on _analyzeResult
//
private void UpdateFileListForIncrementalBuild(ArrayList modifiedXamlFiles)
{
ArrayList recompiledXaml = new ArrayList();
bool recompileApp = false;
int numLocalTypeXamls = 0;
if ((_analyzeResult & RecompileCategory.ContentFiles) == RecompileCategory.ContentFiles)
{
RecompileContentFiles();
}
if ((_analyzeResult & RecompileCategory.ApplicationFile) == RecompileCategory.ApplicationFile)
{
recompileApp = true;
}
if ((_analyzeResult & RecompileCategory.PagesWithLocalType) == RecompileCategory.PagesWithLocalType)
{
CompilerLocalReference.LoadCacheFile();
if (CompilerLocalReference.LocalApplicationFile != null)
{
// Application file contains local types, it will be recompiled.
recompileApp = true;
}
if (ListIsNotEmpty(CompilerLocalReference.LocalMarkupPages))
{
numLocalTypeXamls = CompilerLocalReference.LocalMarkupPages.Length;
for (int i = 0; i < CompilerLocalReference.LocalMarkupPages.Length; i++)
{
recompiledXaml.Add(CompilerLocalReference.LocalMarkupPages[i].FilePath);
}
}
}
if ((_analyzeResult & RecompileCategory.ModifiedPages) == RecompileCategory.ModifiedPages)
{
// If the xaml is already in the local-type-ref xaml file list, don't add a duplicate file path to recompiledXaml list.
for (int i = 0; i < modifiedXamlFiles.Count; i++)
{
string xamlfile = modifiedXamlFiles[i] as string;
bool addToList;
addToList = true;
if (numLocalTypeXamls > 0)
{
for (int j = 0; j < numLocalTypeXamls; j++)
{
if (String.Compare(xamlfile, CompilerLocalReference.LocalMarkupPages[j].FilePath, StringComparison.OrdinalIgnoreCase) == 0)
{
addToList = false;
break;
}
}
}
if (addToList)
{
recompiledXaml.Add(xamlfile);
}
}
}
if (recompiledXaml.Count > 0)
{
_recompileMarkupPages = (string[])recompiledXaml.ToArray(typeof(string));
}
// Set ApplicationFile appropriatelly for this incremental build.
ProcessApplicationFile(recompileApp);
}
//
// To recompile all the xaml files ( including page and application file).
// Transfer all the xaml files to the recompileMarkupPages.
//
private void UpdateFileListForCleanbuild()
{
if (ListIsNotEmpty(_mcPass1.PageMarkup))
{
int count = _mcPass1.PageMarkup.Length;
_recompileMarkupPages = new string[count];
for (int i = 0; i < count; i++)
{
_recompileMarkupPages[i] = Path.GetFullPath(_mcPass1.PageMarkup[i].ItemSpec);
}
}
RecompileContentFiles();
ProcessApplicationFile(true);
}
//
// Content files are only for Application target type.
//
private void RecompileContentFiles()
{
if (!_mcPass1.IsApplicationTarget)
return;
if (_contentFiles == null)
{
if (ListIsNotEmpty(_mcPass1.ContentFiles))
{
string curDir = Directory.GetCurrentDirectory() + "\\";
int count = _mcPass1.ContentFiles.Length;
_contentFiles = new string[count];
for (int i = 0; i < count; i++)
{
string fullPath = Path.GetFullPath(_mcPass1.ContentFiles[i].ItemSpec);
string relContentFilePath = TaskHelper.GetRootRelativePath(curDir, fullPath);
if (String.IsNullOrEmpty(relContentFilePath))
{
relContentFilePath = Path.GetFileName(fullPath);
}
_contentFiles[i] = relContentFilePath;
}
}
}
}
//
// Handle Application definition xaml file and Application Class name.
// recompile parameter indicates whether or not to recompile the appdef file.
// If the appdef file is not recompiled, a specially handling is required to
// take application class name from previous build.
//
private void ProcessApplicationFile(bool recompile)
{
if (!_mcPass1.IsApplicationTarget)
{
return;
}
if (recompile)
{
//
// Take whatever setting in _mcPass1 task.
//
_recompileApplicationFile = _mcPass1.ApplicationFile;
}
else
{
_recompileApplicationFile = String.Empty;
}
}
//
// Detect if at least one file in the same item list has changed since last build.
//
private bool IsFileListChanged(ITaskItem[] fileList)
{
bool isChanged = false;
if (ListIsNotEmpty(fileList))
{
for (int i = 0; i < fileList.Length; i++)
{
if (IsFileChanged(fileList[i].ItemSpec))
{
isChanged = true;
break;
}
}
}
return isChanged;
}
//
// Detect if the input file was changed since last build.
//
private bool IsFileChanged(string inputFile)
{
bool isChanged = false;
DateTime dtFile;
dtFile = TaskFileService.GetLastChangeTime(inputFile);
if (dtFile > LastCompileTime)
{
isChanged = true;
}
return isChanged;
}
// A helper to detect if the list is not empty.
private bool ListIsNotEmpty(object [] list)
{
bool isNotEmpty = false;
if (list != null && list.Length > 0)
{
isNotEmpty = true;
}
return isNotEmpty;
}
#endregion
#region private data
private MarkupCompilePass1 _mcPass1;
private RecompileCategory _analyzeResult;
private DateTime _lastCompileTime = new DateTime(0);
private string[] _recompileMarkupPages;
private string _recompileApplicationFile = null;
private string[] _contentFiles = null;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GridErrorDlg.cs
- NativeMethods.cs
- BindingManagerDataErrorEventArgs.cs
- WeakHashtable.cs
- FileAuthorizationModule.cs
- ToolStripGripRenderEventArgs.cs
- DeferredSelectedIndexReference.cs
- ElementFactory.cs
- _NegotiateClient.cs
- TrustManager.cs
- FormViewUpdatedEventArgs.cs
- FileUpload.cs
- HttpProfileGroupBase.cs
- CacheVirtualItemsEvent.cs
- XPathSelfQuery.cs
- Polygon.cs
- DrawingVisual.cs
- TrackingDataItem.cs
- ExtendedProtectionPolicyTypeConverter.cs
- ExpressionBuilderContext.cs
- DataServiceRequestException.cs
- MessageQueueEnumerator.cs
- Classification.cs
- DocumentPageHost.cs
- _emptywebproxy.cs
- XmlSchemas.cs
- HostingPreferredMapPath.cs
- RefreshEventArgs.cs
- Transform.cs
- WebBrowsableAttribute.cs
- Int32AnimationUsingKeyFrames.cs
- ComponentCommands.cs
- PictureBox.cs
- Suspend.cs
- IInstanceContextProvider.cs
- WorkflowRuntimeServiceElementCollection.cs
- TableLayoutPanel.cs
- HttpVersion.cs
- BindingListCollectionView.cs
- WebPageTraceListener.cs
- WebPartConnectionCollection.cs
- HtmlShimManager.cs
- FlowDocumentPaginator.cs
- LocalizedNameDescriptionPair.cs
- DNS.cs
- InstanceDataCollectionCollection.cs
- StyleModeStack.cs
- CapacityStreamGeometryContext.cs
- WindowsPrincipal.cs
- TrackingValidationObjectDictionary.cs
- BooleanToVisibilityConverter.cs
- XmlCharType.cs
- XamlTreeBuilderBamlRecordWriter.cs
- ObjectQuery.cs
- _UriTypeConverter.cs
- XmlSortKey.cs
- RestrictedTransactionalPackage.cs
- DefaultHttpHandler.cs
- httpserverutility.cs
- ASCIIEncoding.cs
- HTMLTextWriter.cs
- MenuBindingsEditorForm.cs
- TextDecorationCollectionConverter.cs
- WebPartUtil.cs
- Instrumentation.cs
- OpCellTreeNode.cs
- XmlWrappingWriter.cs
- WindowsPrincipal.cs
- FontFamily.cs
- AnimationStorage.cs
- RegexStringValidatorAttribute.cs
- ParameterModifier.cs
- ExtensionDataReader.cs
- CalendarDesigner.cs
- HttpConfigurationSystem.cs
- Baml2006ReaderContext.cs
- _NestedSingleAsyncResult.cs
- TextEditorDragDrop.cs
- ComplexBindingPropertiesAttribute.cs
- NonParentingControl.cs
- GroupItemAutomationPeer.cs
- SqlCacheDependencyDatabaseCollection.cs
- WebScriptMetadataFormatter.cs
- RemotingConfigParser.cs
- TextPenaltyModule.cs
- RenderOptions.cs
- ToolStripSystemRenderer.cs
- RegexTree.cs
- OleDbSchemaGuid.cs
- Atom10FormatterFactory.cs
- XmlSchemaSimpleContent.cs
- AffineTransform3D.cs
- OracleTransaction.cs
- EditorPart.cs
- DBSqlParserTableCollection.cs
- SingleStorage.cs
- Point4D.cs
- FlatButtonAppearance.cs
- MemoryFailPoint.cs
- BindingElementExtensionElement.cs