Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / Microsoft.Build.Tasks / Microsoft.Build.Tasks / GenerateResource.cs
index ed3316abc4dc6c3ed5dad8a0dc12758331f7ae77..8abdad3b7f7f76c0fa61469ae8074bb9487ee1e0 100644 (file)
@@ -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
@@ -36,8 +39,11 @@ 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;
+using Mono.XBuild.Utilities;
 
 namespace Microsoft.Build.Tasks {
        public sealed class GenerateResource : TaskExtension {
@@ -65,47 +71,122 @@ namespace Microsoft.Build.Tasks {
                        if (sources.Length == 0)
                                return true;
 
+                       bool result = true;
                        List  <ITaskItem> temporaryFilesWritten = new List <ITaskItem> ();
                        if (outputResources == null) {
                                foreach (ITaskItem source in sources) {
                                        string sourceFile = source.ItemSpec;
                                        string outputFile = Path.ChangeExtension (sourceFile, "resources");
 
-                                       if (!CompileResourceFile (sourceFile, outputFile)) {
-                                               Log.LogErrorFromException (new Exception ("Error during compiling resource file."));
-                                               return false;
-                                       }
+                                       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.LogErrorFromException (new Exception ("Sources count is different than OutputResources count."));
+                                       Log.LogError ("Sources count is different than OutputResources count.");
                                        return false;
                                }
 
                                for (int i = 0; i < sources.Length; i ++) {
                                        if (String.IsNullOrEmpty (outputResources [i].ItemSpec)) {
-                                               Log.LogErrorFromException (new Exception ("Filename of output can not be empty."));
-                                               return false;
+                                               Log.LogError ("Filename of output can not be empty.");
+                                               result = false;
+                                               continue;
                                        }
 
-                                       if (!CompileResourceFile (sources [i].ItemSpec, outputResources [i].ItemSpec)) {
-                                               Log.LogErrorFromException (new Exception ("Error during compiling resource file."));
-                                               return false;
-                                       }
+                                       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":
@@ -129,7 +210,7 @@ namespace Microsoft.Build.Tasks {
                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":
@@ -147,6 +228,11 @@ namespace Microsoft.Build.Tasks {
                
                private bool CompileResourceFile (string sname, string dname )
                {
+                       if (!File.Exists (sname)) {
+                               Log.LogError ("Resource file '{0}' not found.", sname);
+                               return false;
+                       }
+
                        Resgen resgen = new Resgen ();
                        resgen.BuildEngine = this.BuildEngine;
                        resgen.UseSourcePath = true;
@@ -277,19 +363,22 @@ namespace Microsoft.Build.Tasks {
                        if (UseSourcePath)
                                commandLine.AppendSwitch ("/useSourcePath");
 
-                       commandLine.AppendSwitch (String.Format ("/compile {0}{1}", SourceFile,
+                       commandLine.AppendSwitch (String.Format ("/compile \"{0}{1}\"", SourceFile,
                                                OutputFile != null ? "," + OutputFile : ""));
                }
 
                public override bool Execute ()
                {
-                       EnvironmentOverride ["MONO_IOMAP"] = "drive";
+                       if (String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONO_IOMAP")))
+                               EnvironmentVariables = new string [] { "MONO_IOMAP=drive" };
                        return base.Execute ();
                }
 
                protected override string GenerateFullPathToTool ()
                {
-                       return Path.Combine (ToolPath, ToolExe);
+                       if (!string.IsNullOrEmpty (ToolPath))
+                               return Path.Combine (ToolPath, ToolExe);
+                       return ToolLocationHelper.GetPathToDotNetFrameworkFile (ToolExe, TargetDotNetFrameworkVersion.VersionLatest);
                }
 
                protected override MessageImportance StandardOutputLoggingImportance {
@@ -297,7 +386,7 @@ namespace Microsoft.Build.Tasks {
                }
 
                protected override string ToolName {
-                       get { return Utilities.RunningOnWindows ? "resgen2.bat" : "resgen2"; }
+                       get { return "resgen.exe"; }
                }
 
                public string SourceFile { get; set; }