Passed
Push — master ( 6a9844...07bc4c )
by Valentin
01:50
created

cmd.packHeaders   A

Complexity

Conditions 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
package cmd
2
3
import (
4
	"fmt"
5
	"github.com/spf13/cobra"
6
	"github.com/vvval/go-metadata-scanner/cmd/scancmd"
7
	"github.com/vvval/go-metadata-scanner/cmd/scancmd/writers"
8
	"github.com/vvval/go-metadata-scanner/config"
9
	"github.com/vvval/go-metadata-scanner/etool"
10
	"github.com/vvval/go-metadata-scanner/util"
11
	"github.com/vvval/go-metadata-scanner/util/log"
12
	"github.com/vvval/go-metadata-scanner/util/rand"
13
	"github.com/vvval/go-metadata-scanner/util/scan"
14
	"github.com/vvval/go-metadata-scanner/vars"
15
	"os"
16
	"path/filepath"
17
	"sync"
18
)
19
20
var (
21
	scanFlags    scancmd.Flags
22
	PoolSize     = 10
23
	MinChunkSize = 5
24
)
25
26
func init() {
27
	// cmd represents the scan command
28
	var cmd = &cobra.Command{
29
		Use:   "scan",
30
		Short: "Scan folder and write metadata into the output file.",
31
		Long: `Scan folder and write metadata into the output file.
32
By default output file is a "csv" file.`,
33
		Run: func(cmd *cobra.Command, args []string) {
34
			err := scanHandler(scanFlags, config.App, PoolSize, MinChunkSize)
35
			if err != nil {
36
				log.Failure("Output writer", err.Error())
37
				os.Exit(1)
38
			}
39
		},
40
	}
41
42
	rootCmd.AddCommand(cmd)
43
	scanFlags.Fill(cmd)
44
}
45
46
func scanHandler(flags scancmd.Flags, appConfig config.AppConfig, initialPoolSize, minChunkSize int) error {
47
	if flags.Verbosity() {
48
		log.Visibility.Debug = true
49
		log.Visibility.Log = true
50
		log.Visibility.Command = true
51
	}
52
53
	log.Log("Scanning...", fmt.Sprintf("Directory is \"%s\"", util.Abs(flags.Directory())))
54
55
	var files = scan.MustDir(flags.Directory(), appConfig.Extensions())
56
	poolSize, chunkSize := util.AdjustSizes(len(files), initialPoolSize, minChunkSize)
57
58
	var chunks = make(chan vars.Chunk)
59
	var scannedFiles = make(chan vars.File)
60
	var wg sync.WaitGroup
61
	scancmd.CreatePool(
62
		&wg,
63
		poolSize,
64
		chunks,
65
		func(files vars.Chunk) ([]byte, error) {
66
			return etool.Read(files, appConfig.Fields())
67
		},
68
		func(data []byte) {
69
			for _, parsed := range etool.Parse(data) {
70
				scannedFiles <- parsed
71
			}
72
		},
73
	)
74
75
	for _, chunk := range files.Split(chunkSize) {
76
		wg.Add(1)
77
		chunks <- chunk
78
	}
79
80
	go func() {
81
		wg.Wait()
82
		close(chunks)
83
		close(scannedFiles)
84
	}()
85
86
	outputFilename := randomizeOutputFilename(flags.Filename())
87
88
	headers := packHeaders(appConfig.Fields())
89
	wr, err := writers.Get(flags.Format())
90
	if err != nil {
91
		return err
92
	}
93
94
	err = wr.Open(outputFilename, headers)
95
	if err != nil {
96
		return err
97
	}
98
	defer wr.Close()
99
100
	for file := range scannedFiles {
101
		file.WithRelPath(flags.Directory())
102
		err := wr.Write(&file)
103
		if err != nil {
104
			log.Failure("CSV write", fmt.Sprintf("failed writing data for \"%s\" file", file.RelPath()))
105
		}
106
	}
107
108
	log.Done("Scanning completed", fmt.Sprintf("Output file is \"%s\" file", outputFilename))
109
110
	return nil
111
}
112
113
func randomizeOutputFilename(path string) string {
114
	ext := filepath.Ext(path)
115
	dir := filepath.Dir(path)
116
	base := filepath.Base(path)
117
	hash := rand.Strings(10)
118
119
	return filepath.Join(dir, base[0:len(base)-len(ext)]+"-"+hash+ext)
120
}
121
122
func packHeaders(fields []string) []string {
123
	headers := []string{"Filename"}
124
125
	for _, field := range fields {
126
		headers = append(headers, field)
127
	}
128
129
	return headers
130
}
131