16 |
16 |
17 |
17 |
18 object Phabricator { |
18 object Phabricator { |
19 /** defaults **/ |
19 /** defaults **/ |
20 |
20 |
21 /* required packages */ |
21 /* webservers */ |
|
22 |
|
23 sealed abstract class Webserver { |
|
24 override def toString: String = title |
|
25 def title: String |
|
26 def short_name: String |
|
27 def system_name: String = short_name |
|
28 |
|
29 def packages(): List[String] |
|
30 |
|
31 def system_path: Path = Path.basic(system_name) |
|
32 def root_dir: Path = Path.explode("/etc") + system_path |
|
33 def sites_dir: Path = root_dir + Path.explode("sites-available") |
|
34 |
|
35 def restart(): Unit = Linux.service_restart(system_name) |
|
36 |
|
37 def systemctl(cmd: String): String = "systemctl " + cmd + " " + system_name |
|
38 |
|
39 def php_version(): String = |
|
40 Isabelle_System.bash("""php --run 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'""") |
|
41 .check.out |
|
42 |
|
43 def php_config: String = |
|
44 "post_max_size = 32M\n" + |
|
45 "opcache.validate_timestamps = 0\n" + |
|
46 "memory_limit = 512M\n" + |
|
47 "max_execution_time = 120\n" |
|
48 |
|
49 def php_init(): Unit = () |
|
50 |
|
51 def site_name(name: String): String = isabelle_phabricator_name(name = name) |
|
52 |
|
53 def site_conf(name: String): Path = |
|
54 sites_dir + Path.basic(isabelle_phabricator_name(name = name, ext = "conf")) |
|
55 |
|
56 def site_init(name: String, server_name: String, webroot: String): Unit |
|
57 } |
|
58 |
|
59 object Apache extends Webserver { |
|
60 override val title = "Apache" |
|
61 override val short_name = "apache" |
|
62 override def system_name = "apache2" |
|
63 override def packages(): List[String] = List("apache2", "libapache2-mod-php") |
|
64 |
|
65 override def php_init(): Unit = { |
|
66 val php_conf = |
|
67 Path.explode("/etc/php") + Path.basic(php_version()) + // educated guess |
|
68 Path.basic(system_name) + Path.explode("conf.d") + |
|
69 Path.basic(isabelle_phabricator_name(ext = "ini")) |
|
70 File.write(php_conf, php_config) |
|
71 } |
|
72 |
|
73 override def site_init(name: String, server_name: String, webroot: String): Unit = { |
|
74 File.write(site_conf(name), |
|
75 """<VirtualHost *:80> |
|
76 ServerName """ + server_name + """ |
|
77 ServerAdmin webmaster@localhost |
|
78 DocumentRoot """ + webroot + """ |
|
79 |
|
80 ErrorLog ${APACHE_LOG_DIR}/error.log |
|
81 CustomLog ${APACHE_LOG_DIR}/access.log combined |
|
82 |
|
83 RewriteEngine on |
|
84 RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] |
|
85 </VirtualHost> |
|
86 |
|
87 # vim: syntax=apache ts=4 sw=4 sts=4 sr noet |
|
88 """) |
|
89 Isabelle_System.bash(""" |
|
90 set -e |
|
91 a2enmod rewrite |
|
92 a2ensite """ + Bash.string(site_name(name))).check |
|
93 } |
|
94 } |
|
95 |
|
96 object Nginx extends Webserver { |
|
97 override val title = "Nginx" |
|
98 override val short_name = "nginx" |
|
99 override def packages(): List[String] = List("nginx", "php-fpm") |
|
100 |
|
101 override def site_init(name: String, server_name: String, webroot: String): Unit = { |
|
102 File.write(site_conf(name), |
|
103 """ |
|
104 server { |
|
105 server_name """ + server_name + """; |
|
106 root """ + webroot + """; |
|
107 |
|
108 location / { |
|
109 index index.php; |
|
110 rewrite ^/(.*)$ /index.php?__path__=/$1 last; |
|
111 } |
|
112 |
|
113 location ~ \.php$ { |
|
114 include snippets/fastcgi-php.conf; |
|
115 fastcgi_pass unix:/var/run/php/php""" + php_version() + """-fpm.sock; |
|
116 } |
|
117 |
|
118 location /index.php { |
|
119 fastcgi_index index.php; |
|
120 |
|
121 #required if PHP was built with --enable-force-cgi-redirect |
|
122 fastcgi_param REDIRECT_STATUS 200; |
|
123 |
|
124 #variables to make the $_SERVER populate in PHP |
|
125 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; |
|
126 fastcgi_param QUERY_STRING $query_string; |
|
127 fastcgi_param REQUEST_METHOD $request_method; |
|
128 fastcgi_param CONTENT_TYPE $content_type; |
|
129 fastcgi_param CONTENT_LENGTH $content_length; |
|
130 |
|
131 fastcgi_param SCRIPT_NAME $fastcgi_script_name; |
|
132 |
|
133 fastcgi_param GATEWAY_INTERFACE CGI/1.1; |
|
134 fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; |
|
135 |
|
136 fastcgi_param REMOTE_ADDR $remote_addr; |
|
137 } |
|
138 } |
|
139 """) |
|
140 Isabelle_System.bash( |
|
141 "ln -sf " + File.bash_path(site_conf(name)) + " /etc/nginx/sites-enabled/.").check |
|
142 } |
|
143 } |
|
144 |
|
145 val all_webservers: List[Webserver] = List(Apache, Nginx) |
|
146 |
|
147 def get_webserver(name: String): Webserver = |
|
148 all_webservers.find(w => w.short_name == name) getOrElse |
|
149 error("Bad webserver " + quote(name)) |
|
150 |
|
151 val default_webserver: Webserver = Apache |
|
152 |
|
153 |
|
154 |
|
155 /* system packages */ |
22 |
156 |
23 val packages_ubuntu_20_04: List[String] = |
157 val packages_ubuntu_20_04: List[String] = |
24 Docker_Build.packages ::: |
158 Docker_Build.packages ::: |
25 List( |
159 List( |
26 // https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61 |
160 // https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61 |
27 "git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql", |
161 "git", "mysql-server", "php", "php-mysql", "php-gd", "php-curl", "php-apcu", "php-cli", |
28 "php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring", |
162 "php-json", "php-mbstring", |
29 // more packages |
163 // more packages |
30 "php-xml", "php-zip", "python3-pygments", "ssh", "subversion", "python-pygments", |
164 "php-xml", "php-zip", "python3-pygments", "ssh", "subversion", "python-pygments", |
31 // mercurial build packages |
165 // mercurial build packages |
32 "make", "gcc", "python", "python2-dev", "python-docutils", "python-openssl") |
166 "make", "gcc", "python", "python2-dev", "python-docutils", "python-openssl") |
33 |
167 |
34 val packages_ubuntu_22_04: List[String] = |
168 val packages_ubuntu_22_04: List[String] = |
35 Docker_Build.packages ::: |
169 Docker_Build.packages ::: |
36 List( |
170 List( |
37 // https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61 |
171 // https://secure.phabricator.com/source/phabricator/browse/master/scripts/install/install_ubuntu.sh 15e6e2adea61 |
38 "git", "mysql-server", "apache2", "libapache2-mod-php", "php", "php-mysql", |
172 "git", "mysql-server", "php", "php-mysql", "php-gd", "php-curl", "php-apcu", "php-cli", |
39 "php-gd", "php-curl", "php-apcu", "php-cli", "php-json", "php-mbstring", |
173 "php-json", "php-mbstring", |
40 // more packages |
174 // more packages |
41 "php-xml", "php-zip", "python3-pygments", "ssh", "subversion") |
175 "php-xml", "php-zip", "python3-pygments", "ssh", "subversion") |
42 |
176 |
43 def packages: List[String] = { |
177 def packages(webserver: Webserver): List[String] = { |
44 val release = Linux.Release() |
178 val release = Linux.Release() |
45 if (release.is_ubuntu_20_04) packages_ubuntu_20_04 |
179 val pkgs = |
46 else if (release.is_ubuntu_22_04) packages_ubuntu_22_04 |
180 if (release.is_ubuntu_20_04) packages_ubuntu_20_04 |
47 else error("Bad Linux version: expected Ubuntu 20.04 or 22.04 LTS") |
181 else if (release.is_ubuntu_22_04) packages_ubuntu_22_04 |
|
182 else error("Bad Linux version: expected Ubuntu 20.04 or 22.04 LTS") |
|
183 pkgs ::: webserver.packages() |
48 } |
184 } |
49 |
185 |
50 |
186 |
51 /* global system resources */ |
187 /* global system resources */ |
52 |
188 |
416 done |
554 done |
417 echo -e "\nUpgrading storage ..." |
555 echo -e "\nUpgrading storage ..." |
418 "$ROOT/phabricator/bin/storage" upgrade --force |
556 "$ROOT/phabricator/bin/storage" upgrade --force |
419 """, |
557 """, |
420 exit = |
558 exit = |
421 """systemctl start apache2 |
559 webserver.systemctl("start") + """ |
422 systemctl start isabelle-phabricator-phd""") |
560 systemctl start isabelle-phabricator-phd""") |
423 |
561 |
424 |
562 |
425 /* PHP setup */ |
563 /* webserver setup */ |
426 |
564 |
427 val php_version = |
565 progress.echo(webserver.title + " setup ...") |
428 Isabelle_System.bash("""php --run 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;'""") |
566 |
429 .check.out |
567 val sites_dir = webserver.sites_dir |
430 |
568 if (!sites_dir.is_dir) error("Bad " + webserver + " sites directory " + sites_dir) |
431 val php_conf = |
|
432 Path.explode("/etc/php") + Path.basic(php_version) + // educated guess |
|
433 Path.explode("apache2/conf.d") + |
|
434 Path.basic(isabelle_phabricator_name(ext = "ini")) |
|
435 |
|
436 File.write(php_conf, |
|
437 "post_max_size = 32M\n" + |
|
438 "opcache.validate_timestamps = 0\n" + |
|
439 "memory_limit = 512M\n" + |
|
440 "max_execution_time = 120\n") |
|
441 |
|
442 |
|
443 /* Apache setup */ |
|
444 |
|
445 progress.echo("Apache setup ...") |
|
446 |
|
447 val apache_root = Path.explode("/etc/apache2") |
|
448 val apache_sites = apache_root + Path.explode("sites-available") |
|
449 |
|
450 if (!apache_sites.is_dir) error("Bad Apache sites directory " + apache_sites) |
|
451 |
569 |
452 val server_name = phabricator_name(name = name, ext = "localhost") // alias for "localhost" for testing |
570 val server_name = phabricator_name(name = name, ext = "localhost") // alias for "localhost" for testing |
453 val server_url = "http://" + server_name |
571 val server_url = "http://" + server_name |
454 |
572 |
455 File.write(apache_sites + Path.basic(isabelle_phabricator_name(name = name, ext = "conf")), |
573 webserver.php_init() |
456 """<VirtualHost *:80> |
574 |
457 ServerName """ + server_name + """ |
575 webserver.site_init(name, server_name, config.webroot) |
458 ServerAdmin webmaster@localhost |
|
459 DocumentRoot """ + config.home.implode + """/webroot |
|
460 |
|
461 ErrorLog ${APACHE_LOG_DIR}/error.log |
|
462 CustomLog ${APACHE_LOG_DIR}/access.log combined |
|
463 |
|
464 RewriteEngine on |
|
465 RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] |
|
466 </VirtualHost> |
|
467 |
|
468 # vim: syntax=apache ts=4 sw=4 sts=4 sr noet |
|
469 """) |
|
470 |
|
471 Isabelle_System.bash( """ |
|
472 set -e |
|
473 a2enmod rewrite |
|
474 a2ensite """ + Bash.string(isabelle_phabricator_name(name = name))).check |
|
475 |
576 |
476 config.execute("config set phabricator.base-uri " + Bash.string(server_url)) |
577 config.execute("config set phabricator.base-uri " + Bash.string(server_url)) |
477 |
578 |
478 Linux.service_restart("apache2") |
579 webserver.restart() |
479 |
580 |
480 progress.echo("\nFurther manual configuration via " + server_url) |
581 progress.echo("\nFurther manual configuration via " + server_url) |
481 |
582 |
482 |
583 |
483 /* PHP daemon */ |
584 /* PHP daemon */ |
545 -R DIR repository directory (default: """ + default_repo("NAME") + """) |
647 -R DIR repository directory (default: """ + default_repo("NAME") + """) |
546 -U full update of system packages before installation |
648 -U full update of system packages before installation |
547 -n NAME Phabricator installation name (default: """ + quote(default_name) + """) |
649 -n NAME Phabricator installation name (default: """ + quote(default_name) + """) |
548 -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) |
650 -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) |
549 -r DIR installation root directory (default: """ + default_root("NAME") + """) |
651 -r DIR installation root directory (default: """ + default_root("NAME") + """) |
550 |
652 -w NAME webserver name (""" + |
551 Install Phabricator as LAMP application (Linux, Apache, MySQL, PHP). |
653 all_webservers.map(w => quote(w.short_name)).mkString (" or ") + |
|
654 ", default: " + quote(default_webserver.short_name) + """) |
|
655 |
|
656 Install Phabricator as Linux service, based on webserver + PHP + MySQL. |
552 |
657 |
553 The installation name (default: """ + quote(default_name) + """) is mapped to a regular |
658 The installation name (default: """ + quote(default_name) + """) is mapped to a regular |
554 Unix user; this is relevant for public SSH access. |
659 Unix user; this is relevant for public SSH access. |
555 """, |
660 """, |
556 "M:" -> (arg => mercurial_source = (if (arg == ":") standard_mercurial_source else arg)), |
661 "M:" -> (arg => mercurial_source = (if (arg == ":") standard_mercurial_source else arg)), |
557 "R:" -> (arg => repo = arg), |
662 "R:" -> (arg => repo = arg), |
558 "U" -> (_ => package_update = true), |
663 "U" -> (_ => package_update = true), |
559 "n:" -> (arg => name = arg), |
664 "n:" -> (arg => name = arg), |
560 "o:" -> (arg => options = options + arg), |
665 "o:" -> (arg => options = options + arg), |
561 "r:" -> (arg => root = arg)) |
666 "r:" -> (arg => root = arg), |
|
667 "w:" -> (arg => webserver = get_webserver(arg))) |
562 |
668 |
563 val more_args = getopts(args) |
669 val more_args = getopts(args) |
564 if (more_args.nonEmpty) getopts.usage() |
670 if (more_args.nonEmpty) getopts.usage() |
565 |
671 |
566 val progress = new Console_Progress |
672 val progress = new Console_Progress |
567 |
673 |
568 phabricator_setup(options, name = name, root = root, repo = repo, |
674 phabricator_setup(options, name = name, root = root, repo = repo, webserver = webserver, |
569 package_update = package_update, mercurial_source = mercurial_source, progress = progress) |
675 package_update = package_update, mercurial_source = mercurial_source, progress = progress) |
570 }) |
676 }) |
571 |
677 |
572 |
678 |
573 |
679 |