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.modin 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 ago.modand 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.modor 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
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
def _excluded(path, root)True when path sits under an excluded path component.
#find_go_mod_files
def find_go_mod_files(root)Every go.mod in the tree, absolute, sorted.
#rewrite_go_mod_text
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
def _token_at(text, start)The whole module-path token beginning at start in text.
#declared_modules
def declared_modules(go_mod_paths){abs go.mod path: declared module path} for every readable go.mod.
#_literal_on_line
def _literal_on_line(line, import_path)The quoted literal for import_path as it appears on line, or None.
#rewrite_go_source_text
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
def scan_go_source(path, old)Import sites in path that are under module old.
#observe_file
def observe_file(path, root, old, new)Observe one file, returning a :class:FileRewrite or None.
#recompute
def recompute(rewrite, old, new)Re-derive a file's rewrite from disk. Returns (new_text, count).
#observe
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
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
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.