MyNixOS website logo
Description

Runtime Namespace Patching Utilities for R Packages.

Provides utilities for runtime hotpatching of locked R package namespaces. The package enables dynamic injection of function patches into sealed package environments without rebuilding or redeploying the package. This is particularly useful for legacy containerized workflows where package versions are frozen in place. The core functionality includes inject_patch() to inject patches into package namespaces, undo_patch() to restore original functions, apply_hotfix_file() to apply patches from external R scripts, and test_patched_dir() to run test suites against patched packages. The package implements namespace surgery techniques that allow internal callers to automatically see patched functions.

hotpatchR

R-CMD-check pkgdown

GitHub forks GitHub repo stars

GitHub commit activity GitHub contributors GitHub last commit GitHub pull requests GitHub repo size Project Status: Active – The project has reached a stable, usable state and is being actively developed. Current Version Open Issues

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.

The core problem

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:

  • a broken internal function like broken_fun() is only visible inside the package namespace
  • a package function like caller_fun() resolves internal calls from that same locked namespace
  • sourcing a fixed broken_fun() into the global environment does not update the package's internal pointer

In practice, this forces a painful current workflow:

  • identify the broken function
  • find every package child function that depends on it
  • copy the broken function plus all dependent callers into a hotfix script
  • source the hotfix script into the global environment
  • run tests while fighting CI and namespace isolation

This is manual, brittle, and scales badly for large legacy packages.

What hotpatchR solves

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:

  • surgical patching of exactly the broken functions
  • internal callers automatically see the fix
  • no need to copy parent callers or entire dependency chains
  • easier validation in live test workflows

Test-hotfix use case

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"

Core API

  • inject_patch(pkg, patch_list): overwrite functions inside a package namespace or environment
  • undo_patch(pkg, names = NULL): restore backed-up originals for patched bindings
  • test_patched_dir(pkg, test_path): run testthat tests against the modified namespace
  • apply_hotfix_file(file, pkg = NULL): load a hotfix script and inject the included patch list

How it works

inject_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.

Vignettes and docs

See vignettes/hotpatchR-intro.Rmd for a deeper explanation of the namespace trap, rollback workflows, and example hotfix scripts.

Metadata

Version

0.1.0

License

Unknown

Platforms (80)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arc-linux
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • sh4-linux
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows