Skip to content

Commit

Permalink
[xbuild] Use files referenced by resx for dependency check.
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
radical committed Feb 2, 2011
1 parent b5cf90b commit e0b3ca6
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 9 deletions.
Expand Up @@ -5,8 +5,11 @@
// Marek Sieradzki (marek.sieradzki@gmail.com)
// Paolo Molaro (lupus@ximian.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Lluis Sanchez Gual <lluis@novell.com>
// Ankit Jain <jankit@novell.com>
//
// (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
Expand Down Expand Up @@ -36,6 +39,7 @@
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;
Expand Down Expand Up @@ -73,7 +77,8 @@ public override bool Execute ()
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;
Expand All @@ -93,7 +98,8 @@ public override bool Execute ()
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]);
}
}
Expand All @@ -103,6 +109,78 @@ public override bool Execute ()
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
// <data type="System.Resources.ResXFileRef, System.Windows.Forms" ..>
// <value>... filename;.. </value>
// </data>
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)
{
Expand Down Expand Up @@ -154,13 +232,6 @@ private bool CompileResourceFile (string sname, string dname )
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;
Expand Down
63 changes: 63 additions & 0 deletions mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/Utilities.cs
Expand Up @@ -28,6 +28,7 @@
#if NET_2_0

using System;
using System.IO;

namespace Microsoft.Build.Tasks {
internal static class Utilities {
Expand All @@ -42,6 +43,68 @@ internal static class Utilities {
}

}

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<names.Length; n++) {
string[] entries;

if (names [n] == ".."){
if (part == "/")
return ""; // Can go further back. It's not an existing file
part = Path.GetFullPath (part + "/..");
continue;
}

entries = Directory.GetFileSystemEntries (part);

string fpath = null;
foreach (string e in entries) {
if (string.Compare (Path.GetFileName (e), names[n], true) == 0) {
fpath = e;
break;
}
}
if (fpath == null) {
// Part of the path does not exist. Can't do any more checking.
part = Path.GetFullPath (part);
for (; n < names.Length; n++)
part += "/" + names[n];
return part;
}

part = fpath;
}
return Path.GetFullPath (part);
} else {
return Path.GetFullPath (path);
}
}

}

}
Expand Down

0 comments on commit e0b3ca6

Please sign in to comment.