Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[mono.git] / mcs / class / System.Web / System.Web.Compilation / AppResourcesAssemblyBuilder.cs
index f302cc9fa7881c9fc1e2582765622193d2d7480b..895440d3a6a8ec33f843523b24777261e37e3014 100644 (file)
@@ -2,10 +2,10 @@
 // System.Web.Compilation.AppResourceAseemblyBuilder
 //
 // Authors:
-//   Marek Habersack (mhabersack@novell.com)
-//
-// (C) 2007 Novell, Inc
+//   Marek Habersack <grendel@twistedcode.net>
 //
+// (C) 2007-2009 Novell, Inc (http://novell.com/)
+// (C) 2011 Xamarin, Inc (http://xamarin.com/)
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-#if NET_2_0
+
 using System;
 using System.CodeDom;
 using System.CodeDom.Compiler;
 using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Diagnostics;
 using System.IO;
 using System.Reflection;
+using System.Text;
+using System.Threading;
 using System.Web;
 using System.Web.Configuration;
+using System.Web.Util;
 
 namespace System.Web.Compilation
 {
-       internal class AppResourcesAssemblyBuilder
+       class AppResourcesAssemblyBuilder
        {
+               static string framework_version = "4.5";
+               static string profile_path = "net_4_x";
                CompilationSection config;
                CompilerInfo ci;
                CodeDomProvider _provider;
@@ -90,22 +98,23 @@ namespace System.Web.Compilation
                public void Build (CodeCompileUnit unit)
                {
                        Dictionary <string, List <string>> cultures = appResourcesCompiler.CultureFiles;
-                       string defaultAssemblyKey = AppResourcesCompiler.DefaultCultureKey;
+                       List <string> defaultCultureFiles = appResourcesCompiler.DefaultCultureFiles;
+                       
+                       if (defaultCultureFiles != null)
+                               BuildDefaultAssembly (defaultCultureFiles, unit);
                        
                        foreach (KeyValuePair <string, List <string>> kvp in cultures)
-                               BuildAssembly (kvp.Key, kvp.Value, defaultAssemblyKey, unit);
+                               BuildSatelliteAssembly (kvp.Key, kvp.Value);
                }
 
-               void BuildAssembly (string cultureName, List <string> files, string defaultAssemblyKey, CodeCompileUnit unit)
+               void BuildDefaultAssembly (List <string> files, CodeCompileUnit unit)
                {
-                       bool defaultAssembly = cultureName == defaultAssemblyKey;                       
                        AssemblyBuilder abuilder = new AssemblyBuilder (Provider);
-                       if (unit != null && defaultAssembly)
+                       if (unit != null)
                                abuilder.AddCodeCompileUnit (unit);
                        
-                       string assemblyPath = defaultAssembly ? baseAssemblyPath : BuildAssemblyPath (cultureName, abuilder);
                        CompilerParameters cp = ci.CreateDefaultCompilerParameters ();
-                       cp.OutputAssembly = assemblyPath;
+                       cp.OutputAssembly = baseAssemblyPath;
                        cp.GenerateExecutable = false;
                        cp.TreatWarningsAsErrors = true;
                        cp.IncludeDebugInformation = config.Debug;
@@ -117,27 +126,144 @@ namespace System.Web.Compilation
                        if (results == null)
                                return;
                        
-                       Assembly ret = null;
-                       
                        if (results.NativeCompilerReturnValue == 0) {
-                               ret = results.CompiledAssembly;
-                               if (defaultAssembly) {
-                                       BuildManager.TopLevelAssemblies.Add (ret);
-                                       mainAssembly = ret;
-                               }
+                               mainAssembly = results.CompiledAssembly;
+                               BuildManager.TopLevelAssemblies.Add (mainAssembly);
                        } else {
                                if (HttpContext.Current.IsCustomErrorEnabled)
                                        throw new ApplicationException ("An error occurred while compiling global resources.");
                                throw new CompilationException (null, results.Errors, null);
                        }
                        
-                       if (defaultAssembly) {
-                               HttpRuntime.WritePreservationFile (ret, canonicAssemblyName);
-                               HttpRuntime.EnableAssemblyMapping (true);
+                       HttpRuntime.WritePreservationFile (mainAssembly, canonicAssemblyName);
+                       HttpRuntime.EnableAssemblyMapping (true);
+               }
+
+               void BuildSatelliteAssembly (string cultureName, List <string> files)
+               {
+                       string assemblyPath = BuildAssemblyPath (cultureName);
+                       var info = new ProcessStartInfo ();
+                       var al = new Process ();
+
+                       string arguments = SetAlPath (info);
+                       var sb = new StringBuilder (arguments);
+
+                       sb.Append ("/c:\"" + cultureName + "\" ");
+                       sb.Append ("/t:lib ");
+                       sb.Append ("/out:\"" + assemblyPath + "\" ");
+                       if (mainAssembly != null)
+                               sb.Append ("/template:\"" + mainAssembly.Location + "\" ");
+                       
+                       string responseFilePath = assemblyPath + ".response";
+                       using (FileStream fs = File.OpenWrite (responseFilePath)) {
+                               using (StreamWriter sw = new StreamWriter (fs)) {
+                                       foreach (string f in files) 
+                                               sw.WriteLine ("/embed:\"" + f + "\" ");
+                               }
+                       }
+                       sb.Append ("@\"" + responseFilePath + "\"");
+                       
+                       info.Arguments = sb.ToString ();
+                       info.CreateNoWindow = true;
+                       info.UseShellExecute = false;
+                       info.RedirectStandardOutput = true;
+                       info.RedirectStandardError = true;
+                       
+                       al.StartInfo = info;
+
+                       var alOutput = new StringCollection ();
+                       var alMutex = new Mutex ();
+                       DataReceivedEventHandler outputHandler = (object sender, DataReceivedEventArgs args) => {
+                               if (args.Data != null) {
+                                       alMutex.WaitOne ();
+                                       alOutput.Add (args.Data);
+                                       alMutex.ReleaseMutex ();
+                               }
+                       };
+                       
+                       al.ErrorDataReceived += outputHandler;
+                       al.OutputDataReceived += outputHandler;
+
+                       // TODO: consider using asynchronous processes
+                       try {
+                               al.Start ();
+                       } catch (Exception ex) {
+                               throw new HttpException (String.Format ("Error running {0}", al.StartInfo.FileName), ex);
+                       }
+
+                       Exception alException = null;
+                       int exitCode = 0;
+                       try {
+                               al.BeginOutputReadLine ();
+                               al.BeginErrorReadLine ();
+                               al.WaitForExit ();
+                               exitCode = al.ExitCode;
+                       } catch (Exception ex) {
+                               alException = ex;
+                       } finally {
+                               al.CancelErrorRead ();
+                               al.CancelOutputRead ();
+                               al.Close ();
+                       }
+
+                       if (exitCode != 0 || alException != null) {
+                               // TODO: consider adding a new type of compilation exception,
+                               // tailored for al
+                               CompilerErrorCollection errors = null;
+                               
+                               if (alOutput.Count != 0) {
+                                       foreach (string line in alOutput) {
+                                               if (!line.StartsWith ("ALINK: error ", StringComparison.Ordinal))
+                                                       continue;
+                                               if (errors == null)
+                                                       errors = new CompilerErrorCollection ();
+
+                                               int colon = line.IndexOf (':', 13);
+                                               string errorNumber = colon != -1 ? line.Substring (13, colon - 13) : "Unknown";
+                                               string errorText = colon != -1 ? line.Substring (colon + 1) : line.Substring (13);
+                                               
+                                               errors.Add (new CompilerError (Path.GetFileName (assemblyPath), 0, 0, errorNumber, errorText));
+                                       }
+                               }
+                               
+                               throw new CompilationException (Path.GetFileName (assemblyPath), errors, null);
                        }
                }
 
-               string BuildAssemblyPath (string cultureName, AssemblyBuilder abuilder)
+               string SetAlPath (ProcessStartInfo info)
+               {                       
+                       if (RuntimeHelpers.RunningOnWindows) {
+                               string alPath;
+                               string monoPath;
+                               PropertyInfo gac = typeof (Environment).GetProperty ("GacPath", BindingFlags.Static|BindingFlags.NonPublic);
+                                MethodInfo get_gac = gac.GetGetMethod (true);
+                                string p = Path.GetDirectoryName ((string) get_gac.Invoke (null, null));
+                               monoPath = Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (p)), "bin\\mono.bat");
+                                if (!File.Exists (monoPath)) {
+                                        monoPath = Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (p)), "bin\\mono.exe");
+                                       if (!File.Exists (monoPath)) {
+                                               monoPath = Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (Path.GetDirectoryName (p))), "mono\\mono\\mini\\mono.exe");
+                                               if (!File.Exists (monoPath))
+                                                       throw new FileNotFoundException ("Windows mono path not found: " + monoPath);
+                                       }
+                               }
+                               alPath = Path.Combine (p, framework_version + "\\al.exe");
+                               
+                                if (!File.Exists (alPath)) {
+                                       alPath = Path.Combine (Path.GetDirectoryName (p), "lib\\" + profile_path + "\\al.exe");
+                                       if (!File.Exists (alPath))
+                                               throw new FileNotFoundException ("Windows al path not found: " + alPath);
+                               }
+
+                               info.FileName = monoPath;
+                               return alPath + " ";
+                       } else {
+                               info.FileName = "al";
+                               return String.Empty;
+                       }
+               }
+               
+               string BuildAssemblyPath (string cultureName)
                {
                        string baseDir = Path.Combine (baseAssemblyDirectory, cultureName);
                        if (!Directory.Exists (baseDir))
@@ -147,10 +273,6 @@ namespace System.Web.Compilation
                        string fileName = String.Concat (baseFileName, ".resources.dll");
                        fileName = Path.Combine (baseDir, fileName);
 
-                       CodeCompileUnit assemblyInfo = GenerateAssemblyInfo (cultureName);
-                       if (assemblyInfo != null)
-                               abuilder.AddCodeCompileUnit (assemblyInfo);
-
                        return fileName;
                }
 
@@ -177,4 +299,4 @@ namespace System.Web.Compilation
                }
        }
 }
-#endif
+