Skip to content

Commit

Permalink
Merge pull request #1 from kemokemo/add-delete-flag
Browse files Browse the repository at this point in the history
add delete flag
  • Loading branch information
kemokemo authored Jun 30, 2020
2 parents 99068fa + 9b42858 commit 74e9d04
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- run: go get github.com/mitchellh/gox
- run: go get github.com/tcnksm/ghr
- run: mkdir release
- run: gox -output "./release/{{.Dir}}_{{.OS}}_{{.Arch}}" ./ ./...
- run: gox -ldflags="-X 'main.revision=$(git rev-parse --short HEAD)'" -output "./release/{{.Dir}}_{{.OS}}_{{.Arch}}" ./ ./...
- run: ghr -u $CIRCLE_PROJECT_USERNAME $CIRCLE_TAG release/

workflows:
Expand Down
37 changes: 32 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,48 @@ $ furit -h
Usage: furit [<option>...] <1st path> <2nd path>...
you can set mutiple paths to search invalid images.

-h display help
-d, -delete:
delete unlinked image files (with confirmation)

-f, -force:
delete unlinked image files without prompting for confirmation

-h, -help:
display help

-v, -version:
display version
```

Currently, only Markdown format is supported as text to find links to images.

### Example

```
$ furit lib/test-data/markdown
lib/test-data/markdown/assets/画面.bmp
lib/test-data/markdown/テスト.gif
```sh
$ furit content
content/posts/assets/some_screen.bmp
content/posts/assets/logo.gif
```

This tool looks recursively for the folder you specify, finds links to images in the text it finds, and enumerates the unlinked image files from text.

```sh
$ furit -d content
content/posts/assets/some_screen.bmp
content/posts/assets/logo.gif
Are you sure to delete these unlinked images? [y/n]: n
the file deletion process has been canceled by user input
```

If you want to delete unwanted images found by the tool while reviewing them, specify only the `-d` flag.

```sh
$ furit -d -f content
content/posts/assets/some_screen.bmp
content/posts/assets/logo.gif
```

You can also specify the `-f` flag if you want to run the process of deletion automatically without confirmation. In that case, the list of files to be deleted will still be printed.
## License

[MIT](https://github.com/kemokemo/furit/blob/master/LICENSE)
Expand Down
32 changes: 32 additions & 0 deletions confirm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"bufio"
"fmt"
"io"
"strings"
)

// ** original code: https://gist.github.com/r0l1/3dcbb0c8f6cfe9c66ab8008f55f8f28b
// askForConfirmation returns whether or not the user agrees to the process.
func askForConfirmation(s string, in io.Reader, out io.Writer, retry int) (bool, error) {
reader := bufio.NewReader(in)

for ; retry > 0; retry-- {
fmt.Fprintf(out, "%s [y/n]: ", s)

res, err := reader.ReadString('\n')
if err != nil {
return false, fmt.Errorf("failed to read user input: %s", err)
}

res = strings.ToLower(strings.TrimSpace(res))
if res == "y" || res == "yes" {
return true, nil
} else if res == "n" || res == "no" {
return false, nil
}
}

return false, fmt.Errorf("retry count has been reached")
}
43 changes: 43 additions & 0 deletions confirm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"bytes"
"io"
"testing"
)

func Test_askForConfirmation(t *testing.T) {
type args struct {
s string
in io.Reader
retry int
}
tests := []struct {
name string
args args
want bool
wantOut string
wantErr bool
}{
{"yes", args{"Are you sure to delete it?", bytes.NewBufferString("y\n"), 2}, true, "Are you sure to delete it? [y/n]: ", false},
{"no", args{"Are you sure to delete it?", bytes.NewBufferString("n\n"), 2}, false, "Are you sure to delete it? [y/n]: ", false},
{"no EOF", args{"Are you sure to delete it?", bytes.NewBufferString("hoge"), 2}, false, "Are you sure to delete it? [y/n]: ", true},
{"invalid input", args{"Are you sure to delete it?", bytes.NewBufferString("foo\nbar\n"), 2}, false, "Are you sure to delete it? [y/n]: Are you sure to delete it? [y/n]: ", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
out := &bytes.Buffer{}
got, err := askForConfirmation(tt.args.s, tt.args.in, out, tt.args.retry)
if (err != nil) != tt.wantErr {
t.Errorf("askForConfirmation() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("askForConfirmation() = %v, want %v", got, tt.want)
}
if gotOut := out.String(); gotOut != tt.wantOut {
t.Errorf("askForConfirmation() = %v, want %v", gotOut, tt.wantOut)
}
})
}
}
65 changes: 59 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"testing"

