public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir, ref PropertyList configurableProperties, ReverseFileConditionBuilder.Handle reverseConditions) { List <ParsedCondition> conditions = null; List <ConditionRecord> allConditions = new List <ConditionRecord>(); List <string> preprocessorMacros = new List <string>(); if (SimpleFileConditions != null) { allConditions.AddRange(SimpleFileConditions.Select(c => new ConditionRecord(c, null))); reverseConditions?.FlagIncomplete(ReverseFileConditionWarning.HasRegularConditions); } if (!string.IsNullOrEmpty(PreprocessorMacros)) { preprocessorMacros.AddRange(PreprocessorMacros.Split(';')); foreach (var macro in preprocessorMacros) { reverseConditions?.AttachPreprocessorMacro(macro, null); } } if (SmartFileConditions != null || SmartPreprocessorMacros != null) { PropertyGroup grp; if (configurableProperties == null) { configurableProperties = new PropertyList { PropertyGroups = new List <PropertyGroup>() } } ; if (!string.IsNullOrEmpty(SmartPropertyGroup)) { string[] elements = SmartPropertyGroup.Split('|'); configurableProperties.PropertyGroups.Add(grp = new PropertyGroup { Name = elements[1], UniqueID = elements[0] }); } else { grp = configurableProperties.PropertyGroups.FirstOrDefault(); if (grp == null) { configurableProperties.PropertyGroups.Insert(0, grp = new PropertyGroup { }); } } foreach (var str in SmartFileConditions ?? new string[0]) { var def = SmartPropertyDefinition.Parse(str, grp.UniqueID); if (def.Items.Length == 1) { var item = def.Items[0]; allConditions.Add(new ConditionRecord($"{item.Key}: $${def.IDWithPrefix}$$ == {item.Value.ID}", reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Value.ID))); reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, ""); grp.Properties.Add(new PropertyEntry.Boolean { ValueForTrue = item.Value.ID, Name = def.Name, UniqueID = def.IDWithoutPrefix, DefaultValue = def.IsDefaultOn != false }); } else { List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>(); int?emptyIndex = null; foreach (var item in def.Items) { if (item.Key == "") { // 'None' value. No conditions will trigger when this is selected. emptyIndex = suggestions.Count; } else { allConditions.Add(new ConditionRecord($"{item.Key}: $${def.IDWithPrefix}$$ == {item.Value.ID}", reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Value.ID))); } suggestions.Add(new PropertyEntry.Enumerated.Suggestion { InternalValue = item.Value.ID, UserFriendlyName = item.Value.Name }); } reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, suggestions[emptyIndex ?? def.DefaultItemIndex].InternalValue); grp.Properties.Add(new PropertyEntry.Enumerated { Name = def.Name, UniqueID = def.IDWithoutPrefix, SuggestionList = suggestions.ToArray(), DefaultEntryIndex = def.DefaultItemIndex }); } } foreach (var str in SmartPreprocessorMacros ?? new string[0]) { var def = SmartPropertyDefinition.Parse(str, grp.UniqueID, 1); preprocessorMacros.Add(string.Format(def.ExtraArguments[0], "$$" + def.IDWithPrefix + "$$")); if (def.Items.Length == 1) { var item = def.Items[0]; if (item.Key.StartsWith("@")) { var prop = new PropertyEntry.String { Name = def.Name, UniqueID = def.IDWithoutPrefix, DefaultValue = item.Key.TrimStart('@'), }; grp.Properties.Add(prop); reverseConditions?.AttachFreeformPreprocessorMacro(def.ExtraArguments[0], def.IDWithPrefix); reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, prop.DefaultValue); } else { grp.Properties.Add(new PropertyEntry.Boolean { Name = def.Name, UniqueID = def.IDWithoutPrefix, ValueForTrue = item.Key, DefaultValue = def.IsDefaultOn ?? true, }); string expandedMacro = string.Format(def.ExtraArguments[0], item.Key); reverseConditions?.AttachPreprocessorMacro(expandedMacro, reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Key)); reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, ""); } } else { List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>(); foreach (var item in def.Items) { suggestions.Add(new PropertyEntry.Enumerated.Suggestion { InternalValue = item.Key, UserFriendlyName = item.Value.Name }); string expandedMacro = string.Format(def.ExtraArguments[0], item.Key); reverseConditions?.AttachPreprocessorMacro(expandedMacro, reverseConditions?.CreateSimpleCondition(def.IDWithPrefix, item.Key)); } reverseConditions?.AttachMinimalConfigurationValue(def.IDWithPrefix, suggestions[def.DefaultItemIndex].InternalValue); grp.Properties.Add(new PropertyEntry.Enumerated { Name = def.Name, UniqueID = def.IDWithoutPrefix, SuggestionList = suggestions.ToArray(), DefaultEntryIndex = def.DefaultItemIndex }); } } } if (allConditions.Count > 0) { conditions = new List <ParsedCondition>(); foreach (var cond in allConditions) { int idx = cond.Condition.IndexOf(':'); if (idx == -1) { throw new Exception("Invalid simple condition format"); } Regex rgFile = new Regex(cond.Condition.Substring(0, idx), RegexOptions.IgnoreCase); string rawCond = cond.Condition.Substring(idx + 1).Trim(); Condition parsedCond = ParseCondition(rawCond); conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond, ReverseConditionHandle = cond.Handle }); } } string expandedSourceFolder = SourceFolder; bsp.ExpandVariables(ref expandedSourceFolder); if (TargetFolder == null) { TargetFolder = Path.GetFileName(expandedSourceFolder); } TargetFolder = TargetFolder.Replace('\\', '/'); if (subdir == null) { subdir = ""; } string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder); Directory.CreateDirectory(absTarget); string folderInsideBSPPrefix = TargetFolder; if (!string.IsNullOrEmpty(subdir)) { folderInsideBSPPrefix = subdir + "/" + TargetFolder; } folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/'); if (folderInsideBSPPrefix == "/") { folderInsideBSPPrefix = ""; } else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/")) { folderInsideBSPPrefix = "/" + folderInsideBSPPrefix; } var copyMasks = new CopyFilters(FilesToCopy); var autoIncludes = new CopyFilters(AutoIncludeMask); var potentialSymlinks = new CopyFilters(SymlinkResolutionMask); var projectContents = new CopyFilters(ProjectInclusionMask); var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories) .Where(f => !bsp.SkipHiddenFiles || (File.GetAttributes(f) & FileAttributes.Hidden) != FileAttributes.Hidden) .Select(f => f.Substring(expandedSourceFolder.Length + 1)) .Where(f => copyMasks.IsMatch(f)) .ToArray(); foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct()) { Directory.CreateDirectory(dir); } List <IRenameRule> rules = new List <IRenameRule>(); foreach (var r in (RenameRules ?? "").Split(';').Select(s => s.Trim()).Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) }); } foreach (var r in (AdvancedRenameRules ?? "").Split(';').Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new AdvancedRenamingRule { OldName = new Regex(r.Substring(0, idx), RegexOptions.IgnoreCase), NewNameFormat = r.Substring(idx + 2) }); } var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList(); foreach (var f in filesToCopy) { string renamedRelativePath = f; string pathInsidePackage = Path.Combine(subdir, TargetFolder, f); if (pathInsidePackage.Length > 170) { if (!bsp.OnFilePathTooLong(pathInsidePackage)) { continue; } } string targetFile = Path.Combine(absTarget, f); string newName = rules?.FirstOrDefault(r => r.Matches(f))?.Apply(targetFile); if (newName == null) { if (bsp.RenamedFileTable.TryGetValue(targetFile, out newName) || bsp.RenamedFileTable.TryGetValue(targetFile.Replace('/', '\\'), out newName)) { } } if (newName != null) { var oldTargetFile = targetFile; targetFile = Path.Combine(Path.GetDirectoryName(targetFile), newName); renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), newName); bsp.RenamedFileTable[oldTargetFile] = newName; } if (AlreadyCopied) { if (!File.Exists(targetFile)) { throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist"); } } else { bool resolved = false; var absSourcePath = Path.Combine(expandedSourceFolder, f); if (potentialSymlinks.IsMatch(f)) { for (; ;) { var contents = File.ReadAllLines(absSourcePath); if (contents.Length == 1 && File.Exists(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0]))) { absSourcePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0])); } else { break; } } } if (!resolved) { File.Copy(absSourcePath, targetFile, true); } } File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly); string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/'); bool includedInProject = projectContents.IsMatch(f); if (includedInProject) { projectFiles.Add(encodedPath.Replace('\\', '/')); } bool foundCondition = false; if (conditions != null) { foreach (var cond in conditions) { if (cond.Regex.IsMatch(f)) { bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath }); cond.UseCount++; if (includedInProject) { cond.ReverseConditionHandle?.AttachFile(encodedPath); } foundCondition = true; break; } } } if (!foundCondition && includedInProject) { reverseConditions?.AttachFile(encodedPath); } } if (AdditionalProjectFiles != null) { foreach (var spec in AdditionalProjectFiles.Split(';')) { string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec; projectFiles.Add(encodedPath); } } var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray(); if ((unusedConditions?.Length ?? 0) != 0) { throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length)); } if (Patches != null) { foreach (var p in Patches) { foreach (var fn in p.FilePath.Split(';')) { List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList(); p.Apply(allLines); string targetPath = p.TargetPath; if (targetPath == null) { targetPath = fn; } Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath))); File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines); } } } if (GuardedFiles != null) { foreach (var gf in GuardedFiles) { int idx = gf.IndexOf("=>"); Regex rgFile = new Regex(gf.Substring(0, idx)); string macro = gf.Substring(idx + 2); var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f))); List <string> lines = new List <string>(File.ReadAllLines(fn)); int i = 0; //1. Find first #include for (i = 0; i < lines.Count; i++) { if (lines[i].Trim().StartsWith("#include")) { break; } } //2. Find first non-preprocessor line for (; i < lines.Count; i++) { if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include")) { break; } } if (i == lines.Count) { throw new Exception("Cannot find a place to insert guard in " + fn); } lines.Insert(i, string.Format("#if defined({0}) && {0}", macro)); lines.Add("#endif //" + macro); File.WriteAllLines(fn, lines); } } if (AdditionalIncludeDirs != null) { foreach (var dir in AdditionalIncludeDirs.Split(';')) { var mappedDir = MapIncludeDir(absTarget, subdir, dir); reverseConditions?.AttachIncludeDir(mappedDir); includeDirs.Add(mappedDir); } } return(new ToolFlags { PreprocessorMacros = (preprocessorMacros.Count == 0) ? null : preprocessorMacros.ToArray(), IncludeDirectories = includeDirs.ToArray() }); }
public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir, ref PropertyList configurableProperties) { List <ParsedCondition> conditions = null; List <string> allConditions = new List <string>(); if (SimpleFileConditions != null) { allConditions.AddRange(SimpleFileConditions); } if (SmartFileConditions != null) { foreach (var str in SmartFileConditions) { int idx = str.IndexOf('|'); string name = str.Substring(0, idx); string id = "com.sysprogs.bspoptions." + name.Replace(' ', '_'); string[] values = str.Substring(idx + 1).Split(';'); PropertyEntry entry; if (values.Length == 1) { var val = values[0]; string regex, value; idx = val.IndexOf("=>"); if (idx == -1) { regex = val; value = "1"; } else { regex = val.Substring(0, idx); value = val.Substring(idx + 2); } allConditions.Add($"{regex}: $${id}$$ == {value}"); entry = new PropertyEntry.Boolean { ValueForTrue = value, Name = name, UniqueID = id, DefaultValue = true }; } else { List <PropertyEntry.Enumerated.Suggestion> suggestions = new List <PropertyEntry.Enumerated.Suggestion>(); foreach (var val in values) { idx = val.IndexOf("=>"); string regex = val.Substring(0, idx); string value = val.Substring(idx + 2); allConditions.Add($"{regex}: $${id}$$ == {value}"); suggestions.Add(new PropertyEntry.Enumerated.Suggestion { InternalValue = value }); } entry = new PropertyEntry.Enumerated { Name = name, UniqueID = id, SuggestionList = suggestions.ToArray() }; } if (configurableProperties?.PropertyGroups == null) { configurableProperties = new PropertyList { PropertyGroups = new List <PropertyGroup>() } } ; var grp = configurableProperties.PropertyGroups.FirstOrDefault(g => g.Name == null && g.UniqueID == null); if (grp == null) { configurableProperties.PropertyGroups.Insert(0, grp = new PropertyGroup()); } grp.Properties.Add(entry); } } if (allConditions.Count > 0) { conditions = new List <ParsedCondition>(); foreach (var cond in allConditions) { int idx = cond.IndexOf(':'); if (idx == -1) { throw new Exception("Invalid simple condition format"); } Regex rgFile = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase); string rawCond = cond.Substring(idx + 1).Trim(); Condition parsedCond = ParseCondition(rawCond); conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond }); } } string expandedSourceFolder = SourceFolder; bsp.ExpandVariables(ref expandedSourceFolder); if (TargetFolder == null) { TargetFolder = Path.GetFileName(expandedSourceFolder); } TargetFolder = TargetFolder.Replace('\\', '/'); if (subdir == null) { subdir = ""; } string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder); Directory.CreateDirectory(absTarget); string folderInsideBSPPrefix = TargetFolder; if (!string.IsNullOrEmpty(subdir)) { folderInsideBSPPrefix = subdir + "/" + TargetFolder; } folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/'); if (folderInsideBSPPrefix == "/") { folderInsideBSPPrefix = ""; } else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/")) { folderInsideBSPPrefix = "/" + folderInsideBSPPrefix; } var copyMasks = new CopyFilters(FilesToCopy); var autoIncludes = new CopyFilters(AutoIncludeMask); var potentialSymlinks = new CopyFilters(SymlinkResolutionMask); var projectContents = new CopyFilters(ProjectInclusionMask); var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray(); foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct()) { Directory.CreateDirectory(dir); } List <IRenameRule> rules = new List <IRenameRule>(); foreach (var r in (RenameRules ?? "").Split(';').Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) }); } foreach (var r in (AdvancedRenameRules ?? "").Split(';').Where(s => s != "")) { int idx = r.IndexOf("=>"); rules.Add(new AdvancedRenamingRule { OldName = new Regex(r.Substring(0, idx), RegexOptions.IgnoreCase), NewNameFormat = r.Substring(idx + 2) }); } var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList(); foreach (var f in filesToCopy) { string renamedRelativePath = f; string pathInsidePackage = Path.Combine(subdir, TargetFolder, f); if (pathInsidePackage.Length > 120) { if (!bsp.OnFilePathTooLong(pathInsidePackage)) { continue; } } string targetFile = Path.Combine(absTarget, f); string newName = rules?.FirstOrDefault(r => r.Matches(f))?.Apply(targetFile); if (newName == null) { if (bsp.RenamedFileTable.TryGetValue(targetFile, out newName) || bsp.RenamedFileTable.TryGetValue(targetFile.Replace('/', '\\'), out newName)) { } } if (newName != null) { var oldTargetFile = targetFile; targetFile = Path.Combine(Path.GetDirectoryName(targetFile), newName); renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), newName); bsp.RenamedFileTable[oldTargetFile] = newName; } if (AlreadyCopied) { if (!File.Exists(targetFile)) { throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist"); } } else { bool resolved = false; var absSourcePath = Path.Combine(expandedSourceFolder, f); if (potentialSymlinks.IsMatch(f)) { for (; ;) { var contents = File.ReadAllLines(absSourcePath); if (contents.Length == 1 && File.Exists(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0]))) { absSourcePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(absSourcePath), contents[0])); } else { break; } } } if (!resolved) { File.Copy(absSourcePath, targetFile, true); } } File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly); string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/'); if (projectContents.IsMatch(f)) { projectFiles.Add(encodedPath.Replace('\\', '/')); } if (conditions != null) { foreach (var cond in conditions) { if (cond.Regex.IsMatch(f)) { bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath }); cond.UseCount++; break; } } } } if (AdditionalProjectFiles != null) { foreach (var spec in AdditionalProjectFiles.Split(';')) { string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec; projectFiles.Add(encodedPath); } } var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray(); if ((unusedConditions?.Length ?? 0) != 0) { throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length)); } if (Patches != null) { foreach (var p in Patches) { foreach (var fn in p.FilePath.Split(';')) { List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList(); p.Apply(allLines); string targetPath = p.TargetPath; if (targetPath == null) { targetPath = fn; } Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath))); File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines); } } } if (GuardedFiles != null) { foreach (var gf in GuardedFiles) { int idx = gf.IndexOf("=>"); Regex rgFile = new Regex(gf.Substring(0, idx)); string macro = gf.Substring(idx + 2); var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f))); List <string> lines = new List <string>(File.ReadAllLines(fn)); int i = 0; //1. Find first #include for (i = 0; i < lines.Count; i++) { if (lines[i].Trim().StartsWith("#include")) { break; } } //2. Find first non-preprocessor line for (; i < lines.Count; i++) { if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include")) { break; } } if (i == lines.Count) { throw new Exception("Cannot find a place to insert guard in " + fn); } lines.Insert(i, string.Format("#if defined({0}) && {0}", macro)); lines.Add("#endif //" + macro); File.WriteAllLines(fn, lines); } } if (AdditionalIncludeDirs != null) { includeDirs.AddRange(AdditionalIncludeDirs.Split(';').Select(d => MapIncludeDir(absTarget, d))); } return(new ToolFlags { PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'), IncludeDirectories = includeDirs.ToArray() }); }
public IEnumerable <CopiedSample> CopySamples(IEnumerable <EmbeddedFramework> allFrameworks = null, IEnumerable <SysVarEntry> extraVariablesToValidateSamples = null) { if (Definition.SmartSamples != null) { foreach (var sample in Definition.SmartSamples) { string destFolder = Path.Combine(BSP.BSPRoot, sample.DestinationFolder); string sourceDir = sample.SourceFolder; BSP.ExpandVariables(ref sourceDir); if (sample.CopyFilters == null) { PathTools.CopyDirectoryRecursive(sourceDir, destFolder); } else { var filters = new CopyFilters(sample.CopyFilters); foreach (var fn in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories)) { string relPath = fn.Substring(sourceDir.Length).TrimStart('\\'); if (filters.IsMatch(relPath)) { string targetPath = Path.Combine(destFolder, relPath); Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); File.Copy(fn, targetPath); } } } var sampleObj = sample.EmbeddedSample ?? XmlTools.LoadObject <EmbeddedProjectSample>(Path.Combine(destFolder, "sample.xml")); if (sampleObj.RequiredFrameworks == null && allFrameworks != null) { sampleObj.RequiredFrameworks = allFrameworks.Where(fw => fw.DefaultEnabled).Select(fw => fw.ClassID ?? fw.ID)?.ToArray(); } if (sample.AdditionalSources != null) { sampleObj.AdditionalSourcesToCopy = sample.AdditionalSources.Select(f => { int idx = f.IndexOf("=>"); if (idx == -1) { return new AdditionalSourceFile { SourcePath = f } } ; else { return new AdditionalSourceFile { SourcePath = f.Substring(0, idx).Trim(), TargetFileName = f.Substring(idx + 2).Trim() } }; }).ToArray(); foreach (var f in sampleObj.AdditionalSourcesToCopy) { string path = f.SourcePath.Replace("$$SYS:BSP_ROOT$$", BSP.Directories.OutputDir); if (!File.Exists(path)) { if (extraVariablesToValidateSamples != null) { foreach (var v in extraVariablesToValidateSamples) { path = path.Replace("$$" + v.Key + "$$", v.Value); } } if (!File.Exists(path)) { Console.WriteLine("Missing sample file: " + f.SourcePath); } } } } if (sampleObj.MCUFilterRegex == null & allFrameworks != null && sampleObj.RequiredFrameworks != null) { string[] devices = null; foreach (var fw in allFrameworks) { if (fw.MCUFilterRegex == null) { continue; } if (sampleObj.RequiredFrameworks.Contains(fw.ID) || sampleObj.RequiredFrameworks.Contains(fw.ClassID)) { if (devices == null) { devices = fw.MCUFilterRegex.Split('|'); } else { devices = devices.Intersect(fw.MCUFilterRegex.Split('|')).ToArray(); } } } if (devices != null) { sampleObj.MCUFilterRegex = string.Join("|", devices); } } if (sampleObj.MCUFilterRegex == null && sample.MCUFilterRegex != null) { sampleObj.MCUFilterRegex = sample.MCUFilterRegex; } XmlTools.SaveObject(sampleObj, Path.Combine(destFolder, "sample.xml")); yield return(new CopiedSample { RelativePath = sample.DestinationFolder, IsTestProjectSample = sample.IsTestProjectSample }); } } }
public IEnumerable <CopiedSample> CopySamples(IEnumerable <EmbeddedFramework> allFrameworks = null, IEnumerable <SysVarEntry> extraVariablesToValidateSamples = null) { if (Definition.SmartSamples != null) { foreach (var sample in Definition.SmartSamples) { string destFolder = Path.Combine(BSP.BSPRoot, sample.DestinationFolder); string sourceDir = sample.SourceFolder; BSP.ExpandVariables(ref sourceDir); if (sample.CopyFilters == null) { PathTools.CopyDirectoryRecursive(sourceDir, destFolder); } else { var filters = new CopyFilters(sample.CopyFilters); foreach (var fn in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories)) { string relPath = fn.Substring(sourceDir.Length).TrimStart('\\'); if (filters.IsMatch(relPath)) { string targetPath = Path.Combine(destFolder, relPath); Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); File.Copy(fn, targetPath); } } } if (sample.AdditionalBuildTimeSources != null) { foreach (var src in sample.AdditionalBuildTimeSources) { string source = src; BSP.ExpandVariables(ref source); string targetPath = Path.Combine(destFolder, Path.GetFileName(source)); File.Copy(source, targetPath); } } if (sample.Patches != null) { foreach (var p in sample.Patches) { foreach (var fn in p.FilePath.Split(';')) { List <string> allLines = File.ReadAllLines(Path.Combine(destFolder, fn)).ToList(); p.Apply(allLines); File.WriteAllLines(Path.Combine(destFolder, fn), allLines); } } } var sampleObj = sample.EmbeddedSample ?? XmlTools.LoadObject <EmbeddedProjectSample>(Path.Combine(destFolder, "sample.xml")); if (sampleObj.RequiredFrameworks == null && allFrameworks != null) { sampleObj.RequiredFrameworks = allFrameworks.Where(fw => fw.DefaultEnabled).Select(fw => fw.ClassID ?? fw.ID)?.ToArray(); } if (sample.AdditionalSources != null) { sampleObj.AdditionalSourcesToCopy = sample.AdditionalSources.Select(f => { int idx = f.IndexOf("=>"); if (idx == -1) { return new AdditionalSourceFile { SourcePath = f } } ; else { return new AdditionalSourceFile { SourcePath = f.Substring(0, idx).Trim(), TargetFileName = f.Substring(idx + 2).Trim() } }; }).ToArray(); for (int i = 0; i < sampleObj.AdditionalSourcesToCopy.Length; i++) { string path = sampleObj.AdditionalSourcesToCopy[i].SourcePath.Replace("$$SYS:BSP_ROOT$$", BSP.Directories.OutputDir); if (!File.Exists(path)) { if (extraVariablesToValidateSamples != null) { foreach (var v in extraVariablesToValidateSamples) { path = path.Replace("$$" + v.Key + "$$", v.Value); } } if (!File.Exists(path)) { var args = new MissingSampleFileArgs { UnexpandedPath = sampleObj.AdditionalSourcesToCopy[i].SourcePath, ExpandedPath = path }; OnMissingSampleFile(args); if (args.SubstitutePath != null) { if (args.SubstitutePath.StartsWith(BSP.BSPRoot)) { args.SubstitutePath = "$$SYS:BSP_ROOT$$" + args.SubstitutePath.Substring(BSP.BSPRoot.Length).Replace('\\', '/'); } else if (args.SubstitutePath.StartsWith("$$")) { //Already encoded } else { throw new Exception("Invalid substitute path: " + args.SubstitutePath); } sampleObj.AdditionalSourcesToCopy[i].SourcePath = args.SubstitutePath; } } } } } if (sampleObj.MCUFilterRegex == null & allFrameworks != null && sampleObj.RequiredFrameworks != null) { string[] devices = null; foreach (var fw in allFrameworks) { if (fw.MCUFilterRegex == null) { continue; } if (sampleObj.RequiredFrameworks.Contains(fw.ID) || sampleObj.RequiredFrameworks.Contains(fw.ClassID)) { if (devices == null) { devices = fw.MCUFilterRegex.Split('|'); } else { devices = devices.Intersect(fw.MCUFilterRegex.Split('|')).ToArray(); } } } if (devices != null) { sampleObj.MCUFilterRegex = string.Join("|", devices); } } if (sampleObj.MCUFilterRegex == null && sample.MCUFilterRegex != null) { sampleObj.MCUFilterRegex = sample.MCUFilterRegex; } XmlTools.SaveObject(sampleObj, Path.Combine(destFolder, "sample.xml")); yield return(new CopiedSample { RelativePath = sample.DestinationFolder, IsTestProjectSample = sample.IsTestProjectSample }); } } }
public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List <string> projectFiles, string subdir) { List <ParsedCondition> conditions = null; if (SimpleFileConditions != null) { conditions = new List <ParsedCondition>(); foreach (var cond in SimpleFileConditions) { int idx = cond.IndexOf(':'); if (idx == -1) { throw new Exception("Invalid simple condition format"); } Regex rgFile = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase); string rawCond = cond.Substring(idx + 1).Trim(); Condition parsedCond = ParseCondition(rawCond); conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond }); } } string expandedSourceFolder = SourceFolder; bsp.ExpandVariables(ref expandedSourceFolder); if (TargetFolder == null) { TargetFolder = Path.GetFileName(expandedSourceFolder); } TargetFolder = TargetFolder.Replace('\\', '/'); if (subdir == null) { subdir = ""; } string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder); Directory.CreateDirectory(absTarget); string folderInsideBSPPrefix = TargetFolder; if (!string.IsNullOrEmpty(subdir)) { folderInsideBSPPrefix = subdir + "/" + TargetFolder; } folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/'); if (folderInsideBSPPrefix == "/") { folderInsideBSPPrefix = ""; } else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/")) { folderInsideBSPPrefix = "/" + folderInsideBSPPrefix; } var copyMasks = new CopyFilters(FilesToCopy); var autoIncludes = new CopyFilters(AutoIncludeMask); var projectContents = new CopyFilters(ProjectInclusionMask); var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray(); foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct()) { Directory.CreateDirectory(dir); } RenameRule[] rules = null; if (RenameRules != null) { rules = RenameRules.Split(';').Select(r => { int idx = r.IndexOf("=>"); return(new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) }); }).ToArray(); } var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList(); foreach (var f in filesToCopy) { string renamedRelativePath = f; string pathInsidePackage = Path.Combine(subdir, TargetFolder, f); if (pathInsidePackage.Length > 120) { if (!bsp.OnFilePathTooLong(pathInsidePackage)) { continue; } } string targetFile = Path.Combine(absTarget, f); var rule = rules?.FirstOrDefault(r => r.Matches(f)); if (rule != null) { targetFile = Path.Combine(Path.GetDirectoryName(targetFile), rule.NewName); renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), rule.NewName); } if (AlreadyCopied) { if (!File.Exists(targetFile)) { throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist"); } } else { File.Copy(Path.Combine(expandedSourceFolder, f), targetFile, true); } File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly); string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/'); if (projectContents.IsMatch(f)) { projectFiles.Add(encodedPath.Replace('\\', '/')); } if (conditions != null) { foreach (var cond in conditions) { if (cond.Regex.IsMatch(f)) { bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath }); cond.UseCount++; break; } } } } if (AdditionalProjectFiles != null) { foreach (var spec in AdditionalProjectFiles.Split(';')) { string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + spec; projectFiles.Add(encodedPath); } } var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray(); if ((unusedConditions?.Length ?? 0) != 0) { throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length)); } if (Patches != null) { foreach (var p in Patches) { foreach (var fn in p.FilePath.Split(';')) { List <string> allLines = File.ReadAllLines(Path.Combine(absTarget, fn)).ToList(); p.Apply(allLines); string targetPath = p.TargetPath; if (targetPath == null) { targetPath = fn; } Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath))); File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines); } } } if (GuardedFiles != null) { foreach (var gf in GuardedFiles) { int idx = gf.IndexOf("=>"); Regex rgFile = new Regex(gf.Substring(0, idx)); string macro = gf.Substring(idx + 2); var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f))); List <string> lines = new List <string>(File.ReadAllLines(fn)); int i = 0; //1. Find first #include for (i = 0; i < lines.Count; i++) { if (lines[i].Trim().StartsWith("#include")) { break; } } //2. Find first non-preprocessor line for (; i < lines.Count; i++) { if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include")) { break; } } if (i == lines.Count) { throw new Exception("Cannot find a place to insert guard in " + fn); } lines.Insert(i, string.Format("#if defined({0}) && {0}", macro)); lines.Add("#endif //" + macro); File.WriteAllLines(fn, lines); } } if (AdditionalIncludeDirs != null) { includeDirs.AddRange(AdditionalIncludeDirs.Split(';')); } return(new ToolFlags { PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'), IncludeDirectories = includeDirs.ToArray() }); }
public string TargetFolder; //if null, defaults to (BSP)\(name of source folder), otherwise specifies relative path within the family subdirectory #endregion Fields #region Methods public ToolFlags CopyAndBuildFlags(BSPBuilder bsp, List<string> projectFiles, string subdir) { List<ParsedCondition> conditions = null; if (SimpleFileConditions != null) { conditions = new List<ParsedCondition>(); foreach (var cond in SimpleFileConditions) { int idx = cond.IndexOf(':'); if (idx == -1) throw new Exception("Invalid simple condition format"); Regex rgFile = new Regex(cond.Substring(0, idx), RegexOptions.IgnoreCase); string rawCond = cond.Substring(idx + 1).Trim(); Condition parsedCond = ParseCondition(rawCond); conditions.Add(new ParsedCondition { Regex = rgFile, Condition = parsedCond }); } } string expandedSourceFolder = SourceFolder; bsp.ExpandVariables(ref expandedSourceFolder); if (TargetFolder == null) TargetFolder = Path.GetFileName(expandedSourceFolder); TargetFolder = TargetFolder.Replace('\\', '/'); if (subdir == null) subdir = ""; string absTarget = Path.Combine(bsp.BSPRoot, subdir, TargetFolder); Directory.CreateDirectory(absTarget); string folderInsideBSPPrefix = TargetFolder; if (!string.IsNullOrEmpty(subdir)) folderInsideBSPPrefix = subdir + "/" + TargetFolder; folderInsideBSPPrefix = folderInsideBSPPrefix.Replace('\\', '/'); if (folderInsideBSPPrefix == "/") folderInsideBSPPrefix = ""; else if (folderInsideBSPPrefix != "" && !folderInsideBSPPrefix.StartsWith("/")) folderInsideBSPPrefix = "/" + folderInsideBSPPrefix; var copyMasks = new CopyFilters(FilesToCopy); var autoIncludes = new CopyFilters(AutoIncludeMask); var projectContents = new CopyFilters(ProjectInclusionMask); var filesToCopy = Directory.GetFiles(expandedSourceFolder, "*", SearchOption.AllDirectories).Select(f => f.Substring(expandedSourceFolder.Length + 1)).Where(f => copyMasks.IsMatch(f)).ToArray(); foreach (var dir in filesToCopy.Select(f => Path.Combine(absTarget, Path.GetDirectoryName(f))).Distinct()) Directory.CreateDirectory(dir); RenameRule[] rules = null; if (RenameRules != null) rules = RenameRules.Split(';').Select(r => { int idx = r.IndexOf("=>"); return new RenameRule { OldName = r.Substring(0, idx), NewName = r.Substring(idx + 2) }; }).ToArray(); var includeDirs = filesToCopy.Where(f => autoIncludes.IsMatch(f)).Select(f => Path.GetDirectoryName(f).Replace('\\', '/')).Distinct().Select(d => "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + (string.IsNullOrEmpty(d) ? "" : ("/" + d))).ToList(); foreach (var f in filesToCopy) { string renamedRelativePath = f; string pathInsidePackage = Path.Combine(subdir, TargetFolder, f); if (pathInsidePackage.Length > 120) { if (!bsp.OnFilePathTooLong(pathInsidePackage)) continue; } string targetFile = Path.Combine(absTarget, f); var rule = rules?.FirstOrDefault(r => r.Matches(f)); if (rule != null) { targetFile = Path.Combine(Path.GetDirectoryName(targetFile), rule.NewName); renamedRelativePath = Path.Combine(Path.GetDirectoryName(renamedRelativePath), rule.NewName); } if (AlreadyCopied) { if (!File.Exists(targetFile)) throw new Exception(targetFile + " required by a copy job marked as 'Already Copied' does not exist"); } else File.Copy(Path.Combine(expandedSourceFolder, f), targetFile, true); File.SetAttributes(targetFile, File.GetAttributes(targetFile) & ~FileAttributes.ReadOnly); string encodedPath = "$$SYS:BSP_ROOT$$" + folderInsideBSPPrefix + "/" + renamedRelativePath.Replace('\\', '/'); if (projectContents.IsMatch(f)) projectFiles.Add(encodedPath.Replace('\\', '/')); if (conditions != null) { foreach (var cond in conditions) if (cond.Regex.IsMatch(f)) { bsp.MatchedFileConditions.Add(new FileCondition { ConditionToInclude = cond.Condition, FilePath = encodedPath }); cond.UseCount++; break; } } } var unusedConditions = conditions?.Where(c => c.UseCount == 0)?.ToArray(); if ((unusedConditions?.Length ?? 0) != 0) throw new Exception(string.Format("Found {0} unused conditions. Please recheck your rules.", unusedConditions.Length)); if (Patches != null) foreach(var p in Patches) { List<string> allLines = File.ReadAllLines(Path.Combine(absTarget, p.FilePath)).ToList(); p.Apply(allLines); string targetPath = p.TargetPath; if (targetPath == null) targetPath = p.FilePath; Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(absTarget, targetPath))); File.WriteAllLines(Path.Combine(absTarget, targetPath), allLines); } if (GuardedFiles != null) foreach (var gf in GuardedFiles) { int idx = gf.IndexOf("=>"); Regex rgFile = new Regex(gf.Substring(0, idx)); string macro = gf.Substring(idx + 2); var fn = Path.Combine(absTarget, filesToCopy.First(f => rgFile.IsMatch(f))); List<string> lines = new List<string>(File.ReadAllLines(fn)); int i = 0; //1. Find first #include for (i = 0; i < lines.Count; i++) if (lines[i].Trim().StartsWith("#include")) break; //2. Find first non-preprocessor line for (; i < lines.Count; i++) if (!string.IsNullOrWhiteSpace(lines[i]) && !lines[i].Trim().StartsWith("#include")) break; if (i == lines.Count) throw new Exception("Cannot find a place to insert guard in " + fn); lines.Insert(i, string.Format("#if defined({0}) && {0}", macro)); lines.Add("#endif //" + macro); File.WriteAllLines(fn, lines); } if (AdditionalIncludeDirs != null) includeDirs.AddRange(AdditionalIncludeDirs.Split(';')); return new ToolFlags { PreprocessorMacros = (PreprocessorMacros == null) ? null : PreprocessorMacros.Split(';'), IncludeDirectories = includeDirs.ToArray() }; }