internal

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: GPL-3.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const DB_PRAGMAS = "?_foreign_keys=ON&_journal_mode=WAL&_synchronous=NORMAL"

DB_PRAGMAS are the connection parameters for a read-write database: foreign keys enforced, write-ahead logging and synchronous NORMAL. The driver runs each of them as a PRAGMA when a connection is opened.

View Source
const DB_PRAGMAS_READONLY = "?_foreign_keys=ON&mode=ro"

DB_PRAGMAS_READONLY are the connection parameters for a read-only database. There is deliberately no journal mode: a read-only connection can't change it, and asking for WAL on a database that is stored in rollback-journal mode fails with "attempt to write a readonly database". That is exactly how the databases inside an export are stored, since VACUUM INTO writes them that way.

View Source
const DefaultTargetName = "game_dir"

DefaultTargetName is the target used when a command isn't told which one to use.

Variables

View Source
var Migrations embed.FS

Functions

func AddRemapRule

func AddRemapRule(ctx context.Context, db *sql.DB, q *dbq.Queries, itemID int64, ruleType string, intVal sql.NullInt64, textVal sql.NullString, overridePos int64) (position int64, err error)

AddRemapRule adds a single remap rule to the config for a profile item, creating the config if it does not exist yet. The position is auto-assigned as MAX(position)+1 unless overridePos is >= 0. It returns the position the rule was added at.

func CheckTargetCanBeDisabled added in v0.8.0

func CheckTargetCanBeDisabled(t dbq.Target, u TargetUsage) error

CheckTargetCanBeDisabled returns an error explaining why an enabled target can't be disabled: it still has installed files, profile items or overrides pointing at it, or it is the last enabled target.

func ClearRemapConfig

func ClearRemapConfig(ctx context.Context, db *sql.DB, q *dbq.Queries, itemID int64) (cleared bool, err error)

ClearRemapConfig deletes all remap rules for a profile item's config and removes the config itself, leaving remap_config_id NULL on the profile item. No-op if the profile item has no remap config. It reports whether there was a config to clear.

func CopyDeployRules added in v0.6.0

func CopyDeployRules(ctx context.Context, db *sql.DB, q *dbq.Queries, srcItemID, dstItemID int64) (skipBackup, writeOnce int, err error)

CopyDeployRules copies skip-backup and write-once patterns from one profile item to another. If the destination already has patterns of either kind they are replaced. If the source has no patterns for a given kind that kind is a no-op. It returns the number of patterns copied for each kind.

func CopyRemapConfig

func CopyRemapConfig(ctx context.Context, db *sql.DB, q *dbq.Queries, srcItemID, dstItemID int64) (copied int, err error)

CopyRemapConfig copies remap rules from one profile item to another within the same profile. If the destination already has a config its rules are replaced. If the source has no config this is a no-op. It returns the number of rules copied.

func CopySkipBackupPatterns added in v0.6.0

func CopySkipBackupPatterns(ctx context.Context, db *sql.DB, q *dbq.Queries, srcItemID, dstItemID int64) (copied int, err error)

CopySkipBackupPatterns copies skip-backup patterns from one profile item to another within the same profile. If the destination already has patterns they are replaced. If the source has no patterns this is a no-op. It returns the number of patterns copied.

func CopyWriteOncePatterns added in v0.6.0

func CopyWriteOncePatterns(ctx context.Context, db *sql.DB, q *dbq.Queries, srcItemID, dstItemID int64) (copied int, err error)

CopyWriteOncePatterns copies write-once patterns from one profile item to another within the same profile. If the destination already has patterns they are replaced. If the source has no patterns this is a no-op. It returns the number of patterns copied.

func CurrentSchemaVersion added in v0.8.0

func CurrentSchemaVersion(ctx context.Context, db *sql.DB) (int64, error)

CurrentSchemaVersion returns the version of the latest migration that has been applied to db. This is what the database itself is at, which is not necessarily the latest migration this build of modctl knows about: a new database reports 0 and one that has not been migrated since an upgrade reports its older version.

func DSN added in v0.8.0

func DSN(path string, readOnly bool) string

DSN returns the connection string for the SQLite database at path, which every database open in modctl should use rather than building its own.

It is a file: URI with an escaped path. With a plain path the driver cuts the query string off before SQLite sees it, which silently drops mode=ro (the connection stays writable), and a path that contains a '?' is cut short at it. The read-only variant is described at DB_PRAGMAS_READONLY.

func EnabledTargets added in v0.8.0

func EnabledTargets(targets []dbq.Target) []dbq.Target

EnabledTargets returns the enabled subset of targets, preserving order.

func EnsureDBExists

func EnsureDBExists() error

EnsureDBExists verifies that the configured database file exists and is a regular file. If not, it returns a user-friendly error.

func EnsureRemapConfig

func EnsureRemapConfig(ctx context.Context, qtx *dbq.Queries, itemID int64) (int64, error)

