fix: refuse under --yes instead of opening an editor
--yes is for unattended runs, but an album whose names cannot be worked out still sent it into $EDITOR anyway, which then sat waiting for somebody who was not watching. The whole batch hung on that album with no way forward. It now says which names are the problem and stops, which is what the hard-issue path already did for everything else.
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
@@ -191,6 +191,20 @@ func (a *App) process(ctx context.Context, al scan.Album) error {
var resolved *plan.Plan
var editSession *names.Session
needsNames := nameIssues(names0) || strings.TrimSpace(names0.AlbumArt) == ""
+ if a.Yes && needsNames {
+ // --yes is for unattended runs. The editor would sit waiting for a
+ // person who is not watching, which hangs the whole batch on the first
+ // album whose names cannot be worked out, so refuse and say what is
+ // wrong instead. Every case that reaches here is a hard issue.
+ a.logf("")
+ a.logf("REFUSING to proceed: %d issue(s) need a name, and --yes cannot open an editor to supply one.", countHard(names0))
+ for _, i := range names0.Issues {
+ if i.Hard {
+ a.logf(" ! %s", i.Text)
+ }
+ }
+ return errors.New("names need editing, which --yes cannot do")
+ }
if a.EditNames || needsNames {
edited := names0
session, err := a.editNames(&edited)
diff --git a/internal/cli/dryrun_test.go b/internal/cli/dryrun_test.go
@@ -3,7 +3,9 @@ package cli
import (
"bytes"
"context"
+ "intake/internal/audio"
"intake/internal/plan"
+ "intake/internal/scan"
"os"
"path/filepath"
"strings"
@@ -86,3 +88,44 @@ func TestFilingRefusesWhenTheJournalCannotBeWritten(t *testing.T) {
t.Error("the archive was created even though the journal could not be written")
}
}
+
+// --yes is for unattended runs. A name that cannot be worked out used to send it
+// into the editor anyway, which waits for somebody who is not there and hangs
+// the whole batch on that album forever.
+func TestYesRefusesRatherThanOpeningTheEditor(t *testing.T) {
+ root := t.TempDir()
+ marker := filepath.Join(root, "editor-ran")
+ script := filepath.Join(root, "editor.sh")
+ if err := os.WriteFile(script, []byte("#!/bin/sh\ntouch "+marker+"\n"), 0o755); err != nil {
+ t.Fatal(err)
+ }
+
+ cfg := config.Defaults()
+ cfg.Root = root
+ cfg.StagingDir = "staging"
+ cfg.ArchiveDir = "archive"
+ cfg.LibraryDir = "library"
+ cfg.StateDir = filepath.Join(root, "state")
+ cfg.Editor = script
+
+ var out, errBuf bytes.Buffer
+ a := &App{Cfg: cfg, Yes: true, Out: &out, Err: &errBuf}
+
+ album := scan.Album{
+ Name: "nameless",
+ Dir: filepath.Join(root, "staging", "nameless"),
+ Status: scan.StatusReady,
+ // no tags at all, and a folder name with no separator to infer from
+ Tracks: []audio.Track{{
+ Path: filepath.Join(root, "staging", "nameless", "01 untitled.flac"),
+ Ext: ".flac",
+ }},
+ }
+
+ if err := a.process(context.Background(), album); err == nil {
+ t.Fatal("--yes should have refused an album whose names cannot be worked out")
+ }
+ if _, statErr := os.Stat(marker); !os.IsNotExist(statErr) {
+ t.Error("the editor was opened under --yes, which is what hangs an unattended run")
+ }
+}