-
Notifications
You must be signed in to change notification settings - Fork 158
/
build.scala
237 lines (200 loc) · 6.9 KB
/
build.scala
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
233
234
/**
=> Compile all org-mode files to html.
$ scala -save build.scala -make all
=> Clean all compiled (*.html) files.
$ scala -save build.scala -clean
*/
class SFile(path: String) extends java.io.File(path){
/** Return new path with extension changed. */
def changeExt(ext: String) = {
val name = this.getName.split("\\.")(0) + "." + ext
new SFile(new java.io.File(this.getParent, name).getPath())
}
/** Return new path with parent directory changed. */
def changeParent(parent: String) = {
new SFile(new java.io.File(parent, this.getName()).getPath())
}
def changeParentAndExt(parent: String, ext: String) = {
val name = this.getName.split("\\.")(0) + "." + ext
new SFile(new java.io.File(parent, name).getPath())
}
}
/** Allows to print with color in Ansi terminals. */
object AnsiTerm{
/** Check whether terminal is Ansi */
val isAnsi = {
val term = System.getenv("TERM")
term != null && ( term.contains("xterm") || term.contains("ansi"))
}
val colors = Map(
"Red" -> "\u001B[31m",
"Blue" -> "\u001B[34m",
"Cyan" -> "\u001B[36m",
"Yellow" -> "\u001b[33m",
"White" -> "\u001b[37m",
"Green" -> "\u001b[32m",
"Magenta" -> "\u001b[35m",
"DarkRed" -> "\u001B[31m\u001B[1m",
"BrightGreen" -> "\u001b[32;1m",
"BrigthYellow" -> "\u001b[33;1m",
"BrightMagenta" -> "\u001b[35;1m",
"BrightCyan" -> "\u001b[36;1m",
"BrightWhite" -> "\u001b[37;1m",
"Reset" -> "\u001b[0m"
)
def withColor(color: String)(action: => Unit) =
try {
if(isAnsi) print(color)
action
} finally{
if(isAnsi) print("\u001B[0m")
}
def addColor(color: String, text: String) =
if(isAnsi)
color + text + "\u001B[0m"
else
text
def println(text: String, color: String = null) = {
if(color != null && isAnsi)
System.out.println(color + text + "\u001B[0m")
else
System.out.println(text)
}
def progressIndicatorPercent(delayMs: Int) =
for (i <- 0 to 100) {
Thread.sleep(delayMs)
print("\u001b[1000D" + i + "%")
}
def testColors() = {
if(!isAnsi)
println("Warning: This terminal doesn't support ANSI colors")
else
for((k, v) <- colors){
print(v)
println(k)
print("\u001B[0m")
}
}
} // ---- End of object AnsiTerm ----- //
object FileUtils{
import java.io.File
import java.nio.file.{Files, Paths, Path}
import java.util.stream.{Stream => JStream}
def file(path: String) =
new java.io.File(path)
def hasExtension(ext: String) =
(file: File) => file.getPath.endsWith(ext)
def fileInDirectory(dir: File) =
(file: File) => file.getPath().startsWith(dir.getPath())
def walkDirectory(path: String, pred: Path => Boolean)(action: Path => Unit) =
Files.walk(Paths.get(path))
.filter(p => pred(p))
.forEach(p => action(p))
// def fileInDirs(file: File) =
// excludeDirs.exists(dir => file.getPath().startsWith(dir.getPath))
/** Find files matching a predicate function in a directory and all its sub directories */
def findFiles(path: String, pred: File => Boolean) : List[File] = {
val root = Paths.get(path)
Files.walk(root)
.toArray()
.toList.asInstanceOf[List[Path]]
.map(_.toFile)
.filter{f => pred(f) }
}
}
import java.io.File
import FileUtils.hasExtension
val F = FileUtils
val A = AnsiTerm
val logColor = A.colors("Blue")
val logColorOK = A.colors("Green")
val logColorFail = A.colors("Red")
val emacsConfig = System.getProperty("user.home") + "/.emacs.d/init.el"
/** Execute sub-process with a given set of arguments and waits for its end. */
def execWait(program: String, args: List[String] = List()) = {
import java.lang.ProcessBuilder
val pb = new ProcessBuilder(program)
args foreach pb.command.add
pb.inheritIO().start().waitFor()
}
/** Compile org-mode file (*.org) generating .html file and returning 0 if successful. */
def compileOrgToHtml(file: java.io.File): Int = {
// emacs -l ~/.emacs.d/init.el --visit clojure/README.org --batch -f org-html-export-to-html --kill
val args = List(
"-l", emacsConfig,
"--visit", file.getPath,
"--batch",
"-f", "org-html-export-to-html",
"--kill"
)
execWait("emacs", args)
}
/** Build target file if input file has changed or the target does not exist.
*
* @param fileIn: Input file needed for compilation
* @param fileOut: Output file that will build
* @param builder: Function that generates output file returning the process status code.
*/
def buildTarget(
fileIn: java.io.File,
fileOut: java.io.File
)(builder: java.io.File => Int) =
if(!fileOut.isFile() || fileIn.lastModified > fileOut.lastModified){
A.println(s"Building file: <$fileIn> waiting ...", logColor)
val status = builder(fileIn)
// Check process status code
if(status == 0)
A.println(s"SUCCESSFUL: file <$fileIn> compiled to <$fileOut. OK.", logColorOK)
else
A.println(s"ERROR: compilation of file <$fileIn> failed.", logColorFail)
} else {
A.println(s"SUCCESSFUL: File <$fileIn> already compiled to <$fileOut>. OK", logColorOK)
}
def cleanHtmlFiles() =
F.findFiles("dist", F.hasExtension("html")) foreach { file =>
println("Removing file = " + file)
file.delete()
}
def compileFile(file: java.io.File, destDirectory: String, renameToIndex: Boolean = false) = {
val input = new SFile(file.getPath())
val out1 = input.changeExt("html")
val out2: File = if(!(renameToIndex && input.getName() == "README.org"))
out1.changeParent(destDirectory)
else
new java.io.File(destDirectory, "index.html")
println()
A.println("Target = " + out2, logColor)
buildTarget(input, out2){ file =>
// Build file out1 (.html)
val status = compileOrgToHtml(file)
if(status == 0){// Rename out1 to out2
val flag = out1.renameTo(out2)
if(flag)
A.println(s"Moved file <$out1> to <$out2>", logColor)
}
status
}
}
def compileDirectory(directory: String, destDirectory: String) = {
val orgFiles = F.findFiles(directory, F.hasExtension(".org"))
orgFiles foreach { file => compileFile(file, destDirectory) }
}
args.toList match{
case List("-make", "all") => {
// Compile README.org to README.html and then rename to index.html
compileFile(F.file("README.org"), "dist/", true)
compileDirectory("haskell", "dist/haskell")
compileDirectory("clojure", "dist/clojure")
compileDirectory("ocaml", "dist/ocaml")
compileDirectory("scheme", "dist/scheme")
compileDirectory("papers", "dist/papers")
compileDirectory("scala", "dist/scala")
}
case List("-make", "clojure") =>
compileDirectory("clojure", "dist/clojure")
case List("-make", "scala") =>
compileDirectory("scala", "dist/scala")
case List("-clean") =>
cleanHtmlFiles()
case _ => println("Error: invalid option")
}