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()
};
}