This is in conformance with the guidelines that `.md` files under `docs/` must use 80-columns.
6.0 KiB
🩹 Plaster and semantical patching
Plaster is an experimental tool being introduced in Brave to allow us to apply changes to upstream sources files, by relying on regex transformations for to search for patterns and apply substitutions.
Why 🩹 Plaster
The two traditional approaches to introduce changes to Chromium have been git
patches (i.e. patches/), and language overrides (i.e. chromium_src/). The
use of patches is in general avoided whenever possible, as they tend to easily
run into conflicts when rebasing Brave onto a newer Chromium version. With
language overrides, although more flexible than patches, they tend to be
invisible in the source code target, hard to interpret, and lead to many cases
of unintended replacements.
Using regexes, Plaster avoids the brittleness of patch files, while providing matching mechanisms that are more flexible than the methods currently employed for macro replacement. This also means a language-agnostic way to approach source changes semantically, and in place. Plaster changes can be both seen in place, as well as audit as patch files.
How does it work
Plaster files are placed under rewrite/, using a .toml extension, and they
are supposed to match the path for the file being plastered.
Warning
At the moment, only plaster files to sources in Chromium's
srcrepo are supported.
Each plaster file will be used to apply changes into a given source, and then generate a patch for the effected changes.
For example, imagine you want to add changes to
chrome/browser/autocomplete/autocomplete_classifier_factory.cc. You would care
about the following files.
- Plaster file:
brave/rewrite/chrome/browser/autocomplete/autocomplete_classifier_factory.cc.toml - Source file:
chrome/browser/autocomplete/autocomplete_classifier_factory.cc - Patch file
brave/patches/chrome-browser-autocomplete-autocomplete_classifier_factory.cc.patch
Creating a plaster file
A plaster file is a toml file used to list regexes operations to be applied in
the corresponding source, based on its path. The following is plaster file to
apply a few changes to
chrome/browser/autocomplete/autocomplete_classifier_factory.cc.
Creating the source file with vscode:
code rewrite/chrome/browser/autocomplete/autocomplete_classifier_factory.cc.toml
This file below has two substitutions to be applied on its source: The first
adds a header to the list of headers in the source. The second one replaces all
occurrences of ChromeAutocompleteSchemeClassifier with
BraveAutocompleteSchemeClassifier.
# Copyright (c) 2025 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
[[substitution]]
description = 'Adding header for BraveAutocompleteSchemeClassifier'
re_pattern = '(#include "[\s\S]*)'
replace = '#include "brave/browser/autocomplete/brave_autocomplete_scheme_classifier.h"\n\1'
[[substitution]]
description = 'Patching in BraveAutocompleteSchemeClassifier'
pattern = 'ChromeAutocompleteSchemeClassifier'
replace = 'BraveAutocompleteSchemeClassifier'
The basic format for a `[[substitution]]` entry is as follow:
```toml
[[substition]]
description = ''
# One of either pattern or re_pattern must be specified
pattern = '' # non-regex pattern (string will be escaped)
re_pattern = '' # regex pattern
replace = ''
re_flags = [] # These are traditional python regex flags.
count = 1 # use 0 to ignore the match count and replace all
To apply this plaster file, just run plaster.py:
tools/cr/plaster.py apply
Running plaster.py will cause the substitutions to be applied in
chrome/browser/autocomplete/autocomplete_classifier_factory.cc, but it will
cause the creation/update of the corresponding patch file for this source. For
exmample, it may produce a diff file like this:
diff --git a/patches/chrome-browser-autocomplete-autocomplete_classifier_factory.cc.patch b/patches/chrome-browser-autocomplete-autocomplete_classifier_factory.cc.patch
new file mode 100644
index 00000000000..63703e6940b
--- /dev/null
+++ b/patches/chrome-browser-autocomplete-autocomplete_classifier_factory.cc.patch
@@ -0,0 +1,21 @@
+diff --git a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
+index db73283fbc4f5146bb42e2a8abfcdfa4567ab252..f241c6c5f0611dcbcad3e468a7595be75324a8ba 100644
+--- a/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
++++ b/chrome/browser/autocomplete/autocomplete_classifier_factory.cc
+@@ -16,6 +16,7 @@
+ #include "components/omnibox/browser/autocomplete_classifier.h"
+ #include "components/omnibox/browser/autocomplete_controller.h"
+ #include "extensions/buildflags/buildflags.h"
++#include "brave/browser/autocomplete/brave_autocomplete_scheme_classifier.h"
+
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "extensions/browser/extension_system_provider.h"
+@@ -43,7 +44,7 @@ std::unique_ptr<KeyedService> AutocompleteClassifierFactory::BuildInstanceFor(
+ std::make_unique<AutocompleteController>(
+ std::make_unique<ChromeAutocompleteProviderClient>(profile),
+ AutocompleteClassifier::DefaultOmniboxProviders()),
+- std::make_unique<ChromeAutocompleteSchemeClassifier>(profile));
++ std::make_unique<BraveAutocompleteSchemeClassifier>(profile));
+ }
+
+ AutocompleteClassifierFactory::AutocompleteClassifierFactory()
The produced patch is supposed to be committed in the repository as usual.
Checking if files are up-to-date
You can verify if all plaster files are applied, with Chromium sources updated
and patch files checked under path with the following command:
tools/cr/plaster.py check
This is the equivalent of a dry run of plaster.py apply.
Best practices
See https://github.com/brave-experiments/brave-core-tools/blob/master/docs/best-practices/plaster.md