fix(library): expose scan activity and failed analysis file details
ci / api / api (push) Successful in 55s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / db / db (push) Successful in 52s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m38s
release / android (APK в релиз) (push) Successful in 3m50s
ci / ts / ts (packages + web) (push) Successful in 3m20s
release / release (версия и заметки) (push) Successful in 5s
release / desktop (Linux и Windows в релиз) (push) Successful in 44m45s
release / prune (старые файлы и прогоны) (push) Successful in 7s
ci / api / api (push) Successful in 55s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / db / db (push) Successful in 52s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m38s
release / android (APK в релиз) (push) Successful in 3m50s
ci / ts / ts (packages + web) (push) Successful in 3m20s
release / release (версия и заметки) (push) Successful in 5s
release / desktop (Linux и Windows в релиз) (push) Successful in 44m45s
release / prune (старые файлы и прогоны) (push) Successful in 7s
This commit is contained in:
1 parent
17b6dd2041
commit
0dc0384c78
20 files changed
+1114
-326
No files matched your search
@@ -28,6 +28,9 @@ const MissingRetention = 30 * 24 * time.Hour
|
||||
|
||||
// Progress — состояние скана одного источника (для админки).
|
||||
type Progress struct {
|
||||
Phase string
|
||||
WalkedDirs int
|
||||
CurrentDir string
|
||||
SourceID uuid.UUID
|
||||
Running bool
|
||||
Full bool
|
||||
@@ -82,7 +85,7 @@ func (b *ProgressBoard) start(id uuid.UUID, full bool, now time.Time) bool {
|
||||
if p, ok := b.m[id]; ok && p.Running {
|
||||
return false
|
||||
}
|
||||
b.m[id] = &Progress{SourceID: id, Running: true, Full: full, StartedAt: now}
|
||||
b.m[id] = &Progress{SourceID: id, Running: true, Full: full, StartedAt: now, Phase: "walking"}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -202,14 +205,18 @@ func (sc *Scanner) run(ctx context.Context, src Source, root string, full bool)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found, err := walk(root, func(rel string) bool { return meta.MatchPath(patterns, rel).Skip })
|
||||
found, err := walk(root, func(rel string) bool { return meta.MatchPath(patterns, rel).Skip }, func(found, dirs int, currentDir string) {
|
||||
sc.board.update(src.ID, func(p *Progress) {
|
||||
p.Found, p.WalkedDirs, p.CurrentDir = found, dirs, currentDir
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(found) == 0 && hasPresent(existing) {
|
||||
return ErrSourceEmpty
|
||||
}
|
||||
sc.board.update(src.ID, func(p *Progress) { p.Found = len(found) })
|
||||
sc.board.update(src.ID, func(p *Progress) { p.Found, p.Phase = len(found), "preparing" })
|
||||
|
||||
var (
|
||||
jobs []job
|
||||
@@ -256,11 +263,12 @@ func (sc *Scanner) run(ctx context.Context, src Source, root string, full bool)
|
||||
for _, w := range rest {
|
||||
jobs = append(jobs, job{walked: w})
|
||||
}
|
||||
sc.board.update(src.ID, func(p *Progress) { p.ToProcess, p.Moved = len(jobs), len(moves) })
|
||||
sc.board.update(src.ID, func(p *Progress) { p.ToProcess, p.Moved, p.Phase = len(jobs), len(moves), "processing" })
|
||||
|
||||
if err := sc.process(ctx, src, root, patterns, jobs); err != nil {
|
||||
return err
|
||||
}
|
||||
sc.board.update(src.ID, func(p *Progress) { p.Phase = "finalizing" })
|
||||
|
||||
var goneIDs []uuid.UUID
|
||||
affected := map[uuid.UUID]bool{}
|
||||
@@ -462,11 +470,12 @@ func (sc *Scanner) apply(ctx context.Context, src Source, patterns []meta.Patter
|
||||
|
||||
// walk обходит дерево источника и возвращает аудиофайлы. Скрытые файлы и каталоги пропускаются;
|
||||
// skip — пути, которые шаблоны велят игнорировать. Ошибки отдельных каталогов не прерывают обход.
|
||||
func walk(root string, skip func(rel string) bool) ([]walked, error) {
|
||||
func walk(root string, skip func(rel string) bool, report func(found, dirs int, currentDir string)) ([]walked, error) {
|
||||
if _, err := os.Stat(root); err != nil {
|
||||
return nil, fmt.Errorf("library: source root: %w", err)
|
||||
}
|
||||
var out []walked
|
||||
dirs := 0
|
||||
err := filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
if p == root {
|
||||
@@ -481,14 +490,21 @@ func walk(root string, skip func(rel string) bool) ([]walked, error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() || !IsAudio(name) {
|
||||
return nil
|
||||
}
|
||||
rel, err := filepath.Rel(root, p)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
rel = filepath.ToSlash(rel)
|
||||
if d.IsDir() {
|
||||
dirs++
|
||||
if report != nil {
|
||||
report(len(out), dirs, rel)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !IsAudio(name) {
|
||||
return nil
|
||||
}
|
||||
if skip(rel) {
|
||||
return nil
|
||||
}
|
||||
@@ -498,6 +514,9 @@ func walk(root string, skip func(rel string) bool) ([]walked, error) {
|
||||
}
|
||||
// PostgreSQL хранит время с точностью до микросекунд.
|
||||
out = append(out, walked{rel: rel, size: info.Size(), mtime: info.ModTime().UTC().Truncate(time.Microsecond)})
|
||||
if report != nil {
|
||||
report(len(out), dirs, filepath.ToSlash(filepath.Dir(rel)))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
Reference in new issue
Block a user