Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PackageAssetsCompiler.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Linq;
7 using System.Text.RegularExpressions;
8 using SiliconStudio.Assets.Analysis;
9 using SiliconStudio.BuildEngine;
10 using SiliconStudio.Core;
11 using SiliconStudio.Core.IO;
12 
13 namespace SiliconStudio.Assets.Compiler
14 {
15  /// <summary>
16  /// A package assets compiler.
17  /// Creates the build steps necessary to produce the assets of a package.
18  /// </summary>
20  {
21  private readonly PackageSession session;
22 
23  private static readonly AssetCompilerRegistry assetCompilerRegistry = new AssetCompilerRegistry();
24 
25  static PackageAssetsCompiler()
26  {
27  // Compute ParadoxSdkDir from this assembly
28  // TODO Move this code to a reusable method
29  var codeBase = typeof(PackageAssetsCompiler).Assembly.CodeBase;
30  var uri = new UriBuilder(codeBase);
31  var path = Path.GetDirectoryName(Uri.UnescapeDataString(uri.Path));
32  SdkDirectory = Path.GetFullPath(Path.Combine(path, @"..\.."));
33  }
34 
36  : base(assetCompilerRegistry)
37  {
38  if (session == null) throw new ArgumentNullException("session");
39  this.session = session;
40  }
41 
42  /// <summary>
43  /// Gets or sets the SDK directory. Default is bound to env variable ParadoxSdkDir
44  /// </summary>
45  /// <value>The SDK directory.</value>
46  public static string SdkDirectory { get; set; }
47 
48  /// <summary>
49  /// Compile the current package session.
50  /// That is generate the list of build steps to execute to create the package assets.
51  /// </summary>
53  {
54  var result = new AssetCompilerResult { BuildSteps = new ListBuildStep() };
55 
56  // Check integrity of the packages
57  var packageAnalysis = new PackageSessionAnalysis(session, new PackageAnalysisParameters());
58  packageAnalysis.Run(result);
59  if (result.HasErrors)
60  {
61  return result;
62  }
63 
64  // Generate all the other build steps from the packages
65  RecursiveCompile(result, compilerContext, new HashSet<Package>());
66 
67  return result;
68  }
69 
70  /// <summary>
71  /// Compile the current package and all child package recursively by generating a list of build steps
72  /// </summary>
73  private void RecursiveCompile(AssetCompilerResult result, AssetCompilerContext context, HashSet<Package> processed)
74  {
75  if (result == null) throw new ArgumentNullException("result");
76  if (context == null) throw new ArgumentNullException("context");
77  if (context.Package == null) throw new ArgumentException("context.Package cannot be null", "context");
78 
79  if (processed.Contains(context.Package))
80  {
81  return;
82  }
83  processed.Add(context.Package);
84 
85  var package = context.Package;
86  GenerateRawImportBuildSteps(context, result);
87 
88  // 1. first recursively process all store packages
89  foreach (var packageDependency in package.Meta.Dependencies)
90  {
91  var subPackage = session.Packages.Find(packageDependency);
92  if (subPackage != null)
93  {
94  // Work on an immutable copy for the whole set of assets to compile
95  var contextCopy = (AssetCompilerContext)context.Clone();
96  contextCopy.Package = subPackage;
97  RecursiveCompile(result, contextCopy, processed);
98  }
99  else
100  {
101  result.Error("Unable to find package [{0}]", packageDependency);
102  }
103  }
104 
105  // 2. recursively process all local packages
106  foreach (var subPackageReference in package.LocalDependencies)
107  {
108  var subPackage = session.Packages.Find(subPackageReference.Id);
109  if (subPackage != null)
110  {
111  // Work on an immutable copy for the whole set of assets to compile
112  var contextCopy = (AssetCompilerContext)context.Clone();
113  contextCopy.Package = subPackage;
114  RecursiveCompile(result, contextCopy, processed);
115  }
116  else
117  {
118  result.Error("Unable to find package [{0}]", subPackageReference);
119  }
120  }
121 
122  result.Info("Compiling package [{0}]", package.FullPath);
123 
124  // Sort the items to build by build order
125  var assets = package.Assets.ToList();
126  assets.Sort((item1, item2) => item1.Asset != null && item2.Asset != null ? item1.Asset.BuildOrder.CompareTo(item2.Asset.BuildOrder) : 0);
127 
128  // generate the build steps required to build the assets via base class
129  Compile(context, assets, result);
130  }
131 
132  /// <summary>
133  /// Generate the build step corresponding to raw imports of the current package file.
134  /// </summary>
135  /// <param name="context">The compilation context</param>
136  /// <param name="result">The compilation current result</param>
137  private void GenerateRawImportBuildSteps(AssetCompilerContext context, AssetCompilerResult result)
138  {
139  if (context.Package.RootDirectory == null)
140  return;
141 
142  foreach (var profile in context.Package.Profiles)
143  {
144  foreach (var sourceFolder in profile.AssetFolders)
145  {
146  var baseDirectory = Path.GetFullPath(context.Package.RootDirectory);
147  // Use sub directory
148  baseDirectory = Path.Combine(baseDirectory, sourceFolder.Path);
149 
150  if (!Directory.Exists(baseDirectory))
151  {
152  continue;
153  }
154 
155  var baseUDirectory = new UDirectory(baseDirectory);
156  var hashSet = new HashSet<string>();
157 
158  // Imports explicit
159  foreach (var rawImport in sourceFolder.RawImports)
160  {
161  var sourceDirectory = baseUDirectory;
162  if (!string.IsNullOrEmpty(rawImport.SourceDirectory))
163  sourceDirectory = UPath.Combine(sourceDirectory, rawImport.SourceDirectory);
164 
165  if (!Directory.Exists(sourceDirectory))
166  {
167  result.Error("Unable to find raw import directory [{0}]", sourceDirectory);
168  continue;
169  }
170 
171  var files = Directory.EnumerateFiles(sourceDirectory, "*.*", SearchOption.AllDirectories).ToList();
172  var importRegexes = rawImport.Patterns.Select(x => new Regex(Selectors.PathSelector.TransformToRegex(x))).ToArray();
173  foreach (var file in files)
174  {
175  var pathToFileRelativeToProject = new UFile(file).MakeRelative(sourceDirectory);
176  var outputPath = pathToFileRelativeToProject;
177  if (!string.IsNullOrEmpty(rawImport.TargetLocation))
178  outputPath = UPath.Combine(rawImport.TargetLocation, outputPath);
179 
180  foreach (var importRegex in importRegexes)
181  {
182  if (importRegex.Match(pathToFileRelativeToProject).Success && hashSet.Add(outputPath))
183  {
184  result.BuildSteps.Add(new ImportStreamCommand
185  {
186  SourcePath = file,
187  Location = outputPath,
188  });
189  break;
190  }
191  }
192  }
193  }
194  }
195  }
196  }
197 
198  private static readonly Regex ChangeWildcardToRegex = new Regex(@"(?<!\*)\*");
199 
200  private static Regex CompileRawImport(string rawImport)
201  {
202  // Replace / by \
203  rawImport = rawImport.Replace("\\", "/");
204  // escape . by \.
205  rawImport = rawImport.Replace(".", "\\.");
206  // Transform * by .*?
207  rawImport = ChangeWildcardToRegex.Replace(rawImport, ".*?");
208  return new Regex(rawImport, RegexOptions.IgnoreCase);
209  }
210  }
211 }
Result of a compilation of assets when using IAssetCompiler.Compile
A package assets compiler. Creates the build steps necessary to produce the assets of a package...
Class PackageAnalysisParameters. This class cannot be inherited.
The context used when compiling an asset in a Package.
A session for editing a package.
Defines a normalized directory path. See UPath for details. This class cannot be inherited.
Definition: UDirectory.cs:13
A package analysis provides methods to validate the integrity of a whole package. ...
Base class that describes a uniform path and provides method to manipulate them. Concrete class are U...
Definition: UPath.cs:21
The base class to compile a series of AssetItems using associated IAssetCompilers. An item list compiler only creates the build steps required to creates some output items. The result of a compilation has then to be executed by the build engine to effectively create the outputs items.
AssetCompilerResult Compile(AssetCompilerContext compilerContext)
Compile the current package session. That is generate the list of build steps to execute to create th...
A registry containing the asset compilers of the assets.
Defines a normalized file path. See UPath for details. This class cannot be inherited.
Definition: UFile.cs:13