public Dictionary <string, string> GetCodeFiles() { Dictionary <string, string> output = new Dictionary <string, string>(); string fileExtension = ProgrammingLanguageParser.LangToFileExtension(this.RootProgrammingLanguage); foreach (ProjectFilePath sourceDir in this.SourceFolders) { string[] files = FileUtil.GetAllAbsoluteFilePathsDescendentsOf(sourceDir.AbsolutePath); foreach (string filepath in files) { if (filepath.ToLowerInvariant().EndsWith(fileExtension)) { string relativePath = FileUtil.ConvertAbsolutePathToRelativePath( filepath, this.ProjectDirectory); output[relativePath] = FileUtil.ReadFileText(filepath); } } } return(output); }
public static BuildContext Parse( string projectDir, string buildFile, string nullableTargetName, IList <Wax.BuildArg> buildArgOverrides, IList <Wax.ExtensionArg> extensionArgOverrides) { BuildRoot buildInput = GetBuildRoot(buildFile, projectDir); Dictionary <string, Target> targetsByName = new Dictionary <string, Target>(); foreach (Target target in buildInput.Targets) { string name = target.Name; if (name == null) { throw new InvalidOperationException("A target in the build file is missing a name."); } if (targetsByName.ContainsKey(name)) { throw new InvalidOperationException("There are multiple build targets with the name '" + name + "'."); } targetsByName[name] = target; } List <Wax.BuildArg> buildArgs = new List <Wax.BuildArg>(); List <Wax.ExtensionArg> extensionArgs = new List <Wax.ExtensionArg>(); List <BuildVar> buildVars = new List <BuildVar>(); List <BuildItem> buildItems = new List <BuildItem>(); if (nullableTargetName == null) { buildItems.Add(buildInput); } else { HashSet <string> targetsVisited = new HashSet <string>(); string nextItem = nullableTargetName; Target walker; while (nextItem != null) { if (targetsVisited.Contains(nextItem)) { throw new InvalidOperationException("Build target inheritance loop for '" + nextItem + "' contains a cycle."); } targetsVisited.Add(nextItem); if (!targetsByName.ContainsKey(nextItem)) { throw new InvalidOperationException("There is no build target named: '" + nextItem + "'."); } walker = targetsByName[nextItem]; buildItems.Add(walker); nextItem = walker.InheritFrom; } buildItems.Add(buildInput); } buildItems.Reverse(); // The attributes in the leaf node have precedence. foreach (BuildItem currentItem in buildItems) { buildArgs.AddRange(currentItem.BuildArgs); extensionArgs.AddRange(currentItem.ExtensionArgs); buildVars.AddRange(currentItem.BuildVars); } if (buildArgOverrides != null) { buildArgs.AddRange(buildArgOverrides); } if (extensionArgOverrides != null) { extensionArgs.AddRange(extensionArgOverrides); } PercentReplacer pr = new PercentReplacer() .AddReplacement("TARGET_NAME", nullableTargetName ?? ""); // Do a first pass over all the build args to fetch anything that is used by %PERCENT_REPLACEMENT% and anything // that can be defined with multiple values in a list. List <string> sources = new List <string>(); List <string> icons = new List <string>(); string version = "1.0"; Locale compilerLocale = Locale.Get("en"); string projectId = null; ProgrammingLanguage programmingLanguage = ProgrammingLanguage.CRAYON; List <Wax.BuildArg> remainingBuildArgs = new List <Wax.BuildArg>(); List <string> envFilesBuilder = new List <string>(); List <string> deps = new List <string>(); foreach (Wax.BuildArg buildArg in buildArgs) { switch (buildArg.Name) { case "programmingLanguage": ProgrammingLanguage?pl = ProgrammingLanguageParser.Parse(buildArg.Value); if (pl == null) { throw new InvalidOperationException("Invalid programming language in build file: '" + buildArg.Value + "'."); } programmingLanguage = pl.Value; break; case "version": version = buildArg.Value; break; case "source": sources.Add(buildArg.Value); break; case "icon": icons.Add(buildArg.Value); break; case "compilerLocale": compilerLocale = Locale.Get(buildArg.Value); break; case "id": projectId = buildArg.Value; break; case "dependencies": deps.Add(buildArg.Value); break; case "envFile": throw new Exception(); // These are eliminated in the parsing phase. default: remainingBuildArgs.Add(buildArg); break; } } if (projectId == null) { throw new InvalidOperationException("The projectId is not defined in the build file."); } if (projectId.Length == 0) { throw new InvalidOperationException("projectId cannot be blank."); } if (projectId.ToCharArray().Any(c => (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9'))) { throw new InvalidOperationException("projectId can only contain alphanumeric characters."); } if (projectId[0] >= '0' && projectId[0] <= '9') { throw new InvalidOperationException("projectId cannot being with a number."); } pr .AddReplacement("PROJECT_ID", projectId) .AddReplacement("COMPILER_LANGUAGE", programmingLanguage.ToString().ToUpperInvariant()) .AddReplacement("VERSION", version) .AddReplacement("COMPILER_LOCALE", compilerLocale.ID.ToLowerInvariant()); ProjectFilePath[] envFiles = ToFilePaths(projectDir, envFilesBuilder); BuildContext buildContext = new BuildContext() { ProjectID = projectId, ProjectDirectory = projectDir, SourceFolders = ToFilePaths(projectDir, sources), Version = version, RootProgrammingLanguage = programmingLanguage, IconFilePaths = icons // TODO: icon values should be concatenated within a build target, but override previous targets .Select(t => pr.Replace(t)) .Select(t => FileUtil.GetAbsolutePathFromRelativeOrAbsolutePath(projectDir, t)) .Select(t => FileUtil.GetCanonicalizeUniversalPath(t)) .Where(t => { if (!System.IO.File.Exists(t)) { throw new System.InvalidOperationException("The following icon path does not exist: '" + t + "'."); } return(true); }) .ToArray(), CompilerLocale = compilerLocale, LocalDeps = deps .Select(t => Wax.Util.EnvironmentVariables.DoReplacementsInString(t)) .Select(t => pr.Replace(t)) .Select(t => FileUtil.GetCanonicalizeUniversalPath(t)) .ToArray(), ExtensionArgs = extensionArgs.Select(arg => { arg.Value = pr.Replace(arg.Value); return(arg); }).ToArray(), }; foreach (Wax.BuildArg buildArg in remainingBuildArgs) { string value = pr.Replace(buildArg.Value); switch (buildArg.Name) { case "title": buildContext.ProjectTitle = pr.Replace(value); break; case "description": buildContext.Description = pr.Replace(value); break; case "orientation": buildContext.Orientation = ParseOrientations(value); break; case "output": buildContext.OutputFolder = FileUtil.JoinAndCanonicalizePath(projectDir, pr.Replace(value)); break; case "delegateMainTo": buildContext.DelegateMainTo = value; break; case "removeSymbols": buildContext.RemoveSymbols = GetBoolValue(value); break; case "skipRun": buildContext.SkipRun = GetBoolValue(value); break; } } Dictionary <string, BuildVar> buildVarLookup = new Dictionary <string, BuildVar>(); foreach (BuildVar bv in buildVars) { buildVarLookup[bv.ID] = bv; } buildContext.BuildVariableLookup = buildVarLookup; return(buildContext); }