Documentation
¶
Overview ¶
Package tree implements the on-disk Tarantool-rocks layout: the path scheme under <tree>/share/tarantool, <tree>/lib/tarantool, <tree>/bin, and the Deploy operation that copies a built rock's artifacts into it.
Paths is the pure path calculator — every method derives a location from the Tree root without touching disk. Open wraps a rocks.Config into a Tree, which adds the disk-facing operations: Deploy moves a staged build into the per-rock install dir and the shared deploy dirs, Which resolves a dotted module name to its deployed file, and the conflict helpers (MungedPath) compute the versioned fallback names used when two rock versions deploy the same target.
The layout is fixed for Tarantool:
<tree>/share/tarantool/rocks/<name>/<ver>/ — per-rock install dir <tree>/share/tarantool/ — deploy_lua_dir <tree>/lib/tarantool/ — deploy_lib_dir <tree>/bin/ — bin scripts
This package uses forward-slash Unix paths exclusively via path/filepath; no Windows-specific handling.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ModuleIndex ¶
func ModuleIndex(rm *rocks.RockManifest, pkg, ver string) map[string]string
ModuleIndex inverts a deployed RockManifest into the module index the tree manifest carries per installed rock: module name → deployed path, relative to the lua/lib deploy dir.
It mirrors upstream repos.package_modules, which derives the same index from the rock_manifest's lua/lib sections rather than from the rockspec's declared build.modules — and for the same reason. build.modules is populated by the builtin backend only, so a cmake, make or command rock declares no modules at all and an index keyed on that field silently stays empty, however much the rock actually deployed.
Two deliberate departures from upstream, both documented rather than fixed here because each would change behaviour beyond the derivation:
- Upstream scans lib then lua, so a rock shipping both `foo.so` and `foo.lua` records the .lua path. This scans lua then lib, keeping the .so preference the caller's rockspec-driven index has always encoded.
- A conflict-munged key (an inactive install that lost the plain spot to a higher version, see MungedPath) is SKIPPED. Its module name would have to be un-munged first, and the rock recorded as a non-active provider — a distinction the tree manifest writer does not make today, so indexing it would misreport it as the active provider.
Exported for the same reason MungedPath is: the caller that writes the tree manifest must invert exactly the path formation Deploy used.
func MungedPath ¶
MungedPath returns the versioned_name form of target under deployDir: the munged `<pkg>_<ver>` token dash-joined onto the path remainder after the deploy-dir prefix (core/path.lua path.versioned_name). Exported because installer logic — selecting the active version among munged siblings — needs the same string formation that Deploy used.
Example ¶
ExampleMungedPath shows the conflict-resolution filename LuaRocks uses when two rock versions would deploy the same target: the "<pkg>_<ver>" token (dots and dashes turned to underscores) is joined onto the path remainder.
package main
import (
"fmt"
"github.com/tarantool/go-luarocks/tree"
)
func main() {
fmt.Println(tree.MungedPath(
"/opt/tt/.rocks/share/tarantool",
"/opt/tt/.rocks/share/tarantool/demo.lua",
"demo", "1.0.0-1",
))
}
Output: /opt/tt/.rocks/share/tarantool/demo_1_0_0_1-demo.lua
Types ¶
type BinWrap ¶
type BinWrap struct {
// Interpreter is the absolute path to the Lua interpreter the wrapper
// execs, e.g. "/opt/tarantool/bin/tarantool".
Interpreter string
// Sysconfdir is the value exported as LUAROCKS_SYSCONFDIR, matching
// upstream's cfg.sysconfdir (default "/etc/luarocks").
Sysconfdir string
}
BinWrap carries the two environment-dependent inputs upstream bakes into a command wrapper (fs/unix.lua wrap_script): the absolute interpreter path (cfg.variables.LUA_BINDIR + cfg.lua_interpreter) and cfg.sysconfdir.
type Paths ¶
type Paths struct {
// Tree is the tree root (e.g. ".rocks" in a project, or a system
// tarantool prefix). Always an absolute or project-relative path.
Tree string
}
Paths computes the conventional subdirectories under a tree root.
All methods are pure functions of Tree; they do not touch disk. The caller is responsible for ensuring directories exist (Tree.Open does the minimal mkdir).
Example ¶
ExamplePaths computes the conventional subdirectories of a rocks tree. All methods are pure functions of Tree; they touch no disk.
package main
import (
"fmt"
"github.com/tarantool/go-luarocks/tree"
)
func main() {
p := tree.Paths{Tree: "/opt/tt/.rocks"}
fmt.Println(p.RocksDir())
fmt.Println(p.InstallDir("metrics", "1.0-1"))
fmt.Println(p.DeployLuaDir())
fmt.Println(p.DeployLibDir())
fmt.Println(p.BinDir())
fmt.Println(p.ConfDir("metrics", "1.0-1"))
fmt.Println(p.DocDir("metrics", "1.0-1"))
}
Output: /opt/tt/.rocks/share/tarantool/rocks /opt/tt/.rocks/share/tarantool/rocks/metrics/1.0-1 /opt/tt/.rocks/share/tarantool /opt/tt/.rocks/lib/tarantool /opt/tt/.rocks/bin /opt/tt/.rocks/share/tarantool/rocks/metrics/1.0-1/conf /opt/tt/.rocks/share/tarantool/rocks/metrics/1.0-1/doc
func (Paths) ConfDir ¶
ConfDir returns <tree>/share/tarantool/rocks/<name>/<ver>/conf — the per-rock configuration directory. Upstream installs build.install.conf via install_to into path.conf_dir(name,version) (a per-rock dir) and never relocates conf to a shared etc dir (repos.deploy_files handles only bin/lua/lib), so conf files reside permanently under the install dir.
func (Paths) DeployLibDir ¶
DeployLibDir returns <tree>/lib/tarantool — where compiled .so modules are flattened to slashed paths during Deploy.
func (Paths) DeployLuaDir ¶
DeployLuaDir returns <tree>/share/tarantool — where dotted .lua modules are flattened to slashed paths during Deploy.
func (Paths) DocDir ¶
DocDir returns <tree>/share/tarantool/rocks/<name>/<ver>/doc — the per-rock documentation directory.
func (Paths) InstallDir ¶
InstallDir returns <tree>/share/tarantool/rocks/<name>/<ver> — the per-rock install directory holding rockspec, rock_manifest, build/, doc/.
type Tree ¶
type Tree struct {
Paths
// Store reads/writes the tree-level and per-rock manifest files. The
// default is manif.FileStore. Tests inject fakes.
Store rocks.ManifestStore
// BinWrap, when non-nil, makes Deploy reproduce upstream LuaRocks'
// command-script handling (repos.deploy_files → fs.wrap_script): the real
// script is installed under the per-rock dir and the public <tree>/bin entry
// becomes a generated /bin/sh launcher. When nil, build.install.bin entries
// are copied verbatim (the pre-parity behavior; kept for callers that
// construct a Tree without a Tarantool target).
BinWrap *BinWrap
// Provider resolves the currently-active provider of a deploy item (a
// module name for lua/lib, a command name for bin) from the tree manifest,
// returning the provider's rock name+version. It backs Deploy's
// check_spot_if_available (repos.lua:248): when nil, every deployed file is
// treated as having no current provider and takes the plain active path.
// The facade sets this from the pre-install tree manifest.
Provider func(item string) (name, version string, ok bool)
}
Tree is the in-memory handle on a Tarantool rocks tree on disk. It composes the path scheme (Paths) and a ManifestStore. Operations that mutate the tree — Deploy chiefly — go through this type.
func Open ¶
Open returns a Tree handle backed by cfg.Tree on disk. The minimal set of subdirectories — RocksDir, DeployLuaDir, DeployLibDir, BinDir — are created if missing (the tree-init step is idempotent).
cfg.Tarantool fields are not consulted: tree management is independent of the Tarantool target (which only matters at build time).
func (*Tree) DeleteVersion ¶
DeleteVersion undeploys a single installed rock version: it deletes the files this version deployed (recorded in its rock_manifest, at their actual — plain or versioned — paths), removes the per-rock install directory, and prunes the rock's name directory when no other version remains. It is the file-removal half of upstream repos.delete_version (repos.lua:585-695).
Promotion of a next-highest kept version back to the active (unversioned) name is the caller's responsibility via the tree manifest; it only matters when multiple versions of the same rock are installed (the --keep path).
func (*Tree) Deploy ¶
Deploy copies the artifacts of a built rock into the tree, producing the per-rock RockManifest (path → md5 hex) that the caller then writes to <install-dir>/rock_manifest via t.Store.WriteRock.
Two source directories are consulted:
- srcDir holds the original rockspec source tree (the output of fetch.Fetch). Deploy reads .lua modules, prebuilt .so/.dylib modules, install.{lua,lib,bin,conf} files, and copy_directories from srcDir at the rockspec-relative paths.
- buildDir holds compiled artifacts produced by the build subsystem. Deploy reads .c-source-derived .so files and table-form module artifacts from buildDir at the canonical slashed path `<dotted/slashed>.so`.
For callers without a separate build phase (pure-.lua rocks, or unit tests where srcDir already contains every artifact), pass srcDir as both arguments — the lookup is layered and both forms work.
What gets copied where:
- build.modules: dotted module name → slashed path; .lua → DeployLuaDir, .so → DeployLibDir.
- build.install.lua / .lib: the KEY is a dotted module name (upstream is_module_path=true) → module_to_path(key) subdir; a .lua source is renamed to <last-segment>.lua. See installDest.
- build.install.conf: the KEY is a literal path joined under the per-rock ConfDir (<install-dir>/conf); conf is never deployed to a shared dir.
- build.install.bin: the KEY is a literal path. When BinWrap is set the real script lands in the per-rock <install-dir>/bin and BinDir gets an executable launcher (0o755); when nil the script is copied verbatim (0o755).
- build.copy_directories: each entry is a directory under srcDir copied recursively into the per-rock install dir (only a "doc" dir is recorded in the rock_manifest; see copyTree).
Collisions with previously-deployed versions are handled via munged filenames; see conflicts.go.
Deploy is a linear pipeline: each numbered stage below handles one rock artifact section (rockspec, build.modules, build.install.*, copy_directories, installed lua/lib subtrees) in the same order upstream build.lua does. The per-section logic lives in the deploy* helpers so this orchestrator stays a readable sequence.
func (*Tree) Which ¶
Which resolves a dotted Lua module name to the on-disk file that would satisfy `require("<module>")` against this tree.
Search order matches upstream `package.path` then `package.cpath`:
- DeployLuaDir/<slashed>.lua
- DeployLuaDir/<slashed>/init.lua
- DeployLibDir/<slashed>.so
Returns ("", false) when none of the above exist on disk.
Conflict-munged siblings (`.../foo.lua~name_version`) are NOT considered — only the active (plain) path. That mirrors how Tarantool's `require` works against the rocks tree.
Example ¶
ExampleTree_Which resolves a dotted module to its on-disk file; a fresh tree has nothing deployed, so the lookup misses.
package main
import (
"fmt"
"os"
rocks "github.com/tarantool/go-luarocks"
"github.com/tarantool/go-luarocks/tree"
)
func main() {
dir, err := os.MkdirTemp("", "rocks")
if err != nil {
panic(err)
}
defer func() { _ = os.RemoveAll(dir) }()
tr, err := tree.Open(rocks.Config{Tree: dir})
if err != nil {
panic(err)
}
path, ok := tr.Which("no.such.module")
fmt.Printf("%q %v\n", path, ok)
}
Output: "" false