コード例 #1
0
ファイル: SourceCopyTools.cs プロジェクト: atomlong/BSPTools
        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()
            });
        }
コード例 #2
0
        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()
            });
        }
コード例 #3
0
ファイル: SourceCopyTools.cs プロジェクト: gojimmypi/BSPTools
        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()
            });
        }