From ae1aee44394550966eb8acc1b935cd6ff5bb73e1 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Thu, 16 Sep 2010 00:54:25 +0530 Subject: [PATCH] [xbuild] Use files referenced by resx for dependency check. For .resx resource files, check files referenced by the resx file also, to determine whether to resgen it or not. IsResgenRequired () has been taken from MonoDevelop (main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs) --- .../Microsoft.Build.Tasks/GenerateResource.cs | 89 +++++++++++++++++-- .../Microsoft.Build.Tasks/Utilities.cs | 63 +++++++++++++ 2 files changed, 143 insertions(+), 9 deletions(-) diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs index 98b818303b2..31676af3f40 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/GenerateResource.cs @@ -5,8 +5,11 @@ // Marek Sieradzki (marek.sieradzki@gmail.com) // Paolo Molaro (lupus@ximian.com) // Gonzalo Paniagua Javier (gonzalo@ximian.com) +// Lluis Sanchez Gual +// Ankit Jain // // (C) 2005 Marek Sieradzki +// Copyright 2010 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -36,6 +39,7 @@ using System.Collections; using System.Collections.Generic; using System.Resources; using System.Reflection; +using System.Xml; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Mono.XBuild.Tasks.GenerateResourceInternal; @@ -73,7 +77,8 @@ namespace Microsoft.Build.Tasks { string sourceFile = source.ItemSpec; string outputFile = Path.ChangeExtension (sourceFile, "resources"); - result &= CompileResourceFile (sourceFile, outputFile); + if (IsResgenRequired (sourceFile, outputFile)) + result &= CompileResourceFile (sourceFile, outputFile); ITaskItem newItem = new TaskItem (source); source.ItemSpec = outputFile; @@ -93,7 +98,8 @@ namespace Microsoft.Build.Tasks { continue; } - result &= CompileResourceFile (sources [i].ItemSpec, outputResources [i].ItemSpec); + if (IsResgenRequired (sources [i].ItemSpec, outputResources [i].ItemSpec)) + result &= CompileResourceFile (sources [i].ItemSpec, outputResources [i].ItemSpec); temporaryFilesWritten.Add (outputResources [i]); } } @@ -103,6 +109,78 @@ namespace Microsoft.Build.Tasks { return result; } + // true if the resx file or any file referenced + // by the resx is newer than the .resources file + // + // Code taken from monodevelop + // main/src/core/MonoDevelop.Core/MonoDevelop.Projects.Formats.MD1/MD1DotNetProjectHandler.cs + bool IsResgenRequired (string resx_filename, string resources_filename) + { + if (IsFileNewerThan (resx_filename, resources_filename)) { + Log.LogMessage (MessageImportance.Low, + "Resource file '{0}' is newer than the source file '{1}', skipping.", + resources_filename, resx_filename); + return true; + } + + if (String.Compare (Path.GetExtension (resx_filename), ".resx", true) != 0) + return true; + + // resx file, check for files referenced from there + XmlTextReader xr = null; + try { + // look for + // + // ... filename;.. + // + xr = new XmlTextReader (resx_filename); + string basepath = Path.GetDirectoryName (resx_filename); + while (xr.Read ()) { + if (xr.NodeType != XmlNodeType.Element || + String.Compare (xr.LocalName, "data") != 0) + continue; + + string type = xr.GetAttribute ("type"); + if (String.IsNullOrEmpty (type)) + continue; + + if (String.Compare (type, "System.Resources.ResXFileRef, System.Windows.Forms") != 0) + continue; + + xr.ReadToDescendant ("value"); + if (xr.NodeType != XmlNodeType.Element) + continue; + + string value = xr.ReadElementContentAsString (); + + string [] parts = value.Split (';'); + if (parts.Length > 0) { + string referenced_filename = Utilities.FromMSBuildPath ( + Path.Combine (basepath, parts [0]).Trim ()); + if (File.Exists (referenced_filename) && + IsFileNewerThan (referenced_filename, resources_filename)) + return true; + } + } + } catch (XmlException) { + // Ignore xml errors, let resgen handle it + return true; + } finally { + if (xr != null) + xr.Close (); + } + + return false; + } + + // true if first is newer than second + static bool IsFileNewerThan (string first, string second) + { + FileInfo finfo_first = new FileInfo (first); + FileInfo finfo_second = new FileInfo (second); + return finfo_first.LastWriteTime > finfo_second.LastWriteTime; + } + #if false private IResourceReader GetReader (Stream stream, string name) { @@ -154,13 +232,6 @@ namespace Microsoft.Build.Tasks { return false; } - if (File.GetLastWriteTime (sname) <= File.GetLastWriteTime (dname)) { - Log.LogMessage (MessageImportance.Low, - "Resource file '{0}' is newer than the source file '{1}', skipping.", - dname, sname); - return true; - } - Resgen resgen = new Resgen (); resgen.BuildEngine = this.BuildEngine; resgen.UseSourcePath = true; diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Utilities.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Utilities.cs index e9a5ac5915e..5a0c56ec901 100644 --- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Utilities.cs +++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Utilities.cs @@ -28,6 +28,7 @@ #if NET_2_0 using System; +using System.IO; namespace Microsoft.Build.Tasks { internal static class Utilities { @@ -42,6 +43,68 @@ namespace Microsoft.Build.Tasks { } } + + internal static string FromMSBuildPath (string relPath) + { + if (relPath == null || relPath.Length == 0) + return null; + + bool is_windows = Path.DirectorySeparatorChar == '\\'; + string path = relPath; + if (!is_windows) + path = path.Replace ("\\", "/"); + + // a path with drive letter is invalid/unusable on non-windows + if (!is_windows && char.IsLetter (path [0]) && path.Length > 1 && path[1] == ':') + return null; + + if (System.IO.File.Exists (path)){ + return Path.GetFullPath (path); + } + + if (Path.IsPathRooted (path)) { + + // Windows paths are case-insensitive. When mapping an absolute path + // we can try to find the correct case for the path. + + string[] names = path.Substring (1).Split ('/'); + string part = "/"; + + for (int n=0; n