feat: add .gitignore, upgrade to Go 1.23 with deps, improve logging,
config loading, and glob-based deletion, and push image in deploy script
This commit is contained in:
162
main.go
162
main.go
@@ -2,79 +2,133 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
logger "git.site.quack-lab.dev/dave/cylogger"
|
||||
"github.com/bmatcuk/doublestar/v4"
|
||||
)
|
||||
|
||||
const (
|
||||
Black = "\033[30m"
|
||||
Red = "\033[31m"
|
||||
Green = "\033[32m"
|
||||
Yellow = "\033[33m"
|
||||
Blue = "\033[34m"
|
||||
Magenta = "\033[35m"
|
||||
Cyan = "\033[36m"
|
||||
White = "\033[37m"
|
||||
Reset = "\033[0m"
|
||||
PathColor = Magenta
|
||||
ErrorColor = Red
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Lmicroseconds | log.Lshortfile)
|
||||
logFile, err := os.Create("main.log")
|
||||
if err != nil {
|
||||
log.Printf("Error creating log file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
logger := io.MultiWriter(os.Stdout, logFile)
|
||||
log.SetOutput(logger)
|
||||
type Config struct {
|
||||
WorkDir string
|
||||
ScanSeconds int
|
||||
Patterns []string
|
||||
}
|
||||
|
||||
func main() {
|
||||
wd := flag.String("wd", "", "working directory")
|
||||
scanTimer := flag.Int("scan", 60, "scan interval in seconds")
|
||||
func getenv(key, def string) string {
|
||||
if v, ok := os.LookupEnv(key); ok {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func loadConfig() Config {
|
||||
flagWDir := flag.String("wd", "", "working directory")
|
||||
flagScan := flag.Int("scan", 60, "scan interval in seconds")
|
||||
logger.InitFlag()
|
||||
flag.Parse()
|
||||
|
||||
workdir := path.Clean(*wd)
|
||||
forbidden := flag.Args()
|
||||
envForbidden, ok := os.LookupEnv("FORBIDDEN")
|
||||
if ok {
|
||||
forbidden = append(forbidden, strings.Split(envForbidden, ",")...)
|
||||
workdir := filepath.Clean(*flagWDir)
|
||||
if pfx := strings.TrimSpace(getenv("PATH_PREFIX", "")); pfx != "" {
|
||||
workdir = filepath.Join(workdir, pfx)
|
||||
}
|
||||
pathPrefix, ok := os.LookupEnv("PATH_PREFIX")
|
||||
if ok {
|
||||
workdir = path.Join(workdir, pathPrefix)
|
||||
workdir = filepath.ToSlash(workdir)
|
||||
|
||||
// Gather patterns: args + FORBIDDEN env (comma-separated)
|
||||
patterns := []string{}
|
||||
patterns = append(patterns, flag.Args()...)
|
||||
if env := strings.TrimSpace(getenv("FORBIDDEN", "")); env != "" {
|
||||
for _, p := range strings.Split(env, ",") {
|
||||
p = strings.TrimSpace(p)
|
||||
if p != "" {
|
||||
patterns = append(patterns, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("Working directory: %s%s%s", PathColor, workdir, Reset)
|
||||
log.Printf("Forbidden files: %v", forbidden)
|
||||
|
||||
ticker := time.NewTicker(time.Duration(*scanTimer) * time.Second)
|
||||
for {
|
||||
log.Printf("Running at %s", time.Now().Format(time.RFC3339))
|
||||
for _, f := range forbidden {
|
||||
log.Printf("Checking file %s%s%s", PathColor, f, Reset)
|
||||
f = strings.Trim(f, " ")
|
||||
fullPath := path.Join(workdir, f)
|
||||
fullPath = path.Clean(fullPath)
|
||||
// Normalize patterns to slash style; patterns are relative to workdir
|
||||
for i := range patterns {
|
||||
patterns[i] = filepath.ToSlash(strings.TrimSpace(patterns[i]))
|
||||
}
|
||||
|
||||
_, err := os.Stat(fullPath)
|
||||
logger.Info("Config:")
|
||||
logger.Info(" WorkDir: %s", workdir)
|
||||
logger.Info(" ScanSeconds: %d", *flagScan)
|
||||
logger.Info(" Patterns: %v", patterns)
|
||||
|
||||
return Config{
|
||||
WorkDir: workdir,
|
||||
ScanSeconds: *flagScan,
|
||||
Patterns: patterns,
|
||||
}
|
||||
}
|
||||
|
||||
func deleteMatches(cfg Config) {
|
||||
log := logger.Default.WithPrefix("deleteMatches")
|
||||
|
||||
// Ensure workdir exists
|
||||
if cfg.WorkDir == "" {
|
||||
log.Error("WorkDir is empty")
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(cfg.WorkDir); err != nil {
|
||||
log.Error("WorkDir not accessible %s: %v", cfg.WorkDir, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, pat := range cfg.Patterns {
|
||||
if pat == "" {
|
||||
continue
|
||||
}
|
||||
// Use doublestar.Glob against the workdir FS; it returns relative paths
|
||||
matches, err := doublestar.Glob(os.DirFS(cfg.WorkDir), pat)
|
||||
if err != nil {
|
||||
log.Error("glob %q: %v", pat, err)
|
||||
continue
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
log.Debug("No matches for pattern %q", pat)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, rel := range matches {
|
||||
full := filepath.Join(cfg.WorkDir, rel)
|
||||
full = filepath.Clean(full)
|
||||
|
||||
info, err := os.Stat(full)
|
||||
if err != nil {
|
||||
log.Printf("Error stating file %s%s%s: %s%v%s", PathColor, fullPath, Reset, ErrorColor, err, Reset)
|
||||
log.Warning("stat %s: %v", full, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Removing file %s%s%s", PathColor, fullPath, Reset)
|
||||
err = os.RemoveAll(fullPath)
|
||||
if err != nil {
|
||||
log.Printf("Error removing file %s%s%s: %s%v%s", PathColor, fullPath, Reset, ErrorColor, err, Reset)
|
||||
if info.IsDir() {
|
||||
log.Info("Removing directory %s", full)
|
||||
} else {
|
||||
log.Info("Removing file %s", full)
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(full); err != nil {
|
||||
log.Error("remove %s: %v", full, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
<-ticker.C
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
logger.Info("Starting forbidden cleaner")
|
||||
|
||||
// Run immediately, then on interval
|
||||
deleteMatches(cfg)
|
||||
|
||||
ticker := time.NewTicker(time.Duration(cfg.ScanSeconds) * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
ts := <-ticker.C
|
||||
logger.Info("Tick %d", ts.UnixMilli())
|
||||
deleteMatches(cfg)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user