// 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
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;
+using Mono.XBuild.Utilities;
namespace Microsoft.Build.Tasks {
public sealed class GenerateResource : TaskExtension {
public override bool Execute ()
{
+ if (sources.Length == 0)
+ return true;
+
+ bool result = true;
List <ITaskItem> temporaryFilesWritten = new List <ITaskItem> ();
- if (sources.Length != outputResources.Length) {
- Log.LogErrorFromException (new Exception ("Sources count is different than OutputResources count."));
- return false;
- }
-
if (outputResources == null) {
foreach (ITaskItem source in sources) {
string sourceFile = source.ItemSpec;
string outputFile = Path.ChangeExtension (sourceFile, "resources");
- CompileResourceFile (sourceFile, outputFile);
+
+ if (IsResgenRequired (sourceFile, outputFile))
+ result &= CompileResourceFile (sourceFile, outputFile);
+
+ ITaskItem newItem = new TaskItem (source);
+ newItem.ItemSpec = outputFile;
+
+ temporaryFilesWritten.Add (newItem);
}
} else {
+ if (sources.Length != outputResources.Length) {
+ Log.LogError ("Sources count is different than OutputResources count.");
+ return false;
+ }
+
for (int i = 0; i < sources.Length; i ++) {
- string sourceFile = sources [i].ItemSpec;
- for (int j = 0; j < outputResources.Length; j ++) {
- string outputFile = outputResources [j].ItemSpec;
-
- if (outputFile == String.Empty) {
- Log.LogErrorFromException (new Exception ("Filename of output can not be empty."));
- return false;
- }
- if (CompileResourceFile (sourceFile, outputFile) == false) {
- Log.LogErrorFromException (new Exception ("Error during compiling resource file."));
- return false;
- }
- temporaryFilesWritten.Add (outputResources [j]);
+ if (String.IsNullOrEmpty (outputResources [i].ItemSpec)) {
+ Log.LogError ("Filename of output can not be empty.");
+ result = false;
+ continue;
}
+
+ if (IsResgenRequired (sources [i].ItemSpec, outputResources [i].ItemSpec))
+ result &= CompileResourceFile (sources [i].ItemSpec, outputResources [i].ItemSpec);
+ temporaryFilesWritten.Add (outputResources [i]);
}
}
filesWritten = temporaryFilesWritten.ToArray ();
-
- return true;
+
+ 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 = MSBuildUtils.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)
{
string format = Path.GetExtension (name);
- switch (format.ToLower ()) {
+ switch (format.ToLowerInvariant ()) {
case ".po":
return new PoResourceReader (stream);
case ".txt":
case ".resources":
return new ResourceReader (stream);
case ".resx":
- return new System.Resources.ResXResourceReader (stream);
+ ResXResourceReader reader = new ResXResourceReader (stream);
+
+ // set correct basepath to resolve relative paths in file refs
+ if (useSourcePath)
+ reader.BasePath = Path.GetDirectoryName (Path.GetFullPath (name));
+
+ return reader;
default:
throw new Exception ("Unknown format in file " + name);
}
private IResourceWriter GetWriter (Stream stream, string name)
{
string format = Path.GetExtension (name);
- switch (format.ToLower ()) {
+ switch (format.ToLowerInvariant ()) {
case ".po":
return new PoResourceWriter (stream);
case ".txt":
throw new Exception ("Unknown format in file " + name);
}
}
+#endif
private bool CompileResourceFile (string sname, string dname )
{
- FileStream source, dest;
- IResourceReader reader;
- IResourceWriter writer;
-
- try {
- source = new FileStream (sname, FileMode.Open, FileAccess.Read);
-
- reader = GetReader (source, sname);
+ if (!File.Exists (sname)) {
+ Log.LogError ("Resource file '{0}' not found.", sname);
+ return false;
+ }
- dest = new FileStream (dname, FileMode.Create, FileAccess.Write);
- writer = GetWriter (dest, dname);
+ Resgen resgen = new Resgen ();
+ resgen.BuildEngine = this.BuildEngine;
+ resgen.UseSourcePath = true;
- int rescount = 0;
- foreach (DictionaryEntry e in reader) {
- rescount++;
- object val = e.Value;
- if (val is string)
- writer.AddResource ((string)e.Key, (string)e.Value);
- else
- writer.AddResource ((string)e.Key, e.Value);
- }
+ resgen.SourceFile = sname;
+ resgen.OutputFile = dname;
- reader.Close ();
- writer.Close ();
- } catch (Exception e) {
- Log.LogErrorFromException (e);
- return false;
- }
- return true;
+ return resgen.Execute ();
}
[Output]
}
}
}
+
+ class Resgen : ToolTaskExtension
+ {
+ public Resgen ()
+ {
+ }
+
+ protected internal override void AddCommandLineCommands (
+ CommandLineBuilderExtension commandLine)
+ {
+ if (UseSourcePath)
+ commandLine.AppendSwitch ("/useSourcePath");
+
+ commandLine.AppendSwitch (String.Format ("/compile \"{0}{1}\"", SourceFile,
+ OutputFile != null ? "," + OutputFile : ""));
+ }
+
+ public override bool Execute ()
+ {
+ if (String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONO_IOMAP")))
+ EnvironmentVariables = new string [] { "MONO_IOMAP=drive" };
+ return base.Execute ();
+ }
+
+ protected override string GenerateFullPathToTool ()
+ {
+ if (!string.IsNullOrEmpty (ToolPath))
+ return Path.Combine (ToolPath, ToolExe);
+ return ToolLocationHelper.GetPathToDotNetFrameworkFile (ToolExe, TargetDotNetFrameworkVersion.VersionLatest);
+ }
+
+ protected override MessageImportance StandardOutputLoggingImportance {
+ get { return MessageImportance.Low; }
+ }
+
+ protected override string ToolName {
+ get { return "resgen.exe"; }
+ }
+
+ public string SourceFile { get; set; }
+ public string OutputFile { get; set; }
+
+ public bool UseSourcePath { get; set; }
+ }
}
#endif