-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
140 lines (118 loc) · 4.54 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
// A simple file browser written in Go.
package main
import (
"fmt"
"log"
"net/http"
"os"
"runtime/pprof"
"time"
flags "github.com/jessevdk/go-flags"
"github.com/meilisearch/meilisearch-go"
gitignore "github.com/sabhiram/go-gitignore"
)
// Config represents an app configuration.
type Config struct {
InfoDirectory string `env:"INPUT_INFO" short:"i" long:"info" description:"Directory that contains info files" default:"info"`
MediaDirectory string `env:"INPUT_MEDIA" short:"m" long:"media" description:"Directory that contains media files" default:""`
StaticDirectory string `env:"INPUT_STATIC" short:"s" long:"static" description:"Directory that contains static files" default:""`
ConfigFile string `env:"INPUT_CONFIG" short:"c" long:"config" description:"File that contains config" default:"config.yml"`
IgnoreFile string `env:"INPUT_IGNOREFILE" short:"f" long:"ignore" description:"File that contains ignore patterns" default:".ignore"`
TemplatesDirectory string `env:"INPUT_TEMPLATES" short:"t" long:"templates" description:"Directory that contains templates" default:"templates"`
OutputDirectory string `env:"INPUT_OUTPUT" short:"o" long:"output" description:"Directory to output static site" default:"output"`
MediaHost string `env:"INPUT_MEDIA_HOST" short:"M" long:"media-host" description:"Host for media" default:""`
SearchHost string `env:"INPUT_SEARCH_HOST" short:"h" long:"search-host" description:"Host for search" default:""`
SearchAPIKey string `env:"INPUT_SEARCH_API_KEY" short:"k" long:"search-api-key" description:"API key for search" default:""`
NumWorkers int `env:"INPUT_NUMWORKERS" short:"w" long:"workers" description:"Number of workers to use" default:"4"`
SearchMasterKey string `env:"INPUT_SEARCH_MASTER_KEY" long:"master-key" description:"search master key"`
SearchIndexName string `env:"INPUT_SEARCH_INDEX" long:"index" description:"search index name" default:"info"`
StateFile string `env:"INPUT_SEARCH_STATE" long:"state-file" description:"path to state file" default:".state"`
Force string `env:"INPUT_FORCE" long:"force" description:"force reindexing specified path (\"all\" will reindex everything)" default:""`
Timeout time.Duration `env:"INPUT_TIMEOUT" long:"timeout" description:"search timeout" default:"5s"`
Profile bool `env:"INPUT_PROFILE" long:"profile" description:"enable profiling"`
}
var cfg Config // global env config
func main() {
if _, err := flags.Parse(&cfg); err != nil {
log.Fatalf("Error parsing flags: %v", err)
}
fn := run
if cfg.Profile {
fn = profileWrapper(run, "cpu.pprof", "mem.pprof")
}
if err := fn(); err != nil {
log.Fatalf("Error %v", err)
}
}
func run() error {
ignore, err := processIgnoreFile(cfg.IgnoreFile)
if err != nil {
return fmt.Errorf("processing ignore file: %w", err)
}
generator, err := NewGenerator(ignore)
if err != nil {
return fmt.Errorf("creating generator: %v", err)
}
if err := generator.Run(); err != nil {
return fmt.Errorf("running generator: %v", err)
}
if cfg.SearchMasterKey != "" {
if err := indexSite(ignore, generator.hashes); err != nil {
return fmt.Errorf("indexing site: %v", err)
}
}
return nil
}
func indexSite(ignore *gitignore.GitIgnore, state map[string]string) error {
log.Printf("Current state contains %d entries", len(state))
client := meilisearch.New(
cfg.SearchHost,
meilisearch.WithAPIKey(cfg.SearchMasterKey),
meilisearch.WithCustomClient(&http.Client{
Timeout: cfg.Timeout,
}),
)
indexer, err := NewIndexer(
client,
ignore,
cfg.InfoDirectory,
cfg.MediaDirectory,
state,
)
if err != nil {
return fmt.Errorf("creating indexer: %v", err)
}
return indexer.Index(
cfg.StateFile,
cfg.SearchIndexName,
cfg.Force,
)
}
func profileWrapper(fn func() error, cpuProfile, memProfile string) func() error {
return func() error {
f, err := os.Create(cpuProfile)
if err != nil {
return fmt.Errorf("creating cpu profile: %v", err)
}
if err := pprof.StartCPUProfile(f); err != nil {
return fmt.Errorf("starting cpu profile: %v", err)
}
err = fn()
if err != nil {
return err
}
// Stop CPU profiling and take a memory snapshot
pprof.StopCPUProfile()
f, err = os.Create(memProfile)
if err != nil {
return fmt.Errorf("creating memory profile: %v", err)
}
if err := pprof.WriteHeapProfile(f); err != nil {
return fmt.Errorf("writing memory profile: %v", err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("closing memory profile: %v", err)
}
return nil
}
}