Skip to content

Commit acbce38

Browse files
committed
Upgraded library versions; General refactor; Quiet mode
1 parent 4fc4940 commit acbce38

File tree

5 files changed

+79
-61
lines changed

5 files changed

+79
-61
lines changed

entity/output_mode.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ const (
1010

1111
// OutputModes and their brief descriptions
1212
var OutputModes = map[string]string{
13-
OutputModeTextFile: "creates a text file in current directory with basic information",
14-
OutputModeCsvFile: "creates a csv file in current directory with detailed information",
1513
OutputModeStdOut: "just prints the report without creating any file",
16-
OutputModeJSON: "creates a JSON file in the current directory with basic information",
14+
OutputModeTextFile: "creates a text file in the output directory with basic information",
15+
OutputModeCsvFile: "creates a csv file in the output directory with detailed information",
16+
OutputModeJSON: "creates a JSON file in the output directory with basic information",
1717
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ go 1.22
55
require (
66
github.com/deckarep/golang-set/v2 v2.7.0
77
github.com/emirpasic/gods v1.18.1
8-
github.com/spf13/pflag v1.0.5
8+
github.com/spf13/pflag v1.0.6
99
github.com/stretchr/testify v1.10.0
10-
golang.org/x/text v0.21.0
10+
golang.org/x/text v0.22.0
1111
)
1212

1313
require (

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
1111
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1212
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
1313
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
14+
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
15+
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1416
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1517
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
1618
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -24,6 +26,8 @@ golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
2426
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
2527
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
2628
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
29+
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
30+
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
2731
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2832
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2933
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const (
3434
exitCodeErrorCreatingReport
3535
exitCodeInvalidOutputMode
3636
exitCodeReportFileCreationFailed
37-
exitCodeWritingToReportFileFailed
37+
exitCodeOutputDirectoryIsNotReadable
3838
)
3939

4040
const version = "1.8.0"
@@ -43,15 +43,15 @@ const version = "1.8.0"
4343
var defaultExclusionsStr string
4444

4545
var flags struct {
46-
isHelp func() bool
47-
getOutputMode func() string
48-
getExcludedFiles func() set.Set[string]
49-
getMinSize func() int64
50-
getParallelism func() int
51-
isThorough func() bool
52-
useStdout func() bool
53-
getVerbose func() bool
54-
getVersion func() bool
46+
isHelp func() bool
47+
getOutputMode func() string
48+
getExcludedFiles func() set.Set[string]
49+
getMinSize func() int64
50+
getParallelism func() int
51+
isThorough func() bool
52+
getOutputFilePath func() string
53+
getVersion func() bool
54+
isQuiet func() bool
5555
}
5656

5757
func setupExclusionsOpt() {
@@ -144,17 +144,19 @@ func setupOutputModeOpt() {
144144
}
145145
}
146146

147-
func setupStdoutOpt() {
148-
stdoutPtr := flag.Bool("stdout", false, "report output to stdout")
149-
flags.useStdout = func() bool {
150-
return *stdoutPtr
151-
}
152-
}
147+
const DefaultFileName = ""
153148

154-
func setupVerboseOpt() {
155-
verbosePtr := flag.Bool("verbose", false, "verbose output")
156-
flags.getVerbose = func() bool {
157-
return *verbosePtr
149+
func setupOutputFileOpt() {
150+
outputFilePathPtr := flag.StringP("outputfile", "f", DefaultFileName,
151+
"output file path (will be created, but directory needs to be writeable)")
152+
flags.getOutputFilePath = func() string {
153+
outputFilePath := *outputFilePathPtr
154+
outputDir := filepath.Dir(outputFilePath)
155+
if !utils.IsReadableDirectory(outputDir) { // Deliberately not checking whether directory is writable
156+
fmte.PrintfErr("error: output directory '%s' does not exist or is not readable\n", outputDir)
157+
os.Exit(exitCodeOutputDirectoryIsNotReadable)
158+
}
159+
return outputFilePath
158160
}
159161
}
160162

@@ -166,6 +168,14 @@ func setupVersionOpt() {
166168
}
167169
}
168170

171+
func setupQuietOpt() {
172+
isQuietPtr := flag.BoolP("quiet", "q", false,
173+
"quiet mode: no output on stdout/stderr, except for duplicates/errors")
174+
flags.isQuiet = func() bool {
175+
return *isQuietPtr
176+
}
177+
}
178+
169179
func setupUsage() {
170180
flag.Usage = func() {
171181
fmte.PrintfErr("Run \"go-find-duplicates --help\" for usage\n")
@@ -220,40 +230,34 @@ For more details: https://github.com/m-manu/go-find-duplicates
220230
}
221231

222232
func setupFlags() {
233+
setupUsage()
223234
setupExclusionsOpt()
224235
setupHelpOpt()
225236
setupMinSizeOpt()
226237
setupOutputModeOpt()
227238
setupParallelismOpt()
228-
setupStdoutOpt()
229239
setupThoroughOpt()
230-
setupUsage()
231-
setupVerboseOpt()
232240
setupVersionOpt()
241+
setupQuietOpt()
242+
setupOutputFileOpt()
233243
}
234244

235245
func generateRunID() string {
236246
return time.Now().Format("060102_150405")
237247
}
238248

239-
func createReportFileIfApplicable(runID string, outputMode string, useStdout bool) (string, io.WriteCloser) {
240-
if useStdout {
241-
return "", os.Stdout
242-
}
249+
func createReportFileIfApplicable(runID string, outputMode string) (string, io.WriteCloser) {
243250
var reportFileName string
244251
switch outputMode {
245-
case entity.OutputModeStdOut:
246-
return "", os.Stdout
247252
case entity.OutputModeCsvFile:
248253
reportFileName = fmt.Sprintf("./duplicates_%s.csv", runID)
249254
case entity.OutputModeTextFile:
250255
reportFileName = fmt.Sprintf("./duplicates_%s.txt", runID)
251256
case entity.OutputModeJSON:
252257
reportFileName = fmt.Sprintf("./duplicates_%s.json", runID)
253258
default:
254-
panic("unsupport output mode")
259+
panic("unsupported output mode - bug in code")
255260
}
256-
257261
f, err := os.Create(reportFileName)
258262
if err != nil {
259263
fmte.PrintfErr("error: couldn't create report file: %+v\n", err)
@@ -276,14 +280,29 @@ func main() {
276280
os.Exit(exitCodeSuccess)
277281
return
278282
}
279-
if !flags.getVerbose() {
283+
284+
if flags.isQuiet() {
280285
fmte.Off()
281286
}
282287

283288
directories := readDirectories()
284289
outputMode := flags.getOutputMode()
285-
reportFileName, reportFile := createReportFileIfApplicable(runID, outputMode, flags.useStdout())
286-
defer reportFile.Close()
290+
reportFileName := flags.getOutputFilePath()
291+
var reportFile io.Writer
292+
var fErr error
293+
if outputMode == entity.OutputModeStdOut {
294+
reportFile = os.Stdout
295+
} else { // For other modes
296+
if reportFileName == DefaultFileName {
297+
reportFileName, reportFile = createReportFileIfApplicable(runID, outputMode)
298+
} else {
299+
reportFile, fErr = os.Create(reportFileName)
300+
if fErr != nil {
301+
fmte.PrintfErr("error: couldn't create report file: %+v\n", fErr)
302+
os.Exit(exitCodeReportFileCreationFailed)
303+
}
304+
}
305+
}
287306

288307
duplicates, duplicateTotalCount, savingsSize, allFiles, fdErr :=
289308
service.FindDuplicates(directories, flags.getExcludedFiles(), flags.getMinSize(),
@@ -303,11 +322,12 @@ func main() {
303322
fmte.Printf("Found %d duplicates. A total of %s can be saved by removing them.\n",
304323
duplicateTotalCount, bytesutil.BinaryFormat(savingsSize))
305324

306-
err := reportDuplicates(duplicates, outputMode, allFiles, runID, reportFile)
307-
if err != nil {
308-
fmte.PrintfErr("error while reporting to file: %+v\n", err)
309-
os.Exit(exitCodeWritingToReportFileFailed)
310-
} else if reportFileName != "" {
325+
dErr := reportDuplicates(duplicates, outputMode, allFiles, runID, reportFile)
326+
if dErr != nil {
327+
fmte.PrintfErr("error while reporting to file: %+v\n", dErr)
328+
os.Exit(exitCodeErrorCreatingReport)
329+
}
330+
if reportFileName != DefaultFileName {
311331
fmte.Printf("View duplicates report here: %s\n", reportFileName)
312332
}
313333
}

report.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,22 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9-
"os"
109
"sort"
1110
"strconv"
1211
"time"
1312

1413
"github.com/m-manu/go-find-duplicates/entity"
15-
"github.com/m-manu/go-find-duplicates/fmte"
1614
)
1715

1816
const bytesPerLineGuess = 500
1917

2018
func reportDuplicates(duplicates *entity.DigestToFiles, outputMode string, allFiles entity.FilePathToMeta,
2119
runID string, reportFile io.Writer) error {
2220
var err error
23-
if outputMode == entity.OutputModeStdOut || outputMode == entity.OutputModeTextFile {
24-
reportBytes := getReportAsText(duplicates)
25-
if outputMode == entity.OutputModeTextFile {
26-
createTextFileReport(reportFile, reportBytes)
27-
} else if outputMode == entity.OutputModeStdOut {
28-
printReportToStdOut(runID, reportBytes)
29-
}
21+
if outputMode == entity.OutputModeStdOut {
22+
printReportToStdOut(runID, duplicates)
23+
} else if outputMode == entity.OutputModeTextFile {
24+
err = createTextFileReport(duplicates, reportFile)
3025
} else if outputMode == entity.OutputModeCsvFile {
3126
err = createCsvReport(duplicates, allFiles, reportFile)
3227
} else if outputMode == entity.OutputModeJSON {
@@ -35,12 +30,10 @@ func reportDuplicates(duplicates *entity.DigestToFiles, outputMode string, allFi
3530
return err
3631
}
3732

38-
func createTextFileReport(reportFile io.Writer, report bytes.Buffer) {
39-
_, rcErr := reportFile.Write(report.Bytes())
40-
if rcErr != nil {
41-
fmte.PrintfErr("error while write to report file: %+v\n", rcErr)
42-
os.Exit(exitCodeErrorCreatingReport)
43-
}
33+
func createTextFileReport(duplicates *entity.DigestToFiles, reportFile io.Writer) error {
34+
reportBB := getReportAsText(duplicates)
35+
_, rcErr := reportFile.Write(reportBB.Bytes())
36+
return rcErr
4437
}
4538

4639
func getReportAsText(duplicates *entity.DigestToFiles) bytes.Buffer {
@@ -57,13 +50,14 @@ func getReportAsText(duplicates *entity.DigestToFiles) bytes.Buffer {
5750
return bb
5851
}
5952

60-
func printReportToStdOut(runID string, bb bytes.Buffer) {
53+
func printReportToStdOut(runID string, duplicates *entity.DigestToFiles) {
54+
reportBB := getReportAsText(duplicates)
6155
fmt.Printf(`
6256
==========================
6357
Report (run id %s)
6458
==========================
6559
`, runID)
66-
fmt.Printf(bb.String())
60+
fmt.Println(reportBB.String())
6761
}
6862

6963
func createCsvReport(duplicates *entity.DigestToFiles, allFiles entity.FilePathToMeta, reportFile io.Writer) error {

0 commit comments

Comments
 (0)