/// <summary> /// /// </summary> /// <param name="keyPath">Key path</param> /// <param name="baseDir">Base directory</param> /// <param name="buildParameters"></param> /// <param name="context"></param> public AssetSource ( string keyPath, string baseDir, Type assetProcessorType, string[] buildArgs, BuildContext context ) { this.assetProcessorType = assetProcessorType; this.outputDir = context.Options.FullOutputDirectory; this.fullPath = Path.Combine( baseDir, keyPath ); this.baseDir = baseDir; this.keyPath = keyPath; this.BuildArguments = buildArgs; this.context = context; }
/// <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="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="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; }