package io.github.applecommander.acx.command; import java.util.ArrayList; import java.util.List; import com.webcodepro.applecommander.storage.FormattedDisk; import com.webcodepro.applecommander.storage.FormattedDisk.FileColumnHeader; import io.github.applecommander.acx.base.ReadOnlyDiskImageCommandOptions; import io.github.applecommander.filestreamer.FileStreamer; import io.github.applecommander.filestreamer.FileTuple; import io.github.applecommander.filestreamer.TypeOfFile; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @Command(name = "list", description = "List directory of disk image(s).", aliases = { "ls" }) public class ListCommand extends ReadOnlyDiskImageCommandOptions { @ArgGroup(exclusive = true, multiplicity = "0..1", heading = "%nFile display formatting:%n") private FileDisplay fileDisplay = new FileDisplay(); @Option(names = { "-r", "--recursive"}, description = "Display directory recursively.", negatable = true, defaultValue = "false") private boolean recursiveFlag; @Option(names = { "--deleted" }, description = "Show deleted files.") private boolean deletedFlag; @ArgGroup(exclusive = true, multiplicity = "0..1") private TypeOfFileSelection typeOfFile = new TypeOfFileSelection(); @Option(names = "--header", negatable = true, description = "Show header.") private boolean headerFlag = true; @Option(names = "--column", negatable = true, description = "Show column headers.") private boolean columnFlag = true; @Option(names = "--footer", negatable = true, description = "Show footer.") private boolean footerFlag = true; @Option(names = "--globs", defaultValue = "*", split = ",", description = "File glob(s) to match.") private List globs = new ArrayList(); private List fmtSpec; @Override public int handleCommand() throws Exception { FileStreamer.forDisk(disk) .ignoreErrors(true) .includeDeleted(deletedFlag) .recursive(recursiveFlag) .includeTypeOfFile(typeOfFile.typeOfFile()) .matchGlobs(globs) .beforeDisk(this::header) .afterDisk(this::footer) .stream() .forEach(this::list); return 0; } protected void header(FormattedDisk disk) { List headers = disk.getFileColumnHeaders(fileDisplay.format()); fmtSpec = createFormatSpec(headers); System.out.println(); System.out.printf("File: %s\n", disk.getFilename()); System.out.printf("Name: %s\n", disk.getDiskName()); } protected void list(FileTuple tuple) { if (!deletedFlag && tuple.fileEntry.isDeleted()) { return; } List data = tuple.fileEntry.getFileColumnData(fileDisplay.format()); for (int i=0; i createFormatSpec(List fileColumnHeaders) { List fmtSpec = new ArrayList<>(); for (FileColumnHeader h : fileColumnHeaders) { String spec = String.format("%%%s%ds ", h.isRightAlign() ? "" : "-", h.getMaximumWidth()); fmtSpec.add(spec); } return fmtSpec; } public static class FileDisplay { public int format() { if (standardFormat) { return FormattedDisk.FILE_DISPLAY_STANDARD; } if (longFormat) { return FormattedDisk.FILE_DISPLAY_DETAIL; } return FormattedDisk.FILE_DISPLAY_NATIVE; } @Option(names = { "-n", "--native" }, description = "Use native directory format (default).") private boolean nativeFormat; @Option(names = { "-s", "--short", "--standard" }, description = "Use brief directory format.") private boolean standardFormat; @Option(names = { "-l", "--long", "--detail" }, description = "Use long/detailed directory format.") private boolean longFormat; } public static class TypeOfFileSelection { public TypeOfFile typeOfFile() { if (filesOnly) { return TypeOfFile.FILE; } if (directoriesOnly) { return TypeOfFile.DIRECTORY; } return TypeOfFile.BOTH; } @Option(names = "--file", description = "Only include files.") private boolean filesOnly; @Option(names = "--directory", description = "Only include directories.") private boolean directoriesOnly; } }