EnsureRemapConfig returns the existing remap_config_id for a profile item, or creates a new one and links it to the profile item within the provided transaction if none exists yet.

func EnsureTargetEnabled added in v0.8.0

func EnsureTargetEnabled(t dbq.Target) error

EnsureTargetEnabled returns an error if the target is disabled.

func FormatNotesLines added in v0.8.0

func FormatNotesLines(notes string) string

FormatNotesLines renders freeform notes for display under a "notes:" label. A single line stays on the label's line; multi-line notes start on the next line, indented, so they read as one block.

func FullSelector

func FullSelector(storeID, storeGameID, instanceID string) string

FullSelector always includes the instance (even if it's "default").

Example: steam:1091500#default

func GooseProvider

func GooseProvider(db *sql.DB) (*goose.Provider, error)

func IsBinaryContent added in v0.6.0

func IsBinaryContent(data []byte) bool

IsBinaryContent reports whether data appears to be binary by scanning for null bytes in the first 8KB, matching the heuristic used by Git and other tools.

func IsForeignKeyConstraint added in v0.8.0

func IsForeignKeyConstraint(err error) bool

IsForeignKeyConstraint reports whether err is SQLite complaining that a FOREIGN KEY constraint would have been violated: a row that refers to something that isn't there, or the deletion of something that is still referred to.

func IsTriggerConstraint added in v0.8.0

func IsTriggerConstraint(err error) bool

IsTriggerConstraint reports whether err is a trigger of ours stopping the statement with RAISE(ABORT, ...) and the like.

func IsUniqueConstraint added in v0.8.0

func IsUniqueConstraint(err error) bool

IsUniqueConstraint reports whether err is SQLite complaining that a UNIQUE constraint (or unique index) would have been violated. A PRIMARY KEY violation is a different error and is not matched.

func LatestSchemaVersion added in v0.8.0

func LatestSchemaVersion() (int64, error)

LatestSchemaVersion returns the version of the latest migration known to this build of modctl: the highest version among the embedded migrations. It does not look at any database, so it is the version a database ends up at once it has been fully migrated, and what a bundle's schema version has to be compared against to tell whether this build can import it.

func MigrateDB

func MigrateDB(ctx context.Context, db *sql.DB) error

func NormalizeStoreID added in v0.8.0

func NormalizeStoreID(s string) string

NormalizeStoreID normalizes a store id the way store ids are stored and compared: trimmed and lowercased. Store ids are meant to be stable identifiers like "steam", so we normalize them to avoid surprising mismatches.

func NotesTextFromArg added in v0.8.0

func NotesTextFromArg(arg string, stdin io.Reader) (string, error)

NotesTextFromArg returns the notes text given as a command argument. If the argument is "-" the text is read from stdin instead. Trailing newlines are trimmed so that piped input doesn't store them; everything else, including interior newlines and surrounding spaces, is kept exactly as given.

func ParseInt64

func ParseInt64(s string) (int64, bool)

func ParseSelector

func ParseSelector(s string) (storeID, storeGameID, instanceID string, err error)

ParseSelector parses either: - store:game - store:game#instance

If instance is omitted, it returns instanceID="default".

func ResolveEnabledProfileVersionArg added in v0.7.1

func ResolveEnabledProfileVersionArg(ctx context.Context, q *dbq.Queries, gi dbq.GameInstall, profile *dbq.Profile, arg string) (int64, error)

ResolveEnabledProfileVersionArg resolves a mod file version argument for a command that acts on the enabled version of a mod in a profile (e.g., disable). It behaves like ResolveModFileVersionArg except that when the argument is a mod page name matching several versions, the candidates are narrowed to the versions that are enabled in the given profile:

  • exactly one enabled version: that version is returned
  • several enabled versions: an error listing only those is returned
  • none enabled: resolution falls back to ResolveModFileVersionArg so the usual not-in-profile/already-disabled/ambiguity handling applies

func ResolveModFileVersionArg

func ResolveModFileVersionArg(ctx context.Context, q *dbq.Queries, gi dbq.GameInstall, arg string) (dbq.GetModFileVersionByIDRow, error)

ResolveModFileVersionArg resolves a mod file version argument for the given game install. Accepts:

  • a numeric ID (fast path, unambiguous)
  • a mod page name (case-insensitive; errors if ambiguous, listing all candidates with their numeric IDs)

func ResolveModPageArg

func ResolveModPageArg(ctx context.Context, q *dbq.Queries, gi dbq.GameInstall, arg string) (dbq.GetModPageByIDForGameRow, error)

ResolveModPageArg resolves a mod page argument for the given game install. Accepts:

  • a numeric ID (fast path, unambiguous)
  • a mod page name (case-insensitive; errors if ambiguous, listing all candidates with their numeric IDs)

func ResolveProfileItemByVersion

func ResolveProfileItemByVersion(ctx context.Context, profile *dbq.Profile, q *dbq.Queries, versionID int64) (int64, error)

ResolveProfileItemByVersion looks up a profile item by mod file version ID within a profile, returning a clean error if the version is not in the profile.

func ResolveTarget added in v0.8.0

func ResolveTarget(targets []dbq.Target, requested string) (dbq.Target, error)

ResolveTarget picks the install target for a command from the targets of a game install. A requested name must exist and be enabled. With no name the default target (game_dir) is used if it is enabled; if it isn't, the only enabled target is used, and it is an error to have to guess between several.

func RewriteProfilePriorities

func RewriteProfilePriorities(
	ctx context.Context,
	qtx *dbq.Queries,
	profileID int64,
	items []dbq.ListProfileItemsForOrderRow,
	start, step int64,
) error

RewriteProfilePriorities rewrites priorities for the given ordered items.

It is safe under UNIQUE(profile_id, priority) because it first shifts all existing priorities out of the way by an offset, then assigns final values.

start is the first priority value to assign (for compact: 1). step is the increment between consecutive priorities (for compact: 1; for --multiple N: N).

func SetProfileItemEnabled

func SetProfileItemEnabled(ctx context.Context, profile *dbq.Profile, q *dbq.Queries, versionID int64, enabled bool) (changed bool, err error)

SetProfileItemEnabled enables or disables the profile item for a mod file version. It reports whether anything changed: false means the item was already in the requested state.

func SetupDB

func SetupDB() (*sql.DB, error)

func SetupDBReadOnly

func SetupDBReadOnly() (*sql.DB, error)

func ShortSelector

func ShortSelector(storeID, storeGameID, instanceID string) string

ShortSelector includes the instance only if it isn't "default".

Example: steam:1091500 Example: steam:1091500#library_2

func TargetEnabled added in v0.8.0

func TargetEnabled(t dbq.Target) bool

TargetEnabled reports whether the target takes part in planning.

Types

type RefreshChange added in v0.8.0

type RefreshChange struct {
	Name string
	Kind RefreshChangeKind
}

RefreshChange is what a refresh found out about one install.

type RefreshChangeKind added in v0.8.0

type RefreshChangeKind int

RefreshChangeKind says what a refresh found out about an install.

const (
	RefreshNew      RefreshChangeKind = iota // seen for the first time
	RefreshReturned                          // was missing and has come back
	RefreshUpdated                           // seen again, as before
	RefreshMissing                           // was present and has gone
)

type RefreshResult added in v0.2.0

type RefreshResult struct {
	New      []string // display names of newly discovered installs
	Updated  []string // display names of installs seen again (already present)
	Returned []string // display names of installs that were missing and came back
	Missing  []string // display names of installs that disappeared
	Skipped  []string // display names of installs that were filtered out

	// Warnings are the non-fatal problems found along the way, in the order
	// they were found.
	Warnings []string

	// Changes is what happened to each install, in the order to show them:
	// the installs that disappeared first, then the ones that were found.
	Changes []RefreshChange
}

func ScanStores

func ScanStores(ctx context.Context, db *sql.DB) (RefreshResult, error)

ScanStores rescans every enabled store and updates the game installs in the database. It prints nothing: what it found is in the result. If it fails part way, the result still holds the warnings found up to then.

type SqliteStore added in v0.2.0

type SqliteStore struct {
	database.Store // embed and delegate everything
}

A custom goose store to let us override the schema migrations table to use more idiomatic sqlite

func (*SqliteStore) CreateVersionTable added in v0.2.0

func (s *SqliteStore) CreateVersionTable(ctx context.Context, db database.DBTxConn) error

type TargetUsage added in v0.8.0

type TargetUsage struct {
	InstalledFiles int64 // files recorded as installed through the target
	ProfileItems   int64 // profile items deploying to the target
	Overrides      int64 // overrides defined for the target
	EnabledTargets int64 // enabled targets for the game install, counting this one
}

TargetUsage describes what still depends on a target.

Directories

Path Synopsis
Package extractor handles extraction of mod archives to a staging directory and deployment of files into the game target directory.
Package extractor handles extraction of mod archives to a staging directory and deployment of files into the game target directory.
Package lock provides per-game-install exclusive locking for apply and unapply operations.
Package lock provides per-game-install exclusive locking for apply and unapply operations.
Package patchapply applies structured patch entries to ini, yaml, and json files.
Package patchapply applies structured patch entries to ini, yaml, and json files.
Package planner computes the desired file state for a profile apply or unapply.
Package planner computes the desired file state for a profile apply or unapply.
Package remap implements the remap rule engine for modctl.
Package remap implements the remap rule engine for modctl.
Package style holds how modctl looks in a terminal, so that no command formats its own output:
Package style holds how modctl looks in a terminal, so that no command formats its own output:
Package updatechain works out where a file stands against the updates that Nexus Mods knows about for its mod: whether something newer has replaced it, and whether that newer file has already been imported.
Package updatechain works out where a file stands against the updates that Nexus Mods knows about for its mod: whether something newer has replaced it, and whether that newer file has already been imported.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL