|
|
- package Filesystem
-
- import (
- "context"
- "fmt"
- "os"
- "path/filepath"
- "runtime"
-
- "github.com/vbauerster/mpb"
- bolt "go.etcd.io/bbolt"
- "golang.org/x/sync/semaphore"
-
- "PackageManager/Client/Database"
- "PackageManager/Client/ProgressBar"
- "PackageManager/Color"
- "PackageManager/Variables"
- )
-
- type FilesystemStatus struct {
- NewFiles []string
- PickedFiles []string
- ModifiedFiles []string
- MissingFiles []string
- }
-
- func ShowFilesystemDiff(root string) error {
- var (
- fsStatus FilesystemStatus
- //f string
- e error
- )
-
- fsStatus, e = GetFilesystemDiff(root)
- if e != nil {
- return e
- }
-
- fmt.Println("New files:")
- PrintFilesOrLength(fsStatus.NewFiles, Color.Green)
-
- fmt.Println("Added files:")
- PrintFilesOrLength(fsStatus.PickedFiles, Color.Green)
-
- fmt.Println("Modified files:")
- PrintFilesOrLength(fsStatus.ModifiedFiles, Color.Warning)
-
- fmt.Println("Deleted files:")
- PrintFilesOrLength(fsStatus.MissingFiles, Color.Fatal)
-
- return nil
- }
-
- func GetFilesystemLength(root string) (int, error) {
- var (
- rootStat os.FileInfo
- fsCount int = 0
- e error
- )
-
- rootStat, e = os.Stat(root)
- if e != nil {
- return fsCount, e
- }
-
- if rootStat.IsDir() && root[len(root)-1:] != "/" {
- root = root + "/"
- }
-
- filepath.Walk(root, func(p string, i os.FileInfo, _ error) error {
-
- // Ignore path in Variables.PruneRegexPaths
- if i.IsDir() && matchAny(p, PruneRegex) {
- return filepath.SkipDir
- }
-
- // Ignore path in Variables.IgnoreRegexPaths
- if matchAny(p, IgnoreRegex) {
- return nil
- }
-
- if !i.Mode().IsRegular() && (i.Mode()&os.ModeSymlink == 0) {
- return nil
- }
-
- fsCount++
-
- return nil
- })
-
- return fsCount, e
- }
-
- func (fsStatus *FilesystemStatus) parseFile(indexBucket, picksBucket *bolt.Bucket, p string, bar *mpb.Bar) {
- var (
- newFileObject FileObject
- knownFileObject FileObject
- pick, known []byte
- e error
- )
-
- defer func() {
- bar.Increment()
- }()
-
- pick = picksBucket.Get([]byte(p))
- known = indexBucket.Get([]byte(p))
-
- if pick != nil {
- fsStatus.PickedFiles = append(fsStatus.PickedFiles, p)
- return
- }
-
- if known != nil {
- newFileObject, e = CreateFileObject(p)
- if e != nil {
- return
- }
-
- knownFileObject, e = FromBytes(known)
- if e != nil {
- return
- }
-
- e = newFileObject.IsDifferent(knownFileObject)
- if e != nil {
- fsStatus.ModifiedFiles = append(fsStatus.ModifiedFiles, p)
- }
-
- return
- }
-
- fsStatus.NewFiles = append(fsStatus.NewFiles, p)
-
- return
- }
-
- func GetFilesystemDiff(root string) (FilesystemStatus, error) {
- var (
- fsStatus FilesystemStatus = FilesystemStatus{}
- sem *semaphore.Weighted
- picksBucket *bolt.Bucket
- indexBucket *bolt.Bucket
- rootStat os.FileInfo
- bar *mpb.Bar
- fsCount int
- poolSize int
- e error
- )
-
- poolSize = runtime.NumCPU()
- sem = semaphore.NewWeighted(int64(poolSize))
-
- rootStat, e = os.Stat(root)
- if e != nil {
- return fsStatus, e
- }
-
- if rootStat.IsDir() && root[len(root)-1:] != "/" {
- root = root + "/"
- }
-
- fsCount, e = GetFilesystemLength(root)
- if e != nil {
- return fsStatus, e
- }
-
- bar = ProgressBar.InitBar("Scanning...", fsCount)
-
- e = Database.FsDB.View(func(tx *bolt.Tx) error {
-
- picksBucket = tx.Bucket(Variables.FsHashPicksBucket)
- indexBucket = tx.Bucket(Variables.FsHashIndexBucket)
-
- filepath.Walk(root, func(p string, i os.FileInfo, _ error) error {
-
- // Ignore path in Variables.PruneRegexPaths
- if i.IsDir() && matchAny(p, PruneRegex) {
- return filepath.SkipDir
- }
-
- // Ignore path in Variables.IgnoreRegexPaths
- if matchAny(p, IgnoreRegex) {
- return nil
- }
-
- if !i.Mode().IsRegular() && (i.Mode()&os.ModeSymlink == 0) {
- return nil
- }
-
- Variables.WG.Add(1)
- sem.Acquire(context.Background(), 1)
- go func() {
- fsStatus.parseFile(indexBucket, picksBucket, p, bar)
- Variables.WG.Done()
- sem.Release(1)
- }()
-
- return nil
- })
-
- indexBucket.ForEach(func(k, v []byte) error {
- _, e = os.Lstat(string(k))
- if os.IsNotExist(e) {
- fsStatus.MissingFiles = append(fsStatus.MissingFiles, string(k))
- }
- return nil
- })
-
- Variables.WG.Wait()
- ProgressBar.CloseBar(bar)
-
- return nil
- })
-
- return fsStatus, e
- }
|