Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

400 lines
10 KiB
C#

//
// GenerateResource.cs: Task that generates the resources.
//
// Author:
// 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
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Text;
using System.IO;
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 {
ITaskItem[] filesWritten;
bool neverLockTypeAssemblies;
ITaskItem[] outputResources;
bool publicClass;
ITaskItem[] references;
ITaskItem[] sources;
ITaskItem stateFile;
string stronglyTypedClassName;
string stronglyTypedFilename;
string stronglyTypedLanguage;
string stronglyTypedNamespace;
bool useSourcePath;
public GenerateResource ()
{
useSourcePath = false;
}
public override bool Execute ()
{
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 = source.GetMetadata ("AutoGen").Equals ("true", StringComparison.OrdinalIgnoreCase) ?
source.ItemSpec.Replace ('\\', '.').Replace ('/', '.') :
Path.ChangeExtension (sourceFile, "resources");
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 ++) {
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 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.ToLowerInvariant ()) {
case ".po":
return new PoResourceReader (stream);
case ".txt":
case ".text":
return new TxtResourceReader (stream);
case ".resources":
return new ResourceReader (stream);
case ".resx":
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.ToLowerInvariant ()) {
case ".po":
return new PoResourceWriter (stream);
case ".txt":
case ".text":
return new TxtResourceWriter (stream);
case ".resources":
return new ResourceWriter (stream);
case ".resx":
return new System.Resources.ResXResourceWriter (stream);
default:
throw new Exception ("Unknown format in file " + name);
}
}
#endif
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;
resgen.SourceFile = sname;
resgen.OutputFile = dname;
return resgen.Execute ();
}
[Output]
public ITaskItem[] FilesWritten {
get {
return filesWritten;
}
}
[MonoTODO]
public bool NeverLockTypeAssemblies {
get {
return neverLockTypeAssemblies;
}
set {
neverLockTypeAssemblies = value;
}
}
[Output]
public ITaskItem[] OutputResources {
get {
return outputResources;
}
set {
outputResources = value;
}
}
public bool PublicClass {
get { return publicClass; }
set { publicClass = value; }
}
public ITaskItem[] References {
get {
return references;
}
set {
references = value;
}
}
[Required]
public ITaskItem[] Sources {
get {
return sources;
}
set {
sources = value;
}
}
public ITaskItem StateFile {
get {
return stateFile;
}
set {
stateFile = value;
}
}
[Output]
public string StronglyTypedClassName {
get {
return stronglyTypedClassName;
}
set {
stronglyTypedClassName = value;
}
}
[Output]
public string StronglyTypedFileName {
get {
return stronglyTypedFilename;
}
set {
stronglyTypedFilename = value;
}
}
public string StronglyTypedLanguage {
get {
return stronglyTypedLanguage;
}
set {
stronglyTypedLanguage = value;
}
}
public string StronglyTypedNamespace {
get {
return stronglyTypedNamespace;
}
set {
stronglyTypedNamespace = value;
}
}
public bool UseSourcePath {
get {
return useSourcePath;
}
set {
useSourcePath = value;
}
}
}
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; }
}
}