Skip to content
rlsbl.commands.rewrite.go_module_path
On this page

Renames a Go module path across a repository: every go.mod token and every import site, line-scoped, with containment asked of the module-prefix rule.

#rlsbl.commands.rewrite.go_module_path

#rlsbl.commands.rewrite.go_module_path

Rename a Go module path across a repository.

rlsbl rewrite go-module-path --from-module <old> --to-module <new> moves a module and everything under it onto a new path:

  • every go.mod in the repository has its module-path TOKENS rewritten --

the module directive itself, and any require / replace / exclude / retract reference to the old path from a nested module;

  • every Go import site under the old path is rewritten, located by the

tree-sitter import scanner (:func:rlsbl.lint.go_ast.scan_imports) and rewritten line-scoped -- only on the exact line the parser reported an import spec, and only inside that spec's quoted literal.

Containment is never a bare startswith. Both halves ask :mod:rlsbl.module_paths, so a neighbouring module whose path merely begins with the same letters (github.com/o/foobar beside github.com/o/foo) is left alone.

What is deliberately NOT rewritten ----------------------------------

  • Comments. // text in a go.mod and anything outside an import

spec in a .go file are prose; rewriting them would make the occurrence counts describe something other than the code being moved. Grep for the old path after the rename to catch documentation.

  • **Any file that is not a go.mod or a .go.** READMEs, CI workflows

and generated code are outside this command's scope, on purpose: it renames a module, it does not sweep a repository for a string.

  • **vendor/ and .git/, and nothing else.** A vendored tree is a

third-party copy, not this module, and .git is the repository's own storage. Every other directory is visited, INCLUDING build, dist, static, public, assets and node_modules: those are a linter's build-output exclusions, and each of them is also a perfectly ordinary Go package directory (internal/assets, cmd/build, web/static). Pruning them here skipped real packages silently and left a tree that does not compile, so this command passes its own exclusion set to the shared walker rather than inheriting the linters' one.

#GoModuleRewriteError

A hard error in the module-path rewrite (bad input, count mismatch).

#FileRewrite

One file's pending rewrite, as observed.

#validate_module_paths

python
def validate_module_paths(old, new)

Reject module paths that cannot be renamed between.

A supplied-but-empty path is not refused here: that is one class with one message, and the CLI boundary owns it (rlsbl._refuse_empty_flags), so --from-module "" reads the same as every other empty flag value in rlsbl rather than a message only this command uses.

#_excluded

python
def _excluded(path, root)

True when path sits under an excluded path component.

#find_go_mod_files

python
def find_go_mod_files(root)

Every go.mod in the tree, absolute, sorted.

#rewrite_go_mod_text

python
def rewrite_go_mod_text(text, old, new)

Rewrite module-path tokens in go.mod text.

Returns (new_text, occurrences, sites). Only the code portion of each line is touched: anything after // is a comment and is left verbatim.

#_token_at

python
def _token_at(text, start)

The whole module-path token beginning at start in text.

#declared_modules

python
def declared_modules(go_mod_paths)

{abs go.mod path: declared module path} for every readable go.mod.

#_literal_on_line

python
def _literal_on_line(line, import_path)

The quoted literal for import_path as it appears on line, or None.

#rewrite_go_source_text

python
def rewrite_go_source_text(text, sites, old, new)

Rewrite the import literals sites names, line-scoped.

Args:

  • text: the file's full contents.
  • sites: [(import_path, line_number)] as the tree-sitter scanner

reported them, restricted to imports under old.

Returns (new_text, occurrences, descriptions). An import spec whose quoted literal is not present on the reported line -- in EITHER of Go's two string forms -- is a hard error: the parser and the text disagree, and guessing where to write is exactly the failure this command must not have. The form the file used is preserved: a raw-string import stays a raw string.

#scan_go_source

python
def scan_go_source(path, old)

Import sites in path that are under module old.

#observe_file

python
def observe_file(path, root, old, new)

Observe one file, returning a :class:FileRewrite or None.

#recompute

python
def recompute(rewrite, old, new)

Re-derive a file's rewrite from disk. Returns (new_text, count).

#observe

python
def observe(root, old, new)

Build the whole preview: one item per file that would change.

A sweep that finds NOTHING is a hard error, not an empty plan. The overwhelmingly likely cause is a mistyped --from-module, and a command that answers a typo with "nothing to do, exit 0" teaches the operator to believe a rename happened when none did.

A repository that does not itself DECLARE the module is fine and is reported as such: renaming a dependency's module path across a consumer (upstream moved, the imports must follow) is the same sweep with no module directive in it.

#apply_item

python
def apply_item(item, old, new, applied=None)

Write one file, refusing when its count moved since the preview.

applied is an optional list the caller passes through every item; each successful write appends its key, so an abort can name what is already on disk.

#cmd_go_module_path

python
def cmd_go_module_path(flags, project_root)

rlsbl rewrite go-module-path -- rename a Go module across the repo.

flags["from-module"] / flags["to-module"] -- the module paths. flags["dry-run"] -- plan only.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search