aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes19
-rw-r--r--AUTHORS7
-rw-r--r--CONTRIBUTING.md13
-rw-r--r--INSTALL143
-rw-r--r--INSTALL-DEV4
-rw-r--r--INSTALL-PROXY136
-rw-r--r--LEGAL6
-rw-r--r--LICENSE35
-rw-r--r--NEWS15
-rw-r--r--brep/handler/buildfile1
-rw-r--r--brep/handler/ci/buildfile1
-rw-r--r--brep/handler/ci/ci-dir.in1
-rw-r--r--brep/handler/ci/ci-load.in1
-rw-r--r--brep/handler/ci/ci.bash.in1
-rw-r--r--brep/handler/handler.bash.in1
-rw-r--r--brep/handler/submit/buildfile1
-rw-r--r--brep/handler/submit/submit-dir.in1
-rw-r--r--brep/handler/submit/submit-git.bash.in1
-rw-r--r--brep/handler/submit/submit-git.in10
-rw-r--r--brep/handler/submit/submit.bash.in1
-rw-r--r--build/bootstrap.build1
-rw-r--r--build/export.build1
-rw-r--r--build/root.build8
-rw-r--r--buildfile5
-rw-r--r--clean/buildfile5
-rw-r--r--clean/clean.cli5
-rw-r--r--clean/clean.cxx13
-rw-r--r--doc/buildfile10
-rwxr-xr-xdoc/cli.sh36
-rw-r--r--doc/manual.cli12
m---------doc/style0
-rw-r--r--etc/brep-module.conf33
-rw-r--r--etc/buildfile1
-rw-r--r--etc/proxy-apache2.conf144
-rw-r--r--etc/systemd/brep-clean.timer4
-rw-r--r--etc/systemd/brep-monitor.service14
-rw-r--r--etc/systemd/brep-monitor.timer23
-rw-r--r--libbrep/build-extra.sql27
-rw-r--r--libbrep/build-package.hxx26
-rw-r--r--libbrep/build.cxx22
-rw-r--r--libbrep/build.hxx90
-rw-r--r--libbrep/build.xml37
-rw-r--r--libbrep/buildfile1
-rw-r--r--libbrep/common-traits.hxx1
-rw-r--r--libbrep/common.cxx27
-rw-r--r--libbrep/common.hxx63
-rw-r--r--libbrep/database-lock.cxx1
-rw-r--r--libbrep/database-lock.hxx1
-rwxr-xr-xlibbrep/odb.sh2
-rw-r--r--libbrep/package-traits.cxx1
-rw-r--r--libbrep/package-traits.hxx1
-rw-r--r--libbrep/package.cxx36
-rw-r--r--libbrep/package.hxx112
-rw-r--r--libbrep/package.xml234
-rw-r--r--libbrep/types.hxx7
-rw-r--r--libbrep/utility.hxx2
-rw-r--r--libbrep/version.hxx.in1
-rw-r--r--libbrep/wrapper-traits.hxx1
-rw-r--r--load/buildfile5
-rw-r--r--load/load.cli8
-rw-r--r--load/load.cxx135
-rw-r--r--load/types-parsers.cxx1
-rw-r--r--load/types-parsers.hxx1
-rw-r--r--manifest22
-rw-r--r--migrate/buildfile5
-rw-r--r--migrate/migrate.cli5
-rw-r--r--migrate/migrate.cxx11
-rw-r--r--mod/.gitignore2
-rw-r--r--mod/build-config-module.cxx237
-rw-r--r--mod/build-config-module.hxx43
-rw-r--r--mod/build-config.cxx255
-rw-r--r--mod/build-config.hxx49
-rw-r--r--mod/build.cxx3
-rw-r--r--mod/build.hxx1
-rw-r--r--mod/buildfile32
-rw-r--r--mod/database-module.cxx3
-rw-r--r--mod/database-module.hxx3
-rw-r--r--mod/database.cxx1
-rw-r--r--mod/database.hxx1
-rw-r--r--mod/diagnostics.cxx1
-rw-r--r--mod/diagnostics.hxx1
-rw-r--r--mod/external-handler.cxx1
-rw-r--r--mod/external-handler.hxx1
-rw-r--r--mod/mod-build-configs.cxx8
-rw-r--r--mod/mod-build-configs.hxx3
-rw-r--r--mod/mod-build-force.cxx5
-rw-r--r--mod/mod-build-force.hxx3
-rw-r--r--mod/mod-build-log.cxx5
-rw-r--r--mod/mod-build-log.hxx3
-rw-r--r--mod/mod-build-result.cxx8
-rw-r--r--mod/mod-build-result.hxx3
-rw-r--r--mod/mod-build-task.cxx130
-rw-r--r--mod/mod-build-task.hxx3
-rw-r--r--mod/mod-builds.cxx44
-rw-r--r--mod/mod-builds.hxx3
-rw-r--r--mod/mod-ci.cxx31
-rw-r--r--mod/mod-ci.hxx5
-rw-r--r--mod/mod-package-details.cxx10
-rw-r--r--mod/mod-package-details.hxx3
-rw-r--r--mod/mod-package-version-details.cxx61
-rw-r--r--mod/mod-package-version-details.hxx3
-rw-r--r--mod/mod-packages.cxx10
-rw-r--r--mod/mod-packages.hxx3
-rw-r--r--mod/mod-repository-details.cxx10
-rw-r--r--mod/mod-repository-details.hxx3
-rw-r--r--mod/mod-repository-root.cxx5
-rw-r--r--mod/mod-repository-root.hxx3
-rw-r--r--mod/mod-submit.cxx27
-rw-r--r--mod/mod-submit.hxx5
-rw-r--r--mod/module.cli (renamed from mod/options.cli)43
-rw-r--r--mod/module.cxx7
-rw-r--r--mod/module.hxx5
-rw-r--r--mod/options-types.hxx1
-rw-r--r--mod/page.cxx10
-rw-r--r--mod/page.hxx8
-rw-r--r--mod/services.cxx3
-rw-r--r--mod/types-parsers.cxx39
-rw-r--r--mod/types-parsers.hxx12
-rw-r--r--mod/utility.hxx1
-rw-r--r--monitor/.gitignore2
-rw-r--r--monitor/buildfile45
-rw-r--r--monitor/module.cli16
-rw-r--r--monitor/monitor.cli190
-rw-r--r--monitor/monitor.cxx883
-rw-r--r--tests/ci/buildfile1
-rw-r--r--tests/ci/ci-dir.testscript1
-rw-r--r--tests/ci/ci-load.testscript1
-rw-r--r--tests/ci/data.testscript1
-rw-r--r--tests/load/1/math/libfoo-benchmarks-1.2.4.tar.gzbin262 -> 264 bytes
-rw-r--r--tests/load/1/math/libfoo-examples-1.2.4.tar.gzbin268 -> 263 bytes
-rw-r--r--tests/load/1/math/libfoo-tests-1.2.4.tar.gzbin259 -> 260 bytes
-rw-r--r--tests/load/1/math/packages.manifest12
-rw-r--r--tests/load/buildfile1
-rw-r--r--tests/load/driver.cxx3
-rw-r--r--tests/submit/buildfile1
-rw-r--r--tests/submit/data.testscript1
-rw-r--r--tests/submit/submit-dir.testscript1
-rw-r--r--tests/submit/submit-git.testscript1
-rw-r--r--tests/web/xhtml/buildfile5
-rw-r--r--tests/web/xhtml/driver.cxx3
-rw-r--r--web/server/apache/log.hxx (renamed from web/apache/log.hxx)11
-rw-r--r--web/server/apache/request.cxx (renamed from web/apache/request.cxx)7
-rw-r--r--web/server/apache/request.hxx (renamed from web/apache/request.hxx)15
-rw-r--r--web/server/apache/request.ixx (renamed from web/apache/request.ixx)3
-rw-r--r--web/server/apache/service.cxx (renamed from web/apache/service.cxx)9
-rw-r--r--web/server/apache/service.hxx (renamed from web/apache/service.hxx)17
-rw-r--r--web/server/apache/service.txx (renamed from web/apache/service.txx)3
-rw-r--r--web/server/apache/stream.hxx (renamed from web/apache/stream.hxx)11
-rw-r--r--web/server/buildfile (renamed from web/buildfile)8
-rw-r--r--web/server/mime-url-encoding.cxx (renamed from web/mime-url-encoding.cxx)5
-rw-r--r--web/server/mime-url-encoding.hxx (renamed from web/mime-url-encoding.hxx)9
-rw-r--r--web/server/module.hxx (renamed from web/module.hxx)9
-rw-r--r--web/version.hxx.in12
-rw-r--r--web/xhtml/.gitignore (renamed from web/.gitignore)0
-rw-r--r--web/xhtml/buildfile10
-rw-r--r--web/xhtml/fragment.cxx (renamed from web/xhtml-fragment.cxx)7
-rw-r--r--web/xhtml/fragment.hxx (renamed from web/xhtml-fragment.hxx)3
-rw-r--r--web/xhtml/serialization.hxx (renamed from web/xhtml.hxx)11
-rw-r--r--web/xhtml/version.hxx.in11
-rw-r--r--www/buildfile1
160 files changed, 2942 insertions, 1147 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..9756e4d
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,19 @@
+# This is a good default: files that are auto-detected by git to be text are
+# converted to the platform-native line ending (LF on Unix, CRLF on Windows)
+# in the working tree and to LF in the repository.
+#
+* text=auto
+
+# Use `eol=crlf` for files that should have the CRLF line ending both in the
+# working tree (even on Unix) and in the repository.
+#
+#*.bat text eol=crlf
+
+# Use `eol=lf` for files that should have the LF line ending both in the
+# working tree (even on Windows) and in the repository.
+#
+#*.sh text eol=lf
+
+# Use `binary` to make sure certain files are never auto-detected as text.
+#
+*.gz binary
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9780708
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+This file contains information about the build2 authors for copyright
+purposes.
+
+The copyright for the code is held by the contributors of the code. The
+revision history in the version control system is the primary source of
+authorship information for copyright purposes. Contributors that have
+requested to also be noted explicitly in this file are listed below:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a3216bb..6bfc34f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,16 @@
This project is part of the `build2` toolchain; see its
[Community](https://build2.org/community.xhtml) page for various ways to
contribute.
+
+The copyright for the code is held by the contributors of the code (see the
+`AUTHORS` file). The code is licensed under permissive open source licensing
+terms (see the `LICENSE` file). When you contribute code to this project, you
+license it under these terms. Before contributing please make sure that these
+terms are acceptable to you (and to your employer(s), if they have rights to
+intellectual property that you create) and that the code being contributed is
+your original creation.
+
+The revision history in the version control system is the primary source of
+authorship information for copyright purposes. If, however, you would like
+to also be noted explicitly, please include the appropriate change to the
+`AUTHORS` file along with your contribution.
diff --git a/INSTALL b/INSTALL
index 59ec07e..94fecf0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,8 +11,9 @@ can be omitted.
1. Create 'brep' User
This user will be used to run the brep package database loader, build database
-cleaner, and the database schemes migration utility. We will also use its home
-directory to build and install the brep module, store its configuration, etc.
+cleaner, monitor, and database schemas migration utility. We will also use its
+home directory to build and install the brep module, store its configuration,
+etc.
Note: if the deployment machine employs SELinux, then this approach may
require additional configuration steps (not shown) in order to allow Apache2
@@ -65,7 +66,7 @@ c) Install PostgreSQL and Apache2 development files. Specifically, we need
files. Below are the names of their packages for some distributions:
Debian/Ubuntu: libpq-dev libapr1-dev libapreq2-dev apache2-dev
- Fedora/RHEL: posqtgresql-devel apr-devel libapreq2-devel httpd-devel
+ Fedora/RHEL: postgresql-devel apr-devel libapreq2-devel httpd-devel
FreeBSD: postgresqlXY-client apr libapreq2 apache24
d) Unless you already have the build2 toolchain, install it by following
@@ -194,7 +195,7 @@ CREATE EXTENSION citext;
Exit psql (^D)
-5. Create Database Schemes and Load Repositories
+5. Create Database Schemas and Load Repositories
$ mkdir config
$ edit config/loadtab # Loader configuration, see brep-load(1).
@@ -261,75 +262,8 @@ $ edit config/ci.xhtml # Add custom form fields, adjust CSS style, etc.
For sample CI request handler implementations see brep/handler/ci/.
Here we assume you have setup an appropriate Apache2 virtual server. Open the
-corresponding Apache2 .conf file and add the following inside VirtualHost (you
-can also find this fragment in install/share/brep/etc/brep-apache2.conf):
-
- # Load the brep module.
- #
- <IfModule !brep_module>
- LoadModule brep_module /home/brep/install/libexec/brep/mod_brep.so
- </IfModule>
-
- # Repository email. This email is used for the From: header in emails
- # send by brep (for example, build failure notifications).
- #
- brep-email admin@example.org
-
- # Repository host. It specifies the scheme and the host address (but
- # not the root path; see brep-root below) that will be used whenever
- # brep needs to construct an absolute URL to one of its locations (for
- # example, a link to a build log that is being send via email).
- #
- brep-host https://example.org
-
- # Repository root. This is the part of the URL between the host name
- # and the start of the repository. For example, root value /pkg means
- # the repository URL is http://example.org/pkg/. Specify / to use the
- # web server root (e.g., http://example.org/). If using a different
- # repository root, don't forget to also change Location and Alias
- # directives below.
- #
- brep-root /pkg
-
- <Location "/pkg">
- SetHandler brep
-
- <IfModule dir_module>
- DirectoryIndex disabled
- DirectorySlash Off
- </IfModule>
- </Location>
-
- # Brep module configuration. If you prefer, you can paste the contents
- # of this file here. However, you will need to prefix every option with
- # 'brep-'.
- #
- brep-conf /home/brep/config/brep-module.conf
-
- # Static brep content (CSS files).
- #
- <IfModule !alias_module>
- Error "mod_alias is not enabled"
- </IfModule>
-
- # Note: trailing slashes are important!
- #
- Alias /pkg/@/ /home/brep/install/share/brep/www/
-
- <Directory "/home/brep/install/share/brep/www">
- Require all granted
- </Directory>
-
- # You can also serve the repository files from the repository root.
- # For example:
- #
- # http://example.org/pkg/1/... -> /path/to/repo/1/...
- #
- #AliasMatch ^/pkg/(\d+)/(.+) /path/to/repo/$1/$2
- #
- #<Directory "/path/to/repo">
- # Require all granted
- #</Directory>
+corresponding Apache2 .conf file and add the contents of
+brep/etc/brep-apache2.conf into the <VirtualHost> section.
The output content types of the brep module are application/xhtml+xml,
text/manifest and text/plain. If you would like to make sure they get
@@ -384,15 +318,15 @@ $ cd install/share/brep/www/
$ for i in *.scss; do sassc -s compressed $i `basename -s .scss $i`.css; done
-8. Setup Periodic Loader and Cleaner Execution
+8. Setup Periodic Loader, Cleaner, and Monitor Execution
Initially this guide suggested using systemd user session support to run the
-loader and the cleaner. However, the current state of user sessions has one
-major drawback: they are not started/attached-to when logging in with su -l
-(see Debian bug #813789 for details). This limitation makes them unusable in
-our setup. If you still would like to use systemd to run the loader and the
-cleaner, then you can set it up as a system-wide service which runs the
-utilities as the brep user/group. Otherwise, a cron job is a natural choice.
+loader, cleaner, and monitor. However, the current state of user sessions has
+one major drawback: they are not started/attached-to when logging in with su
+-l (see Debian bug #813789 for details). This limitation makes them unusable
+in our setup. If you still would like to use systemd to run the utilities,
+then you can set it up as a system-wide service which runs them as the brep
+user/group. Otherwise, a cron job is a natural choice.
Note that the builds cleaner execution is optional and is only required if the
build2 build bot functionality is enabled (see the build bot documentation for
@@ -402,29 +336,37 @@ parts in the subsequent subsections.
If the CI request functionality is enabled you most likely will want to
additionally setup the tenants cleanup.
+The monitor execution is also optional and currently only makes sense if the
+build2 build bot functionality is enabled. Note that you may need to replace
+the public toolchain name argument in the monitor utility command with a real
+list of toolchain names (and optionally versions) used in the brep build
+infrastructure.
+
-8.a Setup Periodic Loader and Cleaner Execution with cron
+8.a Setup Periodic Loader, Cleaner, and Monitor Execution with cron
-The following crontab entries will execute the loader every five minutes
-and the tenants and builds cleaners once a day at midnight:
+The following crontab entries will execute the loader every five minutes, the
+tenants and builds cleaners once a day at midnight, and the monitor every hour
+(all shifted by a few minutes in order not to clash with other jobs):
$ crontab -l
MAILTO=<brep-admin-email>
PATH=/usr/local/bin:/bin:/usr/bin
*/5 * * * * $HOME/install/bin/brep-load $HOME/config/loadtab
-0 0 * * * $HOME/install/bin/brep-clean tenants 240
-0 0 * * * $HOME/install/bin/brep-clean builds $HOME/config/buildtab
+1 0 * * * $HOME/install/bin/brep-clean tenants 240
+2 0 * * * $HOME/install/bin/brep-clean builds $HOME/config/buildtab
+3 * * * * $HOME/install/bin/brep-monitor --report-timeout 86400 --clean $HOME/config/brep-module.conf public
^D
Note that here we assume that bpkg (which is executed by brep-load) is in one
of the PATH's directories (usually /usr/local/bin).
-8.b Setup Periodic Loader and Cleaner Execution with systemd
+8.b Setup Periodic Loader, Cleaner, and Monitor Execution with systemd
In this version we will use the systemd user session to periodically run the
-loader and the cleaner as the brep user. If your installation doesn't use
-systemd, then a cron job would be a natural alternative (see above).
+loader, cleaner, and monitor as the brep user. If your installation doesn't
+use systemd, then a cron job would be a natural alternative (see above).
As the first step, make sure systemd user sessions support is working for the
brep user:
@@ -443,6 +385,7 @@ $ sudo loginctl enable-linger brep
$ mkdir -p .config/systemd/user
$ cp install/share/brep/etc/systemd/brep-load.* .config/systemd/user/
$ cp install/share/brep/etc/systemd/brep-clean.* .config/systemd/user/
+$ cp install/share/brep/etc/systemd/brep-monitor.* .config/systemd/user/
Start the service to make sure there are no issues:
@@ -452,16 +395,21 @@ $ journalctl
$ systemctl --user start brep-clean.service
$ journalctl
+$ systemctl --user start brep-monitor.service
+$ journalctl
+
Start the timers and monitor them to make sure they fire:
$ systemctl --user start brep-load.timer
$ systemctl --user start brep-clean.timer
+$ systemctl --user start brep-monitor.timer
$ journalctl -f
If everything looks good, enable the timer to be started at boot time:
$ systemctl --user enable brep-load.timer
$ systemctl --user enable brep-clean.timer
+$ systemctl --user enable brep-monitor.timer
9. Upgrade Procedure
@@ -483,18 +431,20 @@ $ cd brep
$ bpkg fetch
$ bpkg build brep
-If you are using a systemd-based setup, then stop and disable the loader and
-the cleaner:
+If you are using a systemd-based setup, then stop and disable the loader,
+cleaner, and monitor:
$ systemctl --user disable --now brep-load.timer
$ systemctl --user disable --now brep-clean.timer
+$ systemctl --user disable --now brep-monitor.timer
$ systemctl --user stop brep-load.service
$ systemctl --user stop brep-clean.service
+$ systemctl --user stop brep-monitor.service
If you are using a cron-based setup, then it is not worth it commenting out the
-job entries. If the new version of the loader or the cleaner gets executed
-before or during the migration, then it will fail and you will get an email
-with the diagnostics. Other than that, it should be harmless.
+job entries. If the new version of the brep utilities gets executed before or
+during the migration, then it will fail and you will get an email with the
+diagnostics. Other than that, it should be harmless.
Stop apache:
@@ -510,7 +460,7 @@ Review brep-module.conf changes that may need to be merged:
$ diff -u install/share/brep/etc/brep-module.conf config/brep-module.conf
-Migrate database schemes:
+Migrate database schemas:
$ install/bin/brep-migrate package
$ install/bin/brep-migrate build
@@ -521,17 +471,20 @@ is not possible), then one way to do it would be:
$ psql -d brep_package -c 'DROP OWNED BY brep'
$ psql -d brep_build -c 'DROP OWNED BY brep'
-If using systemd, then start and enable the loader and the cleaner:
+If using systemd, then start and enable the loader, cleaner, and monitor:
$ systemctl --user start brep-load.service
$ systemctl --user status brep-load.service
$ systemctl --user start brep-clean.service
$ systemctl --user status brep-clean.service
+$ systemctl --user start brep-monitor.service
+$ systemctl --user status brep-monitor.service
If everything looks good, enable periodic execution:
$ systemctl --user enable --now brep-load.timer
$ systemctl --user enable --now brep-clean.timer
+$ systemctl --user enable --now brep-monitor.timer
If using cron, then simply wait for the next run.
diff --git a/INSTALL-DEV b/INSTALL-DEV
index 101d9d7..af5c06e 100644
--- a/INSTALL-DEV
+++ b/INSTALL-DEV
@@ -113,7 +113,7 @@ CREATE EXTENSION citext;
Exit psql (^D)
-2. Create Database Schemes and Load the Repository
+2. Create Database Schemas and Load the Repository
All the commands are executed from brep project root.
@@ -205,7 +205,7 @@ $ sudo tail -f /var/log/apache2/error.log
4. Reloading During Development
-To do a "complete reload" (i.e., recreate database schemes, load the repository
+To do a "complete reload" (i.e., recreate database schemas, load the repository
data, and reload the Apache2 plugin), execute the following from brep/:
$ migrate/brep-migrate --recreate package
diff --git a/INSTALL-PROXY b/INSTALL-PROXY
new file mode 100644
index 0000000..418846a
--- /dev/null
+++ b/INSTALL-PROXY
@@ -0,0 +1,136 @@
+This guide shows how to configure the Apache2-based HTTP proxy server for
+proxying HTTP(S) requests and caching the responses.
+
+Note that for security reasons most clients (curl, wget, etc) perform HTTPS
+requests via HTTP proxies by establishing a tunnel using the HTTP CONNECT
+method and encrypting all the communications, thus making the origin server's
+responses non-cacheable. This proxy setup uses the over-HTTP caching for cases
+when the HTTPS response caching is desirable and presumed safe (for example,
+signed repository manifests, checksum'ed package archives, etc., or the proxy
+is located inside a trusted, private network).
+
+Specifically, this setup interprets the requested HTTP URLs as HTTPS URLs by
+default, effectively replacing the http URL scheme with https. If desired, to
+also support proxying/caching of the HTTP URL requests, the proxy can be
+configured to either recognize certain hosts as HTTP-only or to recognize a
+custom HTTP header that can be sent by an HTTP client to prevent the
+http-to-https scheme conversion.
+
+In this guide commands that start with the # shell prompt are expected to be
+executed as root and those starting with $ -- as a regular user in their home
+directory. All the commands are provided for Debian, so you may need to adjust
+them to match your distribution/OS.
+
+1. Enable Apache2 Modules
+
+Here we assume you have the Apache2 server installed and running.
+
+Enable the following Apache2 modules used in the proxy setup:
+
+ rewrite
+ headers
+ ssl
+ proxy
+ proxy_http
+ cache
+ cache_disk
+
+These modules are commonly used and are likely to be installed together with
+the Apache2 server. After the modules are enabled restart Apache2 and make
+sure that the server has started successfully. For example:
+
+# a2enmod rewrite # Enable the rewrite module.
+ ...
+# systemctl restart apache2
+# systemctl status apache2 # Verify started.
+
+To troubleshoot, see Apache logs.
+
+
+2. Setup Proxy in Apache2 Configuration File
+
+Create the directory for the proxy logs. For example:
+
+# mkdir -p /var/www/cache.lan/log
+
+Note that here and below we assume that the host name the Apache2 instance is
+running is cache.lan.
+
+Create a separate <VirtualHost> section intended for proxying HTTP(S) requests
+and caching the responses in the Apache2 configuration file. Note that there
+is no single commonly used HTTP proxy port, thus you may want to use the port
+80 if it is not already assigned to some other virtual host. If you decide to
+use some other port, make sure the corresponding `Listen <port>` directive is
+present in the Apache2 configuration file.
+
+Inside <VirtualHost> replace DocumentRoot (and anything else related to the
+normal document serving) with the contents of brep/etc/proxy-apache2.conf and
+adjust CacheRoot (see below) as well as any other values if desired.
+
+<VirtualHost *:80>
+ LogLevel warn
+ ErrorLog /var/www/cache.lan/log/error.log
+ CustomLog /var/www/cache.lan/log/access.log combined
+
+ <contents of proxy-apache2.conf>
+
+</VirtualHost>
+
+We will assume that the default /var/cache/apache2/mod_cache_disk directory is
+specified for the CacheRoot directive. If that's not the case, then make sure
+the specified directory is writable by the user under which Apache2 is
+running, for example, executing the following command:
+
+# setfacl -m g:www-data:rwx /path/to/proxy/cache
+
+Restart Apache2 and make sure that the server has started successfully.
+
+# systemctl restart apache2
+# systemctl status apache2 # Verify started.
+
+Make sure the proxy functions properly and caches the HTTP responses, for
+example:
+
+$ ls /var/cache/apache2/mod_cache_disk # Empty.
+$ curl --proxy http://cache.lan:80 http://www.example.com # Prints HTML.
+$ ls /var/cache/apache2/mod_cache_disk # Non-empty.
+
+To troubleshoot, see Apache logs.
+
+
+3. Setup Periodic Cache Cleanup
+
+The cache directory cleanup is performed with the htcacheclean utility
+(normally installed together with the Apache2 server) that you can run as a
+cron job or as a systemd service. If you are running a single Apache2-based
+cache on the host, the natural choice is to run it as a system-wide service
+customizing the apache-htcacheclean systemd unit configuration, if required.
+Specifically, you may want to change the max disk cache size limit and/or the
+cache root directory path, so it matches the CacheRoot Apache2 configuration
+directive value (see above). Run the following command to see the current
+cache cleaner service setup.
+
+# systemctl cat apache-htcacheclean
+
+The output may look as follows:
+
+...
+[Service]
+...
+Environment=HTCACHECLEAN_SIZE=300M
+Environment=HTCACHECLEAN_DAEMON_INTERVAL=120
+Environment=HTCACHECLEAN_PATH=/var/cache/apache2/mod_cache_disk
+Environment=HTCACHECLEAN_OPTIONS=-n
+EnvironmentFile=-/etc/default/apache-htcacheclean
+ExecStart=/usr/bin/htcacheclean -d $HTCACHECLEAN_DAEMON_INTERVAL -p $HTCACHECLEAN_PATH -l $HTCACHECLEAN_SIZE $HTCACHECLEAN_OPTIONS
+...
+
+To change the service configuration either use the `systemctl edit
+apache-htcacheclean` command or, as for the above example, edit the
+environment file (/etc/default/apache-htcacheclean).
+
+Restart the cache cleaner service and make sure that it is started
+successfully and the process arguments match the expectations.
+
+# systemctl restart apache-htcacheclean
+# systemctl status apache-htcacheclean # Verify process arguments.
diff --git a/LEGAL b/LEGAL
new file mode 100644
index 0000000..4ccebd9
--- /dev/null
+++ b/LEGAL
@@ -0,0 +1,6 @@
+This file contains additional (to the LICENSE file) notes and details on the
+copyright and/or license for the code.
+
+ODB is licensed under the MIT-compatible terms with a license exception:
+
+https://git.codesynthesis.com/cgit/odb/odb-etc/tree/license-exceptions/build2-odb-license-exception.txt
diff --git a/LICENSE b/LICENSE
index 215ce1d..3be7e89 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,20 +1,21 @@
-Copyright (c) 2014-2019 Code Synthesis Ltd
+MIT License
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
+Copyright (c) 2014-2020 the build2 authors (see the AUTHORS and LEGAL files).
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/NEWS b/NEWS
index 1d3a6e8..9c32c19 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+Version 0.13.0
+
+ * Support for the alternative package rebuild timeout.
+
+ The alternative rebuild timeout can be used to "pull" the rebuild window
+ to the specified time of day, for example, to optimize load and/or power
+ consumption of the build infrastructure (off-work hours, solar, off-peak
+ electricity tariffs, etc).
+
+ * New brep-monitor utility for monitoring for and reporting on brep state
+ issues. Currently it only reports build delays. See brep-monitor(1) for
+ details.
+
+ * Support for test-exclude task manifest value.
+
Version 0.12.0
* Support for specifying explicit environment names in buildtabs.
diff --git a/brep/handler/buildfile b/brep/handler/buildfile
index 3b9245b..b351ca3 100644
--- a/brep/handler/buildfile
+++ b/brep/handler/buildfile
@@ -1,5 +1,4 @@
# file : brep/handler/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
import mods = libbutl.bash%bash{manifest-parser}
diff --git a/brep/handler/ci/buildfile b/brep/handler/ci/buildfile
index 3ed6807..69234d6 100644
--- a/brep/handler/ci/buildfile
+++ b/brep/handler/ci/buildfile
@@ -1,5 +1,4 @@
# file : brep/handler/ci/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
./: exe{brep-ci-dir} exe{brep-ci-load}
diff --git a/brep/handler/ci/ci-dir.in b/brep/handler/ci/ci-dir.in
index 47387ea..58aa991 100644
--- a/brep/handler/ci/ci-dir.in
+++ b/brep/handler/ci/ci-dir.in
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
# file : brep/handler/ci/ci-dir.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Simple package CI request handler with directory storage.
diff --git a/brep/handler/ci/ci-load.in b/brep/handler/ci/ci-load.in
index 915f9a6..f62bb76 100644
--- a/brep/handler/ci/ci-load.in
+++ b/brep/handler/ci/ci-load.in
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
# file : brep/handler/ci/ci-load.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Package CI request handler that loads the packages into the brep database.
diff --git a/brep/handler/ci/ci.bash.in b/brep/handler/ci/ci.bash.in
index c188ab9..4ed5fab 100644
--- a/brep/handler/ci/ci.bash.in
+++ b/brep/handler/ci/ci.bash.in
@@ -1,5 +1,4 @@
# file : brep/handler/ci/ci.bash.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Utility functions useful for implementing CI request handlers.
diff --git a/brep/handler/handler.bash.in b/brep/handler/handler.bash.in
index 2e66afc..b61bbdb 100644
--- a/brep/handler/handler.bash.in
+++ b/brep/handler/handler.bash.in
@@ -1,5 +1,4 @@
# file : brep/handler/handler.bash.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Utility functions useful for implementing request handlers.
diff --git a/brep/handler/submit/buildfile b/brep/handler/submit/buildfile
index 7951a46..d6e04dc 100644
--- a/brep/handler/submit/buildfile
+++ b/brep/handler/submit/buildfile
@@ -1,5 +1,4 @@
# file : brep/handler/submit/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
./: exe{brep-submit-dir} exe{brep-submit-git}
diff --git a/brep/handler/submit/submit-dir.in b/brep/handler/submit/submit-dir.in
index ae0dcbd..16065e6 100644
--- a/brep/handler/submit/submit-dir.in
+++ b/brep/handler/submit/submit-dir.in
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
# file : brep/handler/submit/submit-dir.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Simple package submission handler with directory storage.
diff --git a/brep/handler/submit/submit-git.bash.in b/brep/handler/submit/submit-git.bash.in
index 56cce33..9f25c28 100644
--- a/brep/handler/submit/submit-git.bash.in
+++ b/brep/handler/submit/submit-git.bash.in
@@ -1,5 +1,4 @@
# file : brep/handler/submit/submit-git.bash.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Utility functions for the submit-git handler.
diff --git a/brep/handler/submit/submit-git.in b/brep/handler/submit/submit-git.in
index 8263efe..34b1e90 100644
--- a/brep/handler/submit/submit-git.in
+++ b/brep/handler/submit/submit-git.in
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
# file : brep/handler/submit/submit-git.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Package submission handler with git repository storage.
@@ -558,7 +557,7 @@ for i in {1..11}; do
#
prj_man="$d/project-owner.manifest"
- if [ ! -f "$prj_man" ]; then
+ if [ ! -f "$prj_man" -a "$ref_auth" != "project" ]; then
run mkdir -p "$d" # Also creates the owners directory if not exist.
ctl="$(repository_base "$control")"
@@ -575,7 +574,7 @@ for i in {1..11}; do
# Now the package name.
#
d="$d/$name"
- run mkdir "$d"
+ run mkdir -p "$d" # Also creates the project directory if not exist.
pkg_man="$d/package-owner.manifest"
@@ -662,9 +661,12 @@ for i in {1..11}; do
# Finally, add the package archive to the target repository.
#
- # We copy the archive rather than move it since we may need it for a re-try.
+ # Copy the archive rather than move it since we may need it for a re-try.
+ # Make sure the project directory exists before we copy the archive into it.
+ # Note that it was removed by git-rm if it became empty.
#
a="$d/$archive"
+ run mkdir -p "$d" # Create all the parent directories as well.
run cp "$data_dir/$archive" "$a"
git_add "$tgt_dir" "${a#$tgt_dir/}"
diff --git a/brep/handler/submit/submit.bash.in b/brep/handler/submit/submit.bash.in
index d1d0634..667bbc1 100644
--- a/brep/handler/submit/submit.bash.in
+++ b/brep/handler/submit/submit.bash.in
@@ -1,5 +1,4 @@
# file : brep/handler/submit/submit.bash.in
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Utility functions useful for implementing package submission handlers.
diff --git a/build/bootstrap.build b/build/bootstrap.build
index 3941a63..07bdd4f 100644
--- a/build/bootstrap.build
+++ b/build/bootstrap.build
@@ -1,5 +1,4 @@
# file : build/bootstrap.build
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
project = brep
diff --git a/build/export.build b/build/export.build
index 60bdb11..2293a0e 100644
--- a/build/export.build
+++ b/build/export.build
@@ -1,5 +1,4 @@
# file : build/export.build
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
$out_root/
diff --git a/build/root.build b/build/root.build
index ce8ca41..627f0ee 100644
--- a/build/root.build
+++ b/build/root.build
@@ -1,5 +1,4 @@
# file : build/root.build
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
cxx.std = latest
@@ -51,3 +50,10 @@ tests/{libue libul}{*}: bin.whole = false
# Specify the test target for cross-testing.
#
test.target = $cxx.target
+
+# Extract the copyright notice from the LICENSE file.
+#
+copyright = $process.run_regex( \
+ cat $src_root/LICENSE, \
+ 'Copyright \(c\) (.+) \(see the AUTHORS and LEGAL files\)\.', \
+ '\1')
diff --git a/buildfile b/buildfile
index 5a9ff2e..17ba8ab 100644
--- a/buildfile
+++ b/buildfile
@@ -1,9 +1,8 @@
# file : buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-./: {*/ -build/ -web/} \
- doc{LICENSE NEWS README INSTALL* CONTRIBUTING.md} \
+./: {*/ -build/ -web/} \
+ doc{NEWS README INSTALL*} legal{LICENSE AUTHORS LEGAL} \
manifest
# Don't install tests or the INSTALL* files.
diff --git a/clean/buildfile b/clean/buildfile
index a183ff5..11fa2a2 100644
--- a/clean/buildfile
+++ b/clean/buildfile
@@ -1,5 +1,4 @@
# file : clean/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
import libs = libodb%lib{odb}
@@ -12,6 +11,10 @@ include ../libbrep/
exe{brep-clean}: {hxx ixx cxx}{* -clean-options} {hxx ixx cxx}{clean-options} \
../libbrep/lib{brep} $libs
+# Build options.
+#
+obj{clean}: cxx.poptions += -DBREP_COPYRIGHT=\"$copyright\"
+
# Generated options parser.
#
if $cli.configured
diff --git a/clean/clean.cli b/clean/clean.cli
index 434b32f..d3be4d6 100644
--- a/clean/clean.cli
+++ b/clean/clean.cli
@@ -1,5 +1,4 @@
// file : clean/clean.cli
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
include <vector>;
@@ -128,8 +127,8 @@ Fatal error.|
\li|\cb{2}
-An instance of \cb{brep-clean} or \l{brep-migrate(1)} is already running. Try
-again.|
+An instance of \cb{brep-clean} or some other \cb{brep} utility is already
+running. Try again.|
\li|\cb{3}
diff --git a/clean/clean.cxx b/clean/clean.cxx
index a48308b..5401ab1 100644
--- a/clean/clean.cxx
+++ b/clean/clean.cxx
@@ -1,5 +1,4 @@
// file : clean/clean.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <map>
@@ -62,7 +61,7 @@ namespace brep
<< "libbbot " << LIBBBOT_VERSION_ID << endl
<< "libbpkg " << LIBBPKG_VERSION_ID << endl
<< "libbutl " << LIBBUTL_VERSION_ID << endl
- << "Copyright (c) 2014-2019 Code Synthesis Ltd" << endl
+ << "Copyright (c) " << BREP_COPYRIGHT << "." << endl
<< "This is free software released under the MIT license." << endl;
return 0;
@@ -112,8 +111,8 @@ namespace brep
ops.db_port (),
"options='-c default_transaction_isolation=serializable'");
- // Prevent several brep-clean/migrate instances from updating build
- // database simultaneously.
+ // Prevent several brep utility instances from updating the database
+ // simultaneously.
//
database_lock l (db);
@@ -317,6 +316,12 @@ namespace brep
? i->second
: default_timeout);
+ // @@ Note that this approach doesn't consider the case when both
+ // the configuration and the package still exists but the package
+ // now excludes the configuration (configuration is now of the
+ // legacy class instead of the default class, etc). We should
+ // probably re-implement it in a way brep-monitor does it.
+ //
bool cleanup (
// Check that the build is not stale.
//
diff --git a/doc/buildfile b/doc/buildfile
index 4b2305e..f0a9387 100644
--- a/doc/buildfile
+++ b/doc/buildfile
@@ -1,11 +1,11 @@
# file : doc/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-cmds = \
-brep-clean \
-brep-load \
-brep-migrate
+cmds = \
+brep-clean \
+brep-load \
+brep-migrate \
+brep-monitor
./: {man1 xhtml}{$cmds} \
css{common pre-box man} \
diff --git a/doc/cli.sh b/doc/cli.sh
index 264b299..3475c4b 100755
--- a/doc/cli.sh
+++ b/doc/cli.sh
@@ -1,7 +1,6 @@
#! /usr/bin/env bash
-version=0.13.0-a.0.z
-date="$(date +"%B %Y")"
+version=0.14.0-a.0.z
trap 'exit 1' ERR
set -o errtrace # Trap in functions.
@@ -9,6 +8,9 @@ set -o errtrace # Trap in functions.
function info () { echo "$*" 1>&2; }
function error () { info "$*"; exit 1; }
+date="$(date +"%B %Y")"
+copyright="$(sed -n -re 's%^Copyright \(c\) (.+) \(see the AUTHORS and LEGAL files\)\.$%\1%p' ../LICENSE)"
+
while [ $# -gt 0 ]; do
case $1 in
--clean)
@@ -36,16 +38,28 @@ function compile ()
shift
done
- cli -I .. -v project="brep" -v version="$version" -v date="$date" \
---include-base-last "${o[@]}" --generate-html --html-prologue-file \
-man-prologue.xhtml --html-epilogue-file man-epilogue.xhtml --html-suffix .xhtml \
+ cli -I .. \
+-v project="brep" \
+-v version="$version" \
+-v date="$date" \
+-v copyright="$copyright" \
+--include-base-last "${o[@]}" \
+--generate-html --html-suffix .xhtml \
+--html-prologue-file man-prologue.xhtml \
+--html-epilogue-file man-epilogue.xhtml \
--link-regex '%bpkg([-.].+)%../../bpkg/doc/bpkg$1%' \
--link-regex '%brep(#.+)?%build2-repository-interface-manual.xhtml$1%' \
../$n.cli
- cli -I .. -v project="brep" -v version="$version" -v date="$date" \
---include-base-last "${o[@]}" --generate-man --man-prologue-file \
-man-prologue.1 --man-epilogue-file man-epilogue.1 --man-suffix .1 \
+ cli -I .. \
+-v project="brep" \
+-v version="$version" \
+-v date="$date" \
+-v copyright="$copyright" \
+--include-base-last "${o[@]}" \
+--generate-man --man-suffix .1 \
+--man-prologue-file man-prologue.1 \
+--man-epilogue-file man-epilogue.1 \
--link-regex '%bpkg(#.+)?%$1%' \
--link-regex '%brep(#.+)?%$1%' \
../$n.cli
@@ -57,7 +71,7 @@ o="--output-prefix brep-"
#
#compile "brep" $o --output-prefix ""
-pages="clean/clean load/load migrate/migrate"
+pages="clean/clean load/load migrate/migrate monitor/monitor"
for p in $pages; do
compile $p $o
@@ -79,13 +93,15 @@ function xhtml_to_ps () # <from> <to> [<html2ps-options>]
cli -I .. \
-v version="$(echo "$version" | sed -e 's/^\([^.]*\.[^.]*\).*/\1/')" \
-v date="$date" \
+-v copyright="$copyright" \
--generate-html --html-suffix .xhtml \
--html-prologue-file doc-prologue.xhtml \
--html-epilogue-file doc-epilogue.xhtml \
--link-regex '%b([-.].+)%../../build2/doc/b$1%' \
--link-regex '%bpkg([-.].+)%../../bpkg/doc/bpkg$1%' \
--link-regex '%bpkg(#.+)?%../../bpkg/doc/build2-package-manager-manual.xhtml$1%' \
---output-prefix build2-repository-interface- manual.cli
+--output-prefix build2-repository-interface- \
+manual.cli
xhtml_to_ps build2-repository-interface-manual.xhtml build2-repository-interface-manual-a4.ps -f doc.html2ps:a4.html2ps
ps2pdf14 -sPAPERSIZE=a4 -dOptimize=true -dEmbedAllFonts=true build2-repository-interface-manual-a4.ps build2-repository-interface-manual-a4.pdf
diff --git a/doc/manual.cli b/doc/manual.cli
index 61ef1f8..71a25a5 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -1,5 +1,4 @@
// file : doc/manual.cli
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
"\name=build2-repository-interface-manual"
@@ -16,7 +15,8 @@
This document describes \c{brep}, the \c{build2} package repository web
interface. For the command line interface of \c{brep} utilities refer to the
-\l{brep-load(1)}, \l{brep-clean(1)}, and \l{brep-migrate(1)} man pages.
+\l{brep-load(1)}, \l{brep-clean(1)}, \l{brep-migrate(1)}, and
+\l{brep-monitor(1)} man pages.
\h1#submit|Package Submission|
@@ -51,8 +51,8 @@ binary mode.|
\li|Verify other parameters are valid manifest name/value pairs.
-The value can only contain printable ASCII characters as well as tab
-(\c{\\t}), carriage return (\c{\\r}), and line feed (\c{\\n}).|
+The value can only contain UTF-8 encoded Unicode graphic characters as well as
+tab (\c{\\t}), carriage return (\c{\\r}), and line feed (\c{\\n}).|
\li|Check for a duplicate submission.
@@ -228,8 +228,8 @@ upload.|
\li|Verify other parameters are valid manifest name/value pairs.
-The value can only contain printable ASCII characters as well as tab
-(\c{\\t}), carriage return (\c{\\r}), and line feed (\c{\\n}).|
+The value can only contain UTF-8 encoded Unicode graphic characters as well as
+tab (\c{\\t}), carriage return (\c{\\r}), and line feed (\c{\\n}).|
\li|Generate CI request id and create request directory.
diff --git a/doc/style b/doc/style
-Subproject 7e75bb936cf5b2bd2fa3344e13b6c486c8ecc8a
+Subproject 10f31a8bea8e5817fccf01978009c1ecaf3eabf
diff --git a/etc/brep-module.conf b/etc/brep-module.conf
index 458261e..83d18da 100644
--- a/etc/brep-module.conf
+++ b/etc/brep-module.conf
@@ -3,6 +3,11 @@
# brep-). See brep(1) for detailed description of each configuration option.
# Commented out options indicate their default values.
#
+# Besides being parsed by the brep module, this file may also be parsed by
+# brep utilities that are normally only interested in the subset of the
+# options. To simplify skipping of unrecognized, this file must always have an
+# option name and its value on the same line.
+#
# Package search page title. It is placed inside XHTML5 <title> element.
#
@@ -129,6 +134,34 @@ menu About=?about
# build-normal-rebuild-timeout 86400
+# Alternative package rebuild timeout to use instead of the normal rebuild
+# timeout (see the build-normal-rebuild-timeout option for details) during
+# the specified time interval. Must be specified in seconds. Default is the
+# time interval length.
+#
+# The alternative rebuild timeout can be used to "pull" the rebuild window to
+# the specified time of day, for example, to optimize load and/or power
+# consumption of the build infrastructure (off-work hours, solar, off-peak
+# electricity tariffs, etc). A shorter than the time interval rebuild timeout
+# can also be used to force continuous rebuilds, for example, to shake out
+# flaky tests. Note also that if the alternative rebuild timeout is greater
+# than the normal rebuild timeout, then this will result in slower rebuilds
+# during the alternative time interval. In this case, if the build
+# infrastructure is monitored for delayed package builds, then the alternative
+# rebuild timeout should only be made slightly greater than the normal timeout
+# (see brep-monitor(1) for details).
+#
+# The time interval boundaries must be specified as times of day (in the local
+# timezone) in the <hours>:<minutes> form. If the stop time is less than the
+# start time then the interval extends through midnight. The start and stop
+# times must both be either specified or absent. If unspecified, then no
+# alternative rebuild timeout will be used.
+#
+# build-alt-rebuild-timeout
+# build-alt-rebuild-start
+# build-alt-rebuild-stop
+
+
# The maximum size of the build task request manifest accepted. Note that the
# HTTP POST request body is cached to retry database transactions in the face
# of recoverable failures (deadlock, loss of connection, etc). Default is
diff --git a/etc/buildfile b/etc/buildfile
index 8518b2b..1b78f65 100644
--- a/etc/buildfile
+++ b/etc/buildfile
@@ -1,5 +1,4 @@
# file : etc/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
./: file{** -buildfile}
diff --git a/etc/proxy-apache2.conf b/etc/proxy-apache2.conf
new file mode 100644
index 0000000..fc7cfea
--- /dev/null
+++ b/etc/proxy-apache2.conf
@@ -0,0 +1,144 @@
+# Paste the following fragment into the <VirtualHost> section intended for
+# proxying HTTP(S) requests and caching the responses. See INSTALL-PROXY for
+# details.
+#
+# List of modules used:
+#
+# rewrite
+# headers
+# ssl
+# proxy
+# proxy_http
+# cache
+# cache_disk
+#
+
+ # Enable the rewrite rules functionality.
+ #
+ <IfModule !rewrite_module>
+ Error "rewrite_module is not enabled"
+ </IfModule>
+
+ RewriteEngine on
+ RewriteOptions AllowAnyURI
+
+ # Make sure that the HTTP header management functionality is enabled.
+ #
+ <IfModule !headers_module>
+ Error "headers_module is not enabled"
+ </IfModule>
+
+ # Enable the HTTP proxy.
+ #
+ <IfModule !proxy_module>
+ Error "proxy_module is not enabled"
+ </IfModule>
+
+ <IfModule !proxy_http_module>
+ Error "proxy_http_module is not enabled"
+ </IfModule>
+
+ ProxyRequests On
+
+ # Enable SSL/TLS API usage for querying HTTPS URLs.
+ #
+ <IfModule !ssl_module>
+ Error "ssl_module is not enabled"
+ </IfModule>
+
+ SSLProxyEngine on
+
+ # Optional: prevent non-authorized proxy usage, for example:
+ #
+ # <Proxy *>
+ # Require ip 10.5
+ # </Proxy>
+
+ # Accept only the HTTP GET method and respond with the 403 HTTP status
+ # code (Forbidden) for other methods.
+ #
+ RewriteCond %{REQUEST_METHOD} !GET
+ RewriteRule .* - [F]
+
+ # Optional: restrict the URL set allowed for proxying, for example:
+ #
+ # RewriteCond %{HTTP_HOST} !(.+\.)?example.org
+ # RewriteRule .* - [F]
+
+ # Convert the http scheme to https for URLs being proxied.
+ #
+ # To prevent the conversion we can exclude certain hosts. For example:
+ #
+ # RewriteCond %{HTTP_HOST} !(.+\.)?example.org [OR]
+ # RewriteCond %{HTTP_HOST} !(.+\.)?example.net
+ #
+ # Or check for a custom header value. Note that this header should not
+ # be forwarded to the origin server. For example:
+ #
+ # RewriteCond %{HTTP:X-Preserve-HTTP} !(1|on|true) [NC]
+ # RequestHeader unset X-Preserve-HTTP
+ #
+ RewriteRule ^proxy:http://(.*)$ "https://$1" [P]
+
+ # Enable the disk storage-based cache.
+ #
+ <IfModule !cache_module>
+ Error "cache_module is not enabled"
+ </IfModule>
+
+ <IfModule !cache_disk_module>
+ Error "cache_disk_module is not enabled"
+ </IfModule>
+
+ CacheEnable disk "http://"
+
+ # Specify the cache root directory and make sure it is writable by the
+ # user under which Apache2 is running.
+ #
+ # Note that if there are no other proxies enabled for the WEB server,
+ # you can probably specify (you still have to specify it) the default
+ # cache directory (/var/cache/apache2/mod_cache_disk for Debian/Ubuntu
+ # and /var/cache/httpd/proxy for Fedora/RHEL).
+ #
+ CacheRoot
+
+ # Cache entry maximum size (in bytes).
+ #
+ CacheMaxFileSize 100000000
+
+ # Prevent duplicate caching of responses for the same simultaneously
+ # proxied URL. Specify an appropriate per-URL lock timeout (in
+ # seconds) to avoid stalled downloads from keeping the entries
+ # uncached.
+ #
+ CacheLock on
+ CacheLockMaxAge 600
+
+ # Always validate an existing cache entry by querying the origin
+ # server.
+ #
+ # We do this by injecting the request header which always declares the
+ # existing cache entry as potentially stale (ignoring Expire response
+ # header and Cache-Control header's max-age field) which should also
+ # be propagated through all the upstream proxies forcing them to
+ # validate the resource freshness.
+ #
+ # Note that this relies on both the proxy and origin servers correctly
+ # supporting conditional requests based on entity tags (ETag HTTP
+ # response and If-None-Match HTTP request headers) or less accurate
+ # entity modification times (Last-Modified HTTP response and
+ # If-Modified-Since HTTP request headers), which is normally the case
+ # if both are running Apache. A proxy normally caches the ETag and/or
+ # Last-Modified response header values alongside the cached entity and
+ # adds If-None-Match and/or If-Modified-Since headers respectively to
+ # the entity validation request. An origin server normally checks if
+ # any of the ETag or Last-Modified headers changed for the entity and
+ # responds with its full content, if that's the case, or with the 304
+ # HTTP status code (Not Modified) otherwise (see the Apache Caching
+ # Guide for details).
+ #
+ # Also note that to observe the injected header the cache handler
+ # should not be configured as a quick handler.
+ #
+ RequestHeader set Cache-Control max-age=0
+ CacheQuickHandler off
diff --git a/etc/systemd/brep-clean.timer b/etc/systemd/brep-clean.timer
index f4c587e..8e1e6e7 100644
--- a/etc/systemd/brep-clean.timer
+++ b/etc/systemd/brep-clean.timer
@@ -10,9 +10,9 @@ Unit=brep-clean.service
#
Persistent=false
-# Wait 20 seconds until the first run.
+# Wait 30 seconds until the first run.
#
-OnBootSec=20
+OnBootSec=30
# Then wait 5 minutes until the next run.
#
diff --git a/etc/systemd/brep-monitor.service b/etc/systemd/brep-monitor.service
new file mode 100644
index 0000000..0a5c25e
--- /dev/null
+++ b/etc/systemd/brep-monitor.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=brep infrastructure monitor service
+
+[Service]
+Type=oneshot
+#User=brep
+#Group=brep
+
+# Replace the public toolchain name with a real list of toolchains.
+#
+ExecStart=/home/brep/install/bin/brep-monitor --report-timeout 86400 --clean /home/brep/config/brep-module.conf public
+
+[Install]
+WantedBy=default.target
diff --git a/etc/systemd/brep-monitor.timer b/etc/systemd/brep-monitor.timer
new file mode 100644
index 0000000..f5f5a64
--- /dev/null
+++ b/etc/systemd/brep-monitor.timer
@@ -0,0 +1,23 @@
+[Unit]
+Description=brep infrastructure monitor timer
+RefuseManualStart=no
+RefuseManualStop=no
+
+[Timer]
+Unit=brep-monitor.service
+
+# Don't keep track of the timer across reboots.
+#
+Persistent=false
+
+# Wait 40 seconds until the first run.
+#
+OnBootSec=40
+
+# Then wait 1 hour until the next run.
+#
+OnUnitInactiveSec=1h
+
+
+[Install]
+WantedBy=timers.target
diff --git a/libbrep/build-extra.sql b/libbrep/build-extra.sql
index 9ecbcb1..ddc5961 100644
--- a/libbrep/build-extra.sql
+++ b/libbrep/build-extra.sql
@@ -10,6 +10,8 @@ DROP FOREIGN TABLE IF EXISTS build_package_constraints;
DROP FOREIGN TABLE IF EXISTS build_package_builds;
+DROP FOREIGN TABLE IF EXISTS build_package_tests;
+
DROP FOREIGN TABLE IF EXISTS build_package;
DROP FOREIGN TABLE IF EXISTS build_repository;
@@ -18,7 +20,6 @@ DROP FOREIGN TABLE IF EXISTS build_tenant;
-- The foreign table for build_tenant object.
--
---
CREATE FOREIGN TABLE build_tenant (
id TEXT NOT NULL,
archived BOOLEAN NOT NULL)
@@ -26,7 +27,6 @@ SERVER package_server OPTIONS (table_name 'tenant');
-- The foreign table for build_repository object.
--
---
CREATE FOREIGN TABLE build_repository (
tenant TEXT NOT NULL,
canonical_name TEXT NOT NULL,
@@ -37,7 +37,6 @@ SERVER package_server OPTIONS (table_name 'repository');
-- The foreign table for build_package object.
--
---
CREATE FOREIGN TABLE build_package (
tenant TEXT NOT NULL,
name CITEXT NOT NULL,
@@ -52,9 +51,28 @@ CREATE FOREIGN TABLE build_package (
buildable BOOLEAN NOT NULL)
SERVER package_server OPTIONS (table_name 'package');
--- The foreign table for the build_package object builds member (that is of a
+-- The foreign table for the build_package object tests member (that is of a
-- container type).
--
+CREATE FOREIGN TABLE build_package_tests (
+ tenant TEXT NOT NULL,
+ name CITEXT NOT NULL,
+ version_epoch INTEGER NOT NULL,
+ version_canonical_upstream TEXT NOT NULL,
+ version_canonical_release TEXT NOT NULL COLLATE "C",
+ version_revision INTEGER NOT NULL,
+ index BIGINT NOT NULL,
+ test_name CITEXT NOT NULL,
+ test_package_tenant TEXT NULL,
+ test_package_name CITEXT NULL,
+ test_package_version_epoch INTEGER NULL,
+ test_package_version_canonical_upstream TEXT NULL,
+ test_package_version_canonical_release TEXT NULL COLLATE "C",
+ test_package_version_revision INTEGER NULL)
+SERVER package_server OPTIONS (table_name 'package_tests');
+
+-- The foreign table for the build_package object builds member (that is of a
+-- container type).
--
CREATE FOREIGN TABLE build_package_builds (
tenant TEXT NOT NULL,
@@ -71,7 +89,6 @@ SERVER package_server OPTIONS (table_name 'package_builds');
-- The foreign table for the build_package object constraints member (that is
-- of a container type).
--
---
CREATE FOREIGN TABLE build_package_constraints (
tenant TEXT NOT NULL,
name CITEXT NOT NULL,
diff --git a/libbrep/build-package.hxx b/libbrep/build-package.hxx
index c288f07..09ec41d 100644
--- a/libbrep/build-package.hxx
+++ b/libbrep/build-package.hxx
@@ -1,5 +1,4 @@
// file : libbrep/build-package.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_BUILD_PACKAGE_HXX
@@ -69,6 +68,19 @@ namespace brep
build_repository (): canonical_name (id.canonical_name) {}
};
+ // Forward declarations.
+ //
+ class build_package;
+
+ // Build package external test dependency.
+ //
+ #pragma db value
+ struct build_test_dependency
+ {
+ package_name name;
+ lazy_shared_ptr<build_package> package;
+ };
+
// Foreign object that is mapped to a subset of the package object.
//
#pragma db object table("build_package") pointer(shared_ptr) readonly session
@@ -77,6 +89,12 @@ namespace brep
public:
package_id id;
upstream_version version;
+
+ // Mapped to the package object tests member using the PostgreSQL foreign
+ // table mechanism.
+ //
+ small_vector<build_test_dependency, 1> tests;
+
lazy_shared_ptr<build_repository> internal_repository;
bool buildable;
@@ -90,10 +108,14 @@ namespace brep
//
build_constraints constraints;
+ bool
+ internal () const noexcept {return internal_repository != nullptr;}
+
// Database mapping.
//
#pragma db member(id) id column("")
#pragma db member(version) set(this.version.init (this.id.version, (?)))
+ #pragma db member(tests) id_column("") value_column("test_")
#pragma db member(builds) id_column("") value_column("")
#pragma db member(constraints) id_column("") value_column("")
@@ -119,6 +141,8 @@ namespace brep
package_id id;
upstream_version version;
+ bool archived; // True if the tenant the package belongs to is archived.
+
// Database mapping.
//
#pragma db member(version) set(this.version.init (this.id.version, (?)))
diff --git a/libbrep/build.cxx b/libbrep/build.cxx
index 45ef678..db5bda2 100644
--- a/libbrep/build.cxx
+++ b/libbrep/build.cxx
@@ -1,5 +1,4 @@
// file : libbrep/build.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <libbrep/build.hxx>
@@ -81,4 +80,25 @@ namespace brep
target (move (trg))
{
}
+
+ // build_delay
+ //
+ build_delay::
+ build_delay (string tnt,
+ package_name_type pnm, version pvr,
+ string cfg,
+ string tnm, version tvr,
+ timestamp ptm)
+ : id (package_id (move (tnt), move (pnm), pvr),
+ move (cfg),
+ move (tnm), tvr),
+ tenant (id.package.tenant),
+ package_name (id.package.name),
+ package_version (move (pvr)),
+ configuration (id.configuration),
+ toolchain_name (id.toolchain_name),
+ toolchain_version (move (tvr)),
+ package_timestamp (ptm)
+ {
+ }
}
diff --git a/libbrep/build.hxx b/libbrep/build.hxx
index fc9f675..380b17b 100644
--- a/libbrep/build.hxx
+++ b/libbrep/build.hxx
@@ -1,5 +1,4 @@
// file : libbrep/build.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_BUILD_HXX
@@ -24,9 +23,9 @@
// Used by the data migration entries.
//
-#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 9
+#define LIBBREP_BUILD_SCHEMA_VERSION_BASE 12
-#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 9, closed)
+#pragma db model version(LIBBREP_BUILD_SCHEMA_VERSION_BASE, 12, closed)
// We have to keep these mappings at the global scope instead of inside
// the brep namespace because they need to be also effective in the
@@ -213,6 +212,16 @@ namespace brep
//
optional<result_status> status;
+ // Time of setting the result status that can be considered as the build
+ // task completion (currently all the result_status values). Initialized
+ // with timestamp_nonexistent by default.
+ //
+ // Note that in the future we may not consider abort and abnormal as the
+ // task completion and, for example, proceed with automatic rebuild (the
+ // flake monitor idea).
+ //
+ timestamp_type completion_timestamp;
+
// May be present only for the building state.
//
optional<string> agent_fingerprint;
@@ -245,6 +254,15 @@ namespace brep
//
#pragma db member(timestamp) index
+ // This is not required since 0.14.0. Note however, that just dropping
+ // this line won't pan out since this would require migration which odb is
+ // currently unable to handle automatically, advising to re-implement this
+ // change by adding a new data member with the desired default value,
+ // migrating the data, and deleting the old data member. This sounds a bit
+ // hairy, so let's keep it for now.
+ //
+ #pragma db member(completion_timestamp) default(0)
+
#pragma db member(results) id_column("") value_column("") \
section(results_section)
@@ -260,9 +278,7 @@ namespace brep
: tenant (id.package.tenant),
package_name (id.package.name),
configuration (id.configuration),
- toolchain_name (id.toolchain_name)
- {
- }
+ toolchain_name (id.toolchain_name) {}
};
// Note that ADL can't find the equal operator in join conditions, so we use
@@ -341,6 +357,68 @@ namespace brep
//
#pragma db member(result) column("count(" + build::id.package.name + ")")
};
+
+ // Used to track the package build delays since the last build or, if not
+ // present, since the first opportunity to build the package.
+ //
+ #pragma db object pointer(shared_ptr) session
+ class build_delay
+ {
+ public:
+ using package_name_type = brep::package_name;
+
+ // If toolchain version is empty, then the object represents a minimum
+ // delay across all versions of the toolchain.
+ //
+ build_delay (string tenant,
+ package_name_type, version,
+ string configuration,
+ string toolchain_name, version toolchain_version,
+ timestamp package_timestamp);
+
+ build_id id;
+
+ string& tenant; // Tracks id.package.tenant.
+ package_name_type& package_name; // Tracks id.package.name.
+ upstream_version package_version; // Original of id.package.version.
+ string& configuration; // Tracks id.configuration.
+ string& toolchain_name; // Tracks id.toolchain_name.
+ upstream_version toolchain_version; // Original of id.toolchain_version.
+
+ // Time of the latest delay report. Initialized with timestamp_nonexistent
+ // by default.
+ //
+ timestamp report_timestamp;
+
+ // Time when the package is initially considered as buildable for this
+ // configuration and toolchain. It is used to track the build delay if the
+ // build object is absent (the first build task is not yet issued, the
+ // build is removed by brep-clean, etc).
+ //
+ timestamp package_timestamp;
+
+ // Database mapping.
+ //
+ #pragma db member(id) id column("")
+
+ #pragma db member(tenant) transient
+ #pragma db member(package_name) transient
+ #pragma db member(package_version) \
+ set(this.package_version.init (this.id.package.version, (?)))
+ #pragma db member(configuration) transient
+ #pragma db member(toolchain_name) transient
+ #pragma db member(toolchain_version) \
+ set(this.toolchain_version.init (this.id.toolchain_version, (?)))
+
+ private:
+ friend class odb::access;
+
+ build_delay ()
+ : tenant (id.package.tenant),
+ package_name (id.package.name),
+ configuration (id.configuration),
+ toolchain_name (id.toolchain_name) {}
+ };
}
#endif // LIBBREP_BUILD_HXX
diff --git a/libbrep/build.xml b/libbrep/build.xml
index 3ade7c8..3af7640 100644
--- a/libbrep/build.xml
+++ b/libbrep/build.xml
@@ -1,5 +1,5 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="build" version="1">
- <model version="9">
+ <model version="12">
<table name="build" kind="object">
<column name="package_tenant" type="TEXT" null="false"/>
<column name="package_name" type="CITEXT" null="false"/>
@@ -21,6 +21,7 @@
<column name="timestamp" type="BIGINT" null="false"/>
<column name="force" type="TEXT" null="false"/>
<column name="status" type="TEXT" null="true"/>
+ <column name="completion_timestamp" type="BIGINT" null="false" default="0"/>
<column name="agent_fingerprint" type="TEXT" null="true"/>
<column name="agent_challenge" type="TEXT" null="true"/>
<column name="machine" type="TEXT" null="false"/>
@@ -107,5 +108,39 @@
<column name="index"/>
</index>
</table>
+ <table name="build_delay" kind="object">
+ <column name="package_tenant" type="TEXT" null="false"/>
+ <column name="package_name" type="CITEXT" null="false"/>
+ <column name="package_version_epoch" type="INTEGER" null="false"/>
+ <column name="package_version_canonical_upstream" type="TEXT" null="false"/>
+ <column name="package_version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
+ <column name="package_version_revision" type="INTEGER" null="false"/>
+ <column name="configuration" type="TEXT" null="false"/>
+ <column name="toolchain_name" type="TEXT" null="false"/>
+ <column name="toolchain_version_epoch" type="INTEGER" null="false"/>
+ <column name="toolchain_version_canonical_upstream" type="TEXT" null="false"/>
+ <column name="toolchain_version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
+ <column name="toolchain_version_revision" type="INTEGER" null="false"/>
+ <column name="package_version_upstream" type="TEXT" null="false"/>
+ <column name="package_version_release" type="TEXT" null="true"/>
+ <column name="toolchain_version_upstream" type="TEXT" null="false"/>
+ <column name="toolchain_version_release" type="TEXT" null="true"/>
+ <column name="report_timestamp" type="BIGINT" null="false"/>
+ <column name="package_timestamp" type="BIGINT" null="false"/>
+ <primary-key>
+ <column name="package_tenant"/>
+ <column name="package_name"/>
+ <column name="package_version_epoch"/>
+ <column name="package_version_canonical_upstream"/>
+ <column name="package_version_canonical_release"/>
+ <column name="package_version_revision"/>
+ <column name="configuration"/>
+ <column name="toolchain_name"/>
+ <column name="toolchain_version_epoch"/>
+ <column name="toolchain_version_canonical_upstream"/>
+ <column name="toolchain_version_canonical_release"/>
+ <column name="toolchain_version_revision"/>
+ </primary-key>
+ </table>
</model>
</changelog>
diff --git a/libbrep/buildfile b/libbrep/buildfile
index e649351..9a35a28 100644
--- a/libbrep/buildfile
+++ b/libbrep/buildfile
@@ -1,5 +1,4 @@
# file : libbrep/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
define sql: file
diff --git a/libbrep/common-traits.hxx b/libbrep/common-traits.hxx
index 99002a2..99e8f3e 100644
--- a/libbrep/common-traits.hxx
+++ b/libbrep/common-traits.hxx
@@ -1,5 +1,4 @@
// file : libbrep/common-traits.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_COMMON_TRAITS_HXX
diff --git a/libbrep/common.cxx b/libbrep/common.cxx
index b2429a6..8964e0a 100644
--- a/libbrep/common.cxx
+++ b/libbrep/common.cxx
@@ -1,5 +1,4 @@
// file : libbrep/common.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <libbrep/common.hxx>
@@ -7,4 +6,30 @@
namespace brep
{
const version wildcard_version (0, "0", nullopt, nullopt, 0);
+
+ // unbuildable_reason
+ //
+ string
+ to_string (unbuildable_reason r)
+ {
+ switch (r)
+ {
+ case unbuildable_reason::stub: return "stub";
+ case unbuildable_reason::test: return "test";
+ case unbuildable_reason::external: return "external";
+ case unbuildable_reason::unbuildable: return "unbuildable";
+ }
+
+ return string (); // Should never reach.
+ }
+
+ unbuildable_reason
+ to_unbuildable_reason (const string& r)
+ {
+ if (r == "stub") return unbuildable_reason::stub;
+ else if (r == "test") return unbuildable_reason::test;
+ else if (r == "external") return unbuildable_reason::external;
+ else if (r == "unbuildable") return unbuildable_reason::unbuildable;
+ else throw invalid_argument ("invalid unbuildable reason '" + r + "'");
+ }
}
diff --git a/libbrep/common.hxx b/libbrep/common.hxx
index 6dc4870..73353c7 100644
--- a/libbrep/common.hxx
+++ b/libbrep/common.hxx
@@ -1,5 +1,4 @@
// file : libbrep/common.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_COMMON_HXX
@@ -9,6 +8,8 @@
#include <chrono>
#include <type_traits> // static_assert
+#include <odb/query.hxx>
+
#include <libbpkg/package-name.hxx>
#include <libbrep/types.hxx>
@@ -322,6 +323,38 @@ namespace brep
#pragma db value(build_constraint) definition
+ // The primary reason why a package is unbuildable by the build bot
+ // controller service.
+ //
+ enum class unbuildable_reason: std::uint8_t
+ {
+ stub, // A stub, otherwise
+ test, // A separate test (built as part of primary), otherwise
+ external, // From an external repository, otherwise
+ unbuildable // From an internal unbuildable repository.
+ };
+
+ string
+ to_string (unbuildable_reason);
+
+ unbuildable_reason
+ to_unbuildable_reason (const string&); // May throw invalid_argument.
+
+ inline ostream&
+ operator<< (ostream& os, unbuildable_reason r) {return os << to_string (r);}
+
+ using optional_unbuildable_reason = optional<unbuildable_reason>;
+
+ #pragma db map type(unbuildable_reason) as(string) \
+ to(to_string (?)) \
+ from(brep::to_unbuildable_reason (?))
+
+ #pragma db map type(optional_unbuildable_reason) as(brep::optional_string) \
+ to((?) ? to_string (*(?)) : brep::optional_string ()) \
+ from((?) \
+ ? brep::to_unbuildable_reason (*(?)) \
+ : brep::optional_unbuildable_reason ()) \
+
// Version comparison operators.
//
// They allow comparing objects that have epoch, canonical_upstream,
@@ -511,6 +544,34 @@ namespace brep
compare_version_ne (x.version, y.version, true);
}
+ // Allow comparing the query members with the query parameters bound by
+ // reference to variables of the package id type (in particular in the
+ // prepared queries).
+ //
+ // Note that it is not operator==() since the query template parameter type
+ // can not be deduced from the function parameter types and needs to be
+ // specified explicitly.
+ //
+ template <typename T, typename ID>
+ inline auto
+ equal (const ID& x, const package_id& y)
+ -> decltype (x.tenant == odb::query<T>::_ref (y.tenant) &&
+ x.name == odb::query<T>::_ref (y.name) &&
+ x.version.epoch == odb::query<T>::_ref (y.version.epoch))
+ {
+ using query = odb::query<T>;
+
+ const auto& qv (x.version);
+ const canonical_version& v (y.version);
+
+ return x.tenant == query::_ref (y.tenant) &&
+ x.name == query::_ref (y.name) &&
+ qv.epoch == query::_ref (v.epoch) &&
+ qv.canonical_upstream == query::_ref (v.canonical_upstream) &&
+ qv.canonical_release == query::_ref (v.canonical_release) &&
+ qv.revision == query::_ref (v.revision);
+ }
+
// Repository id comparison operators.
//
inline bool
diff --git a/libbrep/database-lock.cxx b/libbrep/database-lock.cxx
index b295472..1b7f730 100644
--- a/libbrep/database-lock.cxx
+++ b/libbrep/database-lock.cxx
@@ -1,5 +1,4 @@
// file : libbrep/database-lock.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <libbrep/database-lock.hxx>
diff --git a/libbrep/database-lock.hxx b/libbrep/database-lock.hxx
index 832010f..ab5441d 100644
--- a/libbrep/database-lock.hxx
+++ b/libbrep/database-lock.hxx
@@ -1,5 +1,4 @@
// file : libbrep/database-lock.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_DATABASE_LOCK_HXX
diff --git a/libbrep/odb.sh b/libbrep/odb.sh
index 4172e67..9ee11fa 100755
--- a/libbrep/odb.sh
+++ b/libbrep/odb.sh
@@ -43,6 +43,8 @@ else
fi
+rm -f {package,build}-???-{pre,post}.sql
+
$odb "${inc[@]}" -d pgsql --std c++14 --generate-query \
--odb-epilogue '#include <libbutl/small-vector-odb.hxx>' \
--odb-epilogue '#include <libbrep/wrapper-traits.hxx>' \
diff --git a/libbrep/package-traits.cxx b/libbrep/package-traits.cxx
index 1b90483..d6d3525 100644
--- a/libbrep/package-traits.cxx
+++ b/libbrep/package-traits.cxx
@@ -1,5 +1,4 @@
// file : libbrep/package-traits.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <libbrep/package-traits.hxx>
diff --git a/libbrep/package-traits.hxx b/libbrep/package-traits.hxx
index f30459a..f3efa20 100644
--- a/libbrep/package-traits.hxx
+++ b/libbrep/package-traits.hxx
@@ -1,5 +1,4 @@
// file : libbrep/package-traits.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_PACKAGE_TRAITS
diff --git a/libbrep/package.cxx b/libbrep/package.cxx
index e6c543d..564fec7 100644
--- a/libbrep/package.cxx
+++ b/libbrep/package.cxx
@@ -1,5 +1,4 @@
// file : libbrep/package.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <libbrep/package.hxx>
@@ -62,10 +61,10 @@ namespace brep
optional<string> ds,
optional<text_type> dt,
string ch,
- optional<url_type> ur,
- optional<url_type> du,
- optional<url_type> su,
- optional<url_type> pu,
+ optional<manifest_url> ur,
+ optional<manifest_url> du,
+ optional<manifest_url> su,
+ optional<manifest_url> pu,
optional<email_type> em,
optional<email_type> pe,
optional<email_type> be,
@@ -73,9 +72,7 @@ namespace brep
optional<email_type> bee,
dependencies_type dp,
requirements_type rq,
- small_vector<dependency, 1> ts,
- small_vector<dependency, 1> es,
- small_vector<dependency, 1> bms,
+ small_vector<test_dependency, 1> ts,
build_class_exprs bs,
build_constraints_type bc,
optional<path> lc,
@@ -108,28 +105,39 @@ namespace brep
dependencies (move (dp)),
requirements (move (rq)),
tests (move (ts)),
- examples (move (es)),
- benchmarks (move (bms)),
builds (move (bs)),
- build_constraints (!stub () ? move (bc) : build_constraints_type ()),
+ build_constraints (move (bc)),
internal_repository (move (rp)),
location (move (lc)),
fragment (move (fr)),
- sha256sum (move (sh)),
- buildable (!stub () && internal_repository->buildable)
+ sha256sum (move (sh))
{
+ if (stub ())
+ unbuildable_reason = brep::unbuildable_reason::stub;
+ else if (!internal_repository->buildable)
+ unbuildable_reason = brep::unbuildable_reason::unbuildable;
+
+ buildable = !unbuildable_reason;
+
assert (internal_repository->internal);
}
package::
package (package_name nm,
version_type vr,
+ build_class_exprs bs,
+ build_constraints_type bc,
shared_ptr<repository_type> rp)
: id (rp->tenant, move (nm), vr),
tenant (id.tenant),
name (id.name),
version (move (vr)),
- buildable (false)
+ builds (move (bs)),
+ build_constraints (move (bc)),
+ buildable (false),
+ unbuildable_reason (stub ()
+ ? brep::unbuildable_reason::stub
+ : brep::unbuildable_reason::external)
{
assert (!rp->internal);
other_repositories.emplace_back (move (rp));
diff --git a/libbrep/package.hxx b/libbrep/package.hxx
index 47f0ebe..33444a9 100644
--- a/libbrep/package.hxx
+++ b/libbrep/package.hxx
@@ -1,5 +1,4 @@
// file : libbrep/package.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_PACKAGE_HXX
@@ -19,9 +18,9 @@
// Used by the data migration entries.
//
-#define LIBBREP_PACKAGE_SCHEMA_VERSION_BASE 17
+#define LIBBREP_PACKAGE_SCHEMA_VERSION_BASE 19
-#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 17, closed)
+#pragma db model version(LIBBREP_PACKAGE_SCHEMA_VERSION_BASE, 19, closed)
namespace brep
{
@@ -60,14 +59,14 @@ namespace brep
to((?) ? to_string (*(?)) : brep::optional_string ()) \
from((?) ? brep::to_text_type (*(?)) : brep::optional_text_type ())
- // url
+ // manifest_url
//
- using bpkg::url;
+ using bpkg::manifest_url;
- #pragma db value(url) definition
- #pragma db member(url::value) virtual(string) before \
- get(this.string ()) \
- set(this = brep::url ((?), "" /* comment */)) \
+ #pragma db value(manifest_url) definition
+ #pragma db member(manifest_url::value) virtual(string) before \
+ get(this.string ()) \
+ set(this = brep::manifest_url ((?), "" /* comment */)) \
column("")
// email
@@ -141,8 +140,8 @@ namespace brep
package_name name;
optional<version_constraint> constraint;
- // Resolved dependency package. NULL if the repository load was shallow
- // and so the package dependencies are not resolved.
+ // Resolved dependency package. Can be NULL if the repository load was
+ // shallow and the package dependency could not be resolved.
//
lazy_shared_ptr<package_type> package;
@@ -182,6 +181,30 @@ namespace brep
#pragma db value(requirement_alternatives) definition
+ // tests
+ //
+ using bpkg::test_dependency_type;
+ using bpkg::to_test_dependency_type;
+
+ #pragma db map type(test_dependency_type) as(string) \
+ to(to_string (?)) \
+ from(brep::to_test_dependency_type (?))
+
+ #pragma db value
+ struct test_dependency: dependency
+ {
+ test_dependency_type type;
+
+ test_dependency () = default;
+ test_dependency (package_name n,
+ test_dependency_type t,
+ optional<version_constraint> c)
+ : dependency {std::move (n), std::move (c), nullptr /* package */},
+ type (t)
+ {
+ }
+ };
+
// certificate
//
#pragma db value
@@ -357,14 +380,12 @@ namespace brep
using upstream_version_type = brep::upstream_version;
using priority_type = brep::priority;
using license_alternatives_type = brep::license_alternatives;
- using url_type = brep::url;
using email_type = brep::email;
using dependencies_type = brep::dependencies;
using requirements_type = brep::requirements;
using build_constraints_type = brep::build_constraints;
- // Create internal package object. Note that for stubs the build
- // constraints are meaningless, and so not saved.
+ // Create internal package object.
//
package (package_name,
version_type,
@@ -378,10 +399,10 @@ namespace brep
optional<string> description,
optional<text_type> description_type,
string changes,
- optional<url_type>,
- optional<url_type> doc_url,
- optional<url_type> src_url,
- optional<url_type> package_url,
+ optional<manifest_url> url,
+ optional<manifest_url> doc_url,
+ optional<manifest_url> src_url,
+ optional<manifest_url> package_url,
optional<email_type>,
optional<email_type> package_email,
optional<email_type> build_email,
@@ -389,9 +410,7 @@ namespace brep
optional<email_type> build_error_email,
dependencies_type,
requirements_type,
- small_vector<dependency, 1> tests,
- small_vector<dependency, 1> examples,
- small_vector<dependency, 1> benchmarks,
+ small_vector<test_dependency, 1> tests,
build_class_exprs,
build_constraints_type,
optional<path> location,
@@ -401,12 +420,22 @@ namespace brep
// Create external package object.
//
- // External repository packages can appear on the WEB interface only in
- // dependency list in the form of a link to the corresponding WEB page.
- // The only package information required to compose such a link is the
- // package name, version, and repository location.
+ // External package can appear on the WEB interface only in dependency
+ // list in the form of a link to the corresponding WEB page. The only
+ // package information required to compose such a link is the package name,
+ // version, and repository location.
//
- package (package_name name, version_type, shared_ptr<repository_type>);
+ // External package can also be a separate test for some primary package
+ // (and belong to a complement but yet external repository), and so we may
+ // need its build class expressions and constraints to decide if to build
+ // it together with the primary package or not (see test-exclude task
+ // manifest value for details).
+ //
+ package (package_name name,
+ version_type,
+ build_class_exprs,
+ build_constraints_type,
+ shared_ptr<repository_type>);
bool
internal () const noexcept {return internal_repository != nullptr;}
@@ -441,10 +470,10 @@ namespace brep
optional<string> description; // Absent if type is unknown.
optional<text_type> description_type; // Present if description is present.
string changes;
- optional<url_type> url;
- optional<url_type> doc_url;
- optional<url_type> src_url;
- optional<url_type> package_url;
+ optional<manifest_url> url;
+ optional<manifest_url> doc_url;
+ optional<manifest_url> src_url;
+ optional<manifest_url> package_url;
optional<email_type> email;
optional<email_type> package_email;
optional<email_type> build_email;
@@ -452,9 +481,7 @@ namespace brep
optional<email_type> build_error_email;
dependencies_type dependencies;
requirements_type requirements;
- small_vector<dependency, 1> tests;
- small_vector<dependency, 1> examples;
- small_vector<dependency, 1> benchmarks;
+ small_vector<test_dependency, 1> tests; // Note: foreign-mapped in build.
build_class_exprs builds; // Note: foreign-mapped in build.
build_constraints_type build_constraints; // Note: foreign-mapped in build.
@@ -479,16 +506,14 @@ namespace brep
vector<lazy_shared_ptr<repository_type>> other_repositories;
- // Whether the package is buildable by the build bot controller service.
- // Can only be true for non-stubs that belong to at least one buildable
- // (internal) repository.
+ // Whether the package is buildable by the build bot controller service
+ // and the reason if it's not.
//
// While we could potentially calculate this flag on the fly, that would
// complicate the database queries significantly.
//
- // Note: foreign-mapped in build.
- //
- bool buildable;
+ bool buildable; // Note: foreign-mapped in build.
+ optional<brep::unbuildable_reason> unbuildable_reason;
// Database mapping.
//
@@ -558,14 +583,9 @@ namespace brep
set(odb::nested_set (this.requirements, std::move (?))) \
id_column("") key_column("") value_column("id")
- // tests, examples, benchmarks
- //
- // Seeing that these reuse the dependency types, we are also going to
- // have identical database mapping.
+ // tests
//
- #pragma db member(tests) id_column("") value_column("dep_")
- #pragma db member(examples) id_column("") value_column("dep_")
- #pragma db member(benchmarks) id_column("") value_column("dep_")
+ #pragma db member(tests) id_column("") value_column("test_")
// builds
//
diff --git a/libbrep/package.xml b/libbrep/package.xml
index 785ae0f..454cdbc 100644
--- a/libbrep/package.xml
+++ b/libbrep/package.xml
@@ -1,5 +1,5 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" schema-name="package" version="1">
- <model version="17">
+ <model version="19">
<table name="tenant" kind="object">
<column name="id" type="TEXT" null="false"/>
<column name="creation_timestamp" type="BIGINT" null="false"/>
@@ -167,6 +167,7 @@
<column name="fragment" type="TEXT" null="true"/>
<column name="sha256sum" type="TEXT" null="true"/>
<column name="buildable" type="BOOLEAN" null="false"/>
+ <column name="unbuildable_reason" type="TEXT" null="true"/>
<column name="search_index" type="tsvector" null="true"/>
<primary-key>
<column name="tenant"/>
@@ -592,27 +593,28 @@
<column name="version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
<column name="version_revision" type="INTEGER" null="false"/>
<column name="index" type="BIGINT" null="false"/>
- <column name="dep_name" type="CITEXT" null="false"/>
- <column name="dep_min_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_min_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_min_version_revision" type="INTEGER" null="true"/>
- <column name="dep_min_version_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_release" type="TEXT" null="true"/>
- <column name="dep_max_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_max_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_max_version_revision" type="INTEGER" null="true"/>
- <column name="dep_max_version_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_release" type="TEXT" null="true"/>
- <column name="dep_min_open" type="BOOLEAN" null="true"/>
- <column name="dep_max_open" type="BOOLEAN" null="true"/>
- <column name="dep_package_tenant" type="TEXT" null="true"/>
- <column name="dep_package_name" type="CITEXT" null="true"/>
- <column name="dep_package_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_package_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_package_version_canonical_release" type="TEXT" null="true" options="COLLATE &quot;C&quot;"/>
- <column name="dep_package_version_revision" type="INTEGER" null="true"/>
+ <column name="test_name" type="CITEXT" null="false"/>
+ <column name="test_min_version_epoch" type="INTEGER" null="true"/>
+ <column name="test_min_version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="test_min_version_canonical_release" type="TEXT" null="true"/>
+ <column name="test_min_version_revision" type="INTEGER" null="true"/>
+ <column name="test_min_version_upstream" type="TEXT" null="true"/>
+ <column name="test_min_version_release" type="TEXT" null="true"/>
+ <column name="test_max_version_epoch" type="INTEGER" null="true"/>
+ <column name="test_max_version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="test_max_version_canonical_release" type="TEXT" null="true"/>
+ <column name="test_max_version_revision" type="INTEGER" null="true"/>
+ <column name="test_max_version_upstream" type="TEXT" null="true"/>
+ <column name="test_max_version_release" type="TEXT" null="true"/>
+ <column name="test_min_open" type="BOOLEAN" null="true"/>
+ <column name="test_max_open" type="BOOLEAN" null="true"/>
+ <column name="test_package_tenant" type="TEXT" null="true"/>
+ <column name="test_package_name" type="CITEXT" null="true"/>
+ <column name="test_package_version_epoch" type="INTEGER" null="true"/>
+ <column name="test_package_version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="test_package_version_canonical_release" type="TEXT" null="true" options="COLLATE &quot;C&quot;"/>
+ <column name="test_package_version_revision" type="INTEGER" null="true"/>
+ <column name="test_type" type="TEXT" null="false"/>
<foreign-key name="tenant_fk" deferrable="DEFERRED">
<column name="tenant"/>
<references table="tenant">
@@ -646,189 +648,19 @@
<index name="package_tests_index_i">
<column name="index"/>
</index>
- <foreign-key name="dep_package_tenant_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
- <references table="tenant">
- <column name="id"/>
- </references>
- </foreign-key>
- <foreign-key name="dep_package_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
- <column name="dep_package_name"/>
- <column name="dep_package_version_epoch"/>
- <column name="dep_package_version_canonical_upstream"/>
- <column name="dep_package_version_canonical_release"/>
- <column name="dep_package_version_revision"/>
- <references table="package">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </references>
- </foreign-key>
- </table>
- <table name="package_examples" kind="container">
- <column name="tenant" type="TEXT" null="false"/>
- <column name="name" type="CITEXT" null="false"/>
- <column name="version_epoch" type="INTEGER" null="false"/>
- <column name="version_canonical_upstream" type="TEXT" null="false"/>
- <column name="version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
- <column name="version_revision" type="INTEGER" null="false"/>
- <column name="index" type="BIGINT" null="false"/>
- <column name="dep_name" type="CITEXT" null="false"/>
- <column name="dep_min_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_min_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_min_version_revision" type="INTEGER" null="true"/>
- <column name="dep_min_version_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_release" type="TEXT" null="true"/>
- <column name="dep_max_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_max_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_max_version_revision" type="INTEGER" null="true"/>
- <column name="dep_max_version_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_release" type="TEXT" null="true"/>
- <column name="dep_min_open" type="BOOLEAN" null="true"/>
- <column name="dep_max_open" type="BOOLEAN" null="true"/>
- <column name="dep_package_tenant" type="TEXT" null="true"/>
- <column name="dep_package_name" type="CITEXT" null="true"/>
- <column name="dep_package_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_package_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_package_version_canonical_release" type="TEXT" null="true" options="COLLATE &quot;C&quot;"/>
- <column name="dep_package_version_revision" type="INTEGER" null="true"/>
- <foreign-key name="tenant_fk" deferrable="DEFERRED">
- <column name="tenant"/>
- <references table="tenant">
- <column name="id"/>
- </references>
- </foreign-key>
- <foreign-key name="object_id_fk" on-delete="CASCADE">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- <references table="package">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </references>
- </foreign-key>
- <index name="package_examples_object_id_i">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </index>
- <index name="package_examples_index_i">
- <column name="index"/>
- </index>
- <foreign-key name="dep_package_tenant_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
+ <foreign-key name="test_package_tenant_fk" deferrable="DEFERRED">
+ <column name="test_package_tenant"/>
<references table="tenant">
<column name="id"/>
</references>
</foreign-key>
- <foreign-key name="dep_package_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
- <column name="dep_package_name"/>
- <column name="dep_package_version_epoch"/>
- <column name="dep_package_version_canonical_upstream"/>
- <column name="dep_package_version_canonical_release"/>
- <column name="dep_package_version_revision"/>
- <references table="package">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </references>
- </foreign-key>
- </table>
- <table name="package_benchmarks" kind="container">
- <column name="tenant" type="TEXT" null="false"/>
- <column name="name" type="CITEXT" null="false"/>
- <column name="version_epoch" type="INTEGER" null="false"/>
- <column name="version_canonical_upstream" type="TEXT" null="false"/>
- <column name="version_canonical_release" type="TEXT" null="false" options="COLLATE &quot;C&quot;"/>
- <column name="version_revision" type="INTEGER" null="false"/>
- <column name="index" type="BIGINT" null="false"/>
- <column name="dep_name" type="CITEXT" null="false"/>
- <column name="dep_min_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_min_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_min_version_revision" type="INTEGER" null="true"/>
- <column name="dep_min_version_upstream" type="TEXT" null="true"/>
- <column name="dep_min_version_release" type="TEXT" null="true"/>
- <column name="dep_max_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_max_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_canonical_release" type="TEXT" null="true"/>
- <column name="dep_max_version_revision" type="INTEGER" null="true"/>
- <column name="dep_max_version_upstream" type="TEXT" null="true"/>
- <column name="dep_max_version_release" type="TEXT" null="true"/>
- <column name="dep_min_open" type="BOOLEAN" null="true"/>
- <column name="dep_max_open" type="BOOLEAN" null="true"/>
- <column name="dep_package_tenant" type="TEXT" null="true"/>
- <column name="dep_package_name" type="CITEXT" null="true"/>
- <column name="dep_package_version_epoch" type="INTEGER" null="true"/>
- <column name="dep_package_version_canonical_upstream" type="TEXT" null="true"/>
- <column name="dep_package_version_canonical_release" type="TEXT" null="true" options="COLLATE &quot;C&quot;"/>
- <column name="dep_package_version_revision" type="INTEGER" null="true"/>
- <foreign-key name="tenant_fk" deferrable="DEFERRED">
- <column name="tenant"/>
- <references table="tenant">
- <column name="id"/>
- </references>
- </foreign-key>
- <foreign-key name="object_id_fk" on-delete="CASCADE">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- <references table="package">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </references>
- </foreign-key>
- <index name="package_benchmarks_object_id_i">
- <column name="tenant"/>
- <column name="name"/>
- <column name="version_epoch"/>
- <column name="version_canonical_upstream"/>
- <column name="version_canonical_release"/>
- <column name="version_revision"/>
- </index>
- <index name="package_benchmarks_index_i">
- <column name="index"/>
- </index>
- <foreign-key name="dep_package_tenant_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
- <references table="tenant">
- <column name="id"/>
- </references>
- </foreign-key>
- <foreign-key name="dep_package_fk" deferrable="DEFERRED">
- <column name="dep_package_tenant"/>
- <column name="dep_package_name"/>
- <column name="dep_package_version_epoch"/>
- <column name="dep_package_version_canonical_upstream"/>
- <column name="dep_package_version_canonical_release"/>
- <column name="dep_package_version_revision"/>
+ <foreign-key name="test_package_fk" deferrable="DEFERRED">
+ <column name="test_package_tenant"/>
+ <column name="test_package_name"/>
+ <column name="test_package_version_epoch"/>
+ <column name="test_package_version_canonical_upstream"/>
+ <column name="test_package_version_canonical_release"/>
+ <column name="test_package_version_revision"/>
<references table="package">
<column name="tenant"/>
<column name="name"/>
diff --git a/libbrep/types.hxx b/libbrep/types.hxx
index 65c9791..65dfc2d 100644
--- a/libbrep/types.hxx
+++ b/libbrep/types.hxx
@@ -1,5 +1,4 @@
// file : libbrep/types.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_TYPES_HXX
@@ -22,6 +21,7 @@
#include <odb/lazy-ptr.hxx>
+#include <libbutl/url.mxx>
#include <libbutl/path.mxx>
#include <libbutl/path-io.mxx>
#include <libbutl/optional.mxx>
@@ -91,10 +91,15 @@ namespace brep
using butl::path_cast;
+ // <libbutl/url.mxx>
+ //
+ using butl::url;
+
// <libbutl/timestamp.mxx>
//
using butl::system_clock;
using butl::timestamp;
+ using butl::duration;
using butl::timestamp_nonexistent;
}
diff --git a/libbrep/utility.hxx b/libbrep/utility.hxx
index 96cf1d4..be27a71 100644
--- a/libbrep/utility.hxx
+++ b/libbrep/utility.hxx
@@ -1,5 +1,4 @@
// file : libbrep/utility.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_UTILITY_HXX
@@ -27,6 +26,7 @@ namespace brep
// <libbutl/utility.mxx>
//
+ using butl::utf8;
using butl::icasecmp;
using butl::reverse_iterate;
}
diff --git a/libbrep/version.hxx.in b/libbrep/version.hxx.in
index 00fb4ff..3ac3752 100644
--- a/libbrep/version.hxx.in
+++ b/libbrep/version.hxx.in
@@ -1,5 +1,4 @@
// file : libbrep/version.hxx.in -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef BREP_VERSION // Note: using the version macro itself.
diff --git a/libbrep/wrapper-traits.hxx b/libbrep/wrapper-traits.hxx
index 54c5ef1..9dad27b 100644
--- a/libbrep/wrapper-traits.hxx
+++ b/libbrep/wrapper-traits.hxx
@@ -1,5 +1,4 @@
// file : libbrep/wrapper-traits.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef LIBBREP_WRAPPER_TRAITS_HXX
diff --git a/load/buildfile b/load/buildfile
index 493d067..b55489f 100644
--- a/load/buildfile
+++ b/load/buildfile
@@ -1,5 +1,4 @@
# file : load/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
import libs = libodb%lib{odb}
@@ -12,6 +11,10 @@ include ../libbrep/
exe{brep-load}: {hxx ixx cxx}{* -load-options} {hxx ixx cxx}{load-options} \
../libbrep/lib{brep} $libs
+# Build options.
+#
+obj{load}: cxx.poptions += -DBREP_COPYRIGHT=\"$copyright\"
+
# Generated options parser.
#
if $cli.configured
diff --git a/load/load.cli b/load/load.cli
index 74c91f2..05bbb11 100644
--- a/load/load.cli
+++ b/load/load.cli
@@ -1,5 +1,4 @@
// file : load/load.cli
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
include <vector>;
@@ -54,7 +53,8 @@ class options
bool --shallow
{
"Don't load package information from prerequisite or complement
- repositories."
+ repositories, don't fail if unable to resolve a package dependency, and
+ don't detect package dependency cycles."
};
std::string --tenant
@@ -162,8 +162,8 @@ Fatal error.|
\li|\cb{2}
-An instance of \cb{brep-load} or \l{brep-migrate(1)} is already running. Try
-again.|
+An instance of \cb{brep-load} or some other \cb{brep} utility is already
+running. Try again.|
\li|\cb{3}
diff --git a/load/load.cxx b/load/load.cxx
index 83cc9e6..e6591f5 100644
--- a/load/load.cxx
+++ b/load/load.cxx
@@ -1,5 +1,4 @@
// file : load/load.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <signal.h> // signal()
@@ -501,30 +500,25 @@ load_packages (const shared_ptr<repository>& rp,
ds.emplace_back (pda.conditional, pda.buildtime, move (pda.comment));
for (auto& pd: pda)
+ {
// The package member will be assigned during dependency
// resolution procedure.
//
ds.back ().push_back (dependency {move (pd.name),
move (pd.constraint),
nullptr /* package */});
+ }
}
- auto deps = [] (small_vector<bpkg::dependency, 1>&& ds)
- {
- small_vector<dependency, 1> r;
-
- if (!ds.empty ())
- {
- r.reserve (ds.size ());
+ small_vector<brep::test_dependency, 1> ts;
- for (bpkg::dependency& d: ds)
- r.push_back (dependency {move (d.name),
- move (d.constraint),
- nullptr /* package */});
- }
+ if (!pm.tests.empty ())
+ {
+ ts.reserve (pm.tests.size ());
- return r;
- };
+ for (bpkg::test_dependency& td: pm.tests)
+ ts.emplace_back (move (td.name), td.type, move (td.constraint));
+ }
// Cache before the package name is moved.
//
@@ -554,9 +548,7 @@ load_packages (const shared_ptr<repository>& rp,
move (pm.build_error_email),
move (ds),
move (pm.requirements),
- deps (move (pm.tests)),
- deps (move (pm.examples)),
- deps (move (pm.benchmarks)),
+ move (ts),
move (pm.builds),
move (pm.build_constraints),
move (pm.location),
@@ -567,7 +559,11 @@ load_packages (const shared_ptr<repository>& rp,
else
// Create external package object.
//
- p = make_shared<package> (move (pm.name), move (pm.version), rp);
+ p = make_shared<package> (move (pm.name),
+ move (pm.version),
+ move (pm.builds),
+ move (pm.build_constraints),
+ rp);
db.persist (p);
}
@@ -601,9 +597,14 @@ load_packages (const shared_ptr<repository>& rp,
// A non-stub package is buildable if belongs to at least one
// buildable repository (see libbrep/package.hxx for details).
+ // Note that if this is an external test package it will be marked as
+ // unbuildable later (see resolve_dependencies() for details).
//
- if (!p->stub () && !p->buildable)
- p->buildable = rp->buildable;
+ if (rp->buildable && !p->buildable && !p->stub ())
+ {
+ p->buildable = true;
+ p->unbuildable_reason = nullopt;
+ }
}
p->other_repositories.push_back (rp);
@@ -850,14 +851,16 @@ find (const lazy_shared_ptr<repository>& r,
return false;
}
-// Resolve package run-time dependencies, tests, examples, and benchmarks.
-// Make sure that the best matching dependency belongs to the package
-// repositories, their complements, recursively, or their immediate
-// prerequisite repositories (only for run-time dependencies). Should be
-// called once per internal package.
+// Resolve package run-time dependencies and external tests. Make sure that
+// the best matching dependency belongs to the package repositories, their
+// complements, recursively, or their immediate prerequisite repositories
+// (only for run-time dependencies). Set the buildable flag to false for the
+// resolved external tests packages. Fail if unable to resolve a dependency,
+// unless ignore_unresolved is true in which case leave this dependency
+// NULL. Should be called once per internal package.
//
static void
-resolve_dependencies (package& p, database& db)
+resolve_dependencies (package& p, database& db, bool ignore_unresolved)
{
using brep::dependency;
using brep::dependency_alternatives;
@@ -866,13 +869,10 @@ resolve_dependencies (package& p, database& db)
//
assert (p.internal ());
- if (p.dependencies.empty () &&
- p.tests.empty () &&
- p.examples.empty () &&
- p.benchmarks.empty ())
+ if (p.dependencies.empty () && p.tests.empty ())
return;
- auto resolve = [&p, &db] (dependency& d, bool prereq)
+ auto resolve = [&p, &db] (dependency& d, bool test)
{
// Dependency should not be resolved yet.
//
@@ -934,9 +934,26 @@ resolve_dependencies (package& p, database& db)
for (const auto& pp: db.query<package> (q + order_by_version_desc (vm)))
{
- if (find (p.internal_repository, pp, prereq))
+ if (find (p.internal_repository, pp, !test))
{
d.package.reset (db, pp.id);
+
+ // If the resolved dependency is an external test, then mark it as
+ // such, unless it is a stub.
+ //
+ if (test)
+ {
+ shared_ptr<package> dp (d.package.load ());
+
+ if (!dp->stub ())
+ {
+ dp->buildable = false;
+ dp->unbuildable_reason = unbuildable_reason::test;
+
+ db.update (dp);
+ }
+ }
+
return true;
}
}
@@ -961,32 +978,17 @@ resolve_dependencies (package& p, database& db)
// Practically it is enough to resolve at least one dependency
// alternative to build a package. Meanwhile here we consider an error
// specifying in the manifest file an alternative which can't be
- // resolved.
+ // resolved, unless unresolved dependencies are allowed.
//
- if (!resolve (d, true /* prereq */))
+ if (!resolve (d, false /* test */) && !ignore_unresolved)
bail (d, "dependency");
}
}
- // Should we allow tests, examples, and benchmarks packages to be
- // unresolvable? Let's forbid that until we see a use case for that.
- //
- for (dependency& d: p.tests)
- {
- if (!resolve (d, false /* prereq */))
- bail (d, "tests");
- }
-
- for (dependency& d: p.examples)
- {
- if (!resolve (d, false /* prereq */))
- bail (d, "examples");
- }
-
- for (dependency& d: p.benchmarks)
+ for (brep::test_dependency& td: p.tests)
{
- if (!resolve (d, false /* prereq */))
- bail (d, "benchmarks");
+ if (!resolve (td, true /* test */) && !ignore_unresolved)
+ bail (td, td.name.string ().c_str ());
}
db.update (p); // Update the package state.
@@ -1193,7 +1195,7 @@ try
<< "libbbot " << LIBBBOT_VERSION_ID << endl
<< "libbpkg " << LIBBPKG_VERSION_ID << endl
<< "libbutl " << LIBBUTL_VERSION_ID << endl
- << "Copyright (c) 2014-2019 Code Synthesis Ltd" << endl
+ << "Copyright (c) " << BREP_COPYRIGHT << "." << endl
<< "This is free software released under the MIT license." << endl;
return 0;
@@ -1277,7 +1279,7 @@ try
ops.db_port (),
"options='-c default_transaction_isolation=serializable'");
- // Prevent several brep-load/migrate instances from updating DB
+ // Prevent several brep utility instances from updating the package database
// simultaneously.
//
database_lock l (db);
@@ -1372,9 +1374,9 @@ try
load_repositories (r, db, ops.ignore_unknown (), ops.shallow ());
}
- // Resolve internal packages dependencies unless this is a shallow load.
+ // Resolve internal packages dependencies and, unless this is a shallow
+ // load, make sure there are no package dependency cycles.
//
- if (!ops.shallow ())
{
session s;
using query = query<package>;
@@ -1383,16 +1385,17 @@ try
db.query<package> (
query::id.tenant == tnt &&
query::internal_repository.canonical_name.is_not_null ()))
- resolve_dependencies (p, db);
+ resolve_dependencies (p, db, ops.shallow ());
- // Make sure there is no package dependency cycles.
- //
- package_ids chain;
- for (const auto& p:
- db.query<package> (
- query::id.tenant == tnt &&
- query::internal_repository.canonical_name.is_not_null ()))
- detect_dependency_cycle (p.id, chain, db);
+ if (!ops.shallow ())
+ {
+ package_ids chain;
+ for (const auto& p:
+ db.query<package> (
+ query::id.tenant == tnt &&
+ query::internal_repository.canonical_name.is_not_null ()))
+ detect_dependency_cycle (p.id, chain, db);
+ }
}
}
diff --git a/load/types-parsers.cxx b/load/types-parsers.cxx
index bc829f3..4c4ea9d 100644
--- a/load/types-parsers.cxx
+++ b/load/types-parsers.cxx
@@ -1,5 +1,4 @@
// file : load/types-parsers.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <load/types-parsers.hxx>
diff --git a/load/types-parsers.hxx b/load/types-parsers.hxx
index de7f001..1d2a6c9 100644
--- a/load/types-parsers.hxx
+++ b/load/types-parsers.hxx
@@ -1,5 +1,4 @@
// file : load/types-parsers.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
// CLI parsers, included into the generated source files.
diff --git a/manifest b/manifest
index 36f7fb4..02dd2f0 100644
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
: 1
name: brep
-version: 0.13.0-a.0.z
+version: 0.14.0-a.0.z
project: build2
summary: build2 package repository web interface
license: MIT
@@ -12,24 +12,24 @@ url: https://build2.org
doc-url: https://build2.org/doc.xhtml
src-url: https://git.build2.org/cgit/brep/tree/
email: users@build2.org
-build-email: builds@build2.org
+build-warning-email: builds@build2.org
builds: linux freebsd ; Only supports Linux and FreeBSD.
builds: -linux -freebsd ; Requires system packages.
requires: c++14
requires: postgresql >= 9.0
requires: apache2 ; Including development files (httpd.h header, etc).
-depends: * build2 >= 0.12.0
-depends: * bpkg >= 0.12.0
+depends: * build2 >= 0.13.0
+depends: * bpkg >= 0.13.0
# @@ Should probably become conditional dependency.
requires: ? cli ; Only required if changing .cli files.
depends: libapr1
depends: libapreq2
depends: libcmark-gfm == 0.29.0-a.1
depends: libcmark-gfm-extensions == 0.29.0-a.1
-depends: libstudxml ^1.1.0-b.8
-depends: libodb [2.5.0-b.18.1 2.5.0-b.19)
-depends: libodb-pgsql [2.5.0-b.18.1 2.5.0-b.19)
-depends: libbutl [0.13.0-a.0.1 0.13.0-a.1)
-depends: libbpkg [0.13.0-a.0.1 0.13.0-a.1)
-depends: libbbot [0.13.0-a.0.1 0.13.0-a.1)
-depends: libbutl.bash [0.13.0-a.0.1 0.13.0-a.1)
+depends: libstudxml [1.1.0-b.9.1 1.1.0-b.10)
+depends: libodb [2.5.0-b.20.1 2.5.0-b.21)
+depends: libodb-pgsql [2.5.0-b.20.1 2.5.0-b.21)
+depends: libbutl [0.14.0-a.0.1 0.14.0-a.1)
+depends: libbpkg [0.14.0-a.0.1 0.14.0-a.1)
+depends: libbbot [0.14.0-a.0.1 0.14.0-a.1)
+depends: libbutl.bash [0.14.0-a.0.1 0.14.0-a.1)
diff --git a/migrate/buildfile b/migrate/buildfile
index 0fd6558..0480cc6 100644
--- a/migrate/buildfile
+++ b/migrate/buildfile
@@ -1,5 +1,4 @@
# file : migrate/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
import libs = libodb%lib{odb}
@@ -12,6 +11,10 @@ exe{brep-migrate}: {hxx ixx cxx}{* -migrate-options} \
{hxx ixx cxx}{ migrate-options} \
../libbrep/lib{brep} $libs
+# Build options.
+#
+obj{migrate}: cxx.poptions += -DBREP_COPYRIGHT=\"$copyright\"
+
# Generated options parser.
#
if $cli.configured
diff --git a/migrate/migrate.cli b/migrate/migrate.cli
index 52d31cc..177f991 100644
--- a/migrate/migrate.cli
+++ b/migrate/migrate.cli
@@ -1,5 +1,4 @@
// file : migrate/migrate.cli
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
include <vector>;
@@ -126,8 +125,8 @@ Fatal error.|
\li|\cb{2}
-An instance of \cb{brep-migrate} or \l{brep-load(1)} is already running. Try
-again.|
+An instance of \cb{brep-migrate} or some other \cb{brep} utility is already
+running. Try again.|
\li|\cb{3}
diff --git a/migrate/migrate.cxx b/migrate/migrate.cxx
index c1f4dc1..88c87c1 100644
--- a/migrate/migrate.cxx
+++ b/migrate/migrate.cxx
@@ -1,5 +1,4 @@
// file : migrate/migrate.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <strings.h> // strcasecmp()
@@ -219,8 +218,8 @@ struct package_migration_entry: package_migration_entry_base<v>
: package_migration_entry_base<v> (f, "package") {}
};
-static const package_migration_entry<18>
-package_migrate_v18 ([] (database& db)
+static const package_migration_entry<20>
+package_migrate_v20 ([] (database& db)
{
});
#endif
@@ -243,7 +242,7 @@ try
<< "libbbot " << LIBBBOT_VERSION_ID << endl
<< "libbpkg " << LIBBPKG_VERSION_ID << endl
<< "libbutl " << LIBBUTL_VERSION_ID << endl
- << "Copyright (c) 2014-2019 Code Synthesis Ltd" << endl
+ << "Copyright (c) " << BREP_COPYRIGHT << "." << endl
<< "This is free software released under the MIT license." << endl;
return 0;
@@ -301,12 +300,12 @@ try
ops.db_port (),
"options='-c default_transaction_isolation=serializable'");
- // Prevent several brep-migrate/load instances from updating DB
+ // Prevent several brep utility instances from updating the database
// simultaneously.
//
database_lock l (db);
- // Currently we don't support data migration for the manual database scheme
+ // Currently we don't support data migration for the manual database schema
// migration.
//
if (db.schema_migration (db_schema))
diff --git a/mod/.gitignore b/mod/.gitignore
index c6e608b..6b64ad0 100644
--- a/mod/.gitignore
+++ b/mod/.gitignore
@@ -1 +1 @@
-options.?xx
+*-options.?xx
diff --git a/mod/build-config-module.cxx b/mod/build-config-module.cxx
index 13f61b7..831cb78 100644
--- a/mod/build-config-module.cxx
+++ b/mod/build-config-module.cxx
@@ -1,5 +1,4 @@
// file : mod/build-config-module.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/build-config-module.hxx>
@@ -10,10 +9,9 @@
#include <sstream>
#include <libbutl/sha256.mxx>
-#include <libbutl/utility.mxx> // throw_generic_error(), alpha(), etc.
+#include <libbutl/utility.mxx> // throw_generic_error()
#include <libbutl/openssl.mxx>
#include <libbutl/filesystem.mxx> // dir_iterator, dir_entry
-#include <libbutl/path-pattern.mxx>
namespace brep
{
@@ -158,184 +156,6 @@ namespace brep
build_conf_map_ = make_shared<conf_map_type> (move (conf_map));
}
- // The default underlying class set expression (see below).
- //
- static const build_class_expr default_ucs_expr (
- {"default"}, '+', "Default.");
-
- bool build_config_module::
- exclude (const small_vector<build_class_expr, 1>& exprs,
- const vector<build_constraint>& constrs,
- const build_config& cfg,
- string* reason) const
- {
- // Save the first sentence of the reason, lower-case the first letter if
- // the beginning looks like a word (all subsequent characters until a
- // whitespace are lower-case letters).
- //
- auto sanitize = [] (const string& reason)
- {
- string r (reason.substr (0, reason.find ('.')));
-
- char c (r[0]); // Can be '\0'.
- if (alpha (c) && c == ucase (c))
- {
- bool word (true);
-
- for (size_t i (1);
- i != r.size () && (c = r[i]) != ' ' && c != '\t' && c != '\n';
- ++i)
- {
- // Is not a word if contains a non-letter or an upper-case letter.
- //
- if (!alpha (c) || c == ucase (c))
- {
- word = false;
- break;
- }
- }
-
- if (word)
- r[0] = lcase (r[0]);
- }
-
- return r;
- };
-
- // First, match the configuration against the package underlying build
- // class set and expressions.
- //
- bool m (false);
-
- // Match the configuration against an expression, updating the match
- // result.
- //
- // We will use a comment of the first encountered excluding expression
- // (changing the result from true to false) or non-including one (leaving
- // the false result) as an exclusion reason.
- //
- auto match = [&cfg, &m, reason, &sanitize, this]
- (const build_class_expr& e)
- {
- bool pm (m);
- e.match (cfg.classes, build_conf_->class_inheritance_map, m);
-
- if (reason != nullptr)
- {
- // Reset the reason which, if saved, makes no sense anymore.
- //
- if (m)
- {
- reason->clear ();
- }
- else if (reason->empty () &&
- //
- // Exclusion.
- //
- (pm ||
- //
- // Non-inclusion. Make sure that the build class expression
- // is empty or starts with an addition (+...).
- //
- e.expr.empty () ||
- e.expr.front ().operation == '+'))
- {
- *reason = sanitize (e.comment);
- }
- }
- };
-
- // Determine the underlying class set. Note that in the future we can
- // potentially extend the underlying set with special classes.
- //
- const build_class_expr* ucs (
- !exprs.empty () && !exprs.front ().underlying_classes.empty ()
- ? &exprs.front ()
- : nullptr);
-
- // Note that the combined package build configuration class expression can
- // be represented as the underlying class set used as a starting set for
- // the original expressions and a restricting set, simultaneously. For
- // example, for the expression:
- //
- // default legacy : -msvc
- //
- // the resulting expression will be:
- //
- // +( +default +legacy ) -msvc &( +default +legacy )
- //
- // Let's, however, optimize it a bit based on the following facts:
- //
- // - If the underlying class set expression (+default +legacy in the above
- // example) evaluates to false, then the resulting expression also
- // evaluates to false due to the trailing '&' operation. Thus, we don't
- // need to evaluate further if that's the case.
- //
- // - On the other hand, if the underlying class set expression evaluates
- // to true, then we don't need to apply the trailing '&' operation as it
- // cannot affect the result.
- //
- const build_class_expr& ucs_expr (
- ucs != nullptr
- ? build_class_expr (ucs->underlying_classes, '+', ucs->comment)
- : default_ucs_expr);
-
- match (ucs_expr);
-
- if (m)
- {
- for (const build_class_expr& e: exprs)
- match (e);
- }
-
- // Exclude the configuration if it doesn't match the compound expression.
- //
- if (!m)
- return true;
-
- // Now check if the configuration is excluded/included via the patterns.
- //
- // To implement matching of absent name components with wildcard-only
- // pattern components we are going to convert names to paths (see
- // dash_components_to_path() for details).
- //
- // And if any of the build-{include,exclude} values (which is legal) or
- // the build configuration name/target (illegal) are invalid paths, then
- // we assume no match.
- //
- if (!constrs.empty ())
- try
- {
- path cn (dash_components_to_path (cfg.name));
- path tg (dash_components_to_path (cfg.target.string ()));
-
- for (const build_constraint& c: constrs)
- {
- if (path_match (cn,
- dash_components_to_path (c.config),
- dir_path () /* start */,
- path_match_flags::match_absent) &&
- (!c.target ||
- path_match (tg,
- dash_components_to_path (*c.target),
- dir_path () /* start */,
- path_match_flags::match_absent)))
- {
- if (!c.exclusion)
- return false;
-
- if (reason != nullptr)
- *reason = sanitize (c.comment);
-
- return true;
- }
- }
- }
- catch (const invalid_path&) {}
-
- return false;
- }
-
bool build_config_module::
belongs (const bbot::build_config& cfg, const char* cls) const
{
@@ -361,59 +181,4 @@ namespace brep
return false;
}
-
- path build_config_module::
- dash_components_to_path (const string& pattern)
- {
- string r;
- size_t nstar (0);
- for (const path_pattern_term& pt: path_pattern_iterator (pattern))
- {
- switch (pt.type)
- {
- case path_pattern_term_type::star:
- {
- // Replace ** with */**/* and skip all the remaining stars that may
- // follow in this sequence.
- //
- if (nstar == 0)
- r += "*";
- else if (nstar == 1)
- r += "/**/*"; // The first star is already copied.
-
- break;
- }
- case path_pattern_term_type::literal:
- {
- // Replace '-' with '/' and fall through otherwise.
- //
- if (get_literal (pt) == '-')
- {
- r += '/';
- break;
- }
- }
- // Fall through.
- default:
- {
- r.append (pt.begin, pt.end); // Copy the pattern term as is.
- }
- }
-
- nstar = pt.star () ? nstar + 1 : 0;
- }
-
- // Append the trailing slash to match the resulting paths as directories.
- // This is required for the trailing /* we could append to match absent
- // directory path components (see path_match_flags::match_absent for
- // details).
- //
- // Note that valid dash components may not contain a trailing dash.
- // Anyway, any extra trailing slashes will be ignored by the path
- // constructor.
- //
- r += '/';
-
- return path (move (r));
- }
}
diff --git a/mod/build-config-module.hxx b/mod/build-config-module.hxx
index 25ddbb4..ba2698d 100644
--- a/mod/build-config-module.hxx
+++ b/mod/build-config-module.hxx
@@ -1,12 +1,10 @@
// file : mod/build-config-module.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_BUILD_CONFIG_MODULE_HXX
#define MOD_BUILD_CONFIG_MODULE_HXX
#include <map>
-#include <algorithm> // find()
#include <libbutl/utility.mxx> // compare_c_string
@@ -17,8 +15,8 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/build-config.hxx>
+#include <mod/module-options.hxx>
// Base class for modules that utilize the build controller configuration.
//
@@ -40,17 +38,20 @@ namespace brep
void
init (const options::build&);
- // Return true if the specified build configuration is excluded by a
- // package based on its underlying build class set, build class
- // expressions, and build constraints, potentially extending the
- // underlying set with the special classes. Set the exclusion reason if
- // requested.
- //
bool
- exclude (const small_vector<bpkg::build_class_expr, 1>&,
- const vector<bpkg::build_constraint>&,
- const bbot::build_config&,
- string* reason = nullptr) const;
+ exclude (const small_vector<bpkg::build_class_expr, 1>& exprs,
+ const vector<bpkg::build_constraint>& constrs,
+ const bbot::build_config& cfg,
+ string* reason = nullptr,
+ bool default_all_ucs = false) const
+ {
+ return brep::exclude (exprs,
+ constrs,
+ cfg,
+ build_conf_->class_inheritance_map,
+ reason,
+ default_all_ucs);
+ }
// Check if the configuration belongs to the specified class.
//
@@ -63,20 +64,6 @@ namespace brep
return belongs (cfg, cls.c_str ());
}
- // Convert dash-separated components (target, build configuration name,
- // machine name) or a pattern thereof into a path, replacing dashes with
- // slashes (directory separators), `**` with `*/**/*`, and appending the
- // trailing slash for a subsequent match using the path_match()
- // functionality (the idea here is for `linux**` to match `linux-gcc`
- // which is quite natural to expect). Throw invalid_path if the resulting
- // path is invalid.
- //
- // Note that the match_absent path match flag must be used for the above
- // `**` transformation to work.
- //
- static path
- dash_components_to_path (const string&);
-
// Configuration/toolchain combination that, in particular, can be used as
// a set value.
//
diff --git a/mod/build-config.cxx b/mod/build-config.cxx
new file mode 100644
index 0000000..43a85e8
--- /dev/null
+++ b/mod/build-config.cxx
@@ -0,0 +1,255 @@
+// file : mod/build-config-module.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <mod/build-config.hxx>
+
+#include <libbutl/utility.mxx> // alpha(), etc.
+#include <libbutl/path-pattern.mxx>
+
+namespace brep
+{
+ using namespace std;
+ using namespace butl;
+ using namespace bpkg;
+ using namespace bbot;
+
+ // The default underlying class set expressions (see below).
+ //
+ static const build_class_expr default_ucs_expr (
+ {"default"}, '+', "Default.");
+
+ static const build_class_expr all_ucs_expr (
+ {"all"}, '+', "All.");
+
+ bool
+ exclude (const small_vector<build_class_expr, 1>& exprs,
+ const vector<build_constraint>& constrs,
+ const build_config& cfg,
+ const map<string, string>& class_inheritance_map,
+ string* reason,
+ bool default_all_ucs)
+ {
+ // Save the first sentence of the reason, lower-case the first letter if
+ // the beginning looks like a word (all subsequent characters until a
+ // whitespace are lower-case letters).
+ //
+ auto sanitize = [] (const string& reason)
+ {
+ string r (reason.substr (0, reason.find ('.')));
+
+ char c (r[0]); // Can be '\0'.
+ if (alpha (c) && c == ucase (c))
+ {
+ bool word (true);
+
+ for (size_t i (1);
+ i != r.size () && (c = r[i]) != ' ' && c != '\t' && c != '\n';
+ ++i)
+ {
+ // Is not a word if contains a non-letter or an upper-case letter.
+ //
+ if (!alpha (c) || c == ucase (c))
+ {
+ word = false;
+ break;
+ }
+ }
+
+ if (word)
+ r[0] = lcase (r[0]);
+ }
+
+ return r;
+ };
+
+ // First, match the configuration against the package underlying build
+ // class set and expressions.
+ //
+ bool m (false);
+
+ // Match the configuration against an expression, updating the match
+ // result.
+ //
+ // We will use a comment of the first encountered excluding expression
+ // (changing the result from true to false) or non-including one (leaving
+ // the false result) as an exclusion reason.
+ //
+ auto match = [&cfg, &m, reason, &sanitize, &class_inheritance_map]
+ (const build_class_expr& e)
+ {
+ bool pm (m);
+ e.match (cfg.classes, class_inheritance_map, m);
+
+ if (reason != nullptr)
+ {
+ // Reset the reason which, if saved, makes no sense anymore.
+ //
+ if (m)
+ {
+ reason->clear ();
+ }
+ else if (reason->empty () &&
+ //
+ // Exclusion.
+ //
+ (pm ||
+ //
+ // Non-inclusion. Make sure that the build class expression
+ // is empty or starts with an addition (+...).
+ //
+ e.expr.empty () ||
+ e.expr.front ().operation == '+'))
+ {
+ *reason = sanitize (e.comment);
+ }
+ }
+ };
+
+ // Determine the underlying class set. Note that in the future we can
+ // potentially extend the underlying set with special classes.
+ //
+ const build_class_expr* ucs (
+ !exprs.empty () && !exprs.front ().underlying_classes.empty ()
+ ? &exprs.front ()
+ : nullptr);
+
+ // Note that the combined package build configuration class expression can
+ // be represented as the underlying class set used as a starting set for
+ // the original expressions and a restricting set, simultaneously. For
+ // example, for the expression:
+ //
+ // default legacy : -msvc
+ //
+ // the resulting expression will be:
+ //
+ // +( +default +legacy ) -msvc &( +default +legacy )
+ //
+ // Let's, however, optimize it a bit based on the following facts:
+ //
+ // - If the underlying class set expression (+default +legacy in the above
+ // example) evaluates to false, then the resulting expression also
+ // evaluates to false due to the trailing '&' operation. Thus, we don't
+ // need to evaluate further if that's the case.
+ //
+ // - On the other hand, if the underlying class set expression evaluates
+ // to true, then we don't need to apply the trailing '&' operation as it
+ // cannot affect the result.
+ //
+ const build_class_expr& ucs_expr (
+ ucs != nullptr ? build_class_expr (ucs->underlying_classes,
+ '+',
+ ucs->comment) :
+ default_all_ucs ? all_ucs_expr :
+ default_ucs_expr);
+
+ match (ucs_expr);
+
+ if (m)
+ {
+ for (const build_class_expr& e: exprs)
+ match (e);
+ }
+
+ // Exclude the configuration if it doesn't match the compound expression.
+ //
+ if (!m)
+ return true;
+
+ // Now check if the configuration is excluded/included via the patterns.
+ //
+ // To implement matching of absent name components with wildcard-only
+ // pattern components we are going to convert names to paths (see
+ // dash_components_to_path() for details).
+ //
+ // And if any of the build-{include,exclude} values (which is legal) or
+ // the build configuration name/target (illegal) are invalid paths, then
+ // we assume no match.
+ //
+ if (!constrs.empty ())
+ try
+ {
+ path cn (dash_components_to_path (cfg.name));
+ path tg (dash_components_to_path (cfg.target.string ()));
+
+ for (const build_constraint& c: constrs)
+ {
+ if (path_match (cn,
+ dash_components_to_path (c.config),
+ dir_path () /* start */,
+ path_match_flags::match_absent) &&
+ (!c.target ||
+ path_match (tg,
+ dash_components_to_path (*c.target),
+ dir_path () /* start */,
+ path_match_flags::match_absent)))
+ {
+ if (!c.exclusion)
+ return false;
+
+ if (reason != nullptr)
+ *reason = sanitize (c.comment);
+
+ return true;
+ }
+ }
+ }
+ catch (const invalid_path&) {}
+
+ return false;
+ }
+
+ path
+ dash_components_to_path (const string& pattern)
+ {
+ string r;
+ size_t nstar (0);
+ for (const path_pattern_term& pt: path_pattern_iterator (pattern))
+ {
+ switch (pt.type)
+ {
+ case path_pattern_term_type::star:
+ {
+ // Replace ** with */**/* and skip all the remaining stars that may
+ // follow in this sequence.
+ //
+ if (nstar == 0)
+ r += "*";
+ else if (nstar == 1)
+ r += "/**/*"; // The first star is already copied.
+
+ break;
+ }
+ case path_pattern_term_type::literal:
+ {
+ // Replace '-' with '/' and fall through otherwise.
+ //
+ if (get_literal (pt) == '-')
+ {
+ r += '/';
+ break;
+ }
+ }
+ // Fall through.
+ default:
+ {
+ r.append (pt.begin, pt.end); // Copy the pattern term as is.
+ }
+ }
+
+ nstar = pt.star () ? nstar + 1 : 0;
+ }
+
+ // Append the trailing slash to match the resulting paths as directories.
+ // This is required for the trailing /* we could append to match absent
+ // directory path components (see path_match_flags::match_absent for
+ // details).
+ //
+ // Note that valid dash components may not contain a trailing dash.
+ // Anyway, any extra trailing slashes will be ignored by the path
+ // constructor.
+ //
+ r += '/';
+
+ return path (move (r));
+ }
+}
diff --git a/mod/build-config.hxx b/mod/build-config.hxx
new file mode 100644
index 0000000..e8dfe07
--- /dev/null
+++ b/mod/build-config.hxx
@@ -0,0 +1,49 @@
+// file : mod/build-config.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef MOD_BUILD_CONFIG_HXX
+#define MOD_BUILD_CONFIG_HXX
+
+#include <map>
+
+#include <libbpkg/manifest.hxx>
+
+#include <libbbot/build-config.hxx>
+
+#include <libbrep/types.hxx>
+#include <libbrep/utility.hxx>
+
+namespace brep
+{
+ // Return true if the specified build configuration is excluded by a package
+ // based on its underlying build class set, build class expressions, and
+ // build constraints, potentially extending the underlying set with the
+ // special classes. Set the exclusion reason if requested. Optionally use
+ // the `all` class as a default underlying build class set rather than the
+ // `default` class (which is, for example, the case for the external test
+ // packages not to reduce their build configuration set needlessly).
+ //
+ bool
+ exclude (const small_vector<bpkg::build_class_expr, 1>&,
+ const vector<bpkg::build_constraint>&,
+ const bbot::build_config&,
+ const std::map<string, string>& class_inheritance_map,
+ string* reason = nullptr,
+ bool default_all_ucs = false);
+
+ // Convert dash-separated components (target, build configuration name,
+ // machine name) or a pattern thereof into a path, replacing dashes with
+ // slashes (directory separators), `**` with `*/**/*`, and appending the
+ // trailing slash for a subsequent match using the path_match()
+ // functionality (the idea here is for `linux**` to match `linux-gcc` which
+ // is quite natural to expect). Throw invalid_path if the resulting path is
+ // invalid.
+ //
+ // Note that the match_absent path match flag must be used for the above
+ // `**` transformation to work.
+ //
+ path
+ dash_components_to_path (const string&);
+}
+
+#endif // MOD_BUILD_CONFIG
diff --git a/mod/build.cxx b/mod/build.cxx
index 32f3691..5b9d8aa 100644
--- a/mod/build.cxx
+++ b/mod/build.cxx
@@ -1,10 +1,9 @@
// file : mod/build.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/build.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/mime-url-encoding.hxx>
#include <mod/utility.hxx>
diff --git a/mod/build.hxx b/mod/build.hxx
index 7ae7f95..f0846be 100644
--- a/mod/build.hxx
+++ b/mod/build.hxx
@@ -1,5 +1,4 @@
// file : mod/build.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_BUILD_HXX
diff --git a/mod/buildfile b/mod/buildfile
index ffa9031..191d966 100644
--- a/mod/buildfile
+++ b/mod/buildfile
@@ -1,5 +1,4 @@
# file : mod/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
define mod: libs
@@ -20,25 +19,38 @@ import libs += libbpkg%lib{bpkg}
import libs += libbbot%lib{bbot}
include ../libbrep/
-include ../web/
-mod{brep}: {hxx ixx txx cxx}{* -options} \
- {hxx ixx cxx}{ options} \
- ../libbrep/lib{brep} ../web/libus{web} $libs
+include ../web/xhtml/
+include ../web/server/
+
+./: mod{brep} {libue libus}{mod}
+
+libu_src = options-types types-parsers build-config
+
+mod{brep}: {hxx ixx txx cxx}{* -module-options -{$libu_src}} \
+ libus{mod} ../libbrep/lib{brep} ../web/server/libus{web-server} \
+ $libs
+
+{libue libus}{mod}: {hxx ixx cxx}{module-options} \
+ {hxx ixx txx cxx}{+{$libu_src} } \
+ $libs
+
+libus{mod}: ../web/xhtml/libus{xhtml}
+libue{mod}: ../web/xhtml/libue{xhtml}
# Generated options parser.
#
if $cli.configured
{
- cli.cxx{options}: cli{options}
+ cli.cxx{module-options}: cli{module}
# Set option prefix to the empty value to handle all unknown request
# parameters uniformly with a single catch block.
#
- cli.options += --std c++11 -I $src_root --include-with-brackets \
---include-prefix mod --guard-prefix MOD --generate-specifier \
---cxx-prologue "#include <mod/types-parsers.hxx>" \
---cli-namespace brep::cli --generate-file-scanner --suppress-usage \
+ cli.options += --std c++11 -I $src_root --include-with-brackets \
+--include-prefix mod --guard-prefix MOD --generate-specifier \
+--cxx-prologue "#include <mod/types-parsers.hxx>" \
+--cli-namespace brep::cli --generate-file-scanner --option-length 41 \
--generate-modifier --generate-description --option-prefix ""
# Include the generated cli files into the distribution and don't remove
diff --git a/mod/database-module.cxx b/mod/database-module.cxx
index 5f20c01..f598bfd 100644
--- a/mod/database-module.cxx
+++ b/mod/database-module.cxx
@@ -1,13 +1,12 @@
// file : mod/database-module.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/database-module.hxx>
#include <odb/exceptions.hxx>
-#include <mod/options.hxx>
#include <mod/database.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/database-module.hxx b/mod/database-module.hxx
index 06fc496..f72ba83 100644
--- a/mod/database-module.hxx
+++ b/mod/database-module.hxx
@@ -1,5 +1,4 @@
// file : mod/database-module.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_DATABASE_MODULE_HXX
@@ -11,7 +10,7 @@
#include <libbrep/utility.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/database.cxx b/mod/database.cxx
index 3a3f793..d53ee50 100644
--- a/mod/database.cxx
+++ b/mod/database.cxx
@@ -1,5 +1,4 @@
// file : mod/database.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/database.hxx>
diff --git a/mod/database.hxx b/mod/database.hxx
index 2006e35..ff61433 100644
--- a/mod/database.hxx
+++ b/mod/database.hxx
@@ -1,5 +1,4 @@
// file : mod/database.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_DATABASE_HXX
diff --git a/mod/diagnostics.cxx b/mod/diagnostics.cxx
index 0a2609f..fac251f 100644
--- a/mod/diagnostics.cxx
+++ b/mod/diagnostics.cxx
@@ -1,5 +1,4 @@
// file : mod/diagnostics.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/diagnostics.hxx>
diff --git a/mod/diagnostics.hxx b/mod/diagnostics.hxx
index 15fe7b2..37ab25e 100644
--- a/mod/diagnostics.hxx
+++ b/mod/diagnostics.hxx
@@ -1,5 +1,4 @@
// file : mod/diagnostics.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_DIAGNOSTICS_HXX
diff --git a/mod/external-handler.cxx b/mod/external-handler.cxx
index 4237439..4c1a86f 100644
--- a/mod/external-handler.cxx
+++ b/mod/external-handler.cxx
@@ -1,5 +1,4 @@
// file : mod/external-handler.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/external-handler.hxx>
diff --git a/mod/external-handler.hxx b/mod/external-handler.hxx
index 5a1d731..f8f7ee8 100644
--- a/mod/external-handler.hxx
+++ b/mod/external-handler.hxx
@@ -1,5 +1,4 @@
// file : mod/external-handler.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_EXTERNAL_HANDLER_HXX
diff --git a/mod/mod-build-configs.cxx b/mod/mod-build-configs.cxx
index 0218a5f..6731b28 100644
--- a/mod/mod-build-configs.cxx
+++ b/mod/mod-build-configs.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-configs.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-configs.hxx>
@@ -8,11 +7,12 @@
#include <libstudxml/serializer.hxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace bbot;
diff --git a/mod/mod-build-configs.hxx b/mod/mod-build-configs.hxx
index a8354e6..562ac6d 100644
--- a/mod/mod-build-configs.hxx
+++ b/mod/mod-build-configs.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-configs.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILD_CONFIGS_HXX
@@ -9,7 +8,7 @@
#include <libbrep/utility.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/build-config-module.hxx>
namespace brep
diff --git a/mod/mod-build-force.cxx b/mod/mod-build-force.cxx
index 72c5fdf..bd172e3 100644
--- a/mod/mod-build-force.cxx
+++ b/mod/mod-build-force.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-force.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-force.hxx>
@@ -9,12 +8,12 @@
#include <odb/database.hxx>
#include <odb/transaction.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace bbot;
diff --git a/mod/mod-build-force.hxx b/mod/mod-build-force.hxx
index afae53b..22df383 100644
--- a/mod/mod-build-force.hxx
+++ b/mod/mod-build-force.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-force.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILD_FORCE_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-build-log.cxx b/mod/mod-build-log.cxx
index a6e6730..3032e52 100644
--- a/mod/mod-build-log.cxx
+++ b/mod/mod-build-log.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-log.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-log.hxx>
@@ -11,12 +10,12 @@
#include <libbutl/timestamp.mxx> // to_stream()
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace bbot;
diff --git a/mod/mod-build-log.hxx b/mod/mod-build-log.hxx
index 2a5812c..a2f4e48 100644
--- a/mod/mod-build-log.hxx
+++ b/mod/mod-build-log.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-log.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILD_LOG_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-build-result.cxx b/mod/mod-build-result.cxx
index 860a964..734ea5c 100644
--- a/mod/mod-build-result.cxx
+++ b/mod/mod-build-result.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-result.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-result.hxx>
@@ -16,15 +15,15 @@
#include <libbbot/manifest.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
-#include <mod/build.hxx> // *_url()
-#include <mod/options.hxx>
+#include <mod/build.hxx> // *_url()
+#include <mod/module-options.hxx>
using namespace std;
using namespace butl;
@@ -410,6 +409,7 @@ handle (request& rq, response&)
b->results = move (rqm.result.results);
b->timestamp = system_clock::now ();
+ b->completion_timestamp = b->timestamp;
build_db_->update (b);
diff --git a/mod/mod-build-result.hxx b/mod/mod-build-result.hxx
index f65dc08..71a60f9 100644
--- a/mod/mod-build-result.hxx
+++ b/mod/mod-build-result.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-result.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILD_RESULT_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-build-task.cxx b/mod/mod-build-task.cxx
index 9f97098..04b2a36 100644
--- a/mod/mod-build-task.cxx
+++ b/mod/mod-build-task.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-task.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-task.hxx>
@@ -23,14 +22,14 @@
#include <libbbot/manifest.hxx>
#include <libbbot/build-config.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
#include <libbrep/build-package.hxx>
#include <libbrep/build-package-odb.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace butl;
@@ -60,6 +59,14 @@ init (scanner& s)
if (options_->build_config_specified ())
{
+ // Verify that build-alt-rebuild-{start,stop} are both either specified or
+ // not.
+ //
+ if (options_->build_alt_rebuild_start_specified () !=
+ options_->build_alt_rebuild_stop_specified ())
+ fail << "build-alt-rebuild-start and build-alt-rebuild-stop "
+ << "configuration options must both be either specified or not";
+
database_module::init (*options_, options_->build_db_retry ());
// Check that the database 'build' schema matches the current one. It's
@@ -213,14 +220,47 @@ handle (request& rq, response& rs)
lazy_shared_ptr<build_repository> r (p->internal_repository);
- strings fp;
+ strings fps;
if (r->certificate_fingerprint)
- fp.emplace_back (move (*r->certificate_fingerprint));
+ fps.emplace_back (move (*r->certificate_fingerprint));
+
+ // Exclude external test packages which exclude the task build
+ // configuration.
+ //
+ small_vector<package, 1> tes;
+
+ for (const build_test_dependency& td: p->tests)
+ {
+ // Don't exclude unresolved external tests.
+ //
+ // Note that this may result in the build task failure. However,
+ // silently excluding such tests could end up with missed software
+ // bugs which feels much worse.
+ //
+ if (td.package != nullptr)
+ {
+ shared_ptr<build_package> p (td.package.load ());
+
+ // Use the `all` class as a least restrictive default underlying
+ // build class set. Note that we should only apply the explicit
+ // build restrictions to the external test packages (think about
+ // the `builds: all` and `builds: -windows` manifest values for
+ // the primary and external test packages, respectively).
+ //
+ if (exclude (p->builds,
+ p->constraints,
+ *cm.config,
+ nullptr /* reason */,
+ true /* default_all_ucs */))
+ tes.push_back (package {move (p->id.name), move (p->version)});
+ }
+ }
task_manifest task (move (b->package_name),
move (b->package_version),
move (r->location),
- move (fp),
+ move (fps),
+ move (tes),
cm.machine->name,
cm.config->target,
cm.config->environment,
@@ -255,12 +295,48 @@ handle (request& rq, response& rs)
uint64_t forced_result_expiration_ns (
expiration_ns (options_->build_forced_rebuild_timeout ()));
- timestamp normal_rebuild_expiration (
- expiration (options_->build_normal_rebuild_timeout ()));
-
timestamp forced_rebuild_expiration (
expiration (options_->build_forced_rebuild_timeout ()));
+ timestamp normal_rebuild_expiration;
+
+ if (options_->build_alt_rebuild_start_specified ())
+ {
+ const duration& start (options_->build_alt_rebuild_start ());
+ const duration& stop (options_->build_alt_rebuild_stop ());
+
+ duration dt (daytime (now));
+
+ // Note that if the stop time is less than the start time then the
+ // interval extends through the midnight.
+ //
+ bool alt_timeout (start <= stop
+ ? dt >= start && dt < stop
+ : dt >= start || dt < stop);
+
+ // If we out of the alternative rebuild timeout interval, then fall back
+ // to using the normal rebuild timeout.
+ //
+ if (alt_timeout)
+ {
+ if (!options_->build_alt_rebuild_timeout_specified ())
+ {
+ duration interval_len (start <= stop
+ ? stop - start
+ : (24h - start) + stop);
+
+ normal_rebuild_expiration = now - interval_len;
+ }
+ else
+ normal_rebuild_expiration =
+ expiration (options_->build_alt_rebuild_timeout ());
+ }
+ }
+
+ if (normal_rebuild_expiration == timestamp_nonexistent)
+ normal_rebuild_expiration =
+ expiration (options_->build_normal_rebuild_timeout ());
+
// Return the challenge (nonce) if brep is configured to authenticate bbot
// agents. Return nullopt otherwise.
//
@@ -302,7 +378,7 @@ handle (request& rq, response& rs)
if (!os.wait () || nonce.size () != 64)
fail << "unable to generate nonce";
- uint64_t t (chrono::duration_cast<std::chrono::nanoseconds> (
+ uint64_t t (chrono::duration_cast<chrono::nanoseconds> (
now.time_since_epoch ()).count ());
sha256 cs (nonce.data (), nonce.size ());
@@ -385,34 +461,24 @@ handle (request& rq, response& rs)
using prep_bld_query = prepared_query<build>;
package_id id;
- const auto& qv (bld_query::id.package.version);
bld_query bq (
- bld_query::id.package.tenant == bld_query::_ref (id.tenant) &&
-
- bld_query::id.package.name == bld_query::_ref (id.name) &&
-
- qv.epoch == bld_query::_ref (id.version.epoch) &&
- qv.canonical_upstream ==
- bld_query::_ref (id.version.canonical_upstream) &&
- qv.canonical_release ==
- bld_query::_ref (id.version.canonical_release) &&
- qv.revision == bld_query::_ref (id.version.revision) &&
+ equal<build> (bld_query::id.package, id) &&
bld_query::id.configuration.in_range (cfg_names.begin (),
- cfg_names.end ()) &&
+ cfg_names.end ()) &&
- bld_query::id.toolchain_name == tqm.toolchain_name &&
+ bld_query::id.toolchain_name == tqm.toolchain_name &&
compare_version_eq (bld_query::id.toolchain_version,
canonical_version (toolchain_version),
- true /* revision */) &&
+ true /* revision */) &&
- (bld_query::state == "built" ||
- ((bld_query::force == "forcing" &&
- bld_query::timestamp > forced_result_expiration_ns) ||
- (bld_query::force != "forcing" && // Unforced or forced.
- bld_query::timestamp > normal_result_expiration_ns))));
+ (bld_query::state == "built" ||
+ (bld_query::force == "forcing" &&
+ bld_query::timestamp > forced_result_expiration_ns) ||
+ (bld_query::force != "forcing" && // Unforced or forced.
+ bld_query::timestamp > normal_result_expiration_ns)));
prep_bld_query bld_prep_query (
conn->prepare_query<build> ("mod-build-task-build-query", bq));
@@ -562,7 +628,7 @@ handle (request& rq, response& rs)
//
// We iterate over buildable packages.
//
- assert (p->internal_repository != nullptr);
+ assert (p->internal ());
p->internal_repository.load ();
@@ -644,8 +710,8 @@ handle (request& rq, response& rs)
shared_ptr<build_package> p (
build_db_->find<build_package> (b->id.package));
- if (p != nullptr &&
- p->internal_repository != nullptr &&
+ if (p != nullptr &&
+ p->internal () &&
!exclude (p->builds, p->constraints, *cm.config))
{
assert (b->status);
diff --git a/mod/mod-build-task.hxx b/mod/mod-build-task.hxx
index 3721363..7875db1 100644
--- a/mod/mod-build-task.hxx
+++ b/mod/mod-build-task.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-build-task.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILD_TASK_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx
index e749461..ab9e93e 100644
--- a/mod/mod-builds.cxx
+++ b/mod/mod-builds.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-builds.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-builds.hxx>
@@ -17,9 +16,10 @@
#include <libbbot/manifest.hxx> // to_result_status(), to_string(result_status)
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/module.hxx>
+#include <web/server/mime-url-encoding.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
@@ -27,7 +27,7 @@
#include <libbrep/build-package-odb.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace butl;
@@ -110,7 +110,11 @@ transform (const string& pattern)
case '|':
case '+':
case '{':
- case '(': r += '\\'; break;
+ case '}':
+ case '(':
+ case ')':
+ case '[':
+ case ']': r += '\\'; break;
}
r += c;
@@ -228,7 +232,10 @@ build_query (const brep::cstrings* configs,
else
{
query sq (qb::status == rs);
- result_status st (to_result_status(rs)); // May throw invalid_argument.
+
+ // May throw invalid_argument.
+ //
+ result_status st (to_result_status (rs));
if (st != result_status::success)
{
@@ -309,22 +316,6 @@ package_query (const brep::params::builds& params,
return q;
}
-template <typename T, typename ID>
-static inline query<T>
-package_id_eq (const ID& x, const brep::package_id& y)
-{
- using query = query<T>;
- const auto& qv (x.version);
-
- return
- x.tenant == query::_ref (y.tenant) &&
- x.name == query::_ref (y.name) &&
- qv.epoch == query::_ref (y.version.epoch) &&
- qv.canonical_upstream == query::_ref (y.version.canonical_upstream) &&
- qv.canonical_release == query::_ref (y.version.canonical_release) &&
- qv.revision == query::_ref (y.version.revision);
-}
-
static const vector<pair<string, string>> build_results ({
{"unbuilt", "<unbuilt>"},
{"*", "*"},
@@ -818,9 +809,8 @@ handle (request& rq, response& rs)
const auto& bid (bld_query::build::id);
- bld_query bq (
- package_id_eq<package_build_count> (bid.package, id) &&
- bid.configuration == bld_query::_ref (config) &&
+ bld_query bq (equal<package_build_count> (bid.package, id) &&
+ bid.configuration == bld_query::_ref (config) &&
// Note that the query already constrains configurations via the
// configuration name and the tenant via the build package id.
@@ -933,7 +923,7 @@ handle (request& rq, response& rs)
package_id id;
bld_query bq (
- package_id_eq<package_build> (bld_query::build::id.package, id) &&
+ equal<package_build> (bld_query::build::id.package, id) &&
// Note that the query already constrains the tenant via the build
// package id.
diff --git a/mod/mod-builds.hxx b/mod/mod-builds.hxx
index 1447fab..0aa7916 100644
--- a/mod/mod-builds.hxx
+++ b/mod/mod-builds.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-builds.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_BUILDS_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-ci.cxx b/mod/mod-ci.cxx
index 5a56526..d2da93f 100644
--- a/mod/mod-ci.cxx
+++ b/mod/mod-ci.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-ci.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-ci.hxx>
@@ -18,11 +17,12 @@
#include <libbpkg/manifest.hxx>
#include <libbpkg/package-name.hxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/external-handler.hxx>
using namespace std;
@@ -117,8 +117,8 @@ handle (request& rq, response& rs)
// latter case we will always respond with the same neutral message for
// security reason, logging the error details. Note that descriptions of
// exceptions caught by the web server are returned to the client (see
- // web/module.hxx for details), and we want to avoid this when there is a
- // danger of exposing sensitive data.
+ // web/server/module.hxx for details), and we want to avoid this when there
+ // is a danger of exposing sensitive data.
//
// Also we will pass through exceptions thrown by the underlying API, unless
// we need to handle them or add details for the description, in which case
@@ -265,24 +265,17 @@ handle (request& rq, response& rs)
}
// Verify that unknown parameter values satisfy the requirements (contain
- // only ASCII printable characters plus '\r', '\n', and '\t').
+ // only UTF-8 encoded graphic characters plus '\t', '\r', and '\n').
//
// Actually, the expected ones must satisfy too, so check them as well.
//
- auto printable = [] (const string& s) -> bool
- {
- for (char c: s)
- {
- if (!((c >= 0x20 && c <= 0x7E) || c == '\n' || c == '\r' || c == '\t'))
- return false;
- }
- return true;
- };
-
+ string what;
for (const name_value& nv: rps)
{
- if (nv.value && !printable (*nv.value))
- return respond_manifest (400, "invalid parameter " + nv.name);
+ if (nv.value &&
+ !utf8 (*nv.value, what, codepoint_types::graphic, U"\n\r\t"))
+ return respond_manifest (400,
+ "invalid parameter " + nv.name + ": " + what);
}
// Parse and validate overrides, if present.
diff --git a/mod/mod-ci.hxx b/mod/mod-ci.hxx
index 8a4e51e..431f53b 100644
--- a/mod/mod-ci.hxx
+++ b/mod/mod-ci.hxx
@@ -1,17 +1,16 @@
// file : mod/mod-ci.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_CI_HXX
#define MOD_MOD_CI_HXX
-#include <web/xhtml-fragment.hxx>
+#include <web/xhtml/fragment.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/mod-package-details.cxx b/mod/mod-package-details.cxx
index fc2e6be..e0bd1ef 100644
--- a/mod/mod-package-details.cxx
+++ b/mod/mod-package-details.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-package-details.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-package-details.hxx>
@@ -10,15 +9,16 @@
#include <odb/database.hxx>
#include <odb/transaction.hxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/module.hxx>
+#include <web/server/mime-url-encoding.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace odb::core;
using namespace brep::cli;
diff --git a/mod/mod-package-details.hxx b/mod/mod-package-details.hxx
index 3e2a015..e1b0a9c 100644
--- a/mod/mod-package-details.hxx
+++ b/mod/mod-package-details.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-package-details.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_PACKAGE_DETAILS_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
namespace brep
diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx
index 8787860..a7682ec 100644
--- a/mod/mod-package-version-details.cxx
+++ b/mod/mod-package-version-details.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-package-version-details.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-package-version-details.hxx>
@@ -10,9 +9,10 @@
#include <odb/database.hxx>
#include <odb/transaction.hxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/module.hxx>
+#include <web/server/mime-url-encoding.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
@@ -20,7 +20,7 @@
#include <libbrep/package-odb.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace butl;
@@ -397,38 +397,61 @@ handle (request& rq, response& rs)
<< ~TABLE;
}
- auto print_dependencies = [&s, &print_dependency]
- (const small_vector<dependency, 1>& deps,
- const char* heading,
- const char* id)
+ // Print the test dependencies grouped by types as the separate blocks.
+ //
+ // Print test dependencies of the specific type.
+ //
+ auto print_tests = [&pkg, &s, &print_dependency] (test_dependency_type dt)
{
- if (!deps.empty ())
- {
- s << H3 << heading << ~H3
- << TABLE(CLASS="proplist", ID=id)
- << TBODY;
+ string id;
- for (const dependency& d: deps)
+ bool first (true);
+ for (const test_dependency& td: pkg->tests)
+ {
+ if (td.type == dt)
{
+ // Print the table header if this is a first test dependency.
+ //
+ if (first)
+ {
+ id = to_string (dt);
+
+ // Capitalize the heading.
+ //
+ string heading (id);
+ heading[0] = ucase (id[0]);
+
+ s << H3 << heading << ~H3
+ << TABLE(CLASS="proplist", ID=id)
+ << TBODY;
+
+ first = false;
+ }
+
s << TR(CLASS=id)
<< TD
<< SPAN(CLASS="value");
- print_dependency (d);
+ print_dependency (td);
s << ~SPAN
<< ~TD
<< ~TR;
}
+ }
+ // Print the table closing tags if it was printed.
+ //
+ if (!first)
+ {
s << ~TBODY
<< ~TABLE;
}
};
- print_dependencies (pkg->tests, "Tests", "tests");
- print_dependencies (pkg->examples, "Examples", "examples");
- print_dependencies (pkg->benchmarks, "Benchmarks", "benchmarks");
+ print_tests (test_dependency_type::tests);
+ print_tests (test_dependency_type::examples);
+ print_tests (test_dependency_type::benchmarks);
bool builds (build_db_ != nullptr && pkg->buildable);
diff --git a/mod/mod-package-version-details.hxx b/mod/mod-package-version-details.hxx
index d9a5f72..a88d6c2 100644
--- a/mod/mod-package-version-details.hxx
+++ b/mod/mod-package-version-details.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-package-version-details.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_PACKAGE_VERSION_DETAILS_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
#include <mod/build-config-module.hxx>
diff --git a/mod/mod-packages.cxx b/mod/mod-packages.cxx
index 5d1945a..65c7c5b 100644
--- a/mod/mod-packages.cxx
+++ b/mod/mod-packages.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-packages.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-packages.hxx>
@@ -11,15 +10,16 @@
#include <odb/transaction.hxx>
#include <odb/schema-catalog.hxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/module.hxx>
+#include <web/server/mime-url-encoding.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace odb::core;
using namespace brep::cli;
diff --git a/mod/mod-packages.hxx b/mod/mod-packages.hxx
index a67533c..611d63c 100644
--- a/mod/mod-packages.hxx
+++ b/mod/mod-packages.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-packages.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_PACKAGES_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
namespace brep
diff --git a/mod/mod-repository-details.cxx b/mod/mod-repository-details.cxx
index 398d8a6..813b738 100644
--- a/mod/mod-repository-details.cxx
+++ b/mod/mod-repository-details.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-repository-details.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-repository-details.hxx>
@@ -13,15 +12,16 @@
#include <libbutl/timestamp.mxx> // to_string()
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/module.hxx>
+#include <web/server/mime-url-encoding.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace odb::core;
diff --git a/mod/mod-repository-details.hxx b/mod/mod-repository-details.hxx
index dd6efc1..e83831d 100644
--- a/mod/mod-repository-details.hxx
+++ b/mod/mod-repository-details.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-repository-details.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_REPOSITORY_DETAILS_HXX
@@ -8,7 +7,7 @@
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/database-module.hxx>
namespace brep
diff --git a/mod/mod-repository-root.cxx b/mod/mod-repository-root.cxx
index ed170c9..02d6c93 100644
--- a/mod/mod-repository-root.cxx
+++ b/mod/mod-repository-root.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-repository-root.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-repository-root.hxx>
@@ -11,10 +10,10 @@
#include <sstream>
#include <algorithm> // find()
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/mod-ci.hxx>
#include <mod/mod-submit.hxx>
diff --git a/mod/mod-repository-root.hxx b/mod/mod-repository-root.hxx
index 20ec0b6..9e28797 100644
--- a/mod/mod-repository-root.hxx
+++ b/mod/mod-repository-root.hxx
@@ -1,5 +1,4 @@
// file : mod/mod-repository-root.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_REPOSITORY_ROOT_HXX
@@ -9,7 +8,7 @@
#include <libbrep/utility.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/mod-submit.cxx b/mod/mod-submit.cxx
index 3130823..9c93a36 100644
--- a/mod/mod-submit.cxx
+++ b/mod/mod-submit.cxx
@@ -1,5 +1,4 @@
// file : mod/mod-submit.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-submit.hxx>
@@ -15,11 +14,12 @@
#include <libbutl/manifest-types.mxx>
#include <libbutl/manifest-serializer.mxx>
-#include <web/xhtml.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
+
+#include <web/xhtml/serialization.hxx>
#include <mod/page.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
#include <mod/external-handler.hxx>
using namespace std;
@@ -254,24 +254,17 @@ handle (request& rq, response& rs)
return respond_manifest (400, "invalid package archive checksum");
// Verify that unknown parameter values satisfy the requirements (contain
- // only ASCII printable characters plus '\r', '\n', and '\t').
+ // only UTF-8 encoded graphic characters plus '\t', '\r', and '\n').
//
// Actually, the expected ones must satisfy too, so check them as well.
//
- auto printable = [] (const string& s) -> bool
- {
- for (char c: s)
- {
- if (!((c >= 0x20 && c <= 0x7E) || c == '\n' || c == '\r' || c == '\t'))
- return false;
- }
- return true;
- };
-
+ string what;
for (const name_value& nv: rps)
{
- if (nv.value && !printable (*nv.value))
- return respond_manifest (400, "invalid parameter " + nv.name);
+ if (nv.value &&
+ !utf8 (*nv.value, what, codepoint_types::graphic, U"\n\r\t"))
+ return respond_manifest (400,
+ "invalid parameter " + nv.name + ": " + what);
}
// Note that from now on the result manifest we respond with will contain
diff --git a/mod/mod-submit.hxx b/mod/mod-submit.hxx
index 891f8a6..fc5f8d4 100644
--- a/mod/mod-submit.hxx
+++ b/mod/mod-submit.hxx
@@ -1,17 +1,16 @@
// file : mod/mod-submit.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MOD_SUBMIT_HXX
#define MOD_MOD_SUBMIT_HXX
-#include <web/xhtml-fragment.hxx>
+#include <web/xhtml/fragment.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
#include <mod/module.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/options.cli b/mod/module.cli
index 4004e79..b59158a 100644
--- a/mod/options.cli
+++ b/mod/module.cli
@@ -1,10 +1,9 @@
// file : mod/options.cli -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
include <libbpkg/manifest.hxx>; // repository_location
-include <web/xhtml-fragment.hxx>;
+include <web/xhtml/fragment.hxx>;
include <libbrep/types.hxx>;
@@ -38,7 +37,7 @@ namespace brep
dir_path root = "/"
{
- "<path>"
+ "<path>",
"Repository root. That is, this is the part of the URL between the
host name and the start of the repository. For example, root value
'\cb{/pkg}' means the repository URL is \cb{http://example.org/pkg/}.
@@ -200,6 +199,40 @@ namespace brep
"Time to wait before considering a package for a normal rebuild. Must
be specified in seconds. Default is 24 hours."
}
+
+ size_t build-alt-rebuild-timeout
+ {
+ "<seconds>",
+ "Alternative package rebuild timeout to use instead of the normal
+ rebuild timeout (see \cb{build-normal-rebuild-timeout} for details)
+ during the time interval specified with the
+ \cb{build-alt-rebuild-start} and \cb{build-alt-rebuild-stop} options.
+ Must be specified in seconds. Default is the time interval length."
+ }
+
+ duration build-alt-rebuild-start
+ {
+ "<hours>:<minutes>",
+ "The start time of the alternative package rebuild timeout (see
+ \cb{build-alt-rebuild-timeout} for details). Must be specified as
+ a time of day in the local timezone. The \cb{build-alt-rebuild-start}
+ and \cb{build-alt-rebuild-stop} options must be either both specified
+ or absent. If unspecified, then no alternative rebuild timeout will
+ be used."
+ }
+
+ duration build-alt-rebuild-stop
+ {
+ "<hours>:<minutes>",
+ "The end time of the alternative package rebuild timeout (see
+ \cb{build-alt-rebuild-timeout} for details). Must be specified as
+ a time of day in the local timezone. If it is less than the
+ \cb{build-alt-rebuild-start} option value, then the time interval
+ extends through midnight. The \cb{build-alt-rebuild-start} and
+ \cb{build-alt-rebuild-stop} options must be either both specified or
+ absent. If unspecified, then no alternative rebuild timeout will be
+ used."
+ }
};
class build_db
@@ -215,7 +248,7 @@ namespace brep
{
"<user>",
"Build database execution user name. If not empty then the login
- user will be switched (with \c{SET ROLE}) to this user prior to
+ user will be switched (with \c{SET ROLE}) to this user prior to
executing any statements. If not specified, then \cb{brep} is used."
}
@@ -566,7 +599,7 @@ namespace brep
string root-tenant-view = "packages"
{
- "<service>"
+ "<service>",
"The default view to display for the tenant repository root. The
<service> argument is one of the supported services (\c{packages},
\c{builds}, \c{submit}, \c{ci}, etc). The default service is
diff --git a/mod/module.cxx b/mod/module.cxx
index e0e4de1..06799d7 100644
--- a/mod/module.cxx
+++ b/mod/module.cxx
@@ -1,5 +1,4 @@
// file : mod/module.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/module.hxx>
@@ -11,10 +10,10 @@
#include <cstring> // strchr()
#include <functional> // bind()
-#include <web/module.hxx>
-#include <web/apache/log.hxx>
+#include <web/server/module.hxx>
+#include <web/server/apache/log.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
using namespace std;
using namespace placeholders; // For std::bind's _1, etc.
diff --git a/mod/module.hxx b/mod/module.hxx
index d8ffc5c..b3ed67b 100644
--- a/mod/module.hxx
+++ b/mod/module.hxx
@@ -1,18 +1,17 @@
// file : mod/module.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_MODULE_HXX
#define MOD_MODULE_HXX
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
#include <mod/utility.hxx>
-#include <mod/options.hxx>
#include <mod/diagnostics.hxx>
+#include <mod/module-options.hxx>
namespace brep
{
diff --git a/mod/options-types.hxx b/mod/options-types.hxx
index 8707f7f..4aa573f 100644
--- a/mod/options-types.hxx
+++ b/mod/options-types.hxx
@@ -1,5 +1,4 @@
// file : mod/options-types.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_OPTIONS_TYPES_HXX
diff --git a/mod/page.cxx b/mod/page.cxx
index e34e568..1e317f0 100644
--- a/mod/page.cxx
+++ b/mod/page.cxx
@@ -1,5 +1,4 @@
// file : mod/page.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/page.hxx>
@@ -15,11 +14,10 @@
#include <libstudxml/serializer.hxx>
-#include <libbutl/url.mxx>
+#include <web/xhtml/fragment.hxx>
+#include <web/xhtml/serialization.hxx>
-#include <web/xhtml.hxx>
-#include <web/xhtml-fragment.hxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/mime-url-encoding.hxx>
#include <libbrep/package.hxx>
#include <libbrep/package-odb.hxx>
@@ -576,7 +574,7 @@ namespace brep
if (icasecmp (url_.scheme, "https") == 0 ||
icasecmp (url_.scheme, "http") == 0)
{
- butl::url u (url_);
+ url u (url_);
u.scheme.clear ();
s << A(HREF=url_) << u << ~A;
diff --git a/mod/page.hxx b/mod/page.hxx
index cba8358..cc9840e 100644
--- a/mod/page.hxx
+++ b/mod/page.hxx
@@ -1,5 +1,4 @@
// file : mod/page.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_PAGE_HXX
@@ -9,7 +8,7 @@
#include <libbbot/manifest.hxx>
-#include <web/xhtml-fragment.hxx>
+#include <web/xhtml/fragment.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
@@ -379,13 +378,14 @@ namespace brep
class TR_URL
{
public:
- TR_URL (const url& u, const char* l = "url"): url_ (u), label_ (l) {}
+ TR_URL (const manifest_url& u, const char* l = "url")
+ : url_ (u), label_ (l) {}
void
operator() (xml::serializer&) const;
private:
- const url& url_;
+ const manifest_url& url_;
const char* label_;
};
diff --git a/mod/services.cxx b/mod/services.cxx
index a50e157..b17e32e 100644
--- a/mod/services.cxx
+++ b/mod/services.cxx
@@ -1,10 +1,9 @@
// file : mod/services.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <ap_config.h> // AP_MODULE_DECLARE_DATA
-#include <web/apache/service.hxx>
+#include <web/server/apache/service.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
diff --git a/mod/types-parsers.cxx b/mod/types-parsers.cxx
index dad1c02..dc21e97 100644
--- a/mod/types-parsers.cxx
+++ b/mod/types-parsers.cxx
@@ -1,10 +1,11 @@
// file : mod/types-parsers.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/types-parsers.hxx>
-#include <mod/options.hxx>
+#include <libbutl/timestamp.mxx> // from_string()
+
+#include <mod/module-options.hxx>
using namespace std;
using namespace bpkg;
@@ -51,6 +52,40 @@ namespace brep
parse_path (x, s);
}
+ // Parse time of day.
+ //
+ void parser<duration>::
+ parse (duration& x, bool& xs, scanner& s)
+ {
+ xs = true;
+
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const char* v (s.next ());
+
+ // To avoid the manual time of day parsing and validation, let's parse
+ // it as the first Epoch day time and convert the result (timestamp) to
+ // the time elapsed since Epoch (duration).
+ //
+ try
+ {
+ string t ("1970-01-01 ");
+ t += v;
+
+ x = butl::from_string (t.c_str (),
+ "%Y-%m-%d %H:%M",
+ false /* local */).time_since_epoch ();
+ return;
+ }
+ catch (const invalid_argument&) {}
+ catch (const system_error&) {}
+
+ throw invalid_value (o, v);
+ }
+
// Parse repository_location.
//
void parser<repository_location>::
diff --git a/mod/types-parsers.hxx b/mod/types-parsers.hxx
index 1d8dbe4..6b851eb 100644
--- a/mod/types-parsers.hxx
+++ b/mod/types-parsers.hxx
@@ -1,5 +1,4 @@
// file : mod/types-parsers.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
// CLI parsers, included into the generated source files.
@@ -10,7 +9,7 @@
#include <libbpkg/manifest.hxx> // repository_location
-#include <web/xhtml-fragment.hxx>
+#include <web/xhtml/fragment.hxx>
#include <libbrep/types.hxx>
#include <libbrep/utility.hxx>
@@ -40,6 +39,15 @@ namespace brep
parse (dir_path&, bool&, scanner&);
};
+ // Parse time of day specified in the `hh:mm` form.
+ //
+ template <>
+ struct parser<duration>
+ {
+ static void
+ parse (duration&, bool&, scanner&);
+ };
+
template <>
struct parser<bpkg::repository_location>
{
diff --git a/mod/utility.hxx b/mod/utility.hxx
index beda8c9..43527ae 100644
--- a/mod/utility.hxx
+++ b/mod/utility.hxx
@@ -1,5 +1,4 @@
// file : mod/utility.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#ifndef MOD_UTILITY_HXX
diff --git a/monitor/.gitignore b/monitor/.gitignore
new file mode 100644
index 0000000..21c0e0b
--- /dev/null
+++ b/monitor/.gitignore
@@ -0,0 +1,2 @@
+*-options.?xx
+brep-monitor
diff --git a/monitor/buildfile b/monitor/buildfile
new file mode 100644
index 0000000..dc49a98
--- /dev/null
+++ b/monitor/buildfile
@@ -0,0 +1,45 @@
+# file : monitor/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import libs = libodb%lib{odb}
+import libs += libodb-pgsql%lib{odb-pgsql}
+import libs += libbutl%lib{butl}
+import libs += libbbot%lib{bbot}
+
+include ../libbrep/
+include ../mod/
+
+exe{brep-monitor}: {hxx ixx cxx}{* -*-options} \
+ {hxx ixx cxx}{monitor-options module-options} \
+ ../mod/libue{mod} ../libbrep/lib{brep} $libs
+
+# Build options.
+#
+obj{monitor}: cxx.poptions += -DBREP_COPYRIGHT=\"$copyright\"
+
+# Generated options parser.
+#
+if $cli.configured
+{
+ cli.cxx{monitor-options}: cli{monitor}
+ cli.cxx{module-options}: cli{module}
+
+ cli.options += --std c++11 -I $src_root --include-with-brackets \
+--include-prefix monitor --guard-prefix MONITOR --generate-specifier \
+--cli-namespace brep::cli
+
+ cli.cxx{monitor-options}: cli.options += \
+--page-usage print_ --ansi-color --long-usage
+
+ cli.cxx{module-options}: cli.options += --suppress-usage --generate-parse
+
+ # Include the generated cli files into the distribution and don't remove
+ # them when cleaning in src (so that clean results in a state identical to
+ # distributed).
+ #
+ cli.cxx{*}:
+ {
+ dist = true
+ clean = ($src_root != $out_root)
+ }
+}
diff --git a/monitor/module.cli b/monitor/module.cli
new file mode 100644
index 0000000..c299c5f
--- /dev/null
+++ b/monitor/module.cli
@@ -0,0 +1,16 @@
+// file : monitor/module.cli
+// license : MIT; see accompanying LICENSE file
+
+include <mod/module.cli>;
+
+namespace brep
+{
+ namespace options
+ {
+ // brep web module configuration options we are interested in.
+ //
+ class module: build_task
+ {
+ };
+ }
+}
diff --git a/monitor/monitor.cli b/monitor/monitor.cli
new file mode 100644
index 0000000..edfc004
--- /dev/null
+++ b/monitor/monitor.cli
@@ -0,0 +1,190 @@
+// file : monitor/monitor.cli
+// license : MIT; see accompanying LICENSE file
+
+include <vector>;
+include <string>;
+include <cstddef>; // size_t
+include <cstdint>; // uint16_t
+
+include <mod/module.cli>; // Reuse CLI support types.
+
+"\section=1"
+"\name=brep-monitor"
+"\summary=monitor brep infrastructure"
+
+namespace brep
+{
+ namespace options
+ {
+ {
+ "<options> <brep-config> <toolchain> <name> <version>",
+
+ "\h|SYNOPSIS|
+
+ \c{\b{brep-monitor --help}\n
+ \b{brep-monitor --version}\n
+ \b{brep-monitor} [<options>] <brep-config> <toolchain> [<toolchain>...]}
+
+ \c{<toolchain> = <name>[\b{/}<version>]}
+
+ \h|DESCRIPTION|
+
+ \cb{brep-monitor} analyzes the \cb{brep} internal state and reports the
+ infrastructure issues printing their descriptions to \cb{stderr}.
+
+ The specified \cb{brep} module configuration file (<brep-config>) is
+ used to retrieve information required to access the databases and
+ deduce the expected behavior. Most of this information can be
+ overridden via the command line options.
+
+ Currently, only delayed package builds for the specified toolchains are
+ reported. If toolchain version is omitted then all package builds with
+ this toolchain name are considered.
+
+ \cb{brep-monitor} maintains its own state in the brep \cb{build}
+ database. In particular, it records timestamps of the reported package
+ build delays and optionally omits them from being reported again during
+ the timeout specified with the \cb{--report-timeout} option. If the
+ timeout is unspecified, then the report timestamps are not updated. To
+ report all delays and still update the timestamps specify the zero
+ report timeout.
+
+ By default, a brief report is printed. Use the \cb{--full-report}
+ option to obtain the full report (which may be large).
+
+ Note that \cb{brep-monitor} expects the \cb{build} database schema to
+ have already been created using \l{brep-migrate(1)}."
+ }
+
+ class monitor
+ {
+ "\h|OPTIONS|"
+
+ std::size_t --build-timeout
+ {
+ "<seconds>",
+ "Time to wait (in seconds) before considering a package build as
+ delayed. If unspecified, it is the sum of the package rebuild timeout
+ (normal rebuild timeout if the alternative timeout is unspecified and
+ the maximum of two otherwise) and the build result timeout (see the
+ \cb{build-normal-rebuild-timeout}, \cb{build-alt-rebuild-*}, and
+ \cb{build-result-timeout} \c{brep} module configuration options
+ for details).
+
+ Note that a package that was not built before it was archived is
+ always considered as delayed. However, to distinguish this case from
+ a situation where a package was archived before a configuration have
+ been added, \cb{brep-monitor} needs to observe the package as
+ buildable for this configuration before it is archived. As result, if
+ you run \cb{brep-monitor} periodically (for example, as a cron job),
+ then make sure its running period is less than the tenant archive
+ timeout."
+ }
+
+ std::size_t --report-timeout
+ {
+ "<seconds>",
+ "Time to wait (in seconds) before repeating a report of a package
+ build delay. By default there is no timeout and all reports are
+ repeated."
+ }
+
+ bool --full-report
+ {
+ "Print the list of delayed package builds rather than just their number
+ per build configuration."
+ }
+
+ bool --clean
+ {
+ "Additionally clean the monitor state removing outdated information
+ related to non-existent packages, configurations, etc."
+ }
+
+ // Note that the web service would normally logs in under a different
+ // user (and potentially switch the role afterwords) and so falling back
+ // to brep's user name and password wouldn't make much sense.
+ //
+ std::string --build-db-user|-u
+ {
+ "<user>",
+ "\cb{build} database user name. If unspecified, then operating system
+ (login) name is used."
+ }
+
+ std::string --build-db-password
+ {
+ "<pass>",
+ "\cb{build} database password. If unspecified, then login without
+ password is expected to work."
+ }
+
+ std::string --build-db-name|-n = "brep_package"
+ {
+ "<name>",
+ "\cb{build} database name. If unspecified, then \cb{brep}'s
+ \cb{build-db-name} configuration option value is used."
+ }
+
+ std::string --build-db-host|-h
+ {
+ "<host>",
+ "\cb{build} database host name, address, or socket. If unspecified,
+ then \cb{brep}'s \cb{build-db-host} configuration option value is
+ used."
+ }
+
+ std::uint16_t --build-db-port|-p
+ {
+ "<port>",
+ "\cb{build} database port number. If unspecified, then \cb{brep}'s
+ \cb{build-db-port} configuration option value is used."
+ }
+
+ std::string --pager // String to allow empty value.
+ {
+ "<path>",
+ "The pager program to be used to show long text. Commonly used pager
+ programs are \cb{less} and \cb{more}. You can also specify additional
+ options that should be passed to the pager program with
+ \cb{--pager-option}. If an empty string is specified as the pager
+ program, then no pager will be used. If the pager program is not
+ explicitly specified, then \cb{brep-monitor} will try to use
+ \cb{less}. If it is not available, then no pager will be used."
+ }
+
+ std::vector<std::string> --pager-option
+ {
+ "<opt>",
+ "Additional option to be passed to the pager program. See \cb{--pager}
+ for more information on the pager program. Repeat this option to
+ specify multiple pager options."
+ }
+
+ bool --help {"Print usage information and exit."}
+ bool --version {"Print version and exit."}
+ };
+
+ "\h|EXIT STATUS|
+
+ \dl|
+
+ \li|\cb{0}
+
+ Success.|
+
+ \li|\cb{1}
+
+ Fatal error.|
+
+ \li|\cb{2}
+
+ An instance of \cb{brep-monitor} or some other \cb{brep} utility is
+ already running. Try again.|
+
+ \li|\cb{3}
+
+ Recoverable database error. Try again.||
+ "
+ }
+}
diff --git a/monitor/monitor.cxx b/monitor/monitor.cxx
new file mode 100644
index 0000000..bbab0a5
--- /dev/null
+++ b/monitor/monitor.cxx
@@ -0,0 +1,883 @@
+// file : monitor/monitor.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <map>
+#include <set>
+#include <chrono>
+#include <iostream>
+#include <algorithm> // find_if()
+
+#include <odb/database.hxx>
+#include <odb/transaction.hxx>
+#include <odb/schema-catalog.hxx>
+
+#include <odb/pgsql/database.hxx>
+
+#include <libbutl/pager.mxx>
+#include <libbutl/utility.mxx> // compare_c_string
+
+#include <libbbot/build-config.hxx>
+
+#include <libbrep/build.hxx>
+#include <libbrep/common.hxx>
+#include <libbrep/build-odb.hxx>
+#include <libbrep/build-package.hxx>
+#include <libbrep/build-package-odb.hxx>
+#include <libbrep/database-lock.hxx>
+
+#include <mod/build-config.hxx>
+
+#include <monitor/module-options.hxx>
+#include <monitor/monitor-options.hxx>
+
+using namespace std;
+using namespace butl;
+using namespace bbot;
+using namespace odb::core;
+
+namespace brep
+{
+ // Operation failed, diagnostics has already been issued.
+ //
+ struct failed {};
+
+ static const char* help_info (
+ " info: run 'brep-monitor --help' for more information");
+
+ static int
+ main (int argc, char* argv[])
+ try
+ {
+ cli::argv_scanner scan (argc, argv);
+ options::monitor ops (scan);
+
+ // Version.
+ //
+ if (ops.version ())
+ {
+ cout << "brep-monitor " << BREP_VERSION_ID << endl
+ << "libbrep " << LIBBREP_VERSION_ID << endl
+ << "libbbot " << LIBBBOT_VERSION_ID << endl
+ << "libbpkg " << LIBBPKG_VERSION_ID << endl
+ << "libbutl " << LIBBUTL_VERSION_ID << endl
+ << "Copyright (c) " << BREP_COPYRIGHT << "." << endl
+ << "This is free software released under the MIT license." << endl;
+
+ return 0;
+ }
+
+ // Help.
+ //
+ if (ops.help ())
+ {
+ pager p ("brep-monitor help",
+ false,
+ ops.pager_specified () ? &ops.pager () : nullptr,
+ &ops.pager_option ());
+
+ print_usage (p.stream ());
+
+ // If the pager failed, assume it has issued some diagnostics.
+ //
+ return p.wait () ? 0 : 1;
+ }
+
+ // Parse the brep module configuration.
+ //
+ options::module mod_ops;
+ {
+ if (!scan.more ())
+ {
+ cerr << "error: brep module configuration file is expected" << endl
+ << help_info << endl;
+ return 1;
+ }
+
+ string f (scan.next ());
+
+ try
+ {
+ cli::argv_file_scanner scan (f, "" /* option */);
+
+ // Parse the brep module options skipping those we don't recognize.
+ //
+ while (scan.more ())
+ {
+ // Parse until an unknown option is encountered.
+ //
+ mod_ops.parse (scan,
+ cli::unknown_mode::stop,
+ cli::unknown_mode::stop);
+
+ // Skip the unknown option, unless we are done.
+ //
+ if (scan.more ())
+ {
+ // Skip the option name.
+ //
+ size_t l (scan.peek_line ());
+ scan.skip ();
+
+ // Skip the option value, if present.
+ //
+ // Note that here we rely on the configuration file having both
+ // the option name and its value on the same line.
+ //
+ if (scan.more () && scan.peek_line () == l)
+ scan.skip ();
+ }
+ }
+ }
+ catch (const cli::file_io_failure& e)
+ {
+ cerr << "error: unable to parse brep module configuration: " << e
+ << endl;
+ return 1;
+ }
+ catch (const cli::exception& e)
+ {
+ cerr << "error: unable to parse brep module configuration file '" << f
+ << "': " << e << endl;
+ return 1;
+ }
+
+ if (mod_ops.build_alt_rebuild_start_specified () !=
+ mod_ops.build_alt_rebuild_stop_specified ())
+ {
+ cerr << "build-alt-rebuild-start and build-alt-rebuild-stop "
+ << "configuration options must both be either specified or not "
+ << "in '" << f << "'" << endl;
+ return 1;
+ }
+ }
+
+ // Parse the toolchains suppressing duplicates.
+ //
+ // Note that specifying a toolchain both with and without version doesn't
+ // make sense, so we fail if that's the case.
+ //
+ vector<pair<string, version>> toolchains;
+
+ if (!scan.more ())
+ {
+ cerr << "error: toolchain is expected" << endl << help_info << endl;
+ return 1;
+ }
+
+ while (scan.more ())
+ {
+ string s (scan.next ());
+
+ string tn;
+ version tv;
+
+ try
+ {
+ size_t p (s.find ('/'));
+
+ if (p == string::npos)
+ tn = move (s);
+ else
+ {
+ tn.assign (s, 0, p);
+ tv = version (string (s, p + 1));
+ }
+
+ bool dup (false);
+ for (const pair<string, version>& t: toolchains)
+ {
+ if (tn == t.first)
+ {
+ if (tv == t.second)
+ {
+ dup = true;
+ break;
+ }
+
+ if (tv.empty () != t.second.empty ())
+ {
+ cerr << "error: toolchain '" << tn << "' is specified both "
+ << "with and without version" << endl;
+ return 1;
+ }
+ }
+ }
+
+ if (!dup)
+ toolchains.emplace_back (move (tn), move (tv));
+ }
+ catch (const invalid_argument& e)
+ {
+ cerr << "error: invalid toolchain '" << s << "': " << e << endl;
+ return 1;
+ }
+ }
+
+ // Parse buildtab.
+ //
+ if (!mod_ops.build_config_specified ())
+ {
+ cerr << "warning: package building functionality is disabled" << endl;
+ return 0;
+ }
+
+ build_configs configs;
+
+ try
+ {
+ configs = parse_buildtab (mod_ops.build_config ());
+ }
+ catch (const tab_parsing& e)
+ {
+ cerr << "error: unable to parse buildtab: " << e << endl;
+ return 1;
+ }
+ catch (const io_error& e)
+ {
+ cerr << "error: unable to read '" << mod_ops.build_config () << "': "
+ << e << endl;
+ return 1;
+ }
+
+ // Create the database instance.
+ //
+ odb::pgsql::database db (
+ ops.build_db_user (),
+ ops.build_db_password (),
+ (ops.build_db_name_specified ()
+ ? ops.build_db_name ()
+ : mod_ops.build_db_name ()),
+ (ops.build_db_host_specified ()
+ ? ops.build_db_host ()
+ : mod_ops.build_db_host ()),
+ (ops.build_db_port_specified ()
+ ? ops.build_db_port ()
+ : mod_ops.build_db_port ()),
+ "options='-c default_transaction_isolation=serializable'");
+
+ // Prevent several brep utility instances from updating the build database
+ // simultaneously.
+ //
+ database_lock l (db);
+
+ // Check that the database schema matches the current one.
+ //
+ const string ds ("build");
+ if (schema_catalog::current_version (db, ds) != db.schema_version (ds))
+ {
+ cerr << "error: build database schema differs from the current one"
+ << endl
+ << " info: use brep-migrate to migrate the database" << endl;
+ return 1;
+ }
+
+ // If requested, cleanup delays for package builds that are not expected
+ // anymore (build configuration is not present, etc).
+ //
+ if (ops.clean ())
+ {
+ using config_map = map<const char*,
+ const build_config*,
+ compare_c_string>;
+
+ config_map conf_map;
+ for (const build_config& c: configs)
+ conf_map[c.name.c_str ()] = &c;
+
+ // Prepare the build delay prepared query.
+ //
+ // Query package build delays in chunks in order not to hold locks for
+ // too long. Sort the result by package version as a first priority to
+ // minimize number of queries to the package database. Note that we
+ // still need to sort by configuration and toolchain to make sure that
+ // build delays are sorted consistently across queries and we don't miss
+ // any of them.
+ //
+ using query = query<build_delay>;
+ using prep_query = prepared_query<build_delay>;
+
+ // Specify the portion.
+ //
+ size_t offset (0);
+
+ query q ("ORDER BY" +
+ query::id.package.tenant + "," +
+ query::id.package.name +
+ order_by_version (query::id.package.version,
+ false /* first */) + "," +
+ query::id.configuration + "," +
+ query::id.toolchain_name +
+ order_by_version (query::id.toolchain_version,
+ false /* first */) +
+ "OFFSET" + query::_ref (offset) + "LIMIT 100");
+
+ connection_ptr conn (db.connection ());
+
+ prep_query pq (
+ conn->prepare_query<build_delay> ("build-delay-query", q));
+
+ // Cache the delayed build package object to reuse it in case the next
+ // delay refers to the same package (which is often the case due to the
+ // query result sorting criteria we use).
+ //
+ package_id pid;
+ shared_ptr<build_package> p;
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ // Query delays.
+ //
+ auto delays (pq.execute ());
+
+ if ((ne = !delays.empty ()))
+ {
+ // Iterate over the build delays and cleanup the outdated ones.
+ //
+ for (const build_delay& d: delays)
+ {
+ config_map::const_iterator ci;
+
+ bool cleanup (
+ // Check that the toolchain is still used.
+ //
+ find_if (toolchains.begin (), toolchains.end (),
+ [&d] (const pair<string, version>& t)
+ {
+ return t.first == d.toolchain_name &&
+ t.second == d.toolchain_version;
+ }) == toolchains.end () ||
+ //
+ // Check that the build configuration is still present.
+ //
+ (ci = conf_map.find (d.configuration.c_str ())) ==
+ conf_map.end ());
+
+ // Check that the package still present, is buildable and doesn't
+ // exclude the build configuration.
+ //
+ if (!cleanup)
+ {
+ if (d.id.package != pid)
+ {
+ pid = d.id.package;
+ p = db.find<build_package> (pid);
+ }
+
+ cleanup = (p == nullptr ||
+ !p->buildable ||
+ exclude (p->builds,
+ p->constraints,
+ *ci->second,
+ configs.class_inheritance_map));
+ }
+
+ if (cleanup)
+ db.erase (d);
+ else
+ ++offset;
+ }
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Collect and report delays as separate steps not to hold database locks
+ // while printing to stderr. Also we need to properly order delays for
+ // printing.
+ //
+ // Iterate through all possible package builds creating the list of delays
+ // with the following sort priority:
+ //
+ // 1: toolchain name
+ // 2: toolchain version (descending)
+ // 3: configuration name
+ // 4: tenant
+ // 5: package name
+ // 6: package version (descending)
+ //
+ // Such ordering will allow us to group build delays by toolchain and
+ // configuration while printing the report.
+ //
+ struct compare_delay
+ {
+ bool
+ operator() (const shared_ptr<const build_delay>& x,
+ const shared_ptr<const build_delay>& y) const
+ {
+ if (int r = x->toolchain_name.compare (y->toolchain_name))
+ return r < 0;
+
+ if (int r = x->toolchain_version.compare (y->toolchain_version))
+ return r > 0;
+
+ if (int r = x->configuration.compare (y->configuration))
+ return r < 0;
+
+ if (int r = x->tenant.compare (y->tenant))
+ return r < 0;
+
+ if (int r = x->package_name.compare (y->package_name))
+ return r < 0;
+
+ return x->package_version.compare (y->package_version) > 0;
+ }
+ };
+
+ size_t reported_delay_count (0);
+ size_t total_delay_count (0);
+
+ set<shared_ptr<const build_delay>, compare_delay> delays;
+ {
+ connection_ptr conn (db.connection ());
+
+ // Prepare the buildable package prepared query.
+ //
+ // Query buildable packages in chunks in order not to hold locks for
+ // too long.
+ //
+ using pquery = query<buildable_package>;
+ using prep_pquery = prepared_query<buildable_package>;
+
+ // Specify the portion.
+ //
+ size_t offset (0);
+
+ pquery pq ("ORDER BY" +
+ pquery::build_package::id.tenant + "," +
+ pquery::build_package::id.name +
+ order_by_version (pquery::build_package::id.version,
+ false /* first */) +
+ "OFFSET" + pquery::_ref (offset) + "LIMIT 50");
+
+ prep_pquery ppq (
+ conn->prepare_query<buildable_package> ("buildable-package-query",
+ pq));
+
+ // Prepare the package build prepared query.
+ //
+ // This query will only be used for toolchains that have no version
+ // specified on the command line to obtain the latest completed build
+ // across all toolchain versions, if present, and the latest incomplete
+ // build otherwise.
+ //
+ using bquery = query<package_build>;
+ using prep_bquery = prepared_query<package_build>;
+
+ build_id id;
+ const auto& bid (bquery::build::id);
+
+ bquery bq ((equal<package_build> (bid.package, id.package) &&
+ bid.configuration == bquery::_ref (id.configuration) &&
+ bid.toolchain_name == bquery::_ref (id.toolchain_name)) +
+ "ORDER BY" +
+ bquery::build::completion_timestamp + "DESC, " +
+ bquery::build::timestamp + "DESC" +
+ "LIMIT 1");
+
+ prep_bquery pbq (
+ conn->prepare_query<package_build> ("package-build-query", bq));
+
+ duration build_timeout;
+
+ // If the build timeout is not specified explicitly, then calculate it
+ // as the sum of the package rebuild timeout (normal rebuild timeout if
+ // the alternative timeout is unspecified and the maximum of two
+ // otherwise) and the build result timeout.
+ //
+ if (!ops.build_timeout_specified ())
+ {
+ duration normal_rebuild_timeout (
+ chrono::seconds (mod_ops.build_normal_rebuild_timeout ()));
+
+ if (mod_ops.build_alt_rebuild_start_specified ())
+ {
+ // Calculate the alternative rebuild timeout as the time interval
+ // lenght, unless it is specified explicitly.
+ //
+ if (!mod_ops.build_alt_rebuild_timeout_specified ())
+ {
+ const duration& start (mod_ops.build_alt_rebuild_start ());
+ const duration& stop (mod_ops.build_alt_rebuild_stop ());
+
+ // Note that if the stop time is less than the start time then the
+ // interval extends through the midnight.
+ //
+ build_timeout = start <= stop
+ ? stop - start
+ : (24h - start) + stop;
+ }
+ else
+ build_timeout =
+ chrono::seconds (mod_ops.build_alt_rebuild_timeout ());
+
+ // Take the maximum of the alternative and normal rebuild timeouts.
+ //
+ if (build_timeout < normal_rebuild_timeout)
+ build_timeout = normal_rebuild_timeout;
+ }
+ else
+ build_timeout = normal_rebuild_timeout;
+
+ // Summarize the rebuild and build result timeouts.
+ //
+ build_timeout += chrono::seconds (mod_ops.build_result_timeout ());
+ }
+ else
+ build_timeout = chrono::seconds (ops.build_timeout ());
+
+ timestamp now (system_clock::now ());
+ timestamp build_expiration (now - build_timeout);
+
+ timestamp report_expiration (
+ now - chrono::seconds (ops.report_timeout ()));
+
+ for (bool ne (true); ne; )
+ {
+ transaction t (conn->begin ());
+
+ // Query buildable packages (and cache the result).
+ //
+ auto bps (ppq.execute ());
+
+ if ((ne = !bps.empty ()))
+ {
+ offset += bps.size ();
+
+ for (auto& bp: bps)
+ {
+ shared_ptr<build_package> p (db.load<build_package> (bp.id));
+
+ for (const build_config& c: configs)
+ {
+ if (exclude (p->builds,
+ p->constraints,
+ c,
+ configs.class_inheritance_map))
+ continue;
+
+ for (const pair<string, version>& t: toolchains)
+ {
+ id = build_id (p->id, c.name, t.first, t.second);
+
+ // If the toolchain version is unspecified then search for the
+ // latest build across all toolchain versions and search for a
+ // specific build otherwise.
+ //
+ shared_ptr<build> b;
+
+ if (id.toolchain_version.empty ())
+ {
+ auto pbs (pbq.execute ());
+
+ if (!pbs.empty ())
+ b = move (pbs.begin ()->build);
+ }
+ else
+ b = db.find<build> (id);
+
+ // Note that we consider a build as delayed if it is not
+ // completed in the expected timeframe. So even if the build
+ // task have been issued recently we may still consider the
+ // build as delayed.
+ //
+ timestamp bct (b != nullptr
+ ? b->completion_timestamp
+ : timestamp_nonexistent);
+
+ // Create the delay object to record a timestamp when the
+ // package build could have potentially been started, unless
+ // it already exists.
+ //
+ shared_ptr<build_delay> d (db.find<build_delay> (id));
+
+ if (d == nullptr)
+ {
+ // If the archived package has no build nor build delay
+ // for this configuration, then we assume that the
+ // configuration was added after the package tenant has
+ // been archived and so the package could have never been
+ // built for this configuration. Thus, we don't consider
+ // this build as delayed and so skip it.
+ //
+ if (bp.archived && b == nullptr)
+ continue;
+
+ // Use the build completion or build status change
+ // timestamp, whichever is earlier, as the build delay
+ // tracking starting point and fallback to the current time
+ // if there is no build yet.
+ //
+ timestamp pts (
+ b == nullptr ? now :
+ bct != timestamp_nonexistent && bct < b->timestamp ? bct :
+ b->timestamp);
+
+ d = make_shared<build_delay> (move (id.package.tenant),
+ move (id.package.name),
+ p->version,
+ move (id.configuration),
+ move (id.toolchain_name),
+ t.second,
+ pts);
+ db.persist (d);
+ }
+
+ // Handle package builds differently based on their tenant's
+ // archive status.
+ //
+ // If the package is not archived then consider it as delayed
+ // if it is not (re-)built by the expiration time. Otherwise,
+ // consider it as delayed if it is unbuilt.
+ //
+ bool delayed;
+
+ if (!bp.archived)
+ {
+ timestamp bts (bct != timestamp_nonexistent
+ ? bct
+ : d->package_timestamp);
+
+ delayed = (bts <= build_expiration);
+ }
+ else
+ delayed = (bct == timestamp_nonexistent);
+
+ if (delayed)
+ {
+ // If the report timeout is zero then report the delay
+ // unconditionally. Otherwise, report the active package
+ // build delay if the report timeout is expired and the
+ // archived package build delay if it was never reported.
+ // Note that fixing the building infrastructure won't help
+ // building an archived package, so reporting its build
+ // delays repeatedly is meaningless.
+ //
+ if (ops.report_timeout () == 0 ||
+ (!bp.archived
+ ? d->report_timestamp <= report_expiration
+ : d->report_timestamp == timestamp_nonexistent))
+ {
+ // Note that we update the delay objects persistent state
+ // later, after we successfully print the report.
+ //
+ d->report_timestamp = now;
+ delays.insert (move (d));
+
+ ++reported_delay_count;
+ }
+ //
+ // In the brief mode also collect unreported delays to
+ // deduce and print the total number of delays per
+ // configuration. Mark such delays with the
+ // timestamp_nonexistent report timestamp.
+ //
+ else if (!ops.full_report ())
+ {
+ d->report_timestamp = timestamp_nonexistent;
+ delays.insert (move (d));
+ }
+
+ ++total_delay_count;
+ }
+ }
+ }
+ }
+ }
+
+ t.commit ();
+ }
+ }
+
+ // Report package build delays, if any.
+ //
+ if (reported_delay_count != 0)
+ try
+ {
+ // Print the report.
+ //
+ cerr.exceptions (ostream::badbit | ostream::failbit);
+
+ // Don't print the total delay count if the report timeout is zero since
+ // all delays are reported in this case.
+ //
+ bool print_total_delay_count (ops.report_timeout () != 0);
+
+ cerr << "Package build delays (" << reported_delay_count;
+
+ if (print_total_delay_count)
+ cerr << '/' << total_delay_count;
+
+ cerr << "):" << endl;
+
+ // Group the printed delays by toolchain and configuration.
+ //
+ const string* toolchain_name (nullptr);
+ const version* toolchain_version (nullptr);
+ const string* configuration (nullptr);
+
+ // In the brief report mode print the number of reported/total delayed
+ // package builds per configuration rather than the packages themselves.
+ //
+ size_t config_reported_delay_count (0);
+ size_t config_total_delay_count (0);
+
+ auto brief_config = [&configuration,
+ &config_reported_delay_count,
+ &config_total_delay_count,
+ print_total_delay_count] ()
+ {
+ if (configuration != nullptr)
+ {
+ // Only print configurations with delays that needs to be reported.
+ //
+ if (config_reported_delay_count != 0)
+ {
+ cerr << " " << *configuration << " ("
+ << config_reported_delay_count;
+
+ if (print_total_delay_count)
+ cerr << '/' << config_total_delay_count;
+
+ cerr << ')' << endl;
+ }
+
+ config_reported_delay_count = 0;
+ config_total_delay_count = 0;
+ }
+ };
+
+ for (shared_ptr<const build_delay> d: delays)
+ {
+ // Print the toolchain, if changed.
+ //
+ if (toolchain_name == nullptr ||
+ d->toolchain_name != *toolchain_name ||
+ d->toolchain_version != *toolchain_version)
+ {
+ if (!ops.full_report ())
+ brief_config ();
+
+ if (toolchain_name != nullptr)
+ cerr << endl;
+
+ cerr << " " << d->toolchain_name;
+
+ if (!d->toolchain_version.empty ())
+ cerr << "/" << d->toolchain_version;
+
+ cerr << endl;
+
+ toolchain_name = &d->toolchain_name;
+ toolchain_version = &d->toolchain_version;
+ configuration = nullptr;
+ }
+
+ // Print the configuration, if changed.
+ //
+ if (configuration == nullptr || d->configuration != *configuration)
+ {
+ if (ops.full_report ())
+ {
+ if (configuration != nullptr)
+ cerr << endl;
+
+ cerr << " " << d->configuration << endl;
+ }
+ else
+ brief_config ();
+
+ configuration = &d->configuration;
+ }
+
+ // Print the delayed build package in the full report mode and count
+ // configuration builds otherwise.
+ //
+ if (ops.full_report ())
+ {
+ // We can potentially extend this information with the archived flag
+ // or the delay duration.
+ //
+ cerr << " " << d->package_name << "/" << d->package_version;
+
+ if (!d->tenant.empty ())
+ cerr << " " << d->tenant;
+
+ cerr << endl;
+ }
+ else
+ {
+ if (d->report_timestamp != timestamp_nonexistent)
+ ++config_reported_delay_count;
+
+ ++config_total_delay_count;
+ }
+ }
+
+ if (!ops.full_report ())
+ brief_config ();
+
+ // Persist the delay report timestamps.
+ //
+ // If we don't consider the report timestamps for reporting delays, it
+ // seems natural not to update these timestamps either. Note that
+ // reporting all delays and still updating the report timestamps can be
+ // achieved by specifying the zero report timeout.
+ //
+ if (ops.report_timeout_specified ())
+ {
+ transaction t (db.begin ());
+
+ for (shared_ptr<const build_delay> d: delays)
+ {
+ // Only update timestamps for delays that needs to be reported.
+ //
+ if (d->report_timestamp != timestamp_nonexistent)
+ db.update (d);
+ }
+
+ t.commit ();
+ }
+ }
+ catch (const io_error&)
+ {
+ return 1; // Not much we can do on stderr writing failure.
+ }
+
+ return 0;
+ }
+ catch (const database_locked&)
+ {
+ cerr << "brep-monitor or some other brep utility is running" << endl;
+ return 2;
+ }
+ catch (const recoverable& e)
+ {
+ cerr << "recoverable database error: " << e << endl;
+ return 3;
+ }
+ catch (const cli::exception& e)
+ {
+ cerr << "error: " << e << endl << help_info << endl;
+ return 1;
+ }
+ catch (const failed&)
+ {
+ return 1; // Diagnostics has already been issued.
+ }
+ // Fully qualified to avoid ambiguity with odb exception.
+ //
+ catch (const std::exception& e)
+ {
+ cerr << "error: " << e << endl;
+ return 1;
+ }
+}
+
+int
+main (int argc, char* argv[])
+{
+ return brep::main (argc, argv);
+}
diff --git a/tests/ci/buildfile b/tests/ci/buildfile
index 280e364..6f6e82d 100644
--- a/tests/ci/buildfile
+++ b/tests/ci/buildfile
@@ -1,5 +1,4 @@
# file : tests/ci/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
dir = ../../brep/handler/ci/
diff --git a/tests/ci/ci-dir.testscript b/tests/ci/ci-dir.testscript
index c850df0..be5a9b9 100644
--- a/tests/ci/ci-dir.testscript
+++ b/tests/ci/ci-dir.testscript
@@ -1,5 +1,4 @@
# file : tests/ci/ci-dir.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
.include data.testscript
diff --git a/tests/ci/ci-load.testscript b/tests/ci/ci-load.testscript
index bc0d521..57fa9d1 100644
--- a/tests/ci/ci-load.testscript
+++ b/tests/ci/ci-load.testscript
@@ -1,5 +1,4 @@
# file : tests/ci/ci-load.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
.include data.testscript
diff --git a/tests/ci/data.testscript b/tests/ci/data.testscript
index f584bc6..74a1527 100644
--- a/tests/ci/data.testscript
+++ b/tests/ci/data.testscript
@@ -1,5 +1,4 @@
# file : tests/ci/data.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Pre-created CI request data directory that will be copied by subsequent
diff --git a/tests/load/1/math/libfoo-benchmarks-1.2.4.tar.gz b/tests/load/1/math/libfoo-benchmarks-1.2.4.tar.gz
index 606893a..391eb6f 100644
--- a/tests/load/1/math/libfoo-benchmarks-1.2.4.tar.gz
+++ b/tests/load/1/math/libfoo-benchmarks-1.2.4.tar.gz
Binary files differ
diff --git a/tests/load/1/math/libfoo-examples-1.2.4.tar.gz b/tests/load/1/math/libfoo-examples-1.2.4.tar.gz
index c1d5fbd..eac5190 100644
--- a/tests/load/1/math/libfoo-examples-1.2.4.tar.gz
+++ b/tests/load/1/math/libfoo-examples-1.2.4.tar.gz
Binary files differ
diff --git a/tests/load/1/math/libfoo-tests-1.2.4.tar.gz b/tests/load/1/math/libfoo-tests-1.2.4.tar.gz
index 8e5105f..223e24d 100644
--- a/tests/load/1/math/libfoo-tests-1.2.4.tar.gz
+++ b/tests/load/1/math/libfoo-tests-1.2.4.tar.gz
Binary files differ
diff --git a/tests/load/1/math/packages.manifest b/tests/load/1/math/packages.manifest
index de3b1c5..ea37e2a 100644
--- a/tests/load/1/math/packages.manifest
+++ b/tests/load/1/math/packages.manifest
@@ -89,25 +89,25 @@ name: libfoo-benchmarks
version: 1.2.4
summary: The Foo Math Library benchmarks
license: MIT
-builds: none; Is only build to benchmark libfoo.
+builds: 64; Fails building for 32 bits.
location: libfoo-benchmarks-1.2.4.tar.gz
-sha256sum: 2ec3985a540ca5bf74786d0792820cfa8a2790964a5aeaba443dfa91f2a54c04
+sha256sum: ba664343db5b9bd574450175834b0dd39d038dcff7387477b6eff0d5783a8ac4
:
name: libfoo-examples
version: 1.2.4
summary: The Foo Math Library examples
license: MIT
-builds: none; Is only built to demo libfoo usage.
+builds: 64; Fails building for 32 bits.
location: libfoo-examples-1.2.4.tar.gz
-sha256sum: 99658b9a5a5b834047b692b93ded9f9af3d255eb5ea3b27594f600b902039995
+sha256sum: 1343d1826c3ae5446ad965bc9aa7b1586e4238c7736c344e63a4a6bae3d57a88
:
name: libfoo-tests
version: 1.2.4
summary: The Foo Math Library tests
license: MIT
-builds: none; Is only built to test libfoo.
+builds: 64; Fails building for 32 bits.
location: libfoo-tests-1.2.4.tar.gz
-sha256sum: 16712c90df5ba2ffb920d29c9c25a29564f8ae01f167359c4651572789e6cd6c
+sha256sum: c5c0520b4e612fa2f8948c42824f3e199926c2395bf2c2f898e83f9eb19261a4
:
name: libpq
version: 0
diff --git a/tests/load/buildfile b/tests/load/buildfile
index 61ec037..315b59e 100644
--- a/tests/load/buildfile
+++ b/tests/load/buildfile
@@ -1,5 +1,4 @@
# file : tests/load/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
import libs += libbpkg%lib{bpkg}
diff --git a/tests/load/driver.cxx b/tests/load/driver.cxx
index d685c18..b4c43cc 100644
--- a/tests/load/driver.cxx
+++ b/tests/load/driver.cxx
@@ -1,5 +1,4 @@
// file : tests/load/driver.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <iostream>
@@ -205,7 +204,7 @@ main (int argc, char* argv[])
static inline dependency
dep (const char* n, optional<version_constraint> c)
{
- return dependency {package_name (n), move (c), nullptr};
+ return dependency {package_name (n), move (c), nullptr /* package */};
}
static inline version
diff --git a/tests/submit/buildfile b/tests/submit/buildfile
index aaffede..1845d23 100644
--- a/tests/submit/buildfile
+++ b/tests/submit/buildfile
@@ -1,5 +1,4 @@
# file : tests/submit/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
dir = ../../brep/handler/submit/
diff --git a/tests/submit/data.testscript b/tests/submit/data.testscript
index 70507d5..875b4eb 100644
--- a/tests/submit/data.testscript
+++ b/tests/submit/data.testscript
@@ -1,5 +1,4 @@
# file : tests/submit/data.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
# Pre-created submission data directory that will be copied by subsequent
diff --git a/tests/submit/submit-dir.testscript b/tests/submit/submit-dir.testscript
index 4a0c619..81dc494 100644
--- a/tests/submit/submit-dir.testscript
+++ b/tests/submit/submit-dir.testscript
@@ -1,5 +1,4 @@
# file : tests/submit/submit-dir.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
.include data.testscript
diff --git a/tests/submit/submit-git.testscript b/tests/submit/submit-git.testscript
index 122c9ae..c0a31fe 100644
--- a/tests/submit/submit-git.testscript
+++ b/tests/submit/submit-git.testscript
@@ -1,5 +1,4 @@
# file : tests/submit/submit-git.testscript
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
.include data.testscript
diff --git a/tests/web/xhtml/buildfile b/tests/web/xhtml/buildfile
index 983909f..ff683b9 100644
--- a/tests/web/xhtml/buildfile
+++ b/tests/web/xhtml/buildfile
@@ -1,8 +1,7 @@
# file : tests/web/xhtml/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-include ../../../web/
+include ../../../web/xhtml/
-exe{driver}: {hxx cxx}{*} ../../../web/libus{web}
+exe{driver}: {hxx cxx}{*} ../../../web/xhtml/libue{xhtml}
exe{driver}: file{test.out}: test.stdout = true
diff --git a/tests/web/xhtml/driver.cxx b/tests/web/xhtml/driver.cxx
index 9b35ae8..a0135de 100644
--- a/tests/web/xhtml/driver.cxx
+++ b/tests/web/xhtml/driver.cxx
@@ -1,5 +1,4 @@
// file : tests/web/xhtml/driver.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <iostream>
@@ -7,7 +6,7 @@
#include <libstudxml/serializer.hxx>
-#include <web/xhtml.hxx>
+#include <web/xhtml/serialization.hxx>
using namespace std;
using namespace xml;
diff --git a/web/apache/log.hxx b/web/server/apache/log.hxx
index 147a6af..f7738ef 100644
--- a/web/apache/log.hxx
+++ b/web/server/apache/log.hxx
@@ -1,9 +1,8 @@
-// file : web/apache/log.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/log.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_APACHE_LOG_HXX
-#define WEB_APACHE_LOG_HXX
+#ifndef WEB_SERVER_APACHE_LOG_HXX
+#define WEB_SERVER_APACHE_LOG_HXX
#include <httpd.h> // request_rec, server_rec
#include <http_log.h>
@@ -12,7 +11,7 @@
#include <cstdint> // uint64_t
#include <algorithm> // min()
-#include <web/module.hxx>
+#include <web/server/module.hxx>
namespace web
{
@@ -78,4 +77,4 @@ namespace web
}
}
-#endif // WEB_APACHE_LOG_HXX
+#endif // WEB_SERVER_APACHE_LOG_HXX
diff --git a/web/apache/request.cxx b/web/server/apache/request.cxx
index bed7042..a413081 100644
--- a/web/apache/request.cxx
+++ b/web/server/apache/request.cxx
@@ -1,8 +1,7 @@
-// file : web/apache/request.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/request.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <web/apache/request.hxx>
+#include <web/server/apache/request.hxx>
#include <apr.h> // APR_SIZE_MAX
#include <apr_errno.h> // apr_status_t, APR_SUCCESS, APR_E*, apr_strerror()
@@ -39,7 +38,7 @@
#include <libbutl/optional.mxx>
#include <libbutl/timestamp.mxx>
-#include <web/mime-url-encoding.hxx>
+#include <web/server/mime-url-encoding.hxx>
using namespace std;
using namespace butl;
diff --git a/web/apache/request.hxx b/web/server/apache/request.hxx
index 01c7290..bc105ec 100644
--- a/web/apache/request.hxx
+++ b/web/server/apache/request.hxx
@@ -1,9 +1,8 @@
-// file : web/apache/request.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/request.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_APACHE_REQUEST_HXX
-#define WEB_APACHE_REQUEST_HXX
+#ifndef WEB_SERVER_APACHE_REQUEST_HXX
+#define WEB_SERVER_APACHE_REQUEST_HXX
#include <httpd.h> // request_rec, HTTP_*, OK, M_POST
@@ -15,8 +14,8 @@
#include <ostream>
#include <streambuf>
-#include <web/module.hxx>
-#include <web/apache/stream.hxx>
+#include <web/server/module.hxx>
+#include <web/server/apache/stream.hxx>
namespace web
{
@@ -229,6 +228,6 @@ namespace web
}
}
-#include <web/apache/request.ixx>
+#include <web/server/apache/request.ixx>
-#endif // WEB_APACHE_REQUEST_HXX
+#endif // WEB_SERVER_APACHE_REQUEST_HXX
diff --git a/web/apache/request.ixx b/web/server/apache/request.ixx
index 157a751..119fd2e 100644
--- a/web/apache/request.ixx
+++ b/web/server/apache/request.ixx
@@ -1,5 +1,4 @@
-// file : web/apache/request.ixx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/request.ixx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#include <http_protocol.h> // ap_*()
diff --git a/web/apache/service.cxx b/web/server/apache/service.cxx
index 3306c61..9fb23da 100644
--- a/web/apache/service.cxx
+++ b/web/server/apache/service.cxx
@@ -1,8 +1,7 @@
-// file : web/apache/service.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/service.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <web/apache/service.hxx>
+#include <web/server/apache/service.hxx>
#include <apr_pools.h> // apr_palloc()
@@ -19,8 +18,8 @@
#include <libbutl/utility.mxx> // function_cast()
#include <libbutl/optional.mxx>
-#include <web/module.hxx>
-#include <web/apache/log.hxx>
+#include <web/server/module.hxx>
+#include <web/server/apache/log.hxx>
using namespace std;
using namespace butl;
diff --git a/web/apache/service.hxx b/web/server/apache/service.hxx
index 42ef52f..ad54d2c 100644
--- a/web/apache/service.hxx
+++ b/web/server/apache/service.hxx
@@ -1,9 +1,8 @@
-// file : web/apache/service.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/service.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_APACHE_SERVICE_HXX
-#define WEB_APACHE_SERVICE_HXX
+#ifndef WEB_SERVER_APACHE_SERVICE_HXX
+#define WEB_SERVER_APACHE_SERVICE_HXX
#include <apr_pools.h> // apr_pool_t
#include <apr_hooks.h> // APR_HOOK_*
@@ -16,9 +15,9 @@
#include <string>
#include <cassert>
-#include <web/module.hxx>
-#include <web/apache/log.hxx>
-#include <web/apache/request.hxx>
+#include <web/server/module.hxx>
+#include <web/server/apache/log.hxx>
+#include <web/server/apache/request.hxx>
namespace web
{
@@ -329,6 +328,6 @@ namespace web
}
}
-#include <web/apache/service.txx>
+#include <web/server/apache/service.txx>
-#endif // WEB_APACHE_SERVICE_HXX
+#endif // WEB_SERVER_APACHE_SERVICE_HXX
diff --git a/web/apache/service.txx b/web/server/apache/service.txx
index 99a8110..1b16d0b 100644
--- a/web/apache/service.txx
+++ b/web/server/apache/service.txx
@@ -1,5 +1,4 @@
-// file : web/apache/service.txx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/service.txx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#include <httpd.h> // APEXIT_CHILDSICK
diff --git a/web/apache/stream.hxx b/web/server/apache/stream.hxx
index e103449..77145af 100644
--- a/web/apache/stream.hxx
+++ b/web/server/apache/stream.hxx
@@ -1,9 +1,8 @@
-// file : web/apache/stream.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/apache/stream.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_APACHE_STREAM_HXX
-#define WEB_APACHE_STREAM_HXX
+#ifndef WEB_SERVER_APACHE_STREAM_HXX
+#define WEB_SERVER_APACHE_STREAM_HXX
#include <httpd.h> // request_rec, HTTP_*
#include <http_protocol.h> // ap_*()
@@ -14,7 +13,7 @@
#include <streambuf>
#include <algorithm> // min(), max()
-#include <web/module.hxx> // invalid_request
+#include <web/server/module.hxx> // invalid_request
namespace web
{
@@ -146,4 +145,4 @@ namespace web
}
}
-#endif // WEB_APACHE_STREAM_HXX
+#endif // WEB_SERVER_APACHE_STREAM_HXX
diff --git a/web/buildfile b/web/server/buildfile
index a535574..26de70f 100644
--- a/web/buildfile
+++ b/web/server/buildfile
@@ -1,5 +1,4 @@
-# file : web/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+# file : web/server/buildfile
# license : MIT; see accompanying LICENSE file
# This is currently part of the brep apache module but lives in a separate
@@ -9,11 +8,8 @@
#
import libs = libapr1%lib{apr-1}
import libs += libapreq2%lib{apreq2}
-import libs += libstudxml%lib{studxml}
import libs += libbutl%lib{butl}
-libus{web}: {hxx ixx txx cxx}{** -version} {hxx}{version} $libs
-
-hxx{version}: in{version} $src_root/manifest
+libus{web-server}: {hxx ixx txx cxx}{**} $libs
{hxx ixx txx}{*}: install = false
diff --git a/web/mime-url-encoding.cxx b/web/server/mime-url-encoding.cxx
index c43510e..fd1e4e8 100644
--- a/web/mime-url-encoding.cxx
+++ b/web/server/mime-url-encoding.cxx
@@ -1,8 +1,7 @@
-// file : web/mime-url-encoding.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/mime-url-encoding.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <web/mime-url-encoding.hxx>
+#include <web/server/mime-url-encoding.hxx>
#include <string>
#include <iterator> // back_inserter
diff --git a/web/mime-url-encoding.hxx b/web/server/mime-url-encoding.hxx
index 225215d..34172a4 100644
--- a/web/mime-url-encoding.hxx
+++ b/web/server/mime-url-encoding.hxx
@@ -1,9 +1,8 @@
-// file : web/mime-url-encoding.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/mime-url-encoding.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_MIME_URL_ENCODING_HXX
-#define WEB_MIME_URL_ENCODING_HXX
+#ifndef WEB_SERVER_MIME_URL_ENCODING_HXX
+#define WEB_SERVER_MIME_URL_ENCODING_HXX
#include <string>
@@ -30,4 +29,4 @@ namespace web
bool query = true);
}
-#endif // WEB_MIME_URL_ENCODING_HXX
+#endif // WEB_SERVER_MIME_URL_ENCODING_HXX
diff --git a/web/module.hxx b/web/server/module.hxx
index 73ffcaf..beda73c 100644
--- a/web/module.hxx
+++ b/web/server/module.hxx
@@ -1,9 +1,8 @@
-// file : web/module.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/server/module.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_MODULE_HXX
-#define WEB_MODULE_HXX
+#ifndef WEB_SERVER_MODULE_HXX
+#define WEB_SERVER_MODULE_HXX
#include <map>
#include <string>
@@ -297,4 +296,4 @@ namespace web
};
}
-#endif // WEB_MODULE_HXX
+#endif // WEB_SERVER_MODULE_HXX
diff --git a/web/version.hxx.in b/web/version.hxx.in
deleted file mode 100644
index 10851f4..0000000
--- a/web/version.hxx.in
+++ /dev/null
@@ -1,12 +0,0 @@
-// file : web/version.hxx.in -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef WEB_VERSION_HXX_IN
-#define WEB_VERSION_HXX_IN
-
-#include <libstudxml/version.hxx>
-
-$libstudxml.check(LIBSTUDXML_VERSION, LIBSTUDXML_SNAPSHOT)$
-
-#endif // WEB_VERSION_HXX_IN
diff --git a/web/.gitignore b/web/xhtml/.gitignore
index 426db9e..426db9e 100644
--- a/web/.gitignore
+++ b/web/xhtml/.gitignore
diff --git a/web/xhtml/buildfile b/web/xhtml/buildfile
new file mode 100644
index 0000000..06dd34c
--- /dev/null
+++ b/web/xhtml/buildfile
@@ -0,0 +1,10 @@
+# file : web/xhtml/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import libs = libstudxml%lib{studxml}
+
+./: {libue libus}{xhtml}: {hxx ixx txx cxx}{** -version} {hxx}{version} $libs
+
+hxx{version}: in{version} $src_root/manifest
+
+{hxx ixx txx}{*}: install = false
diff --git a/web/xhtml-fragment.cxx b/web/xhtml/fragment.cxx
index fe8a0a7..843db82 100644
--- a/web/xhtml-fragment.cxx
+++ b/web/xhtml/fragment.cxx
@@ -1,8 +1,7 @@
-// file : web/xhtml-fragment.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/xhtml/fragment.cxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#include <web/xhtml-fragment.hxx>
+#include <web/xhtml/fragment.hxx>
#include <string>
#include <cassert>
@@ -10,7 +9,7 @@
#include <libstudxml/parser.hxx>
#include <libstudxml/serializer.hxx>
-#include <web/xhtml.hxx>
+#include <web/xhtml/serialization.hxx>
using namespace std;
using namespace xml;
diff --git a/web/xhtml-fragment.hxx b/web/xhtml/fragment.hxx
index fd41967..eab4335 100644
--- a/web/xhtml-fragment.hxx
+++ b/web/xhtml/fragment.hxx
@@ -1,5 +1,4 @@
-// file : web/xhtml-fragment.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/xhtml/fragment.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#ifndef WEB_XHTML_FRAGMENT_HXX
diff --git a/web/xhtml.hxx b/web/xhtml/serialization.hxx
index 6d35e49..03e72ff 100644
--- a/web/xhtml.hxx
+++ b/web/xhtml/serialization.hxx
@@ -1,13 +1,12 @@
-// file : web/xhtml.hxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
+// file : web/xhtml/serialization.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef WEB_XHTML_HXX
-#define WEB_XHTML_HXX
+#ifndef WEB_XHTML_SERIALIZATION_HXX
+#define WEB_XHTML_SERIALIZATION_HXX
#include <libstudxml/serializer.hxx>
-#include <web/version.hxx>
+#include <web/xhtml/version.hxx>
namespace web
{
@@ -356,4 +355,4 @@ namespace web
}
}
-#endif // WEB_XHTML_HXX
+#endif // WEB_XHTML_SERIALIZATION_HXX
diff --git a/web/xhtml/version.hxx.in b/web/xhtml/version.hxx.in
new file mode 100644
index 0000000..fe3e4e5
--- /dev/null
+++ b/web/xhtml/version.hxx.in
@@ -0,0 +1,11 @@
+// file : web/xhtml/version.hxx.in -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef WEB_XHTML_VERSION_HXX_IN
+#define WEB_XHTML_VERSION_HXX_IN
+
+#include <libstudxml/version.hxx>
+
+$libstudxml.check(LIBSTUDXML_VERSION, LIBSTUDXML_SNAPSHOT)$
+
+#endif // WEB_XHTML_VERSION_HXX_IN
diff --git a/www/buildfile b/www/buildfile
index 6c2f15f..2a66c93 100644
--- a/www/buildfile
+++ b/www/buildfile
@@ -1,5 +1,4 @@
# file : www/buildfile
-# copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
css{*} xhtml{*}: install = data/www/