--- a/src/Pure/Tools/phabricator.scala Sun Jan 21 14:12:14 2024 +0100
+++ b/src/Pure/Tools/phabricator.scala Mon Jan 22 13:40:45 2024 +0100
@@ -18,14 +18,148 @@
object Phabricator {
/** defaults **/
- /* required packages */
+ /* webservers */
+
+ sealed abstract class Webserver {
+ override def toString: String = title
+ def title: String
+ def short_name: String
+ def system_name: String = short_name
+
+ def packages(): List[String]
+
+ def system_path: Path = Path.basic(system_name)
+ def root_dir: Path = Path.explode("/etc") + system_path
+ def sites_dir: Path = root_dir + Path.explode("sites-available")
+
+ def restart(): Unit = Linux.service_restart(system_name)
+
+ def systemctl(cmd: String): String = "systemctl " + cmd + " " + system_name
+
+ def php_version(): String =
+ Isabelle_System.bash("""php --run 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'""")
+ .check.out
+
+ def php_config: String =
+ "post_max_size = 32M\n" +
+ "opcache.validate_timestamps = 0\n" +
+ "memory_limit = 512M\n" +
+ "max_execution_time = 120\n"
+
+ def php_init(): Unit = ()
+
+ def site_name(name: String): String = isabelle_phabricator_name(name = name)
+
+ def site_conf(name: String): Path =
+ sites_dir + Path.basic(isabelle_phabricator_name(name = name, ext = "conf"))
+
+ def site_init(name: String, server_name: String, webroot: String): Unit
+ }
+
+ object Apache extends Webserver {
+ override val title = "Apache"
+ override val short_name = "apache"
+ override def system_name = "apache2"
+ override def packages(): List[String] = List("apache2", "libapache2-mod-php")
+
+ override def php_init(): Unit = {
+ val php_conf =
+ Path.explode("/etc/php") + Path.basic(php_version()) + // educated guess
+ Path.basic(system_name) + Path.explode("conf.d") +
+ Path.basic(isabelle_phabricator_name(ext = "ini"))
+ File.write(php_conf, php_config)
+ }
+
+ override def site_init(name: String, server_name: String, webroot: String): Unit = {
+ File.write(site_conf(name),
+"""<VirtualHost *:80>
+ ServerName """ + server_name + """
+ ServerAdmin webmaster@localhost
+ DocumentRoot """ + webroot + """
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
+ RewriteEngine on
+ RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
+</VirtualHost>
+
+# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
+""")
+ Isabelle_System.bash("""
+ set -e
+ a2enmod rewrite
+ a2ensite """ + Bash.string(site_name(name))).check
+ }
+ }
+
+ object Nginx extends Webserver {
+ override val title = "Nginx"
+ override val short_name = "nginx"
+ override def packages(): List[String] = List("nginx", "php-fpm")
+
+ override def site_init(name: String, server_name: String, webroot: String): Unit = {
+ File.write(site_conf(name),
+"""
+server {
+ server_name """ + server_name + """;
+ root """ + webroot + """;
+
+ location / {
+ index index.php;
+ rewrite ^/(.*)$ /index.php?__path__=/$1 last;
+ }
+
+ location ~ \.php$ {
+ include snippets/fastcgi-php.conf;
+ fastcgi_pass unix:/var/run/php/php""" + php_version() + """-fpm.sock;
+ }
+
+ location /index.php {
+ fastcgi_index index.php;
+
+ #required if PHP was built with --enable-force-cgi-redirect
+ fastcgi_param REDIRECT_STATUS 200;
+
+ #variables to make the $_SERVER populate in PHP
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_param CONTENT_TYPE $content_type;
+ fastcgi_param CONTENT_LENGTH $content_length;
+
+ fastcgi_param SCRIPT_NAME $fastcgi_script_name;
+
+ fastcgi_param GATEWAY_INTERFACE CGI/1.1;
+ fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
+
+ fastcgi_param REMOTE_ADDR $remote_addr;
+ }
+}
+""")
+ Isabelle_System.bash(
+ "ln -sf " + File.bash_path(site_conf(name)) + " /etc/nginx/sites-enabled/.").check
+ }
+ }
+
+ val all_webservers: List[Webserver] = List(Apache, Nginx)
+
+ def get_webserver(name: String): Webserver =
+ all_webservers.find(w => w.short_name == name) getOrElse
+ error("Bad webserver " + quote(name))
+
+ val default_webserver: Webserver = Apache
+
+
+
+ /* system packages */
val packages_ubuntu_20_04: List[String] =
Docker_Build.packages :::
List(
// https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61
- "git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql",
- "php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring",
+ "git", "mysql-server", "php", "php-mysql", "php-gd", "php-curl", "php-apcu", "php-cli",
+ "php-json", "php-mbstring",
// more packages
"php-xml", "php-zip", "python3-pygments", "ssh", "subversion", "python-pygments",
// mercurial build packages
@@ -35,16 +169,18 @@
Docker_Build.packages :::
List(
// https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61
- "git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql",
- "php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring",
+ "git", "mysql-server", "php", "php-mysql", "php-gd", "php-curl", "php-apcu", "php-cli",
+ "php-json", "php-mbstring",
// more packages
"php-xml", "php-zip", "python3-pygments", "ssh", "subversion")
- def packages: List[String] = {
+ def packages(webserver: Webserver): List[String] = {
val release = Linux.Release()
- if (release.is_ubuntu_20_04) packages_ubuntu_20_04
- else if (release.is_ubuntu_22_04) packages_ubuntu_22_04
- else error("Bad Linux version: expected Ubuntu 20.04 or 22.04 LTS")
+ val pkgs =
+ if (release.is_ubuntu_20_04) packages_ubuntu_20_04
+ else if (release.is_ubuntu_22_04) packages_ubuntu_22_04
+ else error("Bad Linux version: expected Ubuntu 20.04 or 22.04 LTS")
+ pkgs ::: webserver.packages()
}
@@ -110,6 +246,8 @@
def execute(command: String): Process_Result =
Isabelle_System.bash("bin/" + command, cwd = home.file, redirect = true).check
+
+ def webroot: String = home.implode + "/webroot"
}
def read_config(): List[Config] = {
@@ -226,6 +364,7 @@
name: String = default_name,
root: String = "",
repo: String = "",
+ webserver: Webserver = default_webserver,
package_update: Boolean = false,
mercurial_source: String = "",
progress: Progress = new Progress
@@ -241,7 +380,7 @@
Linux.check_reboot_required()
}
- Linux.package_install(packages, progress = progress)
+ Linux.package_install(packages(webserver), progress = progress)
Linux.check_reboot_required()
@@ -403,8 +542,7 @@
fi
systemctl stop isabelle-phabricator-phd
-systemctl stop apache2
-""",
+""" + webserver.systemctl("stop"),
body =
"""echo -e "\nUpgrading phabricator \"$NAME\" root \"$ROOT\" ..."
for REPO in arcanist phabricator
@@ -418,64 +556,27 @@
"$ROOT/phabricator/bin/storage" upgrade --force
""",
exit =
-"""systemctl start apache2
+ webserver.systemctl("start") + """
systemctl start isabelle-phabricator-phd""")
- /* PHP setup */
-
- val php_version =
- Isabelle_System.bash("""php --run 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'""")
- .check.out
-
- val php_conf =
- Path.explode("/etc/php") + Path.basic(php_version) + // educated guess
- Path.explode("apache2/conf.d") +
- Path.basic(isabelle_phabricator_name(ext = "ini"))
+ /* webserver setup */
- File.write(php_conf,
- "post_max_size = 32M\n" +
- "opcache.validate_timestamps = 0\n" +
- "memory_limit = 512M\n" +
- "max_execution_time = 120\n")
-
+ progress.echo(webserver.title + " setup ...")
- /* Apache setup */
-
- progress.echo("Apache setup ...")
-
- val apache_root = Path.explode("/etc/apache2")
- val apache_sites = apache_root + Path.explode("sites-available")
-
- if (!apache_sites.is_dir) error("Bad Apache sites directory " + apache_sites)
+ val sites_dir = webserver.sites_dir
+ if (!sites_dir.is_dir) error("Bad " + webserver + " sites directory " + sites_dir)
val server_name = phabricator_name(name = name, ext = "localhost") // alias for "localhost" for testing
val server_url = "http://" + server_name
- File.write(apache_sites + Path.basic(isabelle_phabricator_name(name = name, ext = "conf")),
-"""<VirtualHost *:80>
- ServerName """ + server_name + """
- ServerAdmin webmaster@localhost
- DocumentRoot """ + config.home.implode + """/webroot
-
- ErrorLog ${APACHE_LOG_DIR}/error.log
- CustomLog ${APACHE_LOG_DIR}/access.log combined
+ webserver.php_init()
- RewriteEngine on
- RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
-</VirtualHost>
-
-# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
-""")
-
- Isabelle_System.bash( """
- set -e
- a2enmod rewrite
- a2ensite """ + Bash.string(isabelle_phabricator_name(name = name))).check
+ webserver.site_init(name, server_name, config.webroot)
config.execute("config set phabricator.base-uri " + Bash.string(server_url))
- Linux.service_restart("apache2")
+ webserver.restart()
progress.echo("\nFurther manual configuration via " + server_url)
@@ -500,7 +601,7 @@
Linux.service_install(phd_name,
"""[Unit]
Description=PHP daemon manager for Isabelle/Phabricator
-After=syslog.target network.target apache2.service mysql.service
+After=syslog.target network.target """ + webserver.system_name + """.service mysql.service
[Service]
Type=oneshot
@@ -535,6 +636,7 @@
var name = default_name
var options = Options.init()
var root = ""
+ var webserver = default_webserver
val getopts = Getopts("""
Usage: isabelle phabricator_setup [OPTIONS]
@@ -547,8 +649,11 @@
-n NAME Phabricator installation name (default: """ + quote(default_name) + """)
-o OPTION override Isabelle system OPTION (via NAME=VAL or NAME)
-r DIR installation root directory (default: """ + default_root("NAME") + """)
+ -w NAME webserver name (""" +
+ all_webservers.map(w => quote(w.short_name)).mkString (" or ") +
+ ", default: " + quote(default_webserver.short_name) + """)
- Install Phabricator as LAMP application (Linux, Apache, MySQL, PHP).
+ Install Phabricator as Linux service, based on webserver + PHP + MySQL.
The installation name (default: """ + quote(default_name) + """) is mapped to a regular
Unix user; this is relevant for public SSH access.
@@ -558,14 +663,15 @@
"U" -> (_ => package_update = true),
"n:" -> (arg => name = arg),
"o:" -> (arg => options = options + arg),
- "r:" -> (arg => root = arg))
+ "r:" -> (arg => root = arg),
+ "w:" -> (arg => webserver = get_webserver(arg)))
val more_args = getopts(args)
if (more_args.nonEmpty) getopts.usage()
val progress = new Console_Progress
- phabricator_setup(options, name = name, root = root, repo = repo,
+ phabricator_setup(options, name = name, root = root, repo = repo, webserver = webserver,
package_update = package_update, mercurial_source = mercurial_source, progress = progress)
})