From 2c8d16f988488ca7558d474393f724f3a4d2fc5c Mon Sep 17 00:00:00 2001 From: TJ Holowaychuk Date: Sat, 18 Nov 2017 17:11:19 -0800 Subject: [PATCH] Initial commit --- Readme.md | 23 ++++++++++++++ main.go | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 Readme.md create mode 100644 main.go diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e50e5a0 --- /dev/null +++ b/Readme.md @@ -0,0 +1,23 @@ + + +## What? + +node-prune is a small tool to prune unecessary files from ./node_modules. + +## Why? + +[]!(https://pbs.twimg.com/media/DEIV_1XWsAAlY29.jpg) + +## Installation + +``` +$ go get github.com/tj/node-prune +``` + +--- + +[![GoDoc](https://godoc.org/github.com/tj/node-prune?status.svg)](https://godoc.org/github.com/tj/node-prune) +![](https://img.shields.io/badge/license-MIT-blue.svg) +![](https://img.shields.io/badge/status-stable-green.svg) + + diff --git a/main.go b/main.go new file mode 100644 index 0000000..140bee6 --- /dev/null +++ b/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "flag" + "os" + "path/filepath" + "sync/atomic" + "time" + + "github.com/apex/log" + "github.com/apex/log/handlers/text" + "github.com/dustin/go-humanize" + "github.com/pkg/errors" +) + +func init() { + log.SetHandler(text.Default) +} + +func main() { + debug := flag.Bool("verbose", false, "Verbose log output.") + flag.Parse() + dir := flag.Arg(0) + + start := time.Now() + + if dir == "" { + dir = "node_modules" + } + + if *debug { + log.SetLevel(log.DebugLevel) + } + + stats, err := prune(dir) + if err != nil { + log.Fatalf("error: %s", err) + } + + log.WithFields(log.Fields{ + "files_total": humanize.Comma(stats.FilesTotal), + "files_removed": humanize.Comma(stats.FilesRemoved), + "size_removed": humanize.Bytes(uint64(stats.SizeRemoved)), + "duration": time.Since(start).Round(time.Millisecond).String(), + }).Info("complete") +} + +// Stats of the prune. +type Stats struct { + FilesTotal int64 + FilesRemoved int64 + SizeRemoved int64 +} + +// prune files in dir. +func prune(dir string) (*Stats, error) { + var stats Stats + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + atomic.AddInt64(&stats.FilesTotal, 1) + + if !prunable(path, info) { + return nil + } + + log.WithField("path", path).Debug("prune") + atomic.AddInt64(&stats.FilesRemoved, 1) + atomic.AddInt64(&stats.SizeRemoved, info.Size()) + if err := os.Remove(path); err != nil { + return errors.Wrap(err, "removing") + } + + return nil + }) + + return &stats, err +} + +// prunable returns true if the file should be pruned. +func prunable(path string, info os.FileInfo) bool { + ext := filepath.Ext(path) + return ext == ".ts" || ext == ".md" +}