70967
|
1 |
/* Title: Pure/Tools/phabricator.scala
|
|
2 |
Author: Makarius
|
|
3 |
|
|
4 |
Support for Phabricator server. See also:
|
|
5 |
- https://www.phacility.com/phabricator
|
|
6 |
- https://secure.phabricator.com/book/phabricator
|
|
7 |
*/
|
|
8 |
|
|
9 |
package isabelle
|
|
10 |
|
|
11 |
|
|
12 |
object Phabricator
|
|
13 |
{
|
|
14 |
/** defaults **/
|
|
15 |
|
|
16 |
val default_name = "vcs"
|
|
17 |
|
70968
|
18 |
def default_prefix(name: String): String = "phabricator-" + name
|
70967
|
19 |
|
|
20 |
def default_root(options: Options, name: String): Path =
|
|
21 |
Path.explode(options.string("phabricator_www_root")) + Path.basic(default_prefix(name))
|
|
22 |
|
|
23 |
def default_repo(options: Options, name: String): Path =
|
|
24 |
default_root(options, name) + Path.basic("repo")
|
|
25 |
|
|
26 |
val packages: List[String] =
|
|
27 |
Build_Docker.packages :::
|
|
28 |
// https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61
|
|
29 |
List("git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql",
|
|
30 |
"php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring")
|
|
31 |
|
|
32 |
|
|
33 |
|
|
34 |
/** global configuration **/
|
|
35 |
|
|
36 |
val global_config = Path.explode("/etc/isabelle-phabricator.conf")
|
|
37 |
|
|
38 |
sealed case class Config(name: String, root: Path)
|
70968
|
39 |
{
|
|
40 |
def www_root: Path = root + Path.explode("phabricator/webroot")
|
|
41 |
}
|
70967
|
42 |
|
|
43 |
def read_config(): List[Config] =
|
|
44 |
{
|
|
45 |
if (global_config.is_file) {
|
|
46 |
for (entry <- Library.trim_split_lines(File.read(global_config)) if entry.nonEmpty)
|
|
47 |
yield {
|
|
48 |
space_explode(':', entry) match {
|
|
49 |
case List(name, root) => Config(name, Path.explode(root))
|
|
50 |
case _ => error("Malformed config file " + global_config + "\nentry " + quote(entry))
|
|
51 |
}
|
|
52 |
}
|
|
53 |
}
|
|
54 |
else Nil
|
|
55 |
}
|
|
56 |
|
|
57 |
def write_config(configs: List[Config])
|
|
58 |
{
|
|
59 |
File.write(global_config,
|
|
60 |
configs.map(config => config.name + ":" + config.root.implode).mkString("", "\n", "\n"))
|
|
61 |
}
|
|
62 |
|
|
63 |
def get_config(name: String): Config =
|
|
64 |
read_config().find(config => config.name == name) getOrElse
|
|
65 |
error("Bad Isabelle/Phabricator installation " + quote(name))
|
|
66 |
|
|
67 |
|
|
68 |
|
|
69 |
/** setup **/
|
|
70 |
|
|
71 |
def phabricator_setup(
|
|
72 |
options: Options,
|
|
73 |
name: String = default_name,
|
|
74 |
prefix: String = "",
|
|
75 |
root: String = "",
|
|
76 |
repo: String = "",
|
|
77 |
progress: Progress = No_Progress)
|
|
78 |
{
|
|
79 |
/* system environment */
|
|
80 |
|
|
81 |
Linux.check_system_root()
|
|
82 |
|
|
83 |
Linux.package_update(progress = progress)
|
|
84 |
Linux.check_reboot_required()
|
|
85 |
|
|
86 |
Linux.package_install(packages, progress = progress)
|
|
87 |
Linux.check_reboot_required()
|
|
88 |
|
|
89 |
|
|
90 |
/* basic installation */
|
|
91 |
|
|
92 |
val prefix_name = proper_string(prefix) getOrElse default_prefix(name)
|
|
93 |
val root_path = if (root.nonEmpty) Path.explode(root) else default_root(options, name)
|
|
94 |
val repo_path = if (repo.nonEmpty) Path.explode(repo) else default_repo(options, name)
|
|
95 |
|
|
96 |
val configs = read_config()
|
|
97 |
|
|
98 |
for (config <- configs if config.name == name) {
|
|
99 |
error("Duplicate Phabricator installation " + quote(name) + " in " + config.root)
|
|
100 |
}
|
|
101 |
|
|
102 |
if (!Isabelle_System.bash("mkdir -p " + File.bash_path(root_path)).ok) {
|
|
103 |
error("Failed to create root directory " + root_path)
|
|
104 |
}
|
|
105 |
|
|
106 |
progress.bash(cwd = root_path.file, echo = true,
|
|
107 |
script = """
|
|
108 |
set -e
|
|
109 |
chown """ + Bash.string(options.string("phabricator_www_user")) + """ .
|
|
110 |
chmod 755 .
|
|
111 |
|
|
112 |
git clone https://github.com/phacility/libphutil.git
|
|
113 |
git clone https://github.com/phacility/arcanist.git
|
|
114 |
git clone https://github.com/phacility/phabricator.git
|
|
115 |
""").check
|
|
116 |
|
|
117 |
val config = Config(name, root_path)
|
|
118 |
write_config(configs ::: List(config))
|
70968
|
119 |
|
|
120 |
|
|
121 |
/* Apache setup */
|
|
122 |
|
|
123 |
progress.echo("Apache setup...")
|
|
124 |
|
|
125 |
val apache_root = Path.explode(options.string("phabricator_apache_root"))
|
|
126 |
val apache_sites = apache_root + Path.explode("sites-available")
|
|
127 |
|
|
128 |
if (!apache_sites.is_dir) error("Bad Apache sites directory " + apache_sites)
|
|
129 |
|
|
130 |
File.write(apache_sites + Path.basic(prefix_name + ".conf"),
|
|
131 |
"""<VirtualHost *:80>
|
|
132 |
#ServerName: "lvh.me" is an alias for "localhost" for testing
|
|
133 |
ServerName """ + prefix_name + """.lvh.me
|
|
134 |
ServerAdmin webmaster@localhost
|
|
135 |
DocumentRoot """ + config.www_root.implode + """
|
|
136 |
|
|
137 |
ErrorLog ${APACHE_LOG_DIR}/error.log
|
|
138 |
RewriteEngine on
|
|
139 |
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
|
|
140 |
</VirtualHost>
|
|
141 |
|
|
142 |
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
|
143 |
""")
|
|
144 |
|
|
145 |
Isabelle_System.bash("""
|
|
146 |
set -e
|
|
147 |
a2enmod rewrite
|
|
148 |
a2ensite """ + Bash.string(prefix_name) + """
|
|
149 |
systemctl restart apache2
|
|
150 |
""").check
|
|
151 |
|
|
152 |
progress.echo("\nDONE\nWeb configuration via http://" + prefix_name + ".lvh.me")
|
70967
|
153 |
}
|
|
154 |
|
|
155 |
|
|
156 |
/* Isabelle tool wrapper */
|
|
157 |
|
|
158 |
val isabelle_tool1 =
|
|
159 |
Isabelle_Tool("phabricator_setup", "setup Phabricator server on Ubuntu Linux", args =>
|
|
160 |
{
|
|
161 |
var options = Options.init()
|
|
162 |
var prefix = ""
|
|
163 |
var root = ""
|
|
164 |
var repo = ""
|
|
165 |
|
|
166 |
val getopts =
|
|
167 |
Getopts("""
|
|
168 |
Usage: isabelle phabricator_setup [OPTIONS] [NAME]
|
|
169 |
|
|
170 |
Options are:
|
|
171 |
-R DIR repository directory (default: """ + default_repo(options, "NAME") + """)
|
|
172 |
-o OPTION override Isabelle system OPTION (via NAME=VAL or NAME)
|
|
173 |
-p PREFIX prefix for derived names (default: """ + default_prefix("NAME") + """)
|
|
174 |
-r DIR installation root directory (default: """ + default_root(options, "NAME") + """)
|
|
175 |
|
|
176 |
Install Phabricator as Ubuntu LAMP application (Linux, Apache, MySQL, PHP).
|
|
177 |
|
|
178 |
Slogan: "Discuss. Plan. Code. Review. Test.
|
|
179 |
Every application your project needs, all in one tool."
|
|
180 |
|
|
181 |
The installation NAME (default: """ + quote(default_name) + """) is mapped to
|
|
182 |
a regular Unix user and used for public SSH access.
|
|
183 |
""",
|
|
184 |
"R:" -> (arg => repo = arg),
|
|
185 |
"o:" -> (arg => options = options + arg),
|
|
186 |
"p:" -> (arg => prefix = arg),
|
|
187 |
"r:" -> (arg => root = arg))
|
|
188 |
|
|
189 |
val more_args = getopts(args)
|
|
190 |
|
|
191 |
val name =
|
|
192 |
more_args match {
|
|
193 |
case Nil => default_name
|
|
194 |
case List(name) => name
|
|
195 |
case _ => getopts.usage()
|
|
196 |
}
|
|
197 |
|
|
198 |
val progress = new Console_Progress
|
|
199 |
|
|
200 |
phabricator_setup(options, name, prefix = prefix, root = root, repo = repo,
|
|
201 |
progress = progress)
|
|
202 |
})
|
|
203 |
|
|
204 |
|
|
205 |
|
|
206 |
/** update **/
|
|
207 |
|
|
208 |
def phabricator_update(name: String, progress: Progress = No_Progress)
|
|
209 |
{
|
|
210 |
Linux.check_system_root()
|
|
211 |
|
|
212 |
???
|
|
213 |
}
|
|
214 |
|
|
215 |
|
|
216 |
/* Isabelle tool wrapper */
|
|
217 |
|
|
218 |
val isabelle_tool2 =
|
|
219 |
Isabelle_Tool("phabricator_update", "update Phabricator server installation", args =>
|
|
220 |
{
|
|
221 |
val getopts =
|
|
222 |
Getopts("""
|
|
223 |
Usage: isabelle phabricator_update [NAME]
|
|
224 |
|
|
225 |
Update Phabricator installation, with lookup of NAME (default + """ + quote(default_name) + """)
|
|
226 |
in """ + global_config + "\n")
|
|
227 |
|
|
228 |
val more_args = getopts(args)
|
|
229 |
val name =
|
|
230 |
more_args match {
|
|
231 |
case Nil => default_name
|
|
232 |
case List(name) => name
|
|
233 |
case _ => getopts.usage()
|
|
234 |
}
|
|
235 |
|
|
236 |
val progress = new Console_Progress
|
|
237 |
|
|
238 |
phabricator_update(name, progress = progress)
|
|
239 |
})
|
|
240 |
}
|