diff --git a/internal/cmd/list.go b/internal/cmd/list.go index daf8170..4c72a6d 100644 --- a/internal/cmd/list.go +++ b/internal/cmd/list.go @@ -7,32 +7,43 @@ import ( "strings" humanize "github.com/dustin/go-humanize" + "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" treeprint "github.com/xlab/treeprint" - "github.com/ryex/dungeondraft-gopackager/pkg/structures" + "github.com/ryex/dungeondraft-gopackager/internal/utils" "github.com/ryex/dungeondraft-gopackager/pkg/ddpackage" + "github.com/ryex/dungeondraft-gopackager/pkg/structures" ) type ListCmd struct { - InputPath string `arg:"" type:"path" help:"the .dungeondraft_pack file to unpack"` + Files ListFilesCmd `cmd:""` + Tags ListTagsCmd `cmd:""` +} + +type ListFilesCmd struct { + InputPath string `arg:"" type:"path" help:"the .dungeondraft_pack file or resource directory to work with"` } -func (ls *ListCmd) Run(ctx *Context) error { - packFilePath, pathErr := filepath.Abs(ls.InputPath) +func (ls *ListFilesCmd) Run(ctx *Context) error { + packPath, pathErr := filepath.Abs(ls.InputPath) if pathErr != nil { return errors.Join(pathErr, errors.New("could not get absolute path for packfile")) } - packFileName := filepath.Base(packFilePath) + if utils.DirExists(packPath) { + return ls.loadUnpacked(packPath) + } + return ls.loadPacked(packPath) +} +func (ls *ListFilesCmd) loadPacked(path string) error { l := log.WithFields(log.Fields{ - "filename": packFileName, + "filename": path, }) - pkg := ddpackage.NewPackage(l) - file, err := pkg.LoadFromPackedPath(packFilePath) + file, err := pkg.LoadFromPackedPath(path) if err != nil { l.WithError(err).Error("failed to load package") return err @@ -40,6 +51,27 @@ func (ls *ListCmd) Run(ctx *Context) error { defer file.Close() + ls.printTree(l, pkg) + return nil +} + +func (ls *ListFilesCmd) loadUnpacked(path string) error { + l := log.WithFields(log.Fields{ + "filename": path, + }) + pkg := ddpackage.NewPackage(l) + + err := pkg.LoadUnpackedFromFolder(path) + if err != nil { + l.WithError(err).Error("failed to load package") + return err + } + + ls.printTree(l, pkg) + return nil +} + +func (ls *ListFilesCmd) printTree(l logrus.FieldLogger, pkg *ddpackage.Package) { tree := treeprint.New() branchMap := make(map[string]treeprint.Tree) @@ -84,6 +116,120 @@ func (ls *ListCmd) Run(ctx *Context) error { } fmt.Println(tree.String()) +} + +type ListTagsCmd struct { + InputPath string `arg:"" type:"path" help:"the .dungeondraft_pack file or resource directory to work with"` +} + +func (ls *ListTagsCmd) Run(ctx *Context) error { + packPath, pathErr := filepath.Abs(ls.InputPath) + if pathErr != nil { + return errors.Join(pathErr, errors.New("could not get absolute path for packfile")) + } + + if utils.DirExists(packPath) { + return ls.loadUnpacked(packPath) + } + return ls.loadPacked(packPath) +} + +func (ls *ListTagsCmd) loadPacked(path string) error { + l := log.WithFields(log.Fields{ + "filename": path, + }) + pkg := ddpackage.NewPackage(l) + + file, err := pkg.LoadFromPackedPath(path) + if err != nil { + l.WithError(err).Error("failed to load package") + return err + } + defer file.Close() + err = pkg.LoadPackedTags(file) + if err != nil { + l.WithError(err).Error("failed to load tags") + return err + } + ls.printTree(l, pkg) return nil } + +func (ls *ListTagsCmd) loadUnpacked(path string) error { + l := log.WithFields(log.Fields{ + "filename": path, + }) + pkg := ddpackage.NewPackage(l) + + err := pkg.LoadUnpackedFromFolder(path) + if err != nil { + l.WithError(err).Error("failed to load package") + return err + } + err = pkg.ReadUnpackedTags() + if err != nil { + l.WithError(err).Error("failed to load tags") + return err + } + + ls.printTree(l, pkg) + return nil +} + +func (ls *ListTagsCmd) printTree(l logrus.FieldLogger, pkg *ddpackage.Package) { + tree := treeprint.New() + branchMap := make(map[string]treeprint.Tree) + + var nodeForPath func(path string, fileInfo *structures.FileInfo) treeprint.Tree + nodeForPath = func(path string, fileInfo *structures.FileInfo) treeprint.Tree { + var tags []string + for tag := range pkg.Tags.Tags { + set := pkg.Tags.Tags[tag] + if set.Has(fileInfo.RelPath) { + tags = append(tags, strings.Join([]string{"\"", tag, "\""}, "")) + } + } + meta := strings.Join(tags, ", ") + useMeta := true + if strings.HasSuffix(path, string(filepath.Separator)) { + path = path[:len(path)-1] + useMeta = false + } + dir, file := filepath.Split(path) + if dir == "" { + if branchMap[file] == nil { + if useMeta { + branchMap[file] = tree.AddMetaBranch(meta, file) + } else { + branchMap[file] = tree.AddBranch(file) + } + } + return branchMap[file] + } else { + if branchMap[path] == nil { + parent := nodeForPath(dir, fileInfo) + if useMeta { + branchMap[path] = parent.AddMetaBranch(meta, file) + } else { + branchMap[path] = parent.AddBranch(file) + } + } + return branchMap[path] + } + } + for i := 0; i < len(pkg.FileList); i++ { + info := &pkg.FileList[i] + if !info.IsTexture() { + continue + } + path := pkg.NormalizeResourcePath(info.ResPath) + l.WithField("res", info.ResPath). + WithField("size", info.Size). + WithField("index", i). + Trace("building tree node") + nodeForPath(path, info) + } + + fmt.Println(tree.String()) +} diff --git a/pkg/structures/set.go b/pkg/structures/set.go index 6d69b6d..e39e42a 100644 --- a/pkg/structures/set.go +++ b/pkg/structures/set.go @@ -1,6 +1,9 @@ package structures -import "encoding/json" +import ( + "encoding/json" + "fmt" +) type Set[T comparable] struct { data map[T]struct{} @@ -13,11 +16,11 @@ func NewSet[T comparable]() *Set[T] { } func (s *Set[T]) AsSlice() []T { - res := make([]T, len(s.data)) - for d := range s.data { - res = append(res, d) - } - return res + res := make([]T, len(s.data)) + for d := range s.data { + res = append(res, d) + } + return res } func (s *Set[T]) Has(d T) bool { @@ -46,6 +49,7 @@ func (s *Set[T]) AddM(list ...T) { s.Add(d) } } + func (s *Set[T]) RemoveM(list ...T) { for _, d := range list { s.Remove(d) @@ -99,20 +103,23 @@ func (s *Set[T]) Difference(s2 *Set[T]) *Set[T] { } func (s *Set[T]) UnmarshalJSON(bytes []byte) error { - var data []T + var data []T err := json.Unmarshal(bytes, &data) if err != nil { - return err + return err } s.Clear() for _, d := range data { - s.Add(d) + s.Add(d) } return nil } func (s *Set[T]) MarshalJSON() ([]byte, error) { - data := s.AsSlice() - return json.Marshal(data) + data := s.AsSlice() + return json.Marshal(data) } +func (s Set[T]) String() string { + return fmt.Sprintf("%v", s.AsSlice()) +}