Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
579b091
Use WalkDir instead of Walk
stirante Jul 3, 2025
a1dae94
Reuse timer in watch mode
stirante Jul 3, 2025
0994b99
Use Map instead of Slice for marking files for removal
stirante Jul 3, 2025
11c8146
Use io.Copy instead of reading and writing files
stirante Jul 3, 2025
baf9e29
Parallelize copying into tmp
stirante Jul 3, 2025
8b27b47
Parallelize copying into tmp
stirante Jul 3, 2025
6626cb6
Implement symlink_export experiment
stirante Jul 4, 2025
743d87e
Refactor filter installer creation using a factory pattern
stirante Jul 4, 2025
a375c34
Attempt to speed up file protection by using map instead of a slice
stirante Jul 4, 2025
61fedd6
Use filepath.Rel instead of comparing strings
stirante Jul 4, 2025
602b82c
Add ShutdownLogging function to ensure log flushing on exit
stirante Jul 4, 2025
5410216
Refactor code into a single function for loading filter config
stirante Jul 4, 2025
635ca77
Unify copy file function
stirante Jul 4, 2025
f3461f3
Add optional ID argument to filter creation
stirante Jul 4, 2025
18afc26
Extract copyParentACL helper
stirante Jul 4, 2025
be577ba
Refactor move function
stirante Jul 4, 2025
d803ed1
Improve command output logging with goroutines and wait groups
stirante Jul 4, 2025
073e9cb
Improve path resolving
stirante Jul 4, 2025
09194f5
Improve comparing file paths
stirante Jul 4, 2025
736e0e5
Unify Delete and DeleteDir functions
stirante Jul 4, 2025
50b69af
Check after each subfilter whether it was interrupted
stirante Jul 4, 2025
06946ec
Reduce buffer size
stirante Jul 4, 2025
667ee3a
Reduce buffer size
stirante Jul 4, 2025
2723f0d
Move shutdownLogging() function call always to a defered call, instea…
Nusiq Jul 12, 2025
5cfc56f
Removed unused private 'deleteDir' method of 'revertibleFsOperations'.
Nusiq Jul 12, 2025
8a03821
Remove unused 'compareFilePaths' function and its associated test file
Nusiq Jul 12, 2025
b23eaac
Improved the error message about nested remote filters and fixed the …
Nusiq Jul 12, 2025
021396e
Fixed a typo.
Nusiq Jul 12, 2025
c1e3ebc
Removed redundant test `IsExperimentEnabled(SymlinkExport)` from `Exp…
Nusiq Jul 12, 2025
7bc9bd4
Refactor ExportProject() to streamline pack export logic by consolida…
Nusiq Jul 12, 2025
5f504ca
Error channel size in ExportProject() is adjusted to the to match th…
Nusiq Jul 13, 2025
9c1b143
Added some doc-comments for DirWatcher and RunContext.
Nusiq Jul 13, 2025
5e08be8
Removed link path deletion from "createDirLink":
Nusiq Jul 13, 2025
64f0ac8
added mode to the go-simple-eval set
iEnis Aug 29, 2025
6bee827
added additional initial variable to go-simple-eval that returns true…
iEnis Sep 3, 2025
a1a4c75
Removed unnecessary Context.IsInWatchMode() function calls and made R…
Nusiq Sep 6, 2025
e615e3f
Changed the value of the 'mode' property from 'build' to 'run' when r…
Nusiq Sep 6, 2025
7fbfd9d
Merge pull request #332 from Bedrock-OSS/go-simple-eval-properties
Nusiq Sep 6, 2025
c2840ca
Updated the 'checkDeletionSafety' doc-comment to make it match the ne…
Nusiq Oct 27, 2025
42f475e
Instead silently switching off the useSymlinkExport experiment, when …
Nusiq Oct 27, 2025
59b0b5f
When SetupTmpFile fails to create symlinks while using useSymlinkExpo…
Nusiq Oct 27, 2025
d6caf3c
Improved error handling of the 'createDirLink' function.
Nusiq Oct 27, 2025
e084f70
Updated used Go version and ran 'go mod tidy' and 'go mod vendor'.
Nusiq Nov 2, 2025
17b9fb1
Refactored SyncDirectories to detect and remove extra directories in the
Nusiq Nov 2, 2025
1cb6683
Fixed incorrect use of the WrapErrorf function to attempt to wrap a n…
Nusiq Nov 2, 2025
8a41185
Refactored ResolvePath to robustly expand environment variables using
Nusiq Nov 4, 2025
59c7146
Undo d803ed11d38d01671ec87ded654ed9f41c5f1b1b to fix potential deadlock
Nusiq Nov 4, 2025
3b3d066
The paths in 'edited_files.json' now use '/' as path separator instead
Nusiq Nov 4, 2025
45b3a18
Fixed symlinkExport experiment, skipping expor of the data files of the
Nusiq Nov 6, 2025
8f6e509
Added experiments validation to disallow combining size_time_check wi…
Nusiq Nov 6, 2025
f806df4
The symlink_export experiment doesn't skip the deletion safety check.
Nusiq Nov 6, 2025
7ab7ff8
The SetupTmpFiles function makes sure to unlink the symlinks to RP or BP
Nusiq Nov 6, 2025
45db0fc
Undo 8f6e509837047e7b19418f5b11499424e8939072, symlink_export and siz…
Nusiq Nov 6, 2025
beb6cdd
Merge pull request #328 from Bedrock-OSS/optimizations
Nusiq Nov 6, 2025
170f564
Modernized the code with 'go run golang.org/x/tools/gopls/internal/an…
Nusiq Nov 7, 2025
02aa63d
Updated how Regolith looks for the com.mojang path to match changes i…
Nusiq Nov 7, 2025
9130080
Proper error handling (using go-burrito) for the function that finds the
Nusiq Nov 8, 2025
7917bc7
Fixed incorrect error reporting (or lack of it) of the GetExportPaths…
Nusiq Nov 8, 2025
887acb7
Merge pull request #333 from Bedrock-OSS/export-paths-mc-1-21-120
Nusiq Nov 8, 2025
23341b0
Fixed some errors detected by linter.
Nusiq Nov 8, 2025
bb50677
Regolith removes the pack path if they're empty after run.
Nusiq Nov 8, 2025
c426772
Code cleanup:
Nusiq Nov 8, 2025
74f343d
Removed TestMoveFilesAcl test.
Nusiq Nov 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 3 additions & 30 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module github.com/Bedrock-OSS/regolith

go 1.18
go 1.25.3

require (
github.com/Bedrock-OSS/go-burrito v1.0.3
github.com/alessio/shellescape v1.4.1
github.com/arexon/fsnotify v0.0.0-20240929211932-1ebdc44d4bc2
github.com/fatih/color v1.14.1
github.com/google/go-github/v39 v39.2.0
github.com/hashicorp/go-getter v1.6.2
github.com/muhammadmuzzammil1998/jsonc v1.0.0
github.com/nightlyone/lockfile v1.0.0
github.com/otiai10/copy v1.7.0
Expand All @@ -22,44 +22,17 @@ require (
replace github.com/hashicorp/go-getter => github.com/arikkfir/go-getter v1.6.3-0.20220803164326-281b7670b734

require (
cloud.google.com/go v0.100.2 // indirect
cloud.google.com/go/compute v1.5.0 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
cloud.google.com/go/storage v1.21.0 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect
github.com/arexon/fsnotify v0.0.0-20240929211932-1ebdc44d4bc2 // indirect
github.com/aws/aws-sdk-go v1.43.25 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/gammazero/deque v0.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.2.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.4.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/exp v0.0.0-20230131013936-aae9b4e6329d // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/text v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.73.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
)
641 changes: 3 additions & 638 deletions go.sum

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ func main() {
Long: regolithConfigDesc,
Run: func(cmd *cobra.Command, args []string) {
regolith.InitLogging(burrito.PrintStackTrace)
defer regolith.ShutdownLogging()
full, _ := cmd.Flags().GetBool("full")
delete, _ := cmd.Flags().GetBool("delete")
append, _ := cmd.Flags().GetBool("append")
Expand Down
48 changes: 40 additions & 8 deletions regolith/compatibility_other_os.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,52 @@ func copyFileSecurityInfo(source string, target string) error {
return nil
}

func FindStandardMojangDir() (string, error) {
comMojang := os.Getenv("COM_MOJANG")
func findSomeMojangDir(
comMojangWordsVar,
comMojangPacksVar,
comMojangVar,
comMojangEnvUnsetError string,
pathType ComMojangPathType,
) (string, error) {
// Try specific path environment variables first
switch pathType {
case WorldPath:
comMojang := os.Getenv(comMojangWordsVar)
if comMojang != "" {
return comMojang, nil
}
case PacksPath:
comMojang := os.Getenv(comMojangPacksVar)
if comMojang != "" {
return comMojang, nil
}
}
// Try general environment variable
comMojang := os.Getenv(comMojangVar)
if comMojang == "" {
return "", burrito.WrappedError(comMojangEnvUnsetError)
}
return comMojang, nil
}

func FindPreviewDir() (string, error) {
comMojangPreview := os.Getenv("COM_MOJANG_PREVIEW")
if comMojangPreview == "" {
return "", burrito.WrappedError(comMojangPreviewEnvUnsetError)
}
return comMojangPreview, nil
func FindStandardMojangDir(pathType ComMojangPathType) (string, error) {
return findSomeMojangDir(
"COM_MOJANG_WORLDS",
"COM_MOJANG_PACKS",
"COM_MOJANG",
comMojangEnvUnsetError,
pathType,
)
}

func FindPreviewDir(pathType ComMojangPathType) (string, error) {
return findSomeMojangDir(
"COM_MOJANG_WORLDS_PREVIEW",
"COM_MOJANG_PACKS_PREVIEW",
"COM_MOJANG_PREVIEW",
comMojangPreviewEnvUnsetError,
pathType,
)
}

func FindEducationDir() (string, error) {
Expand Down
137 changes: 105 additions & 32 deletions regolith/compatibility_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,116 @@ func copyFileSecurityInfo(source string, target string) error {
return nil
}

// FindStandardMojangDir returns path to the com.mojang folder in the standard
// Minecraft build.
func FindStandardMojangDir() (string, error) {
comMojang := os.Getenv("COM_MOJANG")
// findSomeMojangDir is reused in FindStandardMojangDir and
// FindPreviewMojangDir functions to avoid code duplication.
func findSomeMojangDir(
comMojangWordsVar string,
comMojangPacksVar string,
comMojangVar string,
theSomeDirName string,
pathType ComMojangPathType,
) (string, error) {
// Try specific path environment variables first
switch pathType {
case WorldPath:
comMojang := os.Getenv(comMojangWordsVar)
if comMojang != "" {
return comMojang, nil
}
case PacksPath:
comMojang := os.Getenv(comMojangPacksVar)
if comMojang != "" {
return comMojang, nil
}
}
// Try general environment variable
comMojang := os.Getenv(comMojangVar)
if comMojang != "" {
return comMojang, nil
}
result := filepath.Join(
os.Getenv("LOCALAPPDATA"), "Packages",
"Microsoft.MinecraftUWP_8wekyb3d8bbwe", "LocalState", "games",
"com.mojang")
if _, err := os.Stat(result); err != nil {
if os.IsNotExist(err) {
return "", burrito.WrapErrorf(err, osStatErrorIsNotExist, result)

var result string
checkResult := func() error {
if _, err := os.Stat(result); err != nil {
if os.IsNotExist(err) {
return burrito.WrapErrorf(err, osStatErrorIsNotExist, result)
}
return burrito.WrapErrorf(err, osStatErrorAny, result)
}
return "", burrito.WrapErrorf(err, osStatErrorAny, result)
return nil
}
return result, nil
switch pathType {
case WorldPath:
result = filepath.Join(os.Getenv("APPDATA"), theSomeDirName, "Users")
if err := checkResult(); err != nil {
return "", burrito.PassError(err)
}
// List directories in the Users folder and pick the first one that isn't
// "Shared". From that folder navigate to "games/com.mojang" and validate
// the path.
entries, err := os.ReadDir(result)
if err != nil {
return "", burrito.WrapErrorf(err, osReadDirError, result)
}
var chosen string
for _, e := range entries {
if !e.IsDir() {
continue
}
// Skip the shared folder (case insensitive)
if strings.EqualFold(e.Name(), "Shared") {
continue
}
chosen = e.Name()
break
}
if chosen == "" {
return "", burrito.WrappedErrorf(findMojangDirError)
}
result = filepath.Join(result, chosen, "games", "com.mojang")
if err := checkResult(); err != nil {
return "", burrito.PassError(err)
}
return result, nil
case PacksPath:
result = filepath.Join(
os.Getenv("APPDATA"), theSomeDirName, "Users", "Shared", "games",
"com.mojang")
if err := checkResult(); err != nil {
return "", burrito.PassError(err)
}
return result, nil
}
// Should never happen
return "", burrito.WrappedErrorf("Invalid path type")
}

// FindStandardMojangDir returns path to the com.mojang folder in the standard
// Minecraft build.
func FindStandardMojangDir(pathType ComMojangPathType) (string, error) {
return findSomeMojangDir(
// Environment variables
"COM_MOJANG_WORLDS",
"COM_MOJANG_PACKS",
"COM_MOJANG",
// The name of the folder in APPDATA
"Minecraft Bedrock",
pathType,
)
}

// FindPreviewDir returns path to the com.mojang folder in the preview
// Minecraft build.
func FindPreviewDir() (string, error) {
comMojang := os.Getenv("COM_MOJANG_PREVIEW")
if comMojang != "" {
return comMojang, nil
}
result := filepath.Join(
os.Getenv("LOCALAPPDATA"), "Packages",
"Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe", "LocalState", "games",
"com.mojang")
if _, err := os.Stat(result); err != nil {
if os.IsNotExist(err) {
return "", burrito.WrapErrorf(err, osStatErrorIsNotExist, result)
}
return "", burrito.WrapErrorf(
err, osStatErrorAny, result)
}
return result, nil
func FindPreviewDir(pathType ComMojangPathType) (string, error) {
return findSomeMojangDir(
// Environment variables
"COM_MOJANG_WORLDS_PREVIEW",
"COM_MOJANG_PACKS_PREVIEW",
"COM_MOJANG_PREVIEW",
// The name of the folder in APPDATA
"Minecraft Bedrock Preview",
pathType,
)
}

// FindEducationDir returns path to the com.mojang folder in the education
Expand All @@ -114,13 +185,15 @@ func FindEducationDir() (string, error) {
return result, nil
}

// CheckSuspiciousLocation checks if the current working directory is within
// one of directories not valid for a Regolith project.
func CheckSuspiciousLocation() error {
path, err := os.Getwd()
if err != nil {
return burrito.WrapErrorf(err, osGetwdError)
}
// Check if project directory is within mojang dir
dir, err := FindStandardMojangDir()
dir, err := FindStandardMojangDir(PacksPath)
if err == nil {
dir1 := filepath.Join(dir, "development_behavior_packs")
if isPathWithinDirectory(path, dir1) {
Expand All @@ -132,7 +205,7 @@ func CheckSuspiciousLocation() error {
}
}
// Check if project directory is within mojang dir
dir, err = FindPreviewDir()
dir, err = FindPreviewDir(PacksPath)
if err == nil {
dir1 := filepath.Join(dir, "development_behavior_packs")
if isPathWithinDirectory(path, dir1) {
Expand Down
24 changes: 12 additions & 12 deletions regolith/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const GitIgnore = "/build\n/.regolith"
type Config struct {
Name string `json:"name,omitempty"`
Author string `json:"author,omitempty"`
Packs `json:"packs,omitempty"`
RegolithProject `json:"regolith,omitempty"`
Packs `json:"packs,omitzero"`
RegolithProject `json:"regolith,omitzero"`
}

// ExportTarget is a part of "config.json" that contains export information
Expand Down Expand Up @@ -55,7 +55,7 @@ type RegolithProject struct {
}

// ConfigFromObject creates a "Config" object from map[string]interface{}
func ConfigFromObject(obj map[string]interface{}) (*Config, error) {
func ConfigFromObject(obj map[string]any) (*Config, error) {
result := &Config{}
// Name
name, ok := obj["name"].(string)
Expand All @@ -71,7 +71,7 @@ func ConfigFromObject(obj map[string]interface{}) (*Config, error) {
result.Author = author
// Packs
if packs, ok := obj["packs"]; ok {
packs, ok := packs.(map[string]interface{})
packs, ok := packs.(map[string]any)
if !ok {
return nil, burrito.WrappedErrorf(jsonPathTypeError, "packs", "object")
}
Expand All @@ -82,7 +82,7 @@ func ConfigFromObject(obj map[string]interface{}) (*Config, error) {
}
// Regolith
if regolith, ok := obj["regolith"]; ok {
regolith, ok := regolith.(map[string]interface{})
regolith, ok := regolith.(map[string]any)
if !ok {
return nil, burrito.WrappedErrorf(
jsonPathTypeError, "regolith", "object")
Expand All @@ -99,7 +99,7 @@ func ConfigFromObject(obj map[string]interface{}) (*Config, error) {
}

// ProfileFromObject creates a "Profile" object from map[string]interface{}
func PacksFromObject(obj map[string]interface{}) Packs {
func PacksFromObject(obj map[string]any) Packs {
result := Packs{}
// BehaviorPack
behaviorPack, _ := obj["behaviorPack"].(string)
Expand All @@ -113,7 +113,7 @@ func PacksFromObject(obj map[string]interface{}) Packs {
// RegolithProjectFromObject creates a "RegolithProject" object from
// map[string]interface{}
func RegolithProjectFromObject(
obj map[string]interface{},
obj map[string]any,
) (RegolithProject, error) {
result := RegolithProject{
Profiles: make(map[string]Profile),
Expand Down Expand Up @@ -166,10 +166,10 @@ func RegolithProjectFromObject(
}
}
// Filter definitions
filterDefinitions, ok := obj["filterDefinitions"].(map[string]interface{})
filterDefinitions, ok := obj["filterDefinitions"].(map[string]any)
if ok { // filter definitions are optional
for filterDefinitionName, filterDefinition := range filterDefinitions {
filterDefinitionMap, ok := filterDefinition.(map[string]interface{})
filterDefinitionMap, ok := filterDefinition.(map[string]any)
if !ok {
return result, burrito.WrappedErrorf(
jsonPropertyTypeError, "filterDefinitions",
Expand All @@ -185,12 +185,12 @@ func RegolithProjectFromObject(
}
}
// Profiles
profiles, ok := obj["profiles"].(map[string]interface{})
profiles, ok := obj["profiles"].(map[string]any)
if !ok {
return result, burrito.WrappedErrorf(jsonPropertyMissingError, "profiles")
}
for profileName, profile := range profiles {
profileMap, ok := profile.(map[string]interface{})
profileMap, ok := profile.(map[string]any)
if !ok {
return result, burrito.WrappedErrorf(
jsonPropertyTypeError,
Expand All @@ -209,7 +209,7 @@ func RegolithProjectFromObject(

// ExportTargetFromObject creates a "ExportTarget" object from
// map[string]interface{}
func ExportTargetFromObject(obj map[string]interface{}) (ExportTarget, error) {
func ExportTargetFromObject(obj map[string]any) (ExportTarget, error) {
result := ExportTarget{}
// Target
targetObj, ok := obj["target"]
Expand Down
Loading