
hotpatchR is a runtime hotfix utility for locked R
package namespaces. It is built for legacy container workflows where a
package version is sealed in place and cannot be rebuilt or
redeployed.
When R loads a package, it builds a locked namespace. Internal package functions call each other inside that namespace, and the namespace acts as a protective bubble.
That means:
broken_fun() is only
visible inside the package namespacecaller_fun() resolves internal
calls from that same locked namespacebroken_fun() into the global
environment does not update the package’s internal pointerIn practice, this forces a painful current workflow:
This is manual, brittle, and scales badly for large legacy packages.
hotpatchR changes the problem from “global environment
hacking” to “namespace surgery.” Instead of copying dependencies into
the global environment, it overwrites the function inside the package
namespace itself.
Benefits:
hotpatchR is built for the common legacy scenario where
a package version is fixed in place and you want to validate a runtime
correction using existing package tests. With
inject_patch(), you can replace a broken internal
function.
A typical test-hotfix flow looks like this:
library(hotpatchR)
baseline <- dummy_parent_func("test")
print(baseline)
#> "Parent output -> I am the BROKEN child. Input: test"
inject_patch(
pkg = "hotpatchR",
patch_list = list(dummy_child_func = function(x) {
paste("I am the FIXED child! Input:", x)
})
)
patched_result <- dummy_parent_func("test")
print(patched_result)
#> "Parent output -> I am the FIXED child! Input: test"
#Eventually, you can reverse the patch to restore the original behavior if needed:
undo_patch(pkg = "hotpatchR", names = "dummy_child_func")
restored_result <- dummy_parent_func("test")
print(restored_result)
#> "Parent output -> I am the BROKEN child. Input: test"inject_patch(pkg, patch_list): overwrite functions
inside a package namespace or environmentundo_patch(pkg, names = NULL): restore backed-up
originals for patched bindingstest_patched_dir(pkg, test_path): run
testthat tests against the modified namespaceapply_hotfix_file(file, pkg = NULL): load a hotfix
script and inject the included patch listinject_patch() unlocks the binding inside the target
namespace, assigns the replacement function, and then re-locks the
binding. This keeps the change local to the package namespace and
preserves normal internal function resolution.
See vignettes/hotpatchR-intro.Rmd for a deeper
explanation of the namespace trap, rollback workflows, and example
hotfix scripts.