FeedImportCommand.java

package net.sasasin.sreader.cli;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import net.sasasin.sreader.service.FeedTomlService;
import org.springframework.stereotype.Component;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

@Command(
    name = "import",
    description = "Import feeds from a TOML file. Creates/updates feed_url records.",
    mixinStandardHelpOptions = true,
    usageHelpWidth = 100)
@Component
public class FeedImportCommand implements Runnable {

  private final FeedTomlService feedTomlService;

  @Option(
      names = {"--input", "-i"},
      paramLabel = "<PATH>",
      description = "Path to the TOML file containing feeds to import (required)",
      required = true)
  private String input;

  @Option(
      names = "--dry-run",
      description = "Parse and validate the TOML but do not modify the database")
  private boolean dryRun;

  @Option(
      names = "--resubscribe",
      description =
          "When a feed is unsubscribed in DB but listed as active in TOML, resubscribe it")
  private boolean resubscribe;

  public FeedImportCommand(FeedTomlService feedTomlService) {
    this.feedTomlService = feedTomlService;
  }

  @Override
  public void run() {
    try {
      String toml = Files.readString(Path.of(input), StandardCharsets.UTF_8);
      FeedTomlService.ImportResult result =
          feedTomlService.importToml(toml, new FeedTomlService.ImportOptions(dryRun, resubscribe));
      System.out.println(
          "Import result: inserted="
              + result.inserted()
              + ", updated="
              + result.updated()
              + ", unchanged="
              + result.unchanged()
              + ", unsubscribed="
              + result.unsubscribed()
              + ", resubscribed="
              + result.resubscribed()
              + ", conflicts="
              + result.conflicts()
              + ", errors="
              + result.errors().size());
      for (String conflict : result.conflictMessages()) {
        System.out.println("Conflict: " + conflict);
      }
    } catch (IOException e) {
      throw new RuntimeException("Failed to read input file: " + input, e);
    }
  }
}