Skip to content

Commit 5433ab7

Browse files
committed
Fix bugs
1 parent 3d10b14 commit 5433ab7

File tree

5 files changed

+180
-126
lines changed

5 files changed

+180
-126
lines changed

.github/workflows/release.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ name: goreleaser
22

33
on:
44
push:
5-
branches:
6-
- master
75
tags:
86
- 'v*.*'
97

common/file.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"sync"
8+
)
9+
10+
// Touch file
11+
func Touch(filename *string, dirMutex *sync.Mutex, maxRetry int) bool {
12+
touched := false
13+
ext := filepath.Ext(*filename)
14+
baseName := (*filename)[:len(*filename)-len(ext)]
15+
dirMutex.Lock()
16+
defer dirMutex.Unlock()
17+
for i := 1; i < maxRetry; i++ {
18+
_, err := os.Stat(*filename)
19+
// if file exist
20+
if err == nil {
21+
*filename = fmt.Sprintf("%s (%d)%s", baseName, i, ext)
22+
} else if os.IsNotExist(err) {
23+
// touch
24+
_, err := os.OpenFile(*filename, os.O_RDONLY|os.O_CREATE, 0644)
25+
if err == nil {
26+
touched = true
27+
}
28+
break
29+
}
30+
}
31+
return touched
32+
}

common/logger.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package common
2+
3+
import (
4+
"io"
5+
"log"
6+
"os"
7+
)
8+
9+
func GetLogger(id string) *log.Logger {
10+
// create log file and init logger
11+
logFile, err := os.OpenFile(id+".log", os.O_WRONLY|os.O_CREATE, 0644)
12+
if err != nil {
13+
logger := log.New(os.Stdout, "", log.LstdFlags)
14+
logger.Println(Red("Cannot Create Log File"))
15+
return logger
16+
}
17+
logger := log.New(io.MultiWriter(os.Stdout, logFile), "", log.LstdFlags)
18+
return logger
19+
}

compressor.go

