commit
86ae761d1b
@ -0,0 +1,2 @@
|
||||
emacs-cleaner
|
||||
*~
|
@ -0,0 +1,9 @@
|
||||
|
||||
all: clean emacs-cleaner
|
||||
|
||||
clean:
|
||||
rm -f emacs-cleaner
|
||||
|
||||
emacs-cleaner:
|
||||
go build emacs-cleaner.go
|
||||
strip $@
|
@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"./semaphore"
|
||||
"io/ioutil"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"flag"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"path"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const VERSION string = "0.1.0"
|
||||
|
||||
func walk(rpath string, lock *semaphore.Semaphore, output chan string, wait *sync.WaitGroup) error {
|
||||
defer wait.Done()
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
|
||||
if files, err := ioutil.ReadDir(rpath); err == nil {
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
wait.Add(1)
|
||||
go walk(path.Join(rpath, file.Name()), lock, output, wait)
|
||||
|
||||
} else {
|
||||
output <- path.Join(rpath, file.Name())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return errors.Wrap(err, "failed to read dir")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var work_re *regexp.Regexp = regexp.MustCompile("~$")
|
||||
func work_on(file string) bool {
|
||||
return work_re.MatchString(file)
|
||||
}
|
||||
|
||||
func main() {
|
||||
dry := flag.Bool("dry", false, "Dry run")
|
||||
threads := flag.Int("threads", 10, "Number of threads to use")
|
||||
help := flag.Bool("help", false, "Print this message")
|
||||
flag.Parse()
|
||||
|
||||
dirs := flag.Args()
|
||||
if *help || len(dirs)<1 {
|
||||
fmt.Printf("Emacs Cleaner version %v\nDelete emacs filesystem clutter\n\n", VERSION)
|
||||
fmt.Println("$ emacs-cleaner [--threads <threads> [--dry] <dirs...>")
|
||||
fmt.Println("$ emacs-cleaner [--help]\n")
|
||||
|
||||
flag.PrintDefaults()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if *threads<1 {
|
||||
fmt.Printf("[e] cannot use %v threads\n", threads)
|
||||
return
|
||||
}
|
||||
|
||||
if *dry {
|
||||
fmt.Printf("[i] dry run, will not modify\n")
|
||||
}
|
||||
lock := semaphore.New(*threads)
|
||||
operate := make(chan string, 0)
|
||||
var wait sync.WaitGroup
|
||||
var used uint64 = 0
|
||||
|
||||
go func() {
|
||||
for file := range operate {
|
||||
if stat, err := os.Stat(file); err == nil {
|
||||
if !stat.IsDir() && work_on(file) {
|
||||
fmt.Printf(" -> %v\n", file)
|
||||
if !*dry {
|
||||
os.Remove(file)
|
||||
}
|
||||
atomic.AddUint64(&used, 1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
for _, dir := range dirs {
|
||||
if d, err:= os.Stat(dir); err == nil && d.IsDir() {
|
||||
wait.Add(1)
|
||||
go walk(dir, lock, operate, &wait)
|
||||
} else if err != nil {
|
||||
fmt.Printf("[w] cannot stat %v: %v\n", dir, err)
|
||||
} else {
|
||||
fmt.Printf("[w] %v is not a directory\n", dir)
|
||||
}
|
||||
}
|
||||
wait.Wait()
|
||||
|
||||
close(operate)
|
||||
|
||||
fmt.Printf("deleted %v emacs temporary files\n", used)
|
||||
|
||||
lock.Close()
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package semaphore
|
||||
|
||||
type Semaphore struct {
|
||||
channel chan bool
|
||||
}
|
||||
|
||||
func New(max int) *Semaphore {
|
||||
this:= new(Semaphore)
|
||||
|
||||
this.channel = make(chan bool, max)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
func (sem* Semaphore) Close() {
|
||||
close(sem.channel)
|
||||
}
|
||||
|
||||
func (sem *Semaphore) Lock() {
|
||||
sem.channel <- true
|
||||
}
|
||||
|
||||
func (sem *Semaphore) Unlock() {
|
||||
<- sem.channel
|
||||
}
|
Loading…
Reference in new issue