This repository has been archived by the owner on Apr 15, 2024. It is now read-only.
/
main.go
232 lines (206 loc) · 6.33 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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package main
import (
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"strings"
"sync"
"syscall"
"github.com/docopt/docopt-go"
ortfomk "github.com/ortfo/mk"
)
const CLIUsage = `
Usage:
ortfomk (build|develop) <templates> with <database> to <destination> [--load=<filepath>]... [options]
Commands:
build Build the website
develop Watch for changes and re-build automatically
Arguments:
<database> Path to the database JSON file
<templates> Path to the directory containing .pug or .html template files
<destination> Path to the output directory, where the site will be built.
Options:
--write-progress=<filepath> Write current build progress to <filepath>
--silent Don't output progress status to console
--clean Clean the output directory before building
--load=<filepath> Path to a JSON or YAML file containing additional data which
will be available to templates as objects (or arrays) whose names will
be the files', but without the extension, and turned into camelCase
(e.g. "my-data.json"'s data is available as "myData").
Build Progress:
For integration purposes, the current build progress can be written to a file.
The progress information is written as JSON, and has the following structure:
total: the total number of pages to process (multiple pages of the same template count as different pages).
processed: the number of pages processed so far.
percent: The current overall progress percentage of the build. Equal to processed/total * 100.
current: {
id: The id of the work being built.
step: The current step. One of: "thumbnail", "color extraction", "description", "media analysis"
resolution: The resolution of the thumbnail being generated. 0 when step is not "thumbnails"
file: The file being processed (
original media when making thumbnails or during media analysis,
media the colors are being extracted from, or
the description.md file when parsing description
)
output: The output file being generated.
language: The current language in which the page is being built.
}
`
func main() {
defer func() {
if r := recover(); r != nil {
ortfomk.LogFatal("ortfo/mk crashed… Here's why: %s", r)
}
}()
usage := CLIUsage
args, _ := docopt.ParseDoc(usage)
isSilent, _ := args.Bool("--silent")
clean, _ := args.Bool("--clean")
progressFilePath, _ := args.String("--write-progress")
outputDirectory, _ := args.String("<destination>")
templatesDirectory, _ := args.String("<templates>")
templatesDirectory, _ = filepath.Abs(templatesDirectory)
flags := ortfomk.Flags{
Silent: isSilent,
ProgressFile: progressFilePath,
}
configPath, _ := args.String("--config")
config, err := ortfomk.LoadConfiguration(configPath)
if err != nil {
ortfomk.LogError("Could not load configuration: %s", err)
return
}
additionalDataFiles, _ := args["--load"].([]string)
additionalData, err := ortfomk.LoadAdditionalData(append(additionalDataFiles, config.AdditionalData...))
if err != nil {
ortfomk.LogFatal("couldn't load data files %v: %s", additionalDataFiles, err)
return
}
ortfomk.WarmUp(&ortfomk.GlobalData{
Flags: flags,
OutputDirectory: outputDirectory,
TemplatesDirectory: templatesDirectory,
HTTPLinks: make(map[string][]string),
AdditionalData: additionalData,
Configuration: config,
})
defer ortfomk.CoolDown()
if os.Getenv("DEBUG") == "1" {
cpuProfileFile, err := os.Create("ortfomk_cpu.pprof")
if err != nil {
panic(err)
}
defer cpuProfileFile.Close()
pprof.StartCPUProfile(cpuProfileFile)
defer pprof.StopCPUProfile()
}
//
// Preparing dist directory
//
if _, err := os.Stat(outputDirectory); err == nil && clean {
os.RemoveAll(outputDirectory)
}
//
// Loading files
//
db, err := ortfomk.LoadDatabase("database")
if err != nil {
ortfomk.LogError("Could not load the database: %s", err)
return
}
translations, err := ortfomk.LoadTranslations()
if err != nil {
ortfomk.LogError("Couldn't load the translation files: %s", err)
return
}
ortfomk.SetTranslationsOnGlobalData(translations)
ortfomk.SetDatabaseOnGlobalData(db)
ortfomk.ComputeTotalToBuildCount()
var httpLinks map[string][]string
//
// Watch mode
//
if val, _ := args.Bool("develop"); val {
os.Setenv("ENV", "dev")
go ortfomk.StartDevServer("localhost:8899", "en")
_, httpLinks, err = ortfomk.BuildAll(templatesDirectory, 0)
if err != nil {
ortfomk.LogError("During initial build: %s", err)
}
ortfomk.StartWatcher(db)
} else {
_, httpLinks, err = ortfomk.BuildAll(templatesDirectory, 0)
if err != nil {
ortfomk.LogError("While building: %s", err)
}
for _, lang := range []string{"fr", "en"} {
// Save the updated .po file
translations[lang].SavePO()
// Save list of unused messages
err = translations[lang].WriteUnusedMessages()
if err != nil {
ortfomk.LogError("While writing unused message file: %s", err)
}
}
// Check for dead links
if os.Getenv("DEADLINKS_CHECK") != "0" {
ortfomk.Status(ortfomk.StepDeadLinks, ortfomk.ProgressDetails{})
noneDead := true
channel := make(chan string)
var wg sync.WaitGroup
workersCount := len(httpLinks)
wg.Add(workersCount)
for i := 0; i < workersCount; i++ {
go func(c chan string) {
for {
link, more := <-c
if !more {
wg.Done()
return
}
dead, err := ortfomk.IsLinkDead(link)
if err != nil {
ortfomk.LogError("could not check for dead link %q: %s", link, err)
}
if dead {
noneDead = false
ortfomk.LogInfo("- %s (from %s)", link, strings.Join(httpLinks[link], ", "))
}
}
}(channel)
}
for link, _ := range httpLinks {
channel <- link
}
close(channel)
wg.Wait()
if noneDead {
ortfomk.LogInfo("No dead links found.")
} else {
ortfomk.LogInfo("are dead links.")
}
}
}
if os.Getenv("DEBUG") == "1" {
heapProfileFile, err := os.Create("ortfomk_heap.pprof")
if err != nil {
panic(err)
}
defer heapProfileFile.Close()
runtime.GC()
if err := pprof.WriteHeapProfile(heapProfileFile); err != nil {
ortfomk.LogFatal("couldn't write heap profile: %s", err)
}
}
}
func init() {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
ortfomk.CoolDown()
os.Exit(1)
}()
}