-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
175 lines (143 loc) · 4.73 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Description: Main entry point for the CLI application.
package main
import (
"context"
"fmt"
"imagetools/config"
"log"
"os"
"path/filepath"
"github.com/urfave/cli/v2"
)
// Get profile from home directory.
// This function will trying to get profile from `.imgtools` directory in home directory.
//
// profile_name: Profile name.
// create_dir: Create directory if not exists.
func getProfileFromHomeDir(profile_name string, create_dir bool) (path string, err error) {
// If profile name is empty, use `default``.
if profile_name == "" {
profile_name = "default"
}
profile_name = fmt.Sprintf("%s.yaml", profile_name) // Append `.yaml` extension.
home, err := os.UserHomeDir() // Get home directory.
if err != nil {
return "", err
}
profile_dir := filepath.Join(home, ".imgtools") // Profile directory.
profile_file := filepath.Join(home, ".imgtools", profile_name) // Profile file.
_, err = os.Stat(profile_dir) // Check profile directory.
if err != nil {
// If directory not exists and create_dir is true, create directory.
if os.IsNotExist(err) {
if create_dir { // Making profile directory if not exists.
err = os.Mkdir(profile_dir, 0777)
if err != nil {
return "", err
}
// Writing default profile.
err = os.WriteFile(profile_file, []byte(config.GenerateDefaultConfig().ToYaml()), 0777)
if err != nil {
return "", err
}
} else { // If create_dir is false, return error.
return "", err
}
} else {
return "", err
}
}
return profile_file, err
}
// Main function, defines arguments and flags.
func main() {
// Context for main worker.
ctx := context.Background()
app := &cli.App{
Name: "Image Processing CLI",
Usage: "Batch process images",
Authors: []*cli.Author{
{
Name: "h-alice",
Email: "[email protected]",
},
{
Name: "natlee",
Email: "[email protected]",
},
},
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "f",
Usage: "Config file path (can be specified multiple times)",
},
},
Action: func(c *cli.Context) error {
// Placeholder for input config file paths.
loaded_configs := make([]config.ProfileRoot, 0) // Placeholder for loaded configs.
// Placeholder for config root.
config_root := config.ProfileRoot{}
// First, check if any argument is specified.
if c.NArg() == 0 {
// Show help message.
cli.ShowAppHelpAndExit(c, 1)
}
// And then we chack if any image file is specified.
if c.Args().Len() == 0 {
cli.ShowAppHelp(c)
log.Printf("[!] No image file specified, check again your input.\n")
return nil
}
for _, path := range c.StringSlice("f") { // Iterate through input config file paths.
conf, err := config.LoadConfigFromFile(path) // Load config file.
if err != nil {
log.Printf("[!] Error (%s) while loading config file: %s The config file will be ignored.\n", err, path)
}
loaded_configs = append(loaded_configs, conf) // Append to loaded configs.
}
config_root = config.MergeConfigFiles(loaded_configs...) // Merge all loaded configs.
// If no profile specified, try to load default profile from home directory.
// If there still an error, exit the program.
if len(config_root.Profiles) == 0 {
log.Printf("[!] No profile specified. Trying to load default profile from home directory.\n")
config_path, err := getProfileFromHomeDir("default", true)
if err != nil {
log.Fatalf("[x] Cannot load default config file: %s\n", err)
}
config_root, err = config.LoadConfigFromFile(config_path) // Load default config file.
if err != nil {
log.Fatalf("[x] Cannot load default config file: %s\n", err)
}
}
// Iterate through input images.
for _, f := range c.Args().Slice() {
// Create result channel to capture return from goroutine.
result_chan := make(chan error) // Result channel.
// Currently, this function will only affect the `fileName` field in `write` block.
// This is a temporary solution to the issue which "write" block cannot get original input file name.
config_root.AssignInputFile(f)
// Check if the file exists.
_, err := os.Stat(f) // Check if file exists.
if err != nil {
log.Printf("[!] Input file not found: %s\n", f)
continue // Skip to next file.
}
// Dispatch goroutine for each profile.
for _, pf := range config_root.Profiles { // Apply all profile to input image.
// Process image in goroutine.
go mainWorker(ctx, pf, result_chan)
}
// Wait for all goroutines to finish.
for range config_root.Profiles {
<-result_chan
}
}
return nil
},
}
err := app.Run(os.Args) // Run the app.
if err != nil {
log.Fatalf("[x] Error: %v\n", err)
}
log.Printf("[+] All images processed.\n")
}