/// <summary> /// /// </summary> /// <param name="section"></param> void Download ( BuildContext context, KeyDataCollection section, BuildResult result ) { Log.Message("Downloading..."); foreach ( var keyValue in section ) { if (Path.IsPathRooted(keyValue.KeyName)) { throw new BuildException(string.Format("Rooted paths are not allowed: {0}", keyValue.KeyName)); } var fullPath = Path.Combine( context.Options.FullInputDirectory, keyValue.KeyName ); var urlName = keyValue.Value; Log.Message(" {0} -> {1}", urlName, keyValue.KeyName); try { DownloadIfModified( urlName, fullPath); } catch ( WebException wex ) { Log.Error("{0} : {1}", keyValue.KeyName, wex.Message ); result.Failed++; } } }
/// <summary> /// /// </summary> /// <param name="processor"></param> /// <param name="fileName"></param> void BuildAsset ( AssetProcessor processor, string[] args, AssetSource assetFile, ref BuildResult buildResult ) { try { // Is up-to-date? if (!context.Options.ForceRebuild) { if (!Wildcard.Match(assetFile.KeyPath, context.Options.CleanPattern, true)) { if (assetFile.IsUpToDate) { buildResult.UpToDate ++; return; } } } var keyPath = assetFile.KeyPath; if (keyPath.Length > 40) { keyPath = "..." + keyPath.Substring( keyPath.Length - 40 + 3 ); } Log.Message("{0,-40} {1,-5} {3}", keyPath, Path.GetExtension(keyPath), string.Join(" ", args), assetFile.Hash ); // Apply attribute : var parser = new CommandLineParser( processor ); parser.Configuration.OptionLeadingChar = '/'; parser.Configuration.ThrowExceptionOnShowError = true; parser.ParseCommandLine( args ); // // Build : // processor.Process( assetFile, context ); buildResult.Succeded ++; } catch ( Exception e ) { Log.Error( "{0} : {1}", assetFile.KeyPath, e.Message ); buildResult.Failed ++; } }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <returns></returns> List<AssetSource> GatherAssetFiles ( string[] ignorePatterns, IniData iniData, BuildContext context, ref BuildResult result ) { var assetSources = new List<AssetSource>(); // key contain key path // value containt full path var files = new List<LocalFile>(); // gather files from all directories // and then distinct them by key path. foreach ( var contentDir in context.ContentDirectories ) { var localFiles = Directory.EnumerateFiles( contentDir, "*", SearchOption.AllDirectories ) .Where( f1 => Path.GetFileName(f1).ToLowerInvariant() != ".content" ); files.AddRange( localFiles.Select( fullpath => new LocalFile( contentDir, fullpath ) ) ); } files = files.DistinctBy( file => file.KeyPath ).ToList(); result.Total = files.Count; // ignore files by ignore pattern // and count ignored files : result.Ignored = files.RemoveAll( file => { foreach ( var pattern in ignorePatterns ) { if (Wildcard.Match( file.KeyPath, pattern )) { return true; } } return false; }); foreach ( var section in iniData.Sections ) { // 'Ingore' is a special section. if (section.SectionName=="Ignore") { continue; } if (section.SectionName=="ContentDirectories") { continue; } if (section.SectionName=="BinaryDirectories") { continue; } if (section.SectionName=="Download") { continue; } // get processor : if (!processors.ContainsKey(section.SectionName)) { Log.Warning("Asset processor '{0}' not found. Files will be skipped.", section.SectionName ); Log.Message(""); continue; } var procBind = processors[section.SectionName]; // get mask and arguments : var maskArgs = section.Keys .Reverse() .Select( key => new { Mask = key.KeyName.Split(' ', '\t').FirstOrDefault(), Args = CommandLineParser.SplitCommandLine( key.KeyName ).Skip(1).ToArray() }) .ToList(); foreach ( var file in files ) { if (file.Handled) { continue; } foreach ( var maskArg in maskArgs ) { if ( Wildcard.Match( file.KeyPath, maskArg.Mask, true ) ) { file.Handled = true; assetSources.Add( new AssetSource( file.KeyPath, file.BaseDir, procBind.Type, maskArg.Args, context ) ); break; } } } // count unhandled files : result.Skipped = files.Count( f => !f.Handled ); } return assetSources; }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <param name="targetFolder"></param> /// <param name="force"></param> public BuildResult Build ( BuildOptions options, IniData iniData ) { BuildResult result = new BuildResult(); context = new BuildContext( options, iniData ); var ignorePatterns = new string[0]; if ( iniData.Sections.ContainsSection("Ignore") ) { ignorePatterns = iniData.Sections["Ignore"] .Select( element => element.KeyName ) .Select( key => ContentUtils.BackslashesToSlashes( key ) ) .ToArray(); } if ( iniData.Sections.ContainsSection("Download") ) { Download( context, iniData.Sections["Download"], result ); } // // gather files on source folder ignoring // files that match ignore pattern : // Log.Message("Gathering files..."); var assetSources = GatherAssetFiles( ignorePatterns, iniData, context, ref result ); Log.Message(""); // // Check hash collisions : // var collisions = assetSources .GroupBy( file0 => file0.TargetName ) .Where( fileGroup1 => fileGroup1.Count() > 1 ) .Distinct() .ToArray(); if (collisions.Any()) { Log.Error("Hash collisions detected:"); int collisionCount = 0; foreach ( var collision in collisions ) { Log.Error(" [{0}] {1}", collisionCount++, collision.Key); foreach ( var collisionEntry in collision ) { Log.Error( " {0}", collisionEntry.FullSourcePath ); } } throw new BuildException("Hash collisions detected"); } // // remove stale built content : // Log.Message("Cleaning stale content up..."); CleanStaleContent( options.FullOutputDirectory, assetSources ); Log.Message(""); // // Build everything : // foreach ( var assetSource in assetSources ) { var proc = assetSource.CreateProcessor(); BuildAsset( proc, assetSource.BuildArguments, assetSource, ref result ); } return result; }
/// <summary> /// /// </summary> /// <param name="processor"></param> /// <param name="fileName"></param> void BuildAsset(AssetProcessor processor, string[] args, AssetSource assetFile, ref BuildResult buildResult) { try { // Is up-to-date? if (!context.Options.ForceRebuild) { if (!Wildcard.Match(assetFile.KeyPath, context.Options.CleanPattern, true)) { if (!context.Options.Files.Contains(assetFile.KeyPath)) { if (assetFile.IsUpToDate) { buildResult.UpToDate++; return; } } } } var keyPath = assetFile.KeyPath; if (keyPath.Length > 40) { keyPath = "..." + keyPath.Substring(keyPath.Length - 40 + 3); } Log.Message("{0,-40} {1,-5} {3}", keyPath, Path.GetExtension(keyPath), string.Join(" ", args), assetFile.Hash); // Apply attribute : var parser = new CommandLineParser(processor.GetType()); parser.OptionLeadingChar = '/'; parser.ParseCommandLine(processor, args); // // Build : // processor.Process(assetFile, context); buildResult.Succeded++; } catch (Exception e) { Log.Error("{0} : {1}", assetFile.KeyPath, e.Message); buildResult.Failed++; } }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <returns></returns> List <AssetSource> GatherAssetFiles(string[] ignorePatterns, IniData iniData, BuildContext context, ref BuildResult result) { var assetSources = new List <AssetSource>(); // key contain key path // value containt full path var files = new List <LocalFile>(); // gather files from all directories // and then distinct them by key path. foreach (var contentDir in context.ContentDirectories) { var localFiles = Directory.EnumerateFiles(contentDir, "*", SearchOption.AllDirectories) .Where(f1 => Path.GetFileName(f1).ToLowerInvariant() != ".content"); files.AddRange(localFiles.Select(fullpath => new LocalFile(contentDir, fullpath))); } files = files.DistinctBy(file => file.KeyPath).ToList(); result.Total = files.Count; // ignore files by ignore pattern // and count ignored files : result.Ignored = files.RemoveAll(file => { foreach (var pattern in ignorePatterns) { if (Wildcard.Match(file.KeyPath, pattern)) { return(true); } } return(false); }); foreach (var section in iniData.Sections) { // 'Ingore' is a special section. if (section.SectionName == "Ignore") { continue; } if (section.SectionName == "ContentDirectories") { continue; } if (section.SectionName == "BinaryDirectories") { continue; } if (section.SectionName == "Download") { continue; } // get processor : if (!processors.ContainsKey(section.SectionName)) { Log.Warning("Asset processor '{0}' not found. Files will be skipped.", section.SectionName); Log.Message(""); continue; } var procBind = processors[section.SectionName]; // get mask and arguments : var maskArgs = section.Keys .Reverse() .Select(key => new { Mask = key.KeyName.Split(' ', '\t').FirstOrDefault(), Args = CommandLineParser.SplitCommandLine(key.KeyName).Skip(1).ToArray() }) .ToList(); foreach (var file in files) { if (file.Handled) { continue; } foreach (var maskArg in maskArgs) { if (Wildcard.Match(file.KeyPath, maskArg.Mask, true)) { file.Handled = true; assetSources.Add(new AssetSource(file.KeyPath, file.BaseDir, procBind.Type, maskArg.Args, context)); break; } } } // count unhandled files : result.Skipped = files.Count(f => !f.Handled); } return(assetSources); }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <param name="targetFolder"></param> /// <param name="force"></param> BuildResult Build(BuildOptions options, IniData iniData) { BuildResult result = new BuildResult(); context = new BuildContext(options, iniData); var ignorePatterns = new string[0]; if (iniData.Sections.ContainsSection("Ignore")) { ignorePatterns = iniData.Sections["Ignore"] .Select(element => element.KeyName) .Select(key => ContentUtils.BackslashesToSlashes(key)) .ToArray(); } if (iniData.Sections.ContainsSection("Download")) { Download(context, iniData.Sections["Download"], result); } // // gather files on source folder ignoring // files that match ignore pattern : // Log.Message("Gathering files..."); var assetSources = new List <AssetSource>(); assetSources.AddRange(GatherRequiredShaders(context, result)); assetSources.AddRange(GatherAssetFiles(ignorePatterns, iniData, context, ref result)); Log.Message(""); File.WriteAllLines(Path.Combine(options.FullOutputDirectory, "assetdb"), assetSources.Select(asset => asset.KeyPath).OrderBy(n => n)); // // Check hash collisions : // var collisions = assetSources .GroupBy(file0 => file0.TargetName) .Where(fileGroup1 => fileGroup1.Count() > 1) .Distinct() .ToArray(); if (collisions.Any()) { Log.Error("Hash collisions detected:"); int collisionCount = 0; foreach (var collision in collisions) { Log.Error(" [{0}] {1}", collisionCount++, collision.Key); foreach (var collisionEntry in collision) { Log.Error(" {0}", collisionEntry.FullSourcePath); } } throw new BuildException("Hash collisions detected"); } // // remove stale built content : // Log.Message("Cleaning stale content up..."); CleanStaleContent(options.FullOutputDirectory, assetSources); Log.Message(""); // // Build everything : // foreach (var assetSource in assetSources) { var proc = assetSource.CreateProcessor(); BuildAsset(proc, assetSource.BuildArguments, assetSource, ref result); } // // Build megatexture // BuildMegatexture(ref result); return(result); }