4 using System.Collections.Generic;
9 using System.Text.RegularExpressions;
10 using Mono.TextTemplating;
11 using SiliconStudio.Core;
12 using SiliconStudio.Core.Diagnostics;
13 using SiliconStudio.Core.IO;
14 using SiliconStudio.Core.Yaml;
16 namespace SiliconStudio.ProjectTemplating
21 [DataContract(
"ProjectTemplate")]
29 Files =
new List<ProjectTemplateItem>();
30 Assemblies =
new List<UFile>();
37 public string FilePath {
get;
private set; }
44 public bool IsDynamicTemplate {
get;
private set; }
50 public List<ProjectTemplateItem> Files {
get;
private set; }
56 public List<UFile> Assemblies {
get;
private set; }
70 public LoggerResult Generate(
string outputDirectory,
string projectName, Guid projectGuid, Dictionary<string, object> options = null)
72 if (outputDirectory == null)
throw new ArgumentNullException(
"outputDirectory");
73 if (projectName == null)
throw new ArgumentNullException(
"projectName");
74 if (FilePath == null)
throw new InvalidOperationException(
"FilePath cannot be null on this instance");
77 Generate(outputDirectory, projectName, projectGuid, result, options);
94 public void Generate(
string outputDirectory,
string projectName, Guid projectGuid,
ILogger log, Dictionary<string, object> options = null, List<string> generatedOutputFiles = null )
96 if (outputDirectory == null)
throw new ArgumentNullException(
"outputDirectory");
97 if (projectName == null)
throw new ArgumentNullException(
"projectName");
98 if (log == null)
throw new ArgumentNullException(
"log");
99 if (FilePath == null)
throw new InvalidOperationException(
"FilePath cannot be null on this instance");
104 var templateDirectory =
new FileInfo(FilePath).Directory;
105 if (templateDirectory == null || !templateDirectory.Exists)
107 log.Error(
"Invalid ProjectTemplate directory [{0}]", FilePath);
112 var directory =
new DirectoryInfo(outputDirectory);
113 if (!directory.Exists)
119 var expandoOptions =
new ExpandoObject();
121 expandoOptionsAsDictionary[
"ProjectName"] = projectName;
122 expandoOptionsAsDictionary[
"ProjectGuid"] = projectGuid;
125 foreach (var option
in options)
127 expandoOptionsAsDictionary[option.Key] = option.Value;
131 var engine =
new TemplatingEngine();
134 if (IsDynamicTemplate)
136 var content = File.ReadAllText(FilePath);
137 var host =
new ProjectTemplatingHost(log, FilePath, templateDirectory.FullName, expandoOptions, Assemblies.Select(assembly => assembly.FullPath));
138 var newTemplateAsString = engine.ProcessTemplate(content, host);
140 using (var stream =
new MemoryStream(
Encoding.UTF8.GetBytes(newTemplateAsString)))
143 Files.AddRange(newTemplate.Files);
148 foreach (var fileItem
in Files)
150 if (fileItem.Source == null)
152 log.Warning(
"Invalid empty file item [{0}] with no source location", fileItem);
155 var sourceFilePath = System.IO.Path.Combine(templateDirectory.FullName, fileItem.Source);
156 var targetLocation = fileItem.Target ?? fileItem.Source;
157 if (Path.IsPathRooted(targetLocation))
159 log.Error(
"Invalid file item [{0}]. TargetLocation must be a relative path", fileItem);
163 var targetLocationExpanded = Expand(targetLocation, expandoOptionsAsDictionary, log);
166 if (fileItem.IsTemplate)
168 var targetPath = Path.GetDirectoryName(targetLocationExpanded);
169 var targetFileName = Path.GetFileName(targetLocationExpanded);
170 targetLocationExpanded = targetPath != null ? Path.Combine(targetPath, targetFileName) : targetFileName;
173 var targetFilePath = Path.Combine(outputDirectory, targetLocationExpanded);
177 var targetDirectory =
new FileInfo(targetFilePath).Directory;
178 if (!targetDirectory.Exists)
180 targetDirectory.Create();
183 bool fileGenerated =
false;
184 if (fileItem.IsTemplate)
186 var content = File.ReadAllText(sourceFilePath);
187 var host =
new ProjectTemplatingHost(log, sourceFilePath, templateDirectory.FullName, expandoOptions, Assemblies.Select(assembly => assembly.FullPath));
188 var newContent = engine.ProcessTemplate(content, host);
189 if (newContent != null)
191 fileGenerated =
true;
192 File.WriteAllText(targetFilePath, newContent);
197 fileGenerated =
true;
198 File.Copy(sourceFilePath, targetFilePath,
true);
201 if (generatedOutputFiles != null && fileGenerated)
203 generatedOutputFiles.Add(targetFilePath);
209 log.Error(
"Unexpected exception while processing [{0}]", fileItem, ex);
215 log.Error(
"Unexpected exception while processing project template [{0}] to directory [{1}]", projectName, outputDirectory, ex);
221 if (templatePathPart == null)
throw new ArgumentNullException(
"templatePathPart");
222 if (log == null)
throw new ArgumentNullException(
"log");
223 var expandoOptions =
new ExpandoObject();
225 foreach (var option
in options)
227 expandoOptionsAsDictionary[option.Key] = option.Value;
230 var templateDirectory =
new FileInfo(FilePath).Directory;
231 var sourceFilePath = System.IO.Path.Combine(templateDirectory.FullName, templatePathPart);
232 var content = File.ReadAllText(sourceFilePath);
234 var engine =
new TemplatingEngine();
235 var host =
new ProjectTemplatingHost(log, sourceFilePath, templateDirectory.FullName, expandoOptions, Assemblies.Select(assembly => assembly.FullPath));
236 return engine.ProcessTemplate(content, host);
239 private static bool HasT4Extension(
string filePath)
241 return filePath.EndsWith(
".tt", StringComparison.InvariantCultureIgnoreCase)
242 || filePath.EndsWith(
".t4", StringComparison.InvariantCultureIgnoreCase);
245 private static readonly Regex ExpandRegex =
new Regex(
@"\$(\w+)\$");
249 if (str == null)
throw new ArgumentNullException(
"str");
250 if (properties == null)
throw new ArgumentNullException(
"properties");
252 return ExpandRegex.Replace(str, match =>
254 var propertyName = match.Groups[1].Value;
255 object propertyValue;
256 if (properties.TryGetValue(propertyName, out propertyValue))
258 return propertyValue == null ? string.Empty : propertyValue.ToString();
260 log.Warning(
"Unable to replace property [{0}] not found in options");
273 if (filePath == null)
throw new ArgumentNullException(
"filePath");
275 var fullFilePath = System.IO.Path.Combine(Environment.CurrentDirectory, filePath);
276 var projectFile = File.ReadAllText(fullFilePath);
279 if (projectFile.StartsWith(
"<#@"))
281 template =
new ProjectTemplate() { IsDynamicTemplate =
true };
285 using (var stream =
new FileStream(fullFilePath,
FileMode.Open, FileAccess.Read, FileShare.Read))
291 template.FilePath = fullFilePath;
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
A logger that stores messages locally useful for internal log scenarios.
Defines a project template that allows automated creation of a project structure with files...
System.Text.Encoding Encoding
System.IO.FileMode FileMode
LoggerResult Generate(string outputDirectory, string projectName, Guid projectGuid, Dictionary< string, object > options=null)
Generates this project template to the specified output directory.
Default Yaml serializer used to serialize assets by default.
void Generate(string outputDirectory, string projectName, Guid projectGuid, ILogger log, Dictionary< string, object > options=null, List< string > generatedOutputFiles=null)
Generates this project template to the specified output directory.
string GeneratePart(string templatePathPart, ILogger log, Dictionary< string, object > options)
ProjectTemplate()
Initializes a new instance of the ProjectTemplate class.
static object Deserialize(Stream stream)
Deserializes an object from the specified stream (expecting a YAML string).
static ProjectTemplate Load(string filePath)
Loads the a ProjectTemplate from the specified file path.