1#!/usr/bin/gawk -f
2
3# Not all 4.x versions of gawk can handle @include without ".awk" extension
4# But the build.awk script and the single build should support gawk 4.0+.
5@include "include/Commons.awk"
6@include "include/Utils.awk"
7@include "include/Languages.awk"
8@include "metainfo.awk"
9
10function init() {
11    BuildPath            = "build/"
12    Trans                = BuildPath Command
13    TransAwk             = Trans ".awk"
14
15    ManPath              = "man/"
16    Man                  = ManPath Command ".1"
17    ManTemplate          = Man ".template.md"
18    ManMarkdown          = Man ".md"
19    ManHtmlTemplate      = Man ".template.html"
20    ManHtml              = Man ".html"
21
22    PagesPath            = "gh-pages/"
23    BadgeDownload        = PagesPath "images/badge-download"
24    BadgeRelease         = PagesPath "images/badge-release"
25    Index                = PagesPath "index.md"
26
27    ReadmePath           = "./"
28    ReadmeTemplate       = ReadmePath "README.template.md"
29    Readme               = ReadmePath "README.md"
30
31    WikiPath             = "wiki/"
32    WikiHome             = WikiPath "Home.md"
33    WikiLanguages        = WikiPath "Languages.md"
34    WikiLanguagesHtml    = WikiLanguages ".html"
35
36    RegistryPath         = "registry/"
37    MainRegistryTemplate = RegistryPath "index.template.trans"
38    MainRegistry         = RegistryPath "index.trans"
39}
40
41function man(    text) {
42    text = readFrom(ManTemplate)
43    gsub(/\$Version\$/, Version, text)
44    gsub(/\$ReleaseDate\$/, ReleaseDate, text)
45    writeTo(text, ManMarkdown)
46
47    if (fileExists(ManHtmlTemplate))
48        system("pandoc -s -f markdown-smart -t html --toc --toc-depth 1 --template " ManHtmlTemplate " " ManMarkdown " -o " ManHtml)
49    return system("pandoc -s -f markdown-smart -t man " ManMarkdown " -o " Man)
50}
51
52function readme(    code, col, cols, content, group, i, j, num, language, r, rows, text) {
53    text = readFrom(ReadmeTemplate)
54
55    content = getOutput("gawk -f translate.awk -- -no-ansi -h")
56    gsub(/\$usage\$/, content, text)
57
58    initBiDi(); initLocale()
59    # number of language codes with stable support
60    num = 0
61    for (code in Locale)
62        if (Locale[code]["support"] != "unstable")
63            num++
64    rows = int(num / 3) + (num % 3 ? 1 : 0)
65    cols[0][0] = cols[1][0] = cols[2][0] = NULLSTR
66    i = 0
67    saveSortedIn = PROCINFO["sorted_in"]
68    PROCINFO["sorted_in"] = "compName"
69    for (code in Locale) {
70        # Ignore unstable languages
71        if (Locale[code]["support"] == "unstable") continue
72
73        col = int(i / rows)
74        append(cols[col], code)
75        i++
76    }
77    PROCINFO["sorted_in"] = saveSortedIn
78    r = "| Language | Code | Language | Code | Language | Code |" RS \
79        "| :------: | :--: | :------: | :--: | :------: | :--: |" RS
80    for (i = 0; i < rows; i++) {
81        r = r "| "
82        for (j = 0; j < 3; j++)
83            if (cols[j][i]) {
84                split(getName(cols[j][i]), group, " ")
85                language = length(group) == 1 ? group[1] "_language" : join(group, "_")
86                r = r "**[" getName(cols[j][i]) "](" "http://en.wikipedia.org/wiki/" language ")** <br/> **" getEndonym(cols[j][i]) "** | **`" cols[j][i] "`** | "
87            }
88        r = r RS
89    }
90    gsub(/\$code-list\$/, r, text)
91
92    content = readFrom(WikiHome)
93    gsub(/\$wiki-home\$/, content, text)
94
95    writeTo(text, Readme)
96    return 0
97}
98
99function wiki(    code, group, iso, language, saveSortedIn) {
100    initBiDi(); initLocale()
101
102    #print "***" length(Locale) "*** *languages in total. "
103    print "*Generated from the source code of Translate Shell " Version ".*\n" > WikiLanguages
104    print "*Version: [English](https://github.com/soimort/translate-shell/wiki/Languages) " \
105        "| [Chinese Simplified](https://github.com/soimort/translate-shell/wiki/Languages-%28%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%29)*\n" > WikiLanguages
106    print "| Code | Name | Family | [Writing system](https://github.com/soimort/translate-shell/wiki/Writing-Systems-and-Fonts) | Is [RTL](http://en.wikipedia.org/wiki/Right-to-left)? | Has dictionary? |" > WikiLanguages
107    print "| :--: | ---: | -----: | :------------: | :---------------------------------------------------: | :-------------: |" > WikiLanguages
108    saveSortedIn = PROCINFO["sorted_in"]
109    PROCINFO["sorted_in"] = "@ind_num_asc"
110    for (code in Locale) {
111        # Ignore unstable languages
112        if (Locale[code]["support"] == "unstable") continue
113
114        split(getISO(code), group, "-")
115        iso = group[1]
116        split(getName(code), group, " ")
117        language = length(group) == 1 ? group[1] "_language" :
118            group[2] ~ /^\(.*\)$/ ? group[1] "_language" : join(group, "_")
119        print sprintf("| **`%s`** <br/> [`%s`](%s) | **[%s](%s)** <br/> **%s** | %s | `%s` | %s | %s |",
120                      getCode(code), iso, "http://www.ethnologue.com/language/" iso,
121                      getName(code), "http://en.wikipedia.org/wiki/" language, getEndonym(code),
122                      getFamily(code), getScript(code),
123                      isRTL(code) ? "✓" : NULLSTR,
124                      hasDictionary(code) ? "✓" : NULLSTR) > WikiLanguages
125    }
126    PROCINFO["sorted_in"] = saveSortedIn
127
128    return system("pandoc -s -t html " WikiLanguages " -o " WikiLanguagesHtml)
129}
130
131function doc() {
132    man()
133    readme()
134    wiki()
135    return 0
136}
137
138function readSqueezed(fileName, squeezed,    group, line, ret) {
139    if (fileName ~ /\*$/) # glob simulation
140        return readSqueezed(fileName ".awk", squeezed)
141
142    ret = NULLSTR
143    if (fileExists(fileName))
144        while (getline line < fileName) {
145            match(line, /^[[:space:]]*@include[[:space:]]*"(.*)"$/, group)
146            if (RSTART) { # @include
147                if (group[1] ~ /\.awk$/)
148                    append(Includes, group[1])
149
150                if (ret) ret = ret RS
151                ret = ret readSqueezed(group[1], squeezed)
152            } else if (!squeezed || line = squeeze(line)) { # effective LOC
153                if (ret) ret = ret RS
154                ret = ret line
155            }
156        }
157    return ret
158}
159
160function build(target, type,    i, group, inline, line, temp) {
161    # Default target: bash
162    if (!target) target = "bash"
163
164    ("mkdir -p " parameterize(BuildPath)) | getline
165
166    if (target == "bash" || target == "zsh") {
167
168        print "#!/usr/bin/env " target > Trans
169
170        if (fileExists("DISCLAIMER")) {
171            print "#" > Trans
172            while (getline line < "DISCLAIMER")
173                print "# " line > Trans
174            print "#" > Trans
175        }
176
177        print "export TRANS_ENTRY=\"$0\"" > Trans
178        print "if [[ ! $LANG =~ (UTF|utf)-?8$ ]]; then export LANG=en_US.UTF-8; fi" > Trans
179
180        print "read -r -d '' TRANS_PROGRAM << 'EOF'" > Trans
181        print readSqueezed(EntryPoint, TRUE) > Trans
182        print "EOF" > Trans
183
184        print "read -r -d '' TRANS_MANPAGE << 'EOF'" > Trans
185        if (fileExists(Man))
186            while (getline line < Man)
187                print line > Trans
188        print "EOF" > Trans
189        print "export TRANS_MANPAGE" > Trans
190
191        if (type == "release")
192            print "export TRANS_BUILD=release" temp > Trans
193        else {
194            temp = getGitHead()
195            if (temp)
196                print "export TRANS_BUILD=git:" temp > Trans
197        }
198
199        print "gawk -f <(echo -E \"$TRANS_PROGRAM\") - \"$@\"" > Trans
200
201        ("chmod +x " parameterize(Trans)) | getline
202
203        # Rebuild EntryScript
204        print "#!/bin/sh" > EntryScript
205        print "export TRANS_DIR=`dirname $0`" > EntryScript
206        print "gawk \\" > EntryScript
207        for (i = 0; i < length(Includes) - 1; i++)
208            print "-i \"${TRANS_DIR}/" Includes[i] "\" \\" > EntryScript
209        print "-f \"${TRANS_DIR}/" Includes[i] "\" -- \"$@\"" > EntryScript
210        ("chmod +x " parameterize(EntryScript)) | getline
211        return 0
212
213    } else if (target == "awk" || target == "gawk") {
214
215        "uname -s" | getline temp
216        print (temp == "Darwin" ?
217               "#!/usr/bin/env gawk -f" : # macOS
218               "#!/usr/bin/gawk -f") > TransAwk
219
220        print readSqueezed(EntryPoint, TRUE) > TransAwk
221
222        ("chmod +x " parameterize(TransAwk)) | getline
223        return 0
224
225    } else {
226
227        w("[FAILED] Unknown target: " ansi("underline", target))
228        w("         Supported targets: "                                \
229          ansi("underline", "bash") ", "                                \
230          ansi("underline", "zsh") ", "                                 \
231          ansi("underline", "gawk"))
232        return 1
233
234    }
235}
236
237function clean() {
238    ("rm -f " BuildPath Command "*") | getline
239    return 0
240}
241
242function release(    content, group, sha1, size, temp, text) {
243    d("Updating registry ...")
244    # Update registry
245    text = readFrom(MainRegistryTemplate)
246    gsub(/\$Version\$/, Version, text)
247    writeTo(text, MainRegistry)
248
249    d("Updating gh-pages/images ...")
250    # Update gh-pages/images/badge-release
251    text = readFrom(BadgeRelease ".temp")
252    gsub(/\$Version\$/, Version, text)
253    writeTo(text, BadgeRelease)
254    system("save-to-png " BadgeRelease)
255    # Update gh-pages/images/badge-download
256    ("wc -c " Trans) | getline temp
257    split(temp, group)
258    size = int(group[1] / 1000)
259    text = readFrom(BadgeDownload ".temp")
260    gsub(/\$Size\$/, size, text)
261    writeTo(text, BadgeDownload)
262    system("save-to-png " BadgeDownload)
263
264    d("Updating gh-pages/index.md ...")
265    # Update gh-pages/index.md
266    ("sha1sum " Trans) | getline temp
267    split(temp, group)
268    sha1 = group[1]
269    content = readFrom(Readme)
270    text = readFrom(Index ".temp")
271    gsub(/\$sha1\$/, sha1, text)
272    gsub(/\$Version\$/, Version, text)
273    gsub(/\$readme\$/, content, text)
274    writeTo(text, Index)
275
276    return 0
277}
278
279function test() {
280    return 0
281}
282
283BEGIN {
284    init()
285
286    pos = 0
287    while (ARGV[++pos]) {
288        # -target TARGET
289        match(ARGV[pos], /^--?target(=(.*)?)?$/, group)
290        if (RSTART) {
291            target = tolower(group[2] ? group[2] : ARGV[++pos])
292            continue
293        }
294
295        # -type TYPE
296        match(ARGV[pos], /^--?type(=(.*)?)?$/, group)
297        if (RSTART) {
298            type = tolower(group[2] ? group[2] : ARGV[++pos])
299            continue
300        }
301
302        # TASK
303        match(ARGV[pos], /^[^\-]/, group)
304        if (RSTART) {
305            append(tasks, ARGV[pos])
306            continue
307        }
308    }
309
310    # Default task: build
311    if (!anything(tasks)) tasks[0] = "build"
312
313    for (i = 0; i < length(tasks); i++) {
314        task = tasks[i]
315        status = 0
316        switch (task) {
317
318        case "man":
319            status = man()
320            break
321
322        case "readme":
323            status = readme()
324            break
325
326        case "wiki":
327            status = wiki()
328            break
329
330        case "doc":
331            status = doc()
332            break
333
334        case "build":
335            status = build(target, type)
336            break
337
338        case "clean":
339            status = clean()
340            break
341
342        case "release":
343            status = release()
344            break
345
346        case "test":
347            status = test()
348            break
349
350        default: # unknown task
351            status = -1
352        }
353
354        if (status == 0) {
355            d("[OK] Task " ansi("bold", task) " completed.")
356        } else if (status < 0) {
357            w("[FAILED] Unknown task: " ansi("bold", task))
358            exit 1
359        } else {
360            w("[FAILED] Task " ansi("bold", task) " failed.")
361            exit 1
362        }
363    }
364}
365