furit "github.com/kemokemo/furit/lib"
)
Expand All @@ -19,6 +20,18 @@ const (
const (
usage = `Usage: furit [<option>...] <1st path> <2nd path>...
you can set mutiple paths to search invalid images.`

flags = `-d, -delete:
delete unlinked image files (with confirmation)
-f, -force:
delete unlinked image files without prompting for confirmation
-h, -help:
display help
-v, -version:
display version`
)

var (
Expand All @@ -30,11 +43,22 @@ var (

// flags
var (
help bool
help bool
ver bool
delFlag bool
forceFlag bool
)

func init() {
testing.Init() // require Go 1.13 or later
flag.BoolVar(&help, "help", false, "display help")
flag.BoolVar(&help, "h", false, "display help")
flag.BoolVar(&ver, "version", false, "display version")
flag.BoolVar(&ver, "v", false, "display version")
flag.BoolVar(&delFlag, "delete", false, "delete unlinked image files")
flag.BoolVar(&delFlag, "d", false, "delete unlinked image files")
flag.BoolVar(&forceFlag, "force", false, "delete unlinked image files without prompting for confirmation")
flag.BoolVar(&forceFlag, "f", false, "delete unlinked image files without prompting for confirmation")
flag.Parse()
cmdArgs = flag.Args()
}
Expand All @@ -45,12 +69,15 @@ func main() {

func run(args []string) int {
if help {
fmt.Fprintf(out, "%s\n\n", usage)
flag.PrintDefaults()
fmt.Fprintf(out, "%s\n\n%s\n", usage, flags)
return exitCodeOK
}
if ver {
fmt.Fprintf(out, "%s version %s.%s\n", Name, Version, revision)
return exitCodeOK
}
if len(args) == 0 {
fmt.Fprintf(outerr, "path is empty. please set it.\n\n%v", usage)
fmt.Fprintf(outerr, "path is empty. please set it.\n\n%v\n", usage)
return exitCodeInvalidArgs
}

Expand All @@ -65,14 +92,14 @@ func run(args []string) int {

links, err := furit.Markdown.Find(root)
if err != nil {
fmt.Fprintf(outerr, "failed to find links: %v", err)
fmt.Fprintf(outerr, "failed to find links: %v\n", err)
exitCode = exitCodeInternalOperation
continue
}

imgPaths, err := furit.Image.Find(root)
if err != nil {
fmt.Fprintf(outerr, "failed to find image paths: %v", err)
fmt.Fprintf(outerr, "failed to find image paths: %v\n", err)
exitCode = exitCodeInternalOperation
continue
}
Expand All @@ -82,12 +109,38 @@ func run(args []string) int {
imgMap[link] = false
}

var delPaths []string
for _, imPath := range imgPaths {
_, ok := imgMap[imPath]
if !ok {
delPaths = append(delPaths, imPath)
fmt.Fprintln(out, imPath)
}
}

if !delFlag || len(delPaths) == 0 {
continue
}

if !forceFlag {
res, err := askForConfirmation("Are you sure to delete these unlinked images?", os.Stdin, out, 3)
if !res {
if err != nil {
fmt.Fprintf(outerr, "the file deletion process has been canceled: %s\n", err)
continue
} else {
fmt.Fprintln(outerr, "the file deletion process has been canceled by user input")
continue
}
}
}
for _, delPath := range delPaths {
e := os.Remove(delPath)
if e != nil {
fmt.Fprintf(outerr, "failed to remove file: %s\n", e)
exitCode = exitCodeInternalOperation
}
}
}

return exitCode
Expand Down
Loading

0 comments on commit 74e9d04

Please sign in to comment.