PackageManager just because
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
4.5 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package Filesystem
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "runtime"
  8. "sync"
  9. "github.com/vbauerster/mpb"
  10. bolt "go.etcd.io/bbolt"
  11. "golang.org/x/sync/semaphore"
  12. "PackageManager/Client/Database"
  13. "PackageManager/Client/ProgressBar"
  14. "PackageManager/Color"
  15. "PackageManager/Variables"
  16. )
  17. var (
  18. fsStatusWG sync.WaitGroup
  19. FsWalkWG sync.WaitGroup
  20. )
  21. type FilesystemStatus struct {
  22. NewFiles []string
  23. PickedFiles []string
  24. ModifiedFiles []string
  25. MissingFiles []string
  26. }
  27. func ShowFilesystemDiff(root string) error {
  28. var (
  29. fsStatus FilesystemStatus
  30. picksBucket *bolt.Bucket
  31. pickedFiles []string
  32. e error
  33. )
  34. fsStatus, e = GetFilesystemDiff(root)
  35. if e != nil {
  36. return e
  37. }
  38. e = Database.FsDB.View(func(tx *bolt.Tx) error {
  39. picksBucket = tx.Bucket(Variables.FsHashPicksBucket)
  40. return picksBucket.ForEach(func(key, _ []byte) error {
  41. pickedFiles = append(pickedFiles, string(key))
  42. return nil
  43. })
  44. })
  45. fmt.Println("New files:")
  46. PrintFilesOrLength(fsStatus.NewFiles, Color.Green)
  47. fmt.Println("Added files:")
  48. PrintFilesOrLength(pickedFiles, Color.Green)
  49. fmt.Println("Modified files:")
  50. PrintFilesOrLength(fsStatus.ModifiedFiles, Color.Warning)
  51. fmt.Println("Deleted files:")
  52. PrintFilesOrLength(fsStatus.MissingFiles, Color.Fatal)
  53. return nil
  54. }
  55. func GetFilesystemLength(root string) (int, error) {
  56. var (
  57. rootStat os.FileInfo
  58. fsCount int = 0
  59. e error
  60. )
  61. rootStat, e = os.Stat(root)
  62. if e != nil {
  63. return fsCount, e
  64. }
  65. if rootStat.IsDir() && root[len(root)-1:] != "/" {
  66. root = root + "/"
  67. }
  68. filepath.Walk(root, func(p string, i os.FileInfo, _ error) error {
  69. // Ignore path in Variables.PruneRegexPaths
  70. if i.IsDir() && matchAny(p, PruneRegex) {
  71. return filepath.SkipDir
  72. }
  73. // Ignore path in Variables.IgnoreRegexPaths
  74. if matchAny(p, IgnoreRegex) {
  75. return nil
  76. }
  77. if !i.Mode().IsRegular() && (i.Mode()&os.ModeSymlink == 0) {
  78. return nil
  79. }
  80. fsCount++
  81. return nil
  82. })
  83. return fsCount, e
  84. }
  85. func (fsStatus *FilesystemStatus) parseFile(indexBucket, picksBucket *bolt.Bucket, p string, bar *mpb.Bar) {
  86. var (
  87. newFileObject FileObject
  88. knownFileObject FileObject
  89. pick, known []byte
  90. e error
  91. )
  92. defer func() {
  93. bar.Increment()
  94. fsStatusWG.Done()
  95. }()
  96. pick = picksBucket.Get([]byte(p))
  97. known = indexBucket.Get([]byte(p))
  98. if pick != nil {
  99. fsStatusWG.Wait()
  100. fsStatusWG.Add(1)
  101. fsStatus.PickedFiles = append(fsStatus.PickedFiles, p)
  102. fsStatusWG.Done()
  103. return
  104. }
  105. if known != nil {
  106. newFileObject, e = CreateFileObject(p)
  107. if e != nil {
  108. return
  109. }
  110. knownFileObject, e = FromBytes(known)
  111. if e != nil {
  112. return
  113. }
  114. e = newFileObject.IsDifferent(knownFileObject)
  115. if e != nil {
  116. fsStatusWG.Wait()
  117. fsStatusWG.Add(1)
  118. fsStatus.ModifiedFiles = append(fsStatus.ModifiedFiles, p)
  119. }
  120. return
  121. }
  122. fsStatusWG.Wait()
  123. fsStatusWG.Add(1)
  124. fsStatus.NewFiles = append(fsStatus.NewFiles, p)
  125. return
  126. }
  127. func GetFilesystemDiff(root string) (FilesystemStatus, error) {
  128. var (
  129. fsStatus FilesystemStatus = FilesystemStatus{}
  130. sem *semaphore.Weighted
  131. picksBucket *bolt.Bucket
  132. indexBucket *bolt.Bucket
  133. rootStat os.FileInfo
  134. bar *mpb.Bar
  135. fsCount int
  136. poolSize int
  137. e error
  138. )
  139. poolSize = runtime.NumCPU()
  140. sem = semaphore.NewWeighted(int64(poolSize))
  141. rootStat, e = os.Stat(root)
  142. if e != nil {
  143. return fsStatus, e
  144. }
  145. if rootStat.IsDir() && root[len(root)-1:] != "/" {
  146. root = root + "/"
  147. }
  148. fsCount, e = GetFilesystemLength(root)
  149. if e != nil {
  150. return fsStatus, e
  151. }
  152. bar = ProgressBar.InitBar("Scanning...", fsCount)
  153. e = Database.FsDB.View(func(tx *bolt.Tx) error {
  154. picksBucket = tx.Bucket(Variables.FsHashPicksBucket)
  155. indexBucket = tx.Bucket(Variables.FsHashIndexBucket)
  156. filepath.Walk(root, func(p string, i os.FileInfo, _ error) error {
  157. // Ignore path in Variables.PruneRegexPaths
  158. if i.IsDir() && matchAny(p, PruneRegex) {
  159. return filepath.SkipDir
  160. }
  161. // Ignore path in Variables.IgnoreRegexPaths
  162. if matchAny(p, IgnoreRegex) {
  163. return nil
  164. }
  165. if !i.Mode().IsRegular() && (i.Mode()&os.ModeSymlink == 0) {
  166. return nil
  167. }
  168. FsWalkWG.Add(1)
  169. sem.Acquire(context.Background(), 1)
  170. go func() {
  171. fsStatus.parseFile(indexBucket, picksBucket, p, bar)
  172. sem.Release(1)
  173. FsWalkWG.Done()
  174. }()
  175. FsWalkWG.Wait()
  176. return nil
  177. })
  178. indexBucket.ForEach(func(k, v []byte) error {
  179. _, e = os.Lstat(string(k))
  180. if os.IsNotExist(e) {
  181. fsStatus.MissingFiles = append(fsStatus.MissingFiles, string(k))
  182. }
  183. return nil
  184. })
  185. return nil
  186. })
  187. return fsStatus, e
  188. }