400 lines
10 KiB
C#
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; }
|
|
}
|
|
}
|
|
|