4 using System.CodeDom.Compiler;
5 using System.Collections.Generic;
8 using System.Reflection;
9 using System.Text.RegularExpressions;
11 using Microsoft.CSharp;
13 namespace SiliconStudio.BuildEngine
20 public string ScriptPath {
get;
private set; }
25 public string SourceBaseDirectory {
get;
private set; }
35 public string BuildDirectory {
get;
private set; }
40 public string OutputDirectory {
get;
private set; }
45 public string MetadataDatabaseDirectory {
get;
private set; }
50 public bool HasErrors {
get {
return GetErrors().Any(); } }
55 public bool IsCompiled {
get;
private set; }
57 private string source;
58 private CompilerResults compilerResult;
59 private readonly List<string> parsingErrors =
new List<string>();
60 private readonly List<string> parsingWarnings =
new List<string>();
65 SourceFolders =
new Dictionary<string, string>();
66 ((Dictionary<string, string>)SourceFolders).Add(
"ParadoxSdkDir", paradoxSdkDir);
71 var script =
new BuildScript(paradoxSdkDir) { ScriptPath = filePath, source = File.ReadAllText(filePath) };
75 private static string StripQuotes(
string str)
77 if (str.StartsWith(
"\"") && str.EndsWith(
"\"") && str.Length >= 2)
78 return str.Substring(1, str.Length - 2);
82 private void ParseParameters()
85 var parameterRegex =
new Regex(
@"^//\s*#(\w+)\s+(""[^""]+?""|[\w.\-/\\]+)\s*$", RegexOptions.Multiline);
86 foreach (Match match
in parameterRegex.Matches(source))
88 parameters.Add(StripQuotes(match.Groups[1].Value), StripQuotes(match.Groups[2].Value));
91 parameterRegex =
new Regex(
@"^//\s*#(\w+)\s+(""[^""]+?""|[\w.\-/\\]+)\s+(""[^""]+?""|[\w.\-/\\]+)\s*$", RegexOptions.Multiline);
92 foreach (Match match
in parameterRegex.Matches(source))
94 parameters.Add(StripQuotes(match.Groups[1].Value) +
"Key", StripQuotes(match.Groups[2].Value));
95 parameters.Add(StripQuotes(match.Groups[1].Value) +
"Value", StripQuotes(match.Groups[3].Value));
102 var assemblyLocations =
new List<string> {
106 typeof(
Command).Assembly.Location,
111 foreach (
string additionalPluginDirectories
in parameters.GetRange(
"PluginDirectory"))
113 pluginResolver.AddPluginFolder(Path.Combine(Path.GetDirectoryName(ScriptPath) ??
"", additionalPluginDirectories));
116 foreach (
string assemblyLocation
in parameters.GetRange(
"Assembly"))
119 var testAssemblyLocation = Path.Combine(Path.GetDirectoryName(ScriptPath) ??
"", assemblyLocation);
121 if (!
File.Exists(testAssemblyLocation))
124 testAssemblyLocation = pluginResolver.FindAssembly(Path.GetFileName(assemblyLocation));
126 if (!
File.Exists(testAssemblyLocation))
129 testAssemblyLocation = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ??
"", Path.GetFileName(assemblyLocation) ??
"");
131 if (!
File.Exists(testAssemblyLocation))
132 parsingErrors.Add(
string.Format(
"Could not find assembly {0}", assemblyLocation));
135 assemblyLocations.Add(testAssemblyLocation);
139 if (parameters.ContainsSingle(
"SourceBaseDirectory"))
140 SourceBaseDirectory = parameters.GetSingle(
"SourceBaseDirectory");
141 else if (parameters.ContainsMultiple(
"BuildDirectory"))
142 parsingErrors.Add(
"Source base directory defined multiple times.");
144 parsingWarnings.Add(
"Source base directory not defined.");
147 if (parameters.ContainsSingle(
"BuildDirectory"))
148 BuildDirectory = parameters.GetSingle(
"BuildDirectory");
149 else if (parameters.ContainsMultiple(
"BuildDirectory"))
150 parsingErrors.Add(
"Build directory defined multiple times.");
152 parsingErrors.Add(
"Build directory not defined.");
155 if (parameters.ContainsSingle(
"OutputDirectory"))
156 OutputDirectory = parameters.GetSingle(
"OutputDirectory");
157 else if (parameters.ContainsMultiple(
"OutputDirectory"))
158 parsingErrors.Add(
"Output directory defined multiple times.");
160 parsingWarnings.Add(
"Output directory not defined.");
163 if (parameters.ContainsSingle(
"MetadataDatabaseDirectory"))
164 MetadataDatabaseDirectory = parameters.GetSingle(
"MetadataDatabaseDirectory");
165 else if (parameters.ContainsMultiple(
"MetadataDatabaseDirectory"))
166 parsingErrors.Add(
"Metadata database directory defined multiple times.");
168 parsingWarnings.Add(
"Metadata database not defined.");
170 var sourceFolderKeys = parameters.GetRange(
"SourceFolderKey").ToArray();
171 var sourceFolderValue = parameters.GetRange(
"SourceFolderValue").ToArray();
173 for (
int i = 0; i < sourceFolderKeys.Length; ++i)
175 ((Dictionary<string, string>)SourceFolders).Add(sourceFolderKeys[i], sourceFolderValue[i]);
184 var csc =
new CSharpCodeProvider(
new Dictionary<string, string> { {
"CompilerVersion",
"v4.0" } });
185 var compileParams =
new CompilerParameters(assemblyLocations.ToArray()) { GenerateInMemory =
true, IncludeDebugInformation =
true };
186 compilerResult = csc.CompileAssemblyFromFile(compileParams, ScriptPath);
188 IsCompiled = !HasErrors;
195 if (compilerResult != null)
197 errors = errors.Concat(compilerResult.Errors.Cast<CompilerError>().Where(x => !x.IsWarning).Select(x => x.FileName +
"(" + x.Line +
"): " + x.ErrorText));
205 if (compilerResult != null)
207 warnings = warnings.Concat(compilerResult.Errors.Cast<CompilerError>().Where(x => x.IsWarning).Select(x => x.FileName +
"(" + x.Line +
"): " + x.ErrorText));
215 Type type = compilerResult.CompiledAssembly.GetType(
"BuildScript");
216 object makefile = Activator.CreateInstance(type);
217 MethodInfo executeMethod = type.GetMethod(
"Execute", BindingFlags.Public | BindingFlags.Instance);
218 executeMethod.Invoke(makefile,
new object[] { builder, builder.Root });
224 Type type = compilerResult.CompiledAssembly.GetType(
"BuildScript");
227 object makefile = Activator.CreateInstance(type);
228 MethodInfo executeMethod = type.GetMethod(
"Execute", BindingFlags.Public | BindingFlags.Instance);
229 executeMethod.Invoke(makefile,
new object[] { null, root });
static BuildScript LoadFromFile(string paradoxSdkDir, string filePath)
IEnumerable< string > GetWarnings()
void Execute(Builder builder)
IEnumerable< string > GetErrors()
void Execute(ListBuildStep root)
bool Compile(PluginResolver pluginResolver)