Lines changed: 33 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ package main
33
import (
44
"bytes"
55
"compressor/common"
6-
"encoding/json"
76
"flag"
87
"fmt"
98
"image"
109
"image/jpeg"
1110
_ "image/png"
12-
"io"
1311
"io/ioutil"
1412
"log"
1513
"os"
@@ -21,34 +19,26 @@ import (
2119
"time"
2220
)
2321

24-
type Config struct {
25-
ThreadCount int `json:"thread_count"`
26-
InputFormat []string `json:"input_format"`
27-
InputPath string `json:"input_path"`
28-
OutputPath string `json:"output_path"`
29-
Quality int `json:"quality"`
30-
}
31-
3222
type node struct {
3323
Input string
3424
Output string
3525
}
3626

37-
const OutputFormat = ".jpg"
27+
var (
28+
id string // use unix timestamp as id
29+
logger *log.Logger // global logger
30+
config *Config // from json
31+
failList []node // gather all failed jobs for summary
32+
)
3833

34+
// runtime variable
3935
var (
40-
id string // use unix timestamp as id
41-
logger *log.Logger
42-
config Config // from json
43-
total, count int32 // the number of images
44-
acceptFormat map[string]bool
45-
jpegQuality *jpeg.Options
46-
failList []node // gather all failed jobs for summary
47-
nodeCh chan node
48-
failCh chan node
49-
wg = sync.WaitGroup{}
50-
dirMutex = sync.Mutex{}
51-
travelDone = false
36+
total, count int32 // the number of images
37+
wg *sync.WaitGroup // thread limit
38+
dirMutex *sync.Mutex // dir lock for creating file
39+
travelDone bool // if travel is finished
40+
nodeCh chan node // task channel
41+
failCh chan node // task channel
5242
)
5343

5444
func init() {
@@ -57,77 +47,18 @@ func init() {
5747
configPathPtr := flag.String("c", "config.json", "Configuration Filepath")
5848
flag.Parse()
5949

60-
// init process id
50+
// initialize process id
6151
id = strconv.FormatInt(time.Now().Unix(), 10)
6252

63-
// create log file and init logger
64-
logFile, err := os.OpenFile(id+".log", os.O_WRONLY|os.O_CREATE, 0644)
65-
if err != nil {
66-
logger = log.New(os.Stdout, "", log.LstdFlags)
67-
logger.Println(common.Red("Cannot Create Log File"))
68-
} else {
69-
logger = log.New(io.MultiWriter(os.Stdout, logFile), "", log.LstdFlags)
70-
}
53+
// initialize logger
54+
logger = common.GetLogger(id)
7155

72-
// load json
73-
configFile, err := ioutil.ReadFile(*configPathPtr)
74-
if err != nil {
75-
logger.Println(common.Red("Config File Load Failed"))
76-
os.Exit(1)
77-
}
56+
// parse config file
57+
config = ParseConfig(configPathPtr)
7858

79-
// parse json
80-
if err := json.Unmarshal(configFile, &config); err != nil {
81-
logger.Println(common.Red("Json Unmarshal Failed"))
82-
os.Exit(1)
83-
}
84-
85-
// check quality
86-
if config.Quality <= 0 || config.Quality > 100 {
87-
logger.Println(common.Red("Quality Value Should Between 1 and 100"))
88-
os.Exit(1)
89-
}
90-
jpegQuality = &jpeg.Options{Quality: config.Quality}
91-
92-
// check input path
93-
if inputInfo, err := os.Stat(config.InputPath); err != nil {
94-
if os.IsNotExist(err) {
95-
logger.Println(common.Red("Input Path Not Found"))
96-
os.Exit(1)
97-
}
98-
if !inputInfo.IsDir() {
99-
logger.Println(common.Red("Input Path Should Be a Directory"))
100-
os.Exit(1)
101-
}
102-
}
103-
104-
// check output path
105-
if config.OutputPath != "" {
106-
if config.InputPath == config.OutputPath {
107-
logger.Println(common.Red("Output Path Cannot Be Same As Input Path"))
108-
os.Exit(1)
109-
}
110-
if _, err := os.Stat(config.OutputPath); err != nil {
111-
if os.IsNotExist(err) {
112-
if e := os.MkdirAll(config.OutputPath, 0755); e != nil {
113-
logger.Println(common.Red("Create Output Path Failed"))
114-
os.Exit(1)
115-
}
116-
}
117-
}
118-
} else {
119-
config.OutputPath = config.InputPath + "_" + id
120-
if e := os.Mkdir(config.OutputPath, 0755); e != nil {
121-
logger.Println(common.Red("Create Output Path Failed"))
122-
os.Exit(1)
123-
}
124-
}
125-
126-
// initialize accept input format
127-
acceptFormat = make(map[string]bool)
128-
for _, v := range config.InputFormat {
129-
acceptFormat[fmt.Sprintf(".%s", v)] = true
130-
}
59+
travelDone = false
60+
dirMutex = &sync.Mutex{}
61+
wg = &sync.WaitGroup{}
13162

13263
// initialize channel
13364
nodeCh = make(chan node, 32768)
@@ -146,8 +77,8 @@ func travel() {
14677
return e
14778
}
14879
if !info.IsDir() {
149-
if ext := strings.ToLower(filepath.Ext(info.Name())); acceptFormat[ext] {
150-
newPath := filepath.Join(config.OutputPath, filepath.Base(path))
80+
if ext := strings.ToLower(filepath.Ext(info.Name())); config.acceptFormat[ext] {
81+
newPath := filepath.Join(config.OutputPath, path[len(config.InputPath):])
15182
newPath = strings.TrimSuffix(newPath, filepath.Ext(newPath)) + OutputFormat
15283
if err := os.MkdirAll(filepath.Dir(newPath), 0755); err != nil {
15384
logger.Println(common.Red("Create New Path Failed"))
@@ -166,28 +97,6 @@ func travel() {
16697
travelDone = true
16798
}
16899

169-
// touch file
170-
func touch(filename *string) bool {
171-
dirMutex.Lock()
172-
defer dirMutex.Unlock()
173-
touched := false
174-
for i := 0; i < 7; i++ {
175-
_, err := os.Stat(*filename)
176-
// if file exist
177-
if err == nil {
178-
*filename = fmt.Sprintf("%s (%d)%s", (*filename)[:len(*filename)-len(OutputFormat)], i, OutputFormat)
179-
} else if os.IsNotExist(err) {
180-
// touch
181-
_, err := os.OpenFile(*filename, os.O_RDONLY|os.O_CREATE, 0644)
182-
if err == nil {
183-
touched = true
184-
}
185-
break
186-
}
187-
}
188-
return touched
189-
}
190-
191100
// compress job, multiple goroutine
192101
func compress() {
193102
defer wg.Done()
@@ -202,7 +111,7 @@ func compress() {
202111
continue
203112
}
204113

205-
if !touch(&n.Output) {
114+
if !common.Touch(&n.Output, dirMutex, MaxRenameRetry) {
206115
failCh <- n
207116
continue
208117
}
@@ -214,7 +123,7 @@ func compress() {
214123
}
215124

216125
buf := new(bytes.Buffer)
217-
err = jpeg.Encode(buf, img, jpegQuality)
126+
err = jpeg.Encode(buf, img, config.jpegQuality)
218127
if err != nil {
219128
failCh <- n
220129
continue
@@ -239,27 +148,27 @@ func compress() {
239148
} else {
240149
logger.Printf("%s %s %s %s",
241150
common.Purple(fmt.Sprintf("(%d/loading)", v+1)),
242-
n.Input, common.Green("->"), n.Output) }
151+
n.Input, common.Green("->"), n.Output)
152+
}
243153
}
244154
}
245155

246156
func process() {
247157
defer close(failCh)
248158

249-
logger.Println(common.Blue("========= Pending ========="))
250-
// travel filepath
251-
wg.Add(1)
252-
go travel()
253-
254159
// transfer
255-
// cuz failCh sender is about to close and buffer is limited
256160
// when process finished, failCh will be closed
257161
go func() {
258162
for n := range failCh {
259163
failList = append(failList, n)
260164
}
261165
}()
262166

167+
logger.Println(common.Blue("========= Pending ========="))
168+
// travel filepath
169+
wg.Add(1)
170+
go travel()
171+
263172
// multi-thread compress
264173
for i := 0; i < config.ThreadCount; i++ {
265174
wg.Add(1)
@@ -289,7 +198,7 @@ func main() {
289198

290199
func usage() {
291200
_, _ = fmt.Fprintf(os.Stderr,
292-
`Version: 2.0
201+
`Version: 2.1
293202
Usage: compressor [-h] [-c filename]
294203
295204
Options:

0 commit comments

Comments
 (0)