All pastes #247855 Raw Edit

Unnamed

public text v1 · immutable
#247855 ·published 2006-11-13 22:44 UTC
rendered paste body
Index: IgnoreFileBuildProvider.cs
===================================================================
--- IgnoreFileBuildProvider.cs	(revision 67781)
+++ IgnoreFileBuildProvider.cs	(working copy)
@@ -31,7 +31,7 @@
 #if NET_2_0
 
 namespace System.Web.Compilation {
-
+	[BuildProviderAppliesTo (BuildProviderAppliesTo.All)]
 	class IgnoreFileBuildProvider : BuildProvider
 	{
 		public override void GenerateCode (AssemblyBuilder assemblyBuilder)
Index: WebServiceBuildProvider.cs
===================================================================
--- WebServiceBuildProvider.cs	(revision 67781)
+++ WebServiceBuildProvider.cs	(working copy)
@@ -39,7 +39,7 @@
 using System.Web.UI;
 
 namespace System.Web.Compilation {
-
+	[BuildProviderAppliesTo (BuildProviderAppliesTo.Web)]
 	sealed class WebServiceBuildProvider : BuildProvider {
 		WebServiceCompiler wscompiler;
 		CompilerType compiler_type;
Index: AppResourceFilesCompiler.cs
===================================================================
--- AppResourceFilesCompiler.cs	(revision 67781)
+++ AppResourceFilesCompiler.cs	(working copy)
@@ -37,6 +37,7 @@
 using System.IO;
 using System.Reflection;
 using System.Resources;
+using System.Web.Util;
 
 using Microsoft.CSharp;
 //using Microsoft.VisualBasic;
@@ -574,6 +575,13 @@
 			return resfile;
 		}
 
+		object OnCreateRandomFile (string path)
+		{
+			FileStream f = new FileStream (path, FileMode.CreateNew);
+			f.Close ();
+			return path;
+		}
+		
 		protected string GenRandomFileName (string basepath)
 		{
 			return GenRandomFileName (basepath, null);
@@ -581,50 +589,18 @@
 		
 		protected string GenRandomFileName (string basepath, string ext)
 		{
-			if (rnd == null)
-				rnd = new Random ();
-			FileStream f = null;
-			string path = null;
-			do {
-				int num = rnd.Next ();
-				num++;
-				path = Path.Combine (basepath, num.ToString ("x"));
-				if (ext != null)
-					path = String.Format ("{0}.{1}", path, ext);
-					
-				try {
-					f = new FileStream (path, FileMode.CreateNew);
-				} catch (System.IO.IOException) {
-					f = null;
-					continue;
-				} catch {
-					throw;
-				}
-			} while (f == null);
-			f.Close ();
-			return path;
+			return (string)FileUtils.CreateTemporaryFile (basepath, ext, OnCreateRandomFile);
 		}
+
+		object OnCreateRandomDir (string path)
+		{
+			DirectoryInfo di = Directory.CreateDirectory (path);
+			return di.FullName;
+		}
 		
 		protected string GenTempDir (string basepath)
 		{
-			if (rnd == null)
-				rnd = new Random ();
-			DirectoryInfo di = null;
-			string path;
-			do {
-				int num = rnd.Next ();
-				num++;
-				path = Path.Combine (basepath, num.ToString ("x"));
-				try {
-					di = Directory.CreateDirectory (path);
-				} catch (System.IO.IOException) {
-					di = null;
-					continue;
-				} catch {
-					throw;
-				}
-			} while (di == null);
-			return di.FullName;
+			return (string)FileUtils.CreateTemporaryFile (basepath, OnCreateRandomDir);
 		}
 	}
 }
Index: PageBuildProvider.cs
===================================================================
--- PageBuildProvider.cs	(revision 67781)
+++ PageBuildProvider.cs	(working copy)
@@ -40,6 +40,7 @@
 
 namespace System.Web.Compilation {
 
+	[BuildProviderAppliesTo (BuildProviderAppliesTo.Web)]
 	sealed class PageBuildProvider : BuildProvider {
 		PageCompiler pcompiler;
 		CompilerType compiler_type;
Index: UserControlBuildProvider.cs
===================================================================
--- UserControlBuildProvider.cs	(revision 67781)
+++ UserControlBuildProvider.cs	(working copy)
@@ -39,7 +39,7 @@
 using System.Web.UI;
 
 namespace System.Web.Compilation {
-
+	[BuildProviderAppliesTo (BuildProviderAppliesTo.Web)]
 	sealed class UserControlBuildProvider : BuildProvider {
 		UserControlCompiler uccompiler;
 		CompilerType compiler_type;
Index: AssemblyBuilder.cs
===================================================================
--- AssemblyBuilder.cs	(revision 67781)
+++ AssemblyBuilder.cs	(working copy)
@@ -49,27 +49,35 @@
 		CodeDomProvider provider;
 		List <CodeCompileUnit> units;
 		List <string> source_files;
+		List <string> referenced_assemblies;
 		Dictionary <string, string> resource_files;
 		TempFileCollection temp_files;
 		string virtual_path;
 		//TODO: there should be a Compile () method here which is where all the compilation exceptions are thrown from.
+
+		internal AssemblyBuilder (CodeDomProvider provider)
+		: this (null, provider)
+		{}
 		
 		internal AssemblyBuilder (string virtualPath, CodeDomProvider provider)
 		{
 			this.provider = provider;
 			this.virtual_path = virtualPath;
 			units = new List <CodeCompileUnit> ();
-			units.Add (new CodeCompileUnit ());
 			temp_files = new TempFileCollection ();
+			referenced_assemblies = new List <string> ();
 			CompilationSection section;
-			section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation", virtualPath);
+			if (virtualPath != null)
+				section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation", virtualPath);
+			else
+				section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
 			string tempdir = section.TempDirectory;
 			if (tempdir == null || tempdir == "")
 				tempdir = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
 				
 			temp_files = new TempFileCollection (tempdir, KeepFiles);
 		}
-
+		
 		internal TempFileCollection TempFiles {
 			get { return temp_files; }
 		}
@@ -101,14 +109,10 @@
 		{
 			if (a == null)
 				throw new ArgumentNullException ("a");
-
-			StringCollection coll = units [units.Count - 1].ReferencedAssemblies;
-			string location = a.Location;
-			if (coll.IndexOf (location) == -1)
-				coll.Add (location);
+			
+			referenced_assemblies.Add (a.Location);
 		}
 
-		[MonoTODO ("Do something with the buildProvider argument")]
 		public void AddCodeCompileUnit (BuildProvider buildProvider, CodeCompileUnit compileUnit)
 		{
 			if (buildProvider == null)
@@ -120,18 +124,30 @@
 			units.Add (compileUnit);
 		}
 
-		[MonoTODO ("Anything to do with the buildProvider argument?")]
 		public TextWriter CreateCodeFile (BuildProvider buildProvider)
 		{
 			if (buildProvider == null)
 				throw new ArgumentNullException ("buildProvider");
 
-			string filename = temp_files.AddExtension ("temp", true);
+			// Generate a file name with the correct source language extension
+			string filename = GetTempFilePhysicalPath (provider.FileExtension);
 			SourceFiles.Add (filename);
 			return new StreamWriter (File.OpenWrite (filename), WebEncoding.FileEncoding);
 		}
 
-		[MonoTODO ("Anything to do with the buildProvider argument?")]
+		internal void AddCodeFile (string path)
+		{
+			if (path == null || path.Length == 0)
+				return;
+			string extension = Path.GetExtension (path);
+			if (extension == null || extension.Length == 0)
+				return; // maybe better to throw an exception here?
+			extension = extension.Substring (1);
+			string filename = GetTempFilePhysicalPath (extension);
+			File.Copy (path, filename, true);
+			SourceFiles.Add (filename);
+		}
+		
 		public Stream CreateEmbeddedResource (BuildProvider buildProvider, string name)
 		{
 			if (buildProvider == null)
@@ -140,7 +156,7 @@
 			if (name == null || name == "")
 				throw new ArgumentNullException ("name");
 
-			string filename = temp_files.AddExtension ("resource", true);
+			string filename = GetTempFilePhysicalPath ("resource");
 			Stream stream = File.OpenWrite (filename);
 			ResourceFiles [name] = filename;
 			return stream;
@@ -156,19 +172,59 @@
 		{
 			if (extension == null)
 				throw new ArgumentNullException ("extension");
-
-			return temp_files.AddExtension (extension, true);
+			
+			return temp_files.AddExtension (String.Format ("_{0}.{1}", temp_files.Count, extension), true);
 		}
 
 		public CodeDomProvider CodeDomProvider {
 			get { return provider; }
 		}
 
+		internal CompilerResults BuildAssembly (CompilerParameters options)
+		{
+			return BuildAssembly (null, options);
+		}
+		
 		internal CompilerResults BuildAssembly (string virtualPath, CompilerParameters options)
 		{
+			if (options == null)
+				throw new ArgumentNullException ("options");
+			
 			CompilerResults results;
 			CodeCompileUnit [] units = GetUnitsAsArray ();
-			results = provider.CompileAssemblyFromDom (options, units);
+
+			// Since we may have some source files and some code
+			// units, we generate code from all of them and then
+			// compile the assembly from the set of temporary source
+			// files. This also facilates possible debugging for the
+			// end user, since they get the code beforehand.
+			List <string> files = SourceFiles;
+			string filename;
+			StreamWriter sw = null;
+			foreach (CodeCompileUnit unit in units) {
+				filename = GetTempFilePhysicalPath (provider.FileExtension);
+				try {
+					sw = new StreamWriter (File.OpenWrite (filename), WebEncoding.FileEncoding);
+					provider.GenerateCodeFromCompileUnit (unit, sw, null);
+					files.Add (filename);
+				} catch {
+					throw;
+				} finally {
+					if (sw != null) {
+						sw.Flush ();
+						sw.Close ();
+					}
+				}
+			}
+
+			Dictionary <string, string> resources = ResourceFiles;
+			foreach (KeyValuePair <string, string> de in resources)
+				options.EmbeddedResources.Add (de.Value);
+			foreach (string refasm in referenced_assemblies)
+				options.ReferencedAssemblies.Add (refasm);
+			
+			results = provider.CompileAssemblyFromFile (options, files.ToArray ());
+			
 			// FIXME: generate the code and display it
 			if (results.NativeCompilerReturnValue != 0)
 				throw new CompilationException (virtualPath, results.Errors, "");
@@ -184,7 +240,8 @@
 				results.CompiledAssembly = Assembly.LoadFrom (options.OutputAssembly);
 			}
 
-			results.TempFiles.Delete ();
+			if (!KeepFiles)
+				results.TempFiles.Delete ();
 			return results;
 		}
 	}
Index: WebHandlerBuildProvider.cs
===================================================================
--- WebHandlerBuildProvider.cs	(revision 67781)
+++ WebHandlerBuildProvider.cs	(working copy)
@@ -39,7 +39,7 @@
 using System.Web.UI;
 
 namespace System.Web.Compilation {
-
+	[BuildProviderAppliesTo (BuildProviderAppliesTo.Web)]
 	sealed class WebHandlerBuildProvider : BuildProvider {
 		WebServiceCompiler wscompiler;
 		CompilerType compiler_type;
Index: AppCodeCompiler.cs
===================================================================
--- AppCodeCompiler.cs	(revision 67781)
+++ AppCodeCompiler.cs	(working copy)
@@ -36,13 +36,12 @@
 using System.Globalization;
 using System.IO;
 using System.Web.Configuration;
+using System.Web.Util;
 
 namespace System.Web.Compilation
 {
 	internal class AppCodeAssembly
 	{
-		private static Random rnd = new Random ();
-		
 		private List<string> files;
 		private string name;
 		private string path;
@@ -82,6 +81,13 @@
 		{
 			files.Add (path);
 		}
+
+		object OnCreateTemporaryAssemblyFile (string path)
+		{
+			FileStream f = new FileStream (path, FileMode.CreateNew);
+			f.Close ();
+			return path;
+		}
 		
 		// Build and add the assembly to the BuildManager's
 		// CodeAssemblies collection
@@ -130,30 +136,96 @@
 			}
 
 			CodeDomProvider provider = null;
-			// First the files in the language we are aware of
-			if (compilerInfo != null) {
+			if (compilerInfo == null) {
+				CompilationSection config = WebConfigurationManager.GetSection ("system.web/compilation") as CompilationSection;
+				if (config == null || !CodeDomProvider.IsDefinedLanguage (config.DefaultLanguage))
+					throw new HttpException ("Failed to retrieve default source language");
+				compilerInfo = CodeDomProvider.GetCompilerInfo (config.DefaultLanguage);
+				if (compilerInfo == null || !compilerInfo.IsCodeDomProviderTypeValid)
+					throw new HttpException ("Internal error while initializing application");
 				provider = compilerInfo.CreateProvider ();
 				if (provider == null)
-					throw new HttpException ("Unable to create a compiler for App_Code contents");
+					throw new HttpException ("A code provider error occurred while initializing application.");
+			}
 
-				CompilerParameters parameters = compilerInfo.CreateDefaultCompilerParameters ();
-				int num = rnd.Next () + 1;
+			provider = compilerInfo.CreateProvider ();
+			if (provider == null)
+				throw new HttpException ("A code provider error occurred while initializing application.");
+
+			AssemblyBuilder abuilder = new AssemblyBuilder (provider);
+			foreach (string file in knownfiles)
+				abuilder.AddCodeFile (file);
+			
+			BuildProvider bprovider;
+			CompilationSection compilationSection = WebConfigurationManager.GetSection ("system.web/compilation") as CompilationSection;
+			if (compilationSection != null) {
+				BuildProviderCollection buildProviders = compilationSection.BuildProviders;
 				
-				string assemblyName = Path.Combine (
-					AppDomain.CurrentDomain.SetupInformation.DynamicBase,
-					String.Format ("{0}.{1}.dll", name, num.ToString ("x")));
-				parameters.OutputAssembly = assemblyName;
-				CompilerResults results = provider.CompileAssemblyFromFile (parameters, knownfiles.ToArray ());
-				if (results.Errors.Count == 0) {
-					BuildManager.CodeAssemblies.Add (results.PathToAssembly);
-					BuildManager.TopLevelAssemblies.Add (results.CompiledAssembly);
-				} else {
-					if (HttpContext.Current.IsCustomErrorEnabled)
-						throw new HttpException ("An error occurred while initializing application.");
-					throw new CompilationException (null, results.Errors, null);
+				foreach (string file in unknownfiles) {
+					bprovider = GetBuildProviderFor (file, buildProviders);
+					if (bprovider == null)
+						continue;
+					bprovider.GenerateCode (abuilder);
 				}
 			}
+			
+			string assemblyName = (string)FileUtils.CreateTemporaryFile (
+				AppDomain.CurrentDomain.SetupInformation.DynamicBase,
+				name, "dll", OnCreateTemporaryAssemblyFile);
+			CompilerParameters parameters = compilerInfo.CreateDefaultCompilerParameters ();
+			parameters.OutputAssembly = assemblyName;
+			CompilerResults results = abuilder.BuildAssembly (parameters);
+			if (results.Errors.Count == 0) {
+				BuildManager.CodeAssemblies.Add (results.PathToAssembly);
+				BuildManager.TopLevelAssemblies.Add (results.CompiledAssembly);
+			} else {
+				if (HttpContext.Current.IsCustomErrorEnabled)
+					throw new HttpException ("An error occurred while initializing application.");
+				throw new CompilationException (null, results.Errors, null);
+			}
 		}
+
+		private BuildProvider GetBuildProviderFor (string file, BuildProviderCollection buildProviders)
+		{
+			if (file == null || file.Length == 0 || buildProviders == null || buildProviders.Count == 0)
+				return null;
+
+			foreach (BuildProvider bp in buildProviders)
+				if (IsCorrectBuilderType (bp))
+					return bp;
+
+			return null;
+		}
+
+		private bool IsCorrectBuilderType (BuildProvider bp)
+		{
+			if (bp == null)
+				return false;
+			Type type;
+			object[] attrs;
+
+			type = bp.GetType ();
+			attrs = type.GetCustomAttributes (true);
+			if (attrs == null)
+				return false;
+			
+			BuildProviderAppliesToAttribute bpAppliesTo;
+			bool attributeFound = false;
+			foreach (object attr in attrs) {
+				bpAppliesTo = attr as BuildProviderAppliesToAttribute;
+				if (bpAppliesTo == null)
+					continue;
+				attributeFound = true;
+				if ((bpAppliesTo.AppliesTo & BuildProviderAppliesTo.All) == BuildProviderAppliesTo.All ||
+				    (bpAppliesTo.AppliesTo & BuildProviderAppliesTo.Code) == BuildProviderAppliesTo.Code)
+					return true;
+			}
+
+			if (attributeFound)
+				return false;
+			return true;
+		}
+		
 	}
 	
 	internal class AppCodeCompiler