diff --git a/README.md b/README.md index 4fe2da0..2063a53 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Here are the details of each parameter used in the patching system: 1. **`standard`:** Standard patching type that follows the `+` (add) and `-` (remove) syntax. - Used for general file modifications. + - Supports multi-line block matching: the entire `-` block must be present to be replaced by the `+` block. - **Example:** ```patch i: /browser/branding/official/configure.sh @@ -73,6 +74,21 @@ Here are the details of each parameter used in the patching system: -MOZ_APP_DISPLAYNAME=Firefox +MOZ_APP_DISPLAYNAME=Spitfire ``` + - **Multi-line example:** + ```patch + -project_flag( + - env="MOZ_APP_UA_NAME", + - default="", + - nargs=1, + - help="application name in the User Agent string", + -) + +project_flag( + + env="MOZ_APP_UA_NAME", + + default="Firefox", + + nargs=1, + + help="application name in the User Agent string", + +) + ``` Note: *Type will fallback to t:standard when no type is specified.* 2. **`pref`:** Indicates that the patch is modifying preference settings (e.g., Firefox `prefs.js`). diff --git a/pre-compile-patches/user-agent.patch b/pre-compile-patches/user-agent.patch new file mode 100644 index 0000000..adf2200 --- /dev/null +++ b/pre-compile-patches/user-agent.patch @@ -0,0 +1,16 @@ +t: standard +i: /toolkit/moz.configure +o: /toolkit/moz.configure + +-project_flag( +- env="MOZ_APP_UA_NAME", +- default="", +- nargs=1, +- help="Application name in the User Agent string", +-) ++project_flag( ++ env="MOZ_APP_UA_NAME", ++ default="Firefox", ++ nargs=1, ++ help="application name in the User Agent string", ++) diff --git a/standard.go b/standard.go index 1a88e51..51a8ca4 100644 --- a/standard.go +++ b/standard.go @@ -1,102 +1,75 @@ package main import ( - "bufio" "fmt" "os" "strings" ) // applyStandardModifications handles `standard` type patches -func applyStandardModifications(targetFilePath string, modifications []string) error { - fmt.Printf("Applying standard modifications to file: %s\n", targetFilePath) - - // Open the target file for reading and writing - file, err := os.OpenFile(targetFilePath, os.O_RDWR, 0644) +func applyStandardModifications(filePath string, modifications []string) error { + contentBytes, err := os.ReadFile(filePath) if err != nil { - return fmt.Errorf("failed to open target file '%s': %v", targetFilePath, err) + return fmt.Errorf("failed to read file: %v", err) } - defer file.Close() + lines := strings.Split(string(contentBytes), "\n") - scanner := bufio.NewScanner(file) - targetLines := []string{} - - // Read all lines from the target file - for scanner.Scan() { - targetLines = append(targetLines, scanner.Text()) - } - if err := scanner.Err(); err != nil { - return fmt.Errorf("failed to read target file '%s': %v", targetFilePath, err) + var delBlock []string + var addBlock []string + var patchBlocks []struct { + del []string + add []string } - modifiedLines := map[string]bool{} - modMap := parseModifications(modifications) + // Group lines into delete and add blocks + for _, line := range modifications { + if strings.HasPrefix(line, "-") { + delBlock = append(delBlock, strings.TrimPrefix(line, "-")) + } else if strings.HasPrefix(line, "+") { + addBlock = append(addBlock, strings.TrimPrefix(line, "+")) + } else if line == "" && len(delBlock) > 0 { + patchBlocks = append(patchBlocks, struct { + del []string + add []string + }{append([]string{}, delBlock...), append([]string{}, addBlock...)}) + delBlock = nil + addBlock = nil + } + } + if len(delBlock) > 0 || len(addBlock) > 0 { + patchBlocks = append(patchBlocks, struct { + del []string + add []string + }{delBlock, addBlock}) + } - var updatedContent strings.Builder - - // Apply modifications to the target lines - for _, line := range targetLines { - lineModified := false - - for key, mod := range modMap { - if strings.Contains(line, key) && !modifiedLines[key] { - fmt.Printf("Replacing line in file '%s': %s -> %s\n", targetFilePath, line, mod) - updatedContent.WriteString(mod + "\n") - modifiedLines[key] = true - lineModified = true + // Apply each block + for _, patch := range patchBlocks { + matchIndex := -1 + for i := 0; i <= len(lines)-len(patch.del); i++ { + matched := true + for j := range patch.del { + if strings.TrimSpace(lines[i+j]) != strings.TrimSpace(patch.del[j]) { + matched = false + break + } + } + if matched { + matchIndex = i break } } - - // Write the original line if no modification matches - if !lineModified { - updatedContent.WriteString(line + "\n") + if matchIndex == -1 { + return fmt.Errorf("patch block not found in file: %v", patch.del) } + + // Replace matched block + newLines := append([]string{}, lines[:matchIndex]...) + newLines = append(newLines, patch.add...) + newLines = append(newLines, lines[matchIndex+len(patch.del):]...) + lines = newLines } - // Append any remaining modifications that were not applied - for key, mod := range modMap { - if !modifiedLines[key] { - fmt.Printf("Adding new line to file '%s': %s\n", targetFilePath, mod) - updatedContent.WriteString(mod + "\n") - } - } - - // Truncate and rewrite the file with updated content - if err := file.Truncate(0); err != nil { - return fmt.Errorf("failed to truncate file '%s': %v", targetFilePath, err) - } - if _, err := file.Seek(0, 0); err != nil { - return fmt.Errorf("failed to reset file pointer for '%s': %v", targetFilePath, err) - } - if _, err := file.WriteString(updatedContent.String()); err != nil { - return fmt.Errorf("failed to write updated content to file '%s': %v", targetFilePath, err) - } - - fmt.Printf("Standard modifications successfully applied to file: %s\n", targetFilePath) - return nil -} - -// parseModifications converts a list of modification strings into a map for processing -func parseModifications(modifications []string) map[string]string { - modMap := map[string]string{} - for _, mod := range modifications { - if strings.HasPrefix(mod, "+") || strings.HasPrefix(mod, "-") { - trimmed := strings.TrimSpace(strings.TrimPrefix(mod, "+")) - trimmed = strings.TrimPrefix(trimmed, "-") - key := extractKey(trimmed) - modMap[key] = trimmed - } - } - return modMap -} - -// extractKey extracts the key from a modification string -func extractKey(line string) string { - start := strings.Index(line, "(") - end := strings.LastIndex(line, ")") - if start > 0 && end > start { - return strings.TrimSpace(line[start+1 : end]) - } - return line // Fallback: return the full line + // Write updated file + return os.WriteFile(filePath, []byte(strings.Join(lines, "\n")), 0644) }