Files

136 lines
2.7 KiB
Go

package executor
import (
"context"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
)
// runFileEmpty implements `kopsc file empty`: find empty files and directories.
func runFileEmpty(ctx context.Context, req BuiltinRequest) error {
opts, err := parseFileEmptyArgs(req.Args)
if err != nil {
return err
}
root, err := filepath.Abs(opts.path)
if err != nil {
return fmt.Errorf("无法解析路径 %q: %w", opts.path, err)
}
var emptyFiles []string
var emptyDirs []string
err = filepath.WalkDir(root, func(path string, d fs.DirEntry, walkErr error) error {
if walkErr != nil {
return nil
}
if err := ctx.Err(); err != nil {
return err
}
if d.IsDir() {
// Check if directory is empty
entries, err := os.ReadDir(path)
if err != nil {
return nil
}
if len(entries) == 0 && path != root {
rel, _ := filepath.Rel(root, path)
if rel == "" {
rel = path
}
emptyDirs = append(emptyDirs, rel)
}
return nil
}
// Check if file is empty
info, err := d.Info()
if err != nil {
return nil
}
if info.Size() == 0 {
rel, _ := filepath.Rel(root, path)
if rel == "" {
rel = path
}
emptyFiles = append(emptyFiles, rel)
}
return nil
})
if err != nil {
return err
}
sort.Strings(emptyFiles)
sort.Strings(emptyDirs)
if !opts.dirsOnly {
if len(emptyFiles) == 0 {
fmt.Fprintln(req.Stdout, "没有空文件")
} else {
fmt.Fprintf(req.Stdout, "=== 空文件 (%d 个) ===\n", len(emptyFiles))
for _, f := range emptyFiles {
fmt.Fprintln(req.Stdout, f)
}
fmt.Fprintln(req.Stdout)
}
}
if !opts.filesOnly {
if len(emptyDirs) == 0 {
fmt.Fprintln(req.Stdout, "没有空目录")
} else {
fmt.Fprintf(req.Stdout, "=== 空目录 (%d 个) ===\n", len(emptyDirs))
for _, d := range emptyDirs {
fmt.Fprintln(req.Stdout, d)
}
}
}
return nil
}
type fileEmptyOptions struct {
path string
filesOnly bool
dirsOnly bool
}
func parseFileEmptyArgs(args []string) (fileEmptyOptions, error) {
opts := fileEmptyOptions{path: "."}
var paths []string
for i := 0; i < len(args); i++ {
arg := args[i]
switch {
case arg == "--":
paths = append(paths, args[i+1:]...)
i = len(args)
case arg == "--files-only":
opts.filesOnly = true
case arg == "--dirs-only":
opts.dirsOnly = true
case strings.HasPrefix(arg, "-") && arg != "-":
return opts, fmt.Errorf("未知选项 %q", arg)
default:
paths = append(paths, arg)
}
}
if len(paths) > 1 {
return opts, fmt.Errorf("一次只支持一个路径,收到 %d 个", len(paths))
}
if len(paths) == 1 {
opts.path = paths[0]
}
if opts.filesOnly && opts.dirsOnly {
return opts, fmt.Errorf("--files-only 和 --dirs-only 不能同时使用")
}
return opts, nil
}