diff options
-rw-r--r-- | cmd/server/main.go | 4 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 4 | ||||
-rw-r--r-- | pkg/components/filesystem/controller.go | 6 | ||||
-rw-r--r-- | pkg/database/repository/filesystem.go (renamed from pkg/components/filesystem/model.go) | 4 | ||||
-rw-r--r-- | pkg/database/repository/media.go (renamed from pkg/components/media/model.go) | 4 | ||||
-rw-r--r-- | pkg/database/repository/settings.go (renamed from pkg/components/settings/model.go) | 4 | ||||
-rw-r--r-- | pkg/database/sql/media.go | 28 | ||||
-rw-r--r-- | pkg/database/sql/settings.go | 10 | ||||
-rw-r--r-- | pkg/database/sql/user_test.go | 20 | ||||
-rw-r--r-- | pkg/fileop/exif.go | 8 | ||||
-rw-r--r-- | pkg/view/filesystem.go | 6 | ||||
-rw-r--r-- | pkg/view/media.go | 16 | ||||
-rw-r--r-- | pkg/view/settings.go | 9 | ||||
-rw-r--r-- | pkg/worker/exif_scanner.go | 16 | ||||
-rw-r--r-- | pkg/worker/file_scanner.go | 8 |
16 files changed, 72 insertions, 77 deletions
diff --git a/cmd/server/main.go b/cmd/server/main.go index 4942ac3..76cf0c0 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -19,8 +19,8 @@ import ( "git.sr.ht/~gabrielgio/img" "git.sr.ht/~gabrielgio/img/pkg/components/auth" "git.sr.ht/~gabrielgio/img/pkg/components/filesystem" - "git.sr.ht/~gabrielgio/img/pkg/components/media" "git.sr.ht/~gabrielgio/img/pkg/database/localfs" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/database/sql" "git.sr.ht/~gabrielgio/img/pkg/ext" "git.sr.ht/~gabrielgio/img/pkg/view" @@ -125,7 +125,7 @@ func main() { scheduler, logrus.WithField("context", "file scanner"), ) - exifWorker = worker.NewWorkerFromBatchProcessor[*media.Media]( + exifWorker = worker.NewWorkerFromBatchProcessor[*repository.Media]( exifScanner, scheduler, logrus.WithField("context", "exif scanner"), @@ -6,7 +6,6 @@ require ( github.com/barasher/go-exiftool v1.10.0 github.com/fasthttp/router v1.4.19 github.com/google/go-cmp v0.5.9 - github.com/samber/lo v1.38.1 github.com/sirupsen/logrus v1.9.2 github.com/spf13/pflag v1.0.5 github.com/valyala/fasthttp v1.47.0 @@ -30,7 +29,6 @@ require ( github.com/mattn/go-sqlite3 v1.14.16 // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect @@ -34,8 +34,6 @@ github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= @@ -52,8 +50,6 @@ github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= diff --git a/pkg/components/filesystem/controller.go b/pkg/components/filesystem/controller.go index 6b478a5..6c613a3 100644 --- a/pkg/components/filesystem/controller.go +++ b/pkg/components/filesystem/controller.go @@ -5,11 +5,13 @@ import ( "net/url" "path" "strings" + + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) type ( Controller struct { - repository Repository + repository repository.FileSystemRepository } DirectoryParam struct { @@ -28,7 +30,7 @@ type ( } ) -func NewController(repository Repository) *Controller { +func NewController(repository repository.FileSystemRepository) *Controller { return &Controller{ repository: repository, } diff --git a/pkg/components/filesystem/model.go b/pkg/database/repository/filesystem.go index 2caed82..f553b3f 100644 --- a/pkg/components/filesystem/model.go +++ b/pkg/database/repository/filesystem.go @@ -1,9 +1,9 @@ -package filesystem +package repository import "io/fs" type ( - Repository interface { + FileSystemRepository interface { List(path string) ([]fs.FileInfo, error) Stat(path string) (fs.FileInfo, error) } diff --git a/pkg/components/media/model.go b/pkg/database/repository/media.go index 1962a23..2e94ff3 100644 --- a/pkg/components/media/model.go +++ b/pkg/database/repository/media.go @@ -1,4 +1,4 @@ -package media +package repository import ( "context" @@ -46,7 +46,7 @@ type ( MIMEType string } - Repository interface { + MediaRepository interface { Create(context.Context, *CreateMedia) error Exists(context.Context, string) (bool, error) List(context.Context, *Pagination) ([]*Media, error) diff --git a/pkg/components/settings/model.go b/pkg/database/repository/settings.go index da07f2c..6ed1eb6 100644 --- a/pkg/components/settings/model.go +++ b/pkg/database/repository/settings.go @@ -1,4 +1,4 @@ -package settings +package repository import "context" @@ -8,7 +8,7 @@ type ( ShowOwner bool } - Repository interface { + SettingsRepository interface { Save(context.Context, *Settings) error Load(context.Context) (*Settings, error) } diff --git a/pkg/database/sql/media.go b/pkg/database/sql/media.go index 3446f79..27f8cf0 100644 --- a/pkg/database/sql/media.go +++ b/pkg/database/sql/media.go @@ -6,7 +6,7 @@ import ( "gorm.io/gorm" - "git.sr.ht/~gabrielgio/img/pkg/components/media" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/list" ) @@ -46,10 +46,10 @@ type ( } ) -var _ media.Repository = &MediaRepository{} +var _ repository.MediaRepository = &MediaRepository{} -func (self *Media) ToModel() *media.Media { - return &media.Media{ +func (self *Media) ToModel() *repository.Media { + return &repository.Media{ ID: self.ID, Path: self.Path, PathHash: self.PathHash, @@ -58,8 +58,8 @@ func (self *Media) ToModel() *media.Media { } } -func (m *MediaEXIF) ToModel() *media.MediaEXIF { - return &media.MediaEXIF{ +func (m *MediaEXIF) ToModel() *repository.MediaEXIF { + return &repository.MediaEXIF{ Height: m.Height, Width: m.Width, Description: m.Description, @@ -85,7 +85,7 @@ func NewMediaRepository(db *gorm.DB) *MediaRepository { } } -func (self *MediaRepository) Create(ctx context.Context, createMedia *media.CreateMedia) error { +func (self *MediaRepository) Create(ctx context.Context, createMedia *repository.CreateMedia) error { media := &Media{ Name: createMedia.Name, Path: createMedia.Path, @@ -119,7 +119,7 @@ func (self *MediaRepository) Exists(ctx context.Context, path string) (bool, err return exists, nil } -func (self *MediaRepository) List(ctx context.Context, pagination *media.Pagination) ([]*media.Media, error) { +func (self *MediaRepository) List(ctx context.Context, pagination *repository.Pagination) ([]*repository.Media, error) { medias := make([]*Media, 0) result := self.db. WithContext(ctx). @@ -133,14 +133,14 @@ func (self *MediaRepository) List(ctx context.Context, pagination *media.Paginat return nil, result.Error } - m := list.Map(medias, func(s *Media) *media.Media { + m := list.Map(medias, func(s *Media) *repository.Media { return s.ToModel() }) return m, nil } -func (self *MediaRepository) Get(ctx context.Context, pathHash string) (*media.Media, error) { +func (self *MediaRepository) Get(ctx context.Context, pathHash string) (*repository.Media, error) { m := &Media{} result := self.db. WithContext(ctx). @@ -173,7 +173,7 @@ func (self *MediaRepository) GetPath(ctx context.Context, pathHash string) (stri return path, nil } -func (m *MediaRepository) GetEXIF(ctx context.Context, mediaID uint) (*media.MediaEXIF, error) { +func (m *MediaRepository) GetEXIF(ctx context.Context, mediaID uint) (*repository.MediaEXIF, error) { exif := &MediaEXIF{} result := m.db. WithContext(ctx). @@ -189,7 +189,7 @@ func (m *MediaRepository) GetEXIF(ctx context.Context, mediaID uint) (*media.Med return exif.ToModel(), nil } -func (s *MediaRepository) CreateEXIF(ctx context.Context, id uint, info *media.MediaEXIF) error { +func (s *MediaRepository) CreateEXIF(ctx context.Context, id uint, info *repository.MediaEXIF) error { media := &MediaEXIF{ MediaID: id, Width: info.Width, @@ -220,7 +220,7 @@ func (s *MediaRepository) CreateEXIF(ctx context.Context, id uint, info *media.M return nil } -func (r *MediaRepository) GetEmptyEXIF(ctx context.Context, pagination *media.Pagination) ([]*media.Media, error) { +func (r *MediaRepository) GetEmptyEXIF(ctx context.Context, pagination *repository.Pagination) ([]*repository.Media, error) { medias := make([]*Media, 0) result := r.db. WithContext(ctx). @@ -236,7 +236,7 @@ func (r *MediaRepository) GetEmptyEXIF(ctx context.Context, pagination *media.Pa return nil, result.Error } - m := list.Map(medias, func(s *Media) *media.Media { + m := list.Map(medias, func(s *Media) *repository.Media { return s.ToModel() }) diff --git a/pkg/database/sql/settings.go b/pkg/database/sql/settings.go index 7ad718b..4e73878 100644 --- a/pkg/database/sql/settings.go +++ b/pkg/database/sql/settings.go @@ -5,7 +5,7 @@ import ( "gorm.io/gorm" - "git.sr.ht/~gabrielgio/img/pkg/components/settings" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) type ( @@ -20,7 +20,7 @@ type ( } ) -var _ settings.Repository = &SettingsRepository{} +var _ repository.SettingsRepository = &SettingsRepository{} func NewSettingsRespository(db *gorm.DB) *SettingsRepository { return &SettingsRepository{ @@ -41,7 +41,7 @@ func (self *SettingsRepository) ensureSettings(ctx context.Context) (*Settings, return s, nil } -func (self *SettingsRepository) Save(ctx context.Context, toSaveSettings *settings.Settings) error { +func (self *SettingsRepository) Save(ctx context.Context, toSaveSettings *repository.Settings) error { db := self.db.WithContext(ctx) s, err := self.ensureSettings(ctx) @@ -56,13 +56,13 @@ func (self *SettingsRepository) Save(ctx context.Context, toSaveSettings *settin return result.Error } -func (self *SettingsRepository) Load(ctx context.Context) (*settings.Settings, error) { +func (self *SettingsRepository) Load(ctx context.Context) (*repository.Settings, error) { s, err := self.ensureSettings(ctx) if err != nil { return nil, err } - return &settings.Settings{ + return &repository.Settings{ ShowMode: s.ShowMode, ShowOwner: s.ShowOwner, }, nil diff --git a/pkg/database/sql/user_test.go b/pkg/database/sql/user_test.go index f0d89ad..01f6729 100644 --- a/pkg/database/sql/user_test.go +++ b/pkg/database/sql/user_test.go @@ -12,7 +12,7 @@ import ( "gorm.io/gorm" "gorm.io/gorm/logger" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) func setup(t *testing.T) (*gorm.DB, func()) { @@ -46,9 +46,9 @@ func TestCreate(t *testing.T) { db, tearDown := setup(t) defer tearDown() - repository := NewUserRepository(db) + userRepository := NewUserRepository(db) - id, err := repository.Create(context.Background(), &user.CreateUser{ + id, err := userRepository.Create(context.Background(), &repository.CreateUser{ Username: "new_username", Name: "new_name", }) @@ -56,11 +56,11 @@ func TestCreate(t *testing.T) { t.Fatalf("Error creating: %s", err.Error()) } - got, err := repository.Get(context.Background(), id) + got, err := userRepository.Get(context.Background(), id) if err != nil { t.Fatalf("Error getting: %s", err.Error()) } - want := &user.User{ + want := &repository.User{ ID: id, Username: "new_username", Name: "new_name", @@ -76,9 +76,9 @@ func TestUpdate(t *testing.T) { db, tearDown := setup(t) defer tearDown() - repository := NewUserRepository(db) + userRepository := NewUserRepository(db) - id, err := repository.Create(context.Background(), &user.CreateUser{ + id, err := userRepository.Create(context.Background(), &repository.CreateUser{ Username: "username", Name: "name", }) @@ -86,7 +86,7 @@ func TestUpdate(t *testing.T) { t.Fatalf("Error creating user: %s", err.Error()) } - err = repository.Update(context.Background(), id, &user.UpdateUser{ + err = userRepository.Update(context.Background(), id, &repository.UpdateUser{ Username: "new_username", Name: "new_name", }) @@ -94,11 +94,11 @@ func TestUpdate(t *testing.T) { t.Fatalf("Error update user: %s", err.Error()) } - got, err := repository.Get(context.Background(), 1) + got, err := userRepository.Get(context.Background(), 1) if err != nil { t.Fatalf("Error getting user: %s", err.Error()) } - want := &user.User{ + want := &repository.User{ ID: id, Username: "new_username", Name: "new_name", diff --git a/pkg/fileop/exif.go b/pkg/fileop/exif.go index 79716eb..49cd0ce 100644 --- a/pkg/fileop/exif.go +++ b/pkg/fileop/exif.go @@ -6,17 +6,17 @@ import ( "github.com/barasher/go-exiftool" - "git.sr.ht/~gabrielgio/img/pkg/components/media" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) -func ReadExif(path string) (*media.MediaEXIF, error) { +func ReadExif(path string) (*repository.MediaEXIF, error) { et, err := exiftool.NewExiftool() if err != nil { return nil, err } defer et.Close() - newExif := &media.MediaEXIF{} + newExif := &repository.MediaEXIF{} fileInfo := et.ExtractMetadata(path)[0] // Get description @@ -159,7 +159,7 @@ func isFloatReal(v float64) bool { // sanitizeEXIF removes any EXIF float64 field that is not a real number (+Inf, // -Inf or Nan) -func sanitizeEXIF(exif *media.MediaEXIF) { +func sanitizeEXIF(exif *repository.MediaEXIF) { if exif.Exposure != nil && !isFloatReal(*exif.Exposure) { exif.Exposure = nil } diff --git a/pkg/view/filesystem.go b/pkg/view/filesystem.go index f10d788..d2ebff4 100644 --- a/pkg/view/filesystem.go +++ b/pkg/view/filesystem.go @@ -5,14 +5,14 @@ import ( "git.sr.ht/~gabrielgio/img" "git.sr.ht/~gabrielgio/img/pkg/components/filesystem" - "git.sr.ht/~gabrielgio/img/pkg/components/settings" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) type ( FileSystemView struct { controller filesystem.Controller - settings settings.Repository + settings repository.SettingsRepository } FilePage struct { Page *filesystem.Page @@ -23,7 +23,7 @@ type ( func NewFileSystemView( controller filesystem.Controller, - settingsRepository settings.Repository, + settingsRepository repository.SettingsRepository, ) *FileSystemView { return &FileSystemView{ controller: controller, diff --git a/pkg/view/media.go b/pkg/view/media.go index 66e3020..ce9e272 100644 --- a/pkg/view/media.go +++ b/pkg/view/media.go @@ -6,22 +6,22 @@ import ( "github.com/valyala/fasthttp" "git.sr.ht/~gabrielgio/img" - "git.sr.ht/~gabrielgio/img/pkg/components/media" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) type ( MediaView struct { - mediaRepository media.Repository + mediaRepository repository.MediaRepository } Page struct { - Medias []*media.Media - Next *media.Pagination + Medias []*repository.Media + Next *repository.Pagination } ) -func getPagination(ctx *fasthttp.RequestCtx) *media.Pagination { +func getPagination(ctx *fasthttp.RequestCtx) *repository.Pagination { var ( size int page int @@ -45,13 +45,13 @@ func getPagination(ctx *fasthttp.RequestCtx) *media.Pagination { page = p } - return &media.Pagination{ + return &repository.Pagination{ Page: page, Size: size, } } -func NewMediaView(mediaRepository media.Repository) *MediaView { +func NewMediaView(mediaRepository repository.MediaRepository) *MediaView { return &MediaView{ mediaRepository: mediaRepository, } @@ -68,7 +68,7 @@ func (self *MediaView) Index(ctx *fasthttp.RequestCtx) error { Title: "Media", Data: &Page{ Medias: medias, - Next: &media.Pagination{ + Next: &repository.Pagination{ Size: p.Size, Page: p.Page + 1, }, diff --git a/pkg/view/settings.go b/pkg/view/settings.go index 954cc98..14f4e49 100644 --- a/pkg/view/settings.go +++ b/pkg/view/settings.go @@ -4,7 +4,6 @@ import ( "github.com/valyala/fasthttp" "git.sr.ht/~gabrielgio/img" - "git.sr.ht/~gabrielgio/img/pkg/components/settings" "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) @@ -12,18 +11,18 @@ import ( type ( SettingsView struct { // there is not need to create a controller for this - settingsRepository settings.Repository + settingsRepository repository.SettingsRepository userRepository repository.UserRepository } SettingsPage struct { - Settings *settings.Settings + Settings *repository.Settings Users []*repository.User } ) func NewSettingsView( - settingsRespository settings.Repository, + settingsRespository repository.SettingsRepository, userRepository repository.UserRepository, ) *SettingsView { return &SettingsView{ @@ -58,7 +57,7 @@ func (self *SettingsView) Save(ctx *fasthttp.RequestCtx) error { showOwner = string(ctx.FormValue("showOwner")) == "on" ) - err := self.settingsRepository.Save(ctx, &settings.Settings{ + err := self.settingsRepository.Save(ctx, &repository.Settings{ ShowMode: showMode, ShowOwner: showOwner, }) diff --git a/pkg/worker/exif_scanner.go b/pkg/worker/exif_scanner.go index 91eed12..97790a0 100644 --- a/pkg/worker/exif_scanner.go +++ b/pkg/worker/exif_scanner.go @@ -3,27 +3,27 @@ package worker import ( "context" - "git.sr.ht/~gabrielgio/img/pkg/components/media" "git.sr.ht/~gabrielgio/img/pkg/coroutine" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/fileop" ) type ( EXIFScanner struct { - repository media.Repository + repository repository.MediaRepository } ) -var _ BatchProcessor[*media.Media] = &EXIFScanner{} +var _ BatchProcessor[*repository.Media] = &EXIFScanner{} -func NewEXIFScanner(repository media.Repository) *EXIFScanner { +func NewEXIFScanner(repository repository.MediaRepository) *EXIFScanner { return &EXIFScanner{ repository: repository, } } -func (e *EXIFScanner) Query(ctx context.Context) ([]*media.Media, error) { - medias, err := e.repository.GetEmptyEXIF(ctx, &media.Pagination{ +func (e *EXIFScanner) Query(ctx context.Context) ([]*repository.Media, error) { + medias, err := e.repository.GetEmptyEXIF(ctx, &repository.Pagination{ Page: 0, Size: 100, }) @@ -34,8 +34,8 @@ func (e *EXIFScanner) Query(ctx context.Context) ([]*media.Media, error) { return medias, nil } -func (e *EXIFScanner) Process(ctx context.Context, m *media.Media) error { - exif, err := coroutine.WrapProcess(ctx, func() (*media.MediaEXIF, error) { return fileop.ReadExif(m.Path) }) +func (e *EXIFScanner) Process(ctx context.Context, m *repository.Media) error { + exif, err := coroutine.WrapProcess(ctx, func() (*repository.MediaEXIF, error) { return fileop.ReadExif(m.Path) }) if err != nil { return err } diff --git a/pkg/worker/file_scanner.go b/pkg/worker/file_scanner.go index a51f60b..aa79035 100644 --- a/pkg/worker/file_scanner.go +++ b/pkg/worker/file_scanner.go @@ -9,19 +9,19 @@ import ( "path/filepath" "strings" - "git.sr.ht/~gabrielgio/img/pkg/components/media" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" ) type ( FileScanner struct { root string - repository media.Repository + repository repository.MediaRepository } ) var _ ChanProcessor[string] = &FileScanner{} -func NewFileScanner(root string, repository media.Repository) *FileScanner { +func NewFileScanner(root string, repository repository.MediaRepository) *FileScanner { return &FileScanner{ root: root, repository: repository, @@ -77,7 +77,7 @@ func (f *FileScanner) Process(ctx context.Context, path string) error { return nil } - return f.repository.Create(ctx, &media.CreateMedia{ + return f.repository.Create(ctx, &repository.CreateMedia{ Name: name, Path: path, PathHash: str, |