159 Commits

Author SHA1 Message Date
J. King 70b063e028 Make parts of generic packaging conditional 3 weeks ago
J. King cf3d270077 Merge branch 'deb' 3 weeks ago
J. King 1fa75aba4a Generate Debian source package without deb tooling 3 weeks ago
J. King 317d23c1bb Fix copy-paste error in manual 3 weeks ago
J. King 75dbe380ba Add Pandoc to AUR arsse-git build dependencies 3 weeks ago
J. King 08250841a0 Don't sign packages 3 weeks ago
J. King 2452264893 Date release 3 weeks ago
J. King c1e57eb01f Add manual installation instructions 3 weeks ago
J. King e75e0dfd2f Clarify exactly what "older Debians" is 3 weeks ago
J. King 6c11c9e485 Fix Debian bugs 4 weeks ago
J. King 40a2856ae8 Use correct PHP_FPM socket paths for Debian 4 weeks ago
J. King c7dcc36ba1 Update version 4 weeks ago
J. King a31fb896d9 Update changelog 4 weeks ago
J. King def4a3bc77 Move Debian adaptations to Debian packaging rules 4 weeks ago
J. King cd89472575 Fix up Debian documentation 4 weeks ago
J. King beea98040c Initial documentation for Debian packages 4 weeks ago
J. King 59ff88f3b6 Add all-in-one packaging task 4 weeks ago
J. King 4070870421 Enforce external tooling requirements 4 weeks ago
J. King 5ab9dc3840 Add missing pbuilder script 4 weeks ago
J. King 20ffb2484a Simply Robo input for Arch and Deb packaging 4 weeks ago
J. King f91b3c0120 Output packages to a "release" directory 4 weeks ago
J. King 4121fc3e21 Database server ports must be integers 4 weeks ago
J. King 7ad3611a84 Set up configuration file for Debian properly 4 weeks ago
J. King 5412eb348f Clean up maintainer scripts 4 weeks ago
J. King c936ecc1af Fix another typo 4 weeks ago
J. King 99c923b1b1 Fix typos 4 weeks ago
J. King c2237532eb Add glue for dbconfig-common configuration 4 weeks ago
J. King 9687ce026e Add MySQL back to Debian depeendencies 4 weeks ago
J. King 30bed8a9d5 Typo 4 weeks ago
J. King cf9059c2b0 Update tooling 4 weeks ago
J. King 93bcf93685 Prototype Debian maintainer scripts 4 weeks ago
J. King 46e20be983 Test for service reloading 4 weeks ago
J. King ad32bf3340 Style fixes 1 month ago
J. King b8ac646d22 Fix up hangup signal handling 1 month ago
J. King 37c58e186a Handle hangup signal 1 month ago
J. King 88fe3e76cb Fix up missing-extension message 1 month ago
J. King 3c8ee42666 Basic tests for exception checking 1 month ago
J. King 04adc3b997 Document forking in the manpage 1 month ago
J. King c49cb72528 Fail gracefully when extensions are missing 1 month ago
J. King c9a2393a4e Note requirement for filter extension 1 month ago
J. King 75e87f31a0 Prototype code to check for missing extensions 1 month ago
J. King 3b51d4daea Fix license for Debian package 1 month ago
J. King ce9dfc3f30 Add init script to Debian files 1 month ago
J. King cbc7cd8ea7 Add an explicit path to init script 1 month ago
J. King 2e29f3f76e Correct typo 1 month ago
J. King 8a1a1eee42 Prototype init script 1 month ago
J. King e160189224 Handle exceptions from child processes 1 month ago
J. King e9394e8599 More forking tweaks 1 month ago
J. King 577356cd3d Fork error test 1 month ago
J. King 514cb0a351 Ow 1 month ago
J. King 0bb5e916d2 Test PID writing 1 month ago
J. King 2767ab755e Use D modifier in pattern 1 month ago
J. King a4036afbf8 Partial tests for PID file reading 1 month ago
J. King 32c9d761c3 Clean up more exceptions 1 month ago
J. King 5b3e8fbef0 Refine some exceptions 1 month ago
J. King b9fd9ac32e Tweaks 2 months ago
J. King 23749b51aa Tests for path resolution 2 months ago
J. King dfaf44ac68 Basic path resolution tests 2 months ago
J. King bab64add9b Separate PID conflict checking from PID claiming 2 months ago
J. King 822158d1bd Update dependencies 2 months ago
J. King f1c29c99c7 Finish testing PID file path checking 2 months ago
J. King 59cf27089a More daemon cleanup 2 months ago
J. King 4e1193bab2 Move forking daemon support code to own class 2 months ago
J. King 32e04e3938 Move forking and related to Service class 2 months ago
J. King 55acb87577 Start on PI(D file resolution tests 2 months ago
J. King e8cab78bd6 Handle last possible PID failures 2 months ago
J. King 9595c4f019 Start filling out PID file exceptions 2 months ago
J. King 372bf9f630 Exclude code from coverage 2 months ago
J. King 4ffc29781d Remove references to oldpass param 2 months ago
J. King 47af739e47 Catch more PID path failures 2 months ago
J. King 2c7b16ed27 Respond to termination signals and delete PID file 2 months ago
J. King 410310282f Load configuration after forking 2 months ago
J. King 29b83b4453 Prototype forking daemon 2 months ago
J. King fc2abc1203 Use D modifier for all patterns with $ anchors 1 month ago
J. King 59c5c2eb14 Oops 2 months ago
J. King 3cd3ac4a51 Correct filename conflict 2 months ago
J. King 837895fd6a Adapt dist files for Debian 2 months ago
J. King b4c9413130 Update README 2 months ago
J. King bafb788b02 Correct errors in manual 2 months ago
J. King 68e3cd82ca Don't include section number in title 2 months ago
J. King c3fa4788d6 Use proper metadata block for manpage 2 months ago
J. King 3567f294a6 Merge branch 'manpage' 2 months ago
J. King 8c0f047747 Update HTML manual to mention man page 2 months ago
J. King fd76b1b611 Add examples to manual page 2 months ago
J. King 4317a96db1 Work around double spacing 2 months ago
J. King 62d49e0d3c Fill out most of the manual page 2 months ago
J. King 88487d27a2 Expand manual page 2 months ago
J. King 46c88f584f Fix copying of man page in PKGBUILDs 2 months ago
J. King 92823d5bc2 Create directories before executing Pandoc 2 months ago
J. King 3e55ab3849 Move man pages to their own directory 2 months ago
J. King 2ec7acc50b Turn off "smart" character substitution in Pandoc 2 months ago
J. King d3a983e7f0 Move the markdown manpage 2 months ago
J. King 176aac0ad7 Fix stupid typo properly 2 months ago
J. King e439dd8277 Fix manpage in Arch PKGBUILD 2 months ago
J. King 6cc9f96728 Prototype manual page 2 months ago
J. King d4569c77a9 Add database location to tmpfiles 2 months ago
J. King add1acc87a Fix more lintian complaints 2 months ago
J. King 14d3cdfe58 Hopefully fix some Debian problems 2 months ago
J. King 281760be71 Address some lintian complaints 2 months ago
J. King 758a02d667 Move generic configuration file 2 months ago
J. King 18846c19cb Add install list for Debian package 2 months ago
J. King b5bbdc2bc6 Date release 2 months ago
J. King 3be6c9984d Update Apache documentation in manual 2 months ago
J. King 6c84b2199e More Apache fixes 2 months ago
J. King f9cbac2c31 Hopefully fix Apache configuration 2 months ago
J. King 32ca0c3fe4 Appease GitHub once and for all 2 months ago
J. King a81bd0e45c Add whitespace 2 months ago
J. King 86d82a2586 Use global flag when replacing with sed 2 months ago
J. King f0bf55f9cf Add ExecStart to parent systemd unit 2 months ago
J. King 1055611940 Add version constraints to Arch dependencies 2 months ago
J. King 2ccfb1fd33 Fix packaging process 2 months ago
J. King 9eabfd0f27 Fix up sed usage in PKGBUILD 2 months ago
J. King 0236b42052 Use tmpfiles to create link to config file 2 months ago
J. King 8aa9d81fd1 Update changelog 2 months ago
J. King 11fc83da60 Significant edits to the manual 2 months ago
J. King de55290746 Fix build dependencies for Deb package 2 months ago
J. King f844c17a94 More Debian fixes 2 months ago
J. King 0de9647809 Add compat file 2 months ago
J. King e653fb3f73 Enhancements to Debian files 3 months ago
J. King b7909d7cd3 Downgrade tool dependencies for Ubuntu 3 months ago
J. King 3c9f4dd66f Prototype Debian rules file 3 months ago
J. King 3537e74d49 Update dependencies 3 months ago
J. King d031d931a5 Tidy up the Robo file further 3 months ago
J. King 38cb1059b2 Shorten output of packaging task 3 months ago
J. King 16174f11b6 Add changelog parsing to packaging task 3 months ago
J. King 073f6b3c39 Prototype Debian control file and other changes 3 months ago
J. King 3f3f449da1 Re-organize manual 3 months ago
J. King 2260b7cc50 Back up all Web server configuration 3 months ago
J. King 61eb4a252e Fix doc URLs 3 months ago
J. King 3f401f1cfa Fix typo 3 months ago
J. King 6c750d2dc0 Documentation for installing on Arch 3 months ago
J. King 6d790c5efd Add prototype for new Apache configuration 3 months ago
J. King 3a3b9231df Use generic configuration where possible 3 months ago
J. King fbe03a2534 Use chmod instead of touch 3 months ago
J. King e75f8cebfb Add Arch packaging to Robo file 3 months ago
J. King 79391446cd Start moving Arch build responsibility to Robo 3 months ago
J. King 19ab9df063 Fix more bugs 3 months ago
J. King 568b12600b Drop privileges when executing CLI 3 months ago
J. King 488af80a85 Update changelog 3 months ago
J. King 44612cfe8f Add tmpfiles 3 months ago
J. King d1fd6e9653 Correct permissions 3 months ago
J. King a97ca23631 Don't try to enable extensions 3 months ago
J. King e2b182ebe6 Fix errors in Arch config file 3 months ago
J. King 3eab5aad5d Fix adding users to a blank database 3 months ago
J. King 805a508ea6 Use correct state path 3 months ago
J. King 3ebc23ab13 Tweaks 3 months ago
J. King 7abdf05b7f Make package from local files for now 3 months ago
J. King 971c12ff9f Rename sample to example 3 months ago
J. King febc7c7ca4 Add configuration for Nginx 3 months ago
J. King edb146b826 Use PHP-FPM instead of uWSGI 3 months ago
J. King 7ba4cabdde Prototype Arch PKGBUILD and supporting files 3 months ago
J. King 114dcc568f Update dependencies 4 months ago
Dustin Wilson 1331b14a04 Reverting for now 4 months ago
Dustin Wilson 035feae0ce Removed postcss in favor of sass for building manual theme 4 months ago
J. King 8e063bea2f Appease GitHub again 4 months ago
J. King 4a9e66d872 Fix inconsistent grammar 5 months ago
J. King fa4ab3218a Version bump 5 months ago
J. King c4260323bc Answer 201 to PUTs like Miniflux 5 months ago
J. King abc291460c Update Web server configuration in manual 5 months ago
  1. 20
      .gitignore
  2. 37
      CHANGELOG
  3. 27
      README.md
  4. 586
      RoboFile.php
  5. 3
      arsse.php
  6. 4
      composer.json
  7. 85
      composer.lock
  8. 23
      dist/apache.conf
  9. 34
      dist/apache/arsse-loc.conf
  10. 11
      dist/apache/arsse.conf
  11. 9
      dist/apache/example.conf
  12. 57
      dist/arch/PKGBUILD
  13. 74
      dist/arch/PKGBUILD-git
  14. 10
      dist/arsse
  15. 15
      dist/arsse.service
  16. 8
      dist/config.php
  17. 16
      dist/debian/arsse.config
  18. 1
      dist/debian/arsse.dirs
  19. 18
      dist/debian/arsse.install
  20. 1
      dist/debian/arsse.links
  21. 29
      dist/debian/arsse.postinst
  22. 20
      dist/debian/arsse.postrm
  23. 16
      dist/debian/arsse.prerm
  24. 1
      dist/debian/compat
  25. 15
      dist/debian/config.php
  26. 32
      dist/debian/control
  27. 34
      dist/debian/copyright
  28. 44
      dist/debian/dbconfig-common.php
  29. 6
      dist/debian/lintian-overrides
  30. 40
      dist/debian/pbuilder.sh
  31. 26
      dist/debian/rules
  32. 1
      dist/debian/source/format
  33. 2
      dist/debian/source/lintian-overrides
  34. 78
      dist/init.sh
  35. 75
      dist/nginx.conf
  36. 12
      dist/nginx/arsse-fcgi.conf
  37. 49
      dist/nginx/arsse-loc.conf
  38. 17
      dist/nginx/arsse.conf
  39. 13
      dist/nginx/example.conf
  40. 11
      dist/php-fpm.conf
  41. 36
      dist/systemd/arsse-fetch.service
  42. 14
      dist/systemd/arsse.service
  43. 1
      dist/sysuser.conf
  44. 4
      dist/tmpfiles.conf
  45. 16
      docs/en/020_Getting_Started/010_Requirements.md
  46. 41
      docs/en/020_Getting_Started/020_Download_and_Installation.md
  47. 54
      docs/en/020_Getting_Started/020_Download_and_Installation/010_On_Arch_Linux.md
  48. 72
      docs/en/020_Getting_Started/020_Download_and_Installation/020_On_Debian_and_Derivatives.md
  49. 53
      docs/en/020_Getting_Started/020_Download_and_Installation/999_ On_Other_Systems.md
  50. 16
      docs/en/020_Getting_Started/020_Download_and_Installation/index.md
  51. 107
      docs/en/020_Getting_Started/030_Web_Server_Configuration.md
  52. 14
      docs/en/020_Getting_Started/040_Database_Setup/000_SQLite.md
  53. 2
      docs/en/020_Getting_Started/040_Database_Setup/010_PostgreSQL.md
  54. 2
      docs/en/020_Getting_Started/040_Database_Setup/020_MySQL.md
  55. 16
      docs/en/020_Getting_Started/050_Configuration.md
  56. 3
      docs/en/020_Getting_Started/index.md
  57. 22
      docs/en/025_Using_The_Arsse/010_Managing_Users.md
  58. 8
      docs/en/025_Using_The_Arsse/020_Importing_and_Exporting.md
  59. 49
      docs/en/025_Using_The_Arsse/030_Keeping_Newsfeeds_Up_to_Date.md
  60. 34
      docs/en/025_Using_The_Arsse/030_Other_Topics.md
  61. 12
      docs/en/025_Using_The_Arsse/040_Upgrading_to_a_New_Version.md
  62. 15
      docs/en/025_Using_The_Arsse/index.md
  63. 1
      docs/en/030_Supported_Protocols/005_Miniflux.md
  64. 13
      lib/AbstractException.php
  65. 32
      lib/Arsse.php
  66. 251
      lib/CLI.php
  67. 2
      lib/Conf.php
  68. 2
      lib/Database.php
  69. 2
      lib/Db/MySQL/Driver.php
  70. 6
      lib/Db/SQLite3/Driver.php
  71. 2
      lib/Misc/HTTP.php
  72. 2
      lib/Misc/URL.php
  73. 4
      lib/Misc/ValueInfo.php
  74. 16
      lib/REST.php
  75. 2
      lib/REST/Miniflux/Token.php
  76. 8
      lib/REST/Miniflux/V1.php
  77. 2
      lib/REST/NextcloudNews/Versions.php
  78. 2
      lib/REST/TinyTinyRSS/API.php
  79. 2
      lib/REST/TinyTinyRSS/Icon.php
  80. 51
      lib/Service.php
  81. 226
      lib/Service/Daemon.php
  82. 10
      lib/Service/Exception.php
  83. 21
      locale/en.php
  84. 226
      manpages/en.md
  85. 26
      package.json
  86. 2
      tests/bootstrap.php
  87. 36
      tests/cases/CLI/TestCLI.php
  88. 8
      tests/cases/Conf/TestConf.php
  89. 4
      tests/cases/Database/SeriesSubscription.php
  90. 7
      tests/cases/Database/SeriesUser.php
  91. 2
      tests/cases/Db/MySQL/TestStatement.php
  92. 2
      tests/cases/Db/MySQLPDO/TestStatement.php
  93. 2
      tests/cases/Db/PostgreSQL/TestStatement.php
  94. 2
      tests/cases/Db/PostgreSQLPDO/TestStatement.php
  95. 13
      tests/cases/Db/SQLite3/TestCreation.php
  96. 1
      tests/cases/ImportExport/TestOPML.php
  97. 1
      tests/cases/Misc/TestValueInfo.php
  98. 1
      tests/cases/REST/Fever/TestAPI.php
  99. 2
      tests/cases/REST/Fever/TestUser.php
  100. 22
      tests/cases/REST/Miniflux/TestV1.php

20
.gitignore

@ -1,17 +1,26 @@
# Temporary files and dependencies
# Temporary files
/vendor/
/vendor-bin/*/vendor
/node_modules
/release/
/documentation/
/manual/
/tests/coverage/
/dist/arch/arsse/
/dist/arch/src/
/dist/arch/pkg/
/dist/man/
/arsse.db*
/config.php
/.php_cs.cache
/yarn-error.log
/tests/.phpunit.result.cache
# Dependencies
/vendor/
/vendor-bin/*/vendor
/node_modules
/yarn.lock
/yarn-error.log
# Windows files
@ -36,6 +45,7 @@ $RECYCLE.BIN/
*.zip
*.7z
*.tar.gz
*.tar.xz
*.tgz
*.deb
*.rpm

37
CHANGELOG

@ -1,3 +1,35 @@
Version 0.10.0 (2021-07-11)
===========================
New features:
- Complete Unix manual page
- Support for running service as a forking daemon
- Respond to TERM and HUP signals when possible
Changes:
- Packages for Debian and related are now available (see manual for details)
Version 0.9.2 (2021-05-25)
==========================
Bug fixes:
- Do not fail adding users to an empty database (regression since 0.9.0)
- Cleanly ignore unknown configuration properties
- Set access mode to rw-r---- when creating SQLite databases
Changes:
- Packages for Arch Linux are now available (see manual for details)
- Numerous improvements to the manual
Version 0.9.1 (2021-03-18)
==========================
Bug fixes:
- Respond to PUT requests with 201 rather than 200 in Miniflux
Changes:
- Correct Web server configuration in manual
Version 0.9.0 (2021-03-06)
==========================
@ -109,7 +141,7 @@ Bug fixes:
Version 0.6.1 (2019-01-23)
==========================
Bug Fixes:
Bug fixes:
- Unify SQL timeout settings
- Correctly escape shell command in subprocess service driver
- Correctly allow null time intervals in configuration when appropriate
@ -229,4 +261,5 @@ Bug fixes:
Version 0.1.0 (2017-08-29)
==========================
Initial release
New features:
- Initial release

27
README.md

@ -8,7 +8,7 @@ Information on how to install and use the software can be found in [the manual](
The main repository for The Arsse can be found at [code.mensbeam.com](https://code.mensbeam.com/MensBeam/arsse/), with a mirror also available [at GitHub](https://github.com/mensbeam/arsse/). The GitHub mirror does not accept bug reports, but the two should otherwise be equivalent.
[Composer](https://getcomposer.org/) is required to manage PHP dependencies. After cloning the repository or downloading a source code tarball, running `composer install` will download all the required dependencies, and will advise if any PHP extensions need to be installed. If not installing as a programming environment, running `composer install --no-dev` is recommended.
[Composer](https://getcomposer.org/) is required to manage PHP dependencies. After cloning the repository or downloading a source code tarball, running `composer install` will download all the required dependencies, and will advise if any PHP extensions need to be installed. If not installing as a programming environment, running `composer install -o --no-dev --no-scripts` is recommended.
# Repository structure
@ -34,13 +34,15 @@ Also necessary to the functioning of the application is the `/vendor/` directory
The `/locale/` and `/sql/` directories contain human-language files and database schemata, both of which are occasionally used by the application in the course of execution. The `/www/` directory serves as a document root for a few static files to be made available to users by a Web server.
The `/dist/` directory, on the other hand, contains samples of configuration for Web servers and init systems. These are not used by The Arsse itself, but are merely distributed with it for reference.
The `/dist/` directory, on the other hand, contains general and system-specific build files, and samples of configuration for Web servers and other system integration. These are not used by The Arsse itself, but are used during the process of preparing new releases for supported operating systems.
## Documentation
The source text for The Arsse's manual can be found in `/docs/`, with pages written in [Markdown](https://spec.commonmark.org/current/) and converted to HTML [with Daux](#building-the-manual). If a static manual is generated its files will appear under `/manual/`.
In addition to the manual the files `/README.md` (this file), `/CHANGELOG`, `/UPGRADING`, `/LICENSE`, and `/AUTHORS` also document various things about the software, rather than the software itself.
The Arsse also has a UNIX manual page, also written in Markdown, which can be found under `/manpages/`. [Pandoc](https://pandoc.org/) is needed to convert it to the appropriate format, with the results stored under `/dist/man/`.
In addition to the manuals the files `/README.md` (this file), `/CHANGELOG`, `/UPGRADING`, `/LICENSE`, and `/AUTHORS` also document various things about the software, rather than the software itself.
## Tests
@ -50,7 +52,7 @@ The `/tests/` directory contains everything related to automated testing. It is
|--------------------|------------------------------------------------------------------------------------|
| `cases/` | The test cases themselves, organized in roughly the same structure as the code |
| `coverage/` | (optional) Generated code coverage reports |
| `docroot/` | Sample documents used in some tests, to be returned by the PHP's basic HTTP server |
| `docroot/` | Sample documents used in some tests, to be returned by PHP's basic HTTP server |
| `lib/` | Supporting classes which do not contain test cases |
| `bootstrap.php` | Bootstrap script, equivalent to `/arsse.php`, but for tests |
| `phpunit.dist.xml` | PHPUnit configuration file |
@ -74,7 +76,7 @@ The `/vendor-bin/` directory houses the files needed for the tools used in The A
| `/robo` | Simple wrapper for executing Robo on POSIX systems |
| `/robo.bat` | Simple wrapper for executing Robo on Windows |
In addition the files `/package.json`, `/yarn.lock`, and `/postcss.config.js` as well as the `/node_modules/` directory are used by [Yarn](https://yarnpkg.com/) and [PostCSS](https://postcss.org/) when modifying the stylesheet for The Arsse's manual.
In addition the files `/package.json` and `/postcss.config.js` as well as the `/node_modules/` directory are used by [Yarn](https://yarnpkg.com/) and [PostCSS](https://postcss.org/) when modifying the stylesheet for The Arsse's manual.
# Common tasks
@ -105,15 +107,20 @@ The Arsse's user manual, made using [Daux](https://daux.io/), can be compiled by
The manual employs a custom theme derived from the standard Daux theme. If the standard Daux theme receives improvements, the custom theme can be rebuilt by running `./robo manual:theme`. This requires that [NodeJS](https://nodejs.org) and [Yarn](https://yarnpkg.com/) be installed, but JavaScript tools are not required to modify The Arsse itself, nor the content of the manual.
## Building the man page
The Arsse's UNIX manual page is authored in Markdown, and must be converted to the native roff format using [Pandoc](https://pandoc.org/). This can be done by running `./robo manpage`, which will output appropriate files to `/dist/man/`. The conversion should not be done manually as there is post-processing required for optimal output.
## Packaging a release
Producing a release package is done by running `./robo package`. This performs the following operations:
Producing release packages is done by running `./robo package`. This performs the following operations:
- Duplicates a working tree with the commit (usually a release tag) to package
- Generates the manual
- Duplicates a [Git](https://git-scm.com/) working tree with the commit (usually a release tag) to package
- Generates UNIX manual pages with [Pandoc](https://pandoc.org/)
- Generates the HTML manual
- Installs runtime Composer dependencies with an optimized autoloader
- Deletes numerous unneeded files
- Exports the default configuration of The Arsse to a file
- Compresses the remaining files into a tarball
Due to the first step, [Git](https://git-scm.com/) is required to package a release.
- Produces a binary package for Arch Linux, if possible
- Produces source and binary packages for Debian using [pbuilder](https://pbuilder-team.pages.debian.net/pbuilder/), if possible

586
RoboFile.php

@ -1,11 +1,13 @@
<?php
use Robo\Collection\CollectionBuilder;
use Robo\Result;
const BASE = __DIR__.\DIRECTORY_SEPARATOR;
const BASE_TEST = BASE."tests".\DIRECTORY_SEPARATOR;
define("IS_WIN", defined("PHP_WINDOWS_VERSION_MAJOR"));
define("IS_MAC", php_uname("s") === "Darwin");
define("IS_LINUX", !IS_WIN && !IS_MAC);
error_reporting(0);
function norm(string $path): string {
@ -145,62 +147,295 @@ class RoboFile extends \Robo\Tasks {
return $this->taskExec($executor)->option("-d", "zend.assertions=1")->arg($execpath)->option("-c", $confpath)->args(array_merge($set, $args))->run();
}
protected function commitVersion(?string $commit): array {
$target = $commit ?? $this->askDefault("Reference commit:", "HEAD");
$base = escapeshellarg(BASE);
$blackhole = $this->blackhole();
// get useable version strings from Git
$version = trim(`git -C $base describe --tags $target $blackhole`);
if (!$version) {
throw new \Exception("Commit reference invalid");
}
return [$target, $version];
}
protected function toolExists(string ...$binary): bool {
$blackhole = $this->blackhole(IS_WIN);
foreach ($binary as $bin) {
if (
(IS_WIN && (!exec(escapeshellarg($bin)." --help $blackhole", $junk, $status) || $status))
|| (!IS_WIN && (!exec("which ".escapeshellarg($bin)." $blackhole", $junk, $status) || $status))
) {
return false;
}
}
return true;
}
/** Packages a given commit of the software into a release tarball
*
* The version to package may be any Git tree-ish identifier: a tag, a branch,
* The commit to package may be any Git tree-ish identifier: a tag, a branch,
* or any commit hash. If none is provided on the command line, Robo will prompt
* for a commit to package; the default is "head".
* for a commit to package; the default is "HEAD".
*
* Note that while it is possible to re-package old versions, the resultant tarball
* may not be equivalent due to subsequent changes in the exclude list, or because
* of new tooling.
*/
public function package(string $version = null): Result {
public function packageGeneric(string $commit = null): Result {
if (!$this->toolExists("git", "pandoc")) {
throw new \Exception("Git and Pandoc are required in PATH to produce generic release tarballs");
}
// establish which commit to package
$version = $version ?? $this->askDefault("Commit to package:", "HEAD");
$archive = BASE."arsse-$version.tar.gz";
[$commit, $version] = $this->commitVersion($commit);
$archVersion = preg_replace('/^([^-]+)-(\d+)-(\w+)$/', "$1.r$2.$3", $version);
// name the generic release tarball
$tarball = BASE."release/$version/arsse-$version.tar.gz";
// start a collection
$t = $this->collectionBuilder();
// create a temporary directory
$dir = $t->tmpDir().\DIRECTORY_SEPARATOR;
// create a Git worktree for the selected commit in the temp location
$t->taskExec("git worktree add ".escapeshellarg($dir)." ".escapeshellarg($version));
// perform Composer installation in the temp location with dev dependencies
$t->taskComposerInstall()->dir($dir);
// generate the manual
$t->taskExec(escapeshellarg($dir."robo")." manual")->dir($dir);
// perform Composer installation in the temp location for final output
$t->taskComposerInstall()->dir($dir)->noDev()->optimizeAutoloader()->arg("--no-scripts");
// delete unwanted files
$t->taskFilesystemStack()->remove([
$dir.".git",
$dir.".gitignore",
$dir.".gitattributes",
$dir."composer.json",
$dir."composer.lock",
$dir.".php_cs.dist",
$dir."phpdoc.dist.xml",
$dir."build.xml",
$dir."RoboFile.php",
$dir."CONTRIBUTING.md",
$dir."docs",
$dir."tests",
$dir."vendor-bin",
$dir."vendor/bin",
$dir."robo",
$dir."robo.bat",
$dir."package.json",
$dir."yarn.lock",
$dir."postcss.config.js",
]);
// generate a sample configuration file
$t->taskExec(escapeshellarg(\PHP_BINARY)." arsse.php conf save-defaults config.defaults.php")->dir($dir);
// package it all up
$t->taskPack($archive)->addDir("arsse", $dir);
// execute the collection
$result = $this->taskExec("git worktree add ".escapeshellarg($dir)." ".escapeshellarg($version))->dir(BASE)->run();
if ($result->getExitCode() > 0) {
return $result;
}
try {
if (file_exists($dir."dist/debian")) {
// generate the Debian changelog; this also validates our original changelog
$debianChangelog = $this->changelogDebian($this->changelogParse(file_get_contents($dir."CHANGELOG"), $version), $version);
// save the Debian-format changelog
$t->addTask($this->taskWriteToFile($dir."dist/debian/changelog")->text($debianChangelog));
}
if (file_exists($dir."dist/arch")) {
// patch the Arch PKGBUILD file with the correct version string
$t->addTask($this->taskReplaceInFile($dir."dist/arch/PKGBUILD")->regex('/^pkgver=.*$/m')->to("pkgver=$archVersion"));
// patch the Arch PKGBUILD file with the correct source file
$t->addTask($this->taskReplaceInFile($dir."dist/arch/PKGBUILD")->regex('/^source=\("arsse-[^"]+"\)$/m')->to('source=("'.basename($tarball).'")'));
}
// save commit description to VERSION file for reference
$t->addTask($this->taskWriteToFile($dir."VERSION")->text($version));
// perform Composer installation in the temp location with dev dependencies
$t->addTask($this->taskComposerInstall()->arg("-q")->dir($dir));
if (file_exists($dir."manpages")) {
// generate manpages
$t->addTask($this->taskExec("./robo manpage")->dir($dir));
}
if (file_exists($dir."docs")) {
// generate the HTML manual
$t->addTask($this->taskExec("./robo manual -q")->dir($dir));
}
// perform Composer installation in the temp location for final output
$t->addTask($this->taskComposerInstall()->dir($dir)->noDev()->optimizeAutoloader()->arg("--no-scripts")->arg("-q"));
// delete unwanted files
$t->addTask($this->taskFilesystemStack()->remove([
$dir.".git",
$dir.".gitignore",
$dir.".gitattributes",
$dir."dist/debian/.gitignore",
$dir."composer.json",
$dir."composer.lock",
$dir.".php_cs.dist",
$dir."phpdoc.dist.xml",
$dir."build.xml",
$dir."RoboFile.php",
$dir."CONTRIBUTING.md",
$dir."docs",
$dir."manpages",
$dir."tests",
$dir."vendor-bin",
$dir."vendor/bin",
$dir."robo",
$dir."robo.bat",
$dir."package.json",
$dir."yarn.lock",
$dir."postcss.config.js",
]));
$t->addCode(function() use ($dir) {
// Remove files which lintian complains about; they're otherwise harmless
$files = [];
foreach (new \CallbackFilterIterator(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir."vendor", \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)), function($v, $k, $i) {
return preg_match('/\/\.git(?:ignore|attributes|modules)$/D', $v);
}) as $f) {
$files[] = $f;
}
return $this->taskFilesystemStack()->remove($files)->run();
});
// generate a sample configuration file
$t->addTask($this->taskExec(escapeshellarg(\PHP_BINARY)." arsse.php conf save-defaults config.defaults.php")->dir($dir));
// remove any existing archive
$t->addTask($this->taskFilesystemStack()->remove($tarball));
// package it all up
$t->addTask($this->taskFilesystemStack()->mkdir(dirname($tarball)));
$t->addTask($this->taskPack($tarball)->addDir("arsse", $dir));
// execute the collection
$result = $t->run();
} finally {
// remove the Git worktree
$this->taskFilesystemStack()->remove($dir)->run();
$this->taskExec("git worktree prune")->dir(BASE)->run();
}
return $result;
}
/** Packages a given commit of the software into an Arch package
*
* The commit to package may be any Git tree-ish identifier: a tag, a branch,
* or any commit hash. If none is provided on the command line, Robo will prompt
* for a commit to package; the default is "HEAD".
*
* The Arch base-devel group should be installed for this.
*/
public function packageArch(string $commit = null): Result {
if (!$this->toolExists("git", "makepkg", "updpkgsums")) {
throw new \Exception("Git, makepkg, and updpkgsums are required in PATH to produce Arch packages");
}
// establish which commit to package
[$commit, $version] = $this->commitVersion($commit);
$tarball = BASE."release/$version/arsse-$version.tar.gz";
$dir = dirname($tarball).\DIRECTORY_SEPARATOR;
// start a collection
$t = $this->collectionBuilder();
// build the generic release tarball if it doesn't exist
if (!file_exists($tarball)) {
$t->addTask($this->taskExec(BASE."robo package:generic $commit"));
}
// extract the PKGBUILD from the tarball
$t->addCode(function() use ($tarball, $dir) {
// because Robo doesn't support extracting a single file we have to do it ourselves
(new \Archive_Tar($tarball))->extractList("arsse/dist/arch/PKGBUILD", $dir, "arsse/dist/arch/", false);
// perform a do-nothing filesystem operation since we need a Robo task result
return $this->taskFilesystemStack()->chmod($dir."PKGBUILD", 0644)->run();
})->completion($this->taskFilesystemStack()->remove($dir."PKGBUILD"));
// build the package
$t->addTask($this->taskExec("makepkg -Ccf")->dir($dir));
return $t->run();
}
/** Packages a given commit of the software a binary Debian package
*
* The commit to package may be any Git tree-ish identifier: a tag, a branch,
* or any commit hash. If none is provided on the command line, Robo will prompt
* for a commit to package; the default is "HEAD".
*
* The pbuilder tool should be installed for this.
*/
public function packageDeb(string $commit = null): Result {
if (!$this->toolExists("git", "sudo", "pbuilder")) {
throw new \Exception("Git, sudo, and pbuilder are required in PATH to produce Debian packages");
}
// establish which commit to package
[$commit, $version] = $this->commitVersion($commit);
$tarball = BASE."release/$version/arsse-$version.tar.gz";
// define some more variables
$tgz = BASE."release/pbuilder-arsse.tgz";
$bind = dirname($tarball);
$script = BASE."dist/debian/pbuilder.sh";
$user = trim(`id -un`);
$group = trim(`id -gn`);
// start a task collection
$t = $this->collectionBuilder();
// check that the pbuilder base exists and create it if it does not
if (!file_exists($tgz)) {
$t->addTask($this->taskFilesystemStack()->mkdir(BASE."release"));
$t->addTask($this->taskExec('sudo pbuilder create --basetgz '.escapeshellarg($tgz).' --mirror http://ftp.ca.debian.org/debian/ --extrapackages "debhelper devscripts lintian"'));
}
// build the generic release tarball if it doesn't exist
if (!file_exists($tarball)) {
$t->addTask($this->taskExec(BASE."robo package:generic $commit"));
}
// build the packages
$t->addTask($this->taskExec('sudo pbuilder execute --basetgz '.escapeshellarg($tgz).' --bindmounts '.escapeshellarg($bind).' -- '.escapeshellarg($script).' '.escapeshellarg("$bind/".basename($tarball))));
// take ownership of the output files
$t->addTask($this->taskExec("sudo chown -R $user:$group ".escapeshellarg($bind)));
return $t->run();
}
/** Packages a release tarball into a Debian source package
*
* The commit to package may be any Git tree-ish identifier: a tag, a branch,
* or any commit hash. If none is provided on the command line, Robo will prompt
* for a commit to package; the default is "HEAD".
*/
public function packageDebsrc(string $commit = null): Result {
// establish which commit to package
[$commit, $version] = $this->commitVersion($commit);
$tarball = BASE."release/$version/arsse-$version.tar.gz";
// determine the base version (i.e. x.y.z) and the Debian version (i.e. x.y.z-a)
preg_match('/^(\d+(?:\.\d+)+)(?:-(\d+))?/', $version, $m);
$baseVersion = $m[1];
$debVersion = $m[1]."-".($version === $baseVersion ? "1" : $m[2]);
// start a task collection and create a temporary directory
$t = $this->collectionBuilder();
$dir = $t->tmpDir().\DIRECTORY_SEPARATOR;
// build the generic release tarball if it doesn't exist
if (!file_exists($tarball)) {
$t->addTask($this->taskExec(BASE."robo package:generic $commit"));
}
$base = $dir."arsse-$version".\DIRECTORY_SEPARATOR;
// start by extracting the tarball
$t->addCode(function() use ($tarball, $dir, $base) {
// Robo's extract task is broken, so we do it manually
(new \Archive_Tar($tarball))->extract($dir, false);
return $this->taskFilesystemStack()->rename($dir."arsse", $base)->run();
});
// re-pack the tarball using a specific name special to Debian
$t->addTask($this->taskPack($dir."arsse_$baseVersion.orig.tar.gz")->addDir("arsse-$baseVersion", $base));
// pack the debian tarball
$t->addTask($this->taskPack($dir."arsse_$debVersion.debian.tar.gz")->addDir("debian", $base."dist"));
// generate the DSC file
$t->addCode(function() use ($t, $debVersion, $baseVersion, $dir, $base) {
try {
$dsc = $this->generateDebianSourceControl($base."dist/debian/", $debVersion, [$dir."arsse_$baseVersion.orig.tar.gz", $dir."arsse_$debVersion.debian.tar.gz"]);
} catch (\Exception $e) {
return new Result($t, 1, $e->getMessage());
}
// write the DSC file
return $this->taskWriteToFile($dir."arsse_$debVersion.dsc")->text($dsc)->run();
});
// delete any existing files
$t->AddTask($this->taskFilesystemStack()->remove(BASE."release/$version/arsse_$baseVersion.orig.tar.gz")->remove(BASE."release/$version/arsse_$debVersion.debian.tar.gz")->remove(BASE."release/$version/arsse_$debVersion.dsc"));
$t->addTask($this->taskFilesystemStack()->copy($dir."arsse_$baseVersion.orig.tar.gz", BASE."release/$version/arsse_$baseVersion.orig.tar.gz")->copy($dir."arsse_$debVersion.debian.tar.gz", BASE."release/$version/arsse_$debVersion.debian.tar.gz")->copy($dir."arsse_$debVersion.dsc", BASE."release/$version/arsse_$debVersion.dsc"));
return $t->run();
}
/** Generates all possible package types for a given commit of the software
*
* The commit to package may be any Git tree-ish identifier: a tag, a branch,
* or any commit hash. If none is provided on the command line, Robo will prompt
* for a commit to package; the default is "HEAD".
*
* Generic release tarballs will always be generated, but distribution-specific
* packages are skipped when the required tools are not available
*/
public function package(string $commit = null): Result {
if (!$this->toolExists("git")) {
throw new \Exception("Git is required in PATH to produce packages");
}
[$commit,] = $this->commitVersion($commit);
// determine whether the distribution-specific packages can be built
$dist = [
'Arch' => $this->toolExists("git", "makepkg", "updpkgsums"),
'Deb' => $this->toolExists("git", "sudo", "pbuilder"),
];
// start a collection
$t = $this->collectionBuilder();
// build the generic release tarball
$t->addTask($this->taskExec(BASE."robo package:generic $commit"));
// build other packages
foreach ($dist as $distro => $run) {
if ($run) {
$subcmd = strtolower($distro);
$t->addTask($this->taskExec(BASE."robo package:$subcmd $commit"));
}
}
$out = $t->run();
// clean the Git worktree list
$this->_exec("git worktree prune");
// note any packages which were not built
foreach ($dist as $distro => $run) {
if (!$run) {
$this->say("Packages for $distro skipped");
}
}
return $out;
}
@ -230,6 +465,9 @@ class RoboFile extends \Robo\Tasks {
* Daux's theme changes
*/
public function manualTheme(array $args): Result {
if (!$this->toolExists("yarn")) {
throw new \Exception("Yarn is required in PATH to update the Daux theme");
}
$postcss = escapeshellarg(norm(BASE."node_modules/.bin/postcss"));
$themesrc = norm(BASE."docs/theme/src/").\DIRECTORY_SEPARATOR;
$themeout = norm(BASE."docs/theme/arsse/").\DIRECTORY_SEPARATOR;
@ -247,4 +485,270 @@ class RoboFile extends \Robo\Tasks {
// execute the collection
return $t->run();
}
/** Generates the "arsse" command's manual page (UNIX man page)
*
* This requires that the Pandoc document converter be installed and
* available in $PATH.
*/
public function manpage(): Result {
if (!$this->toolExists("pandoc")) {
throw new \Exception("Pandoc is required in PATH to generate manual pages");
}
$t = $this->collectionBuilder();
$man = [
'en' => "man1/arsse.1",
];
foreach ($man as $src => $out) {
$src = BASE."manpages/$src.md";
$out = BASE."dist/man/$out";
$t->addTask($this->taskFilesystemStack()->mkdir(dirname($out), 0755));
$t->addTask($this->taskExec("pandoc -s -f markdown-smart -t man -o ".escapeshellarg($out)." ".escapeshellarg($src)));
$t->addTask($this->taskReplaceInFile($out)->regex('/\.\n(?!\.)/s')->to(". "));
}
return $t->run();
}
protected function changelogParse(string $text, string $targetVersion): array {
$lines = preg_split('/\r?\n/', $text);
$version = "";
$section = "";
$out = [];
$entry = [];
$expected = ["version"];
for ($a = 0; $a < sizeof($lines);) {
$l = rtrim($lines[$a++]);
if (in_array("version", $expected) && preg_match('/^Version (\d+(?:\.\d+)*) \(([\d\?]{4}-[\d\?]{2}-[\d\?]{2})\)\s*$/D', $l, $m)) {
$version = $m[1];
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/D', $m[2])) {
// uncertain dates are allowed only for the top version, and only if it does not match the target version (otherwise we have forgotten to set the correct date before tagging)
if (!$out && $targetVersion !== $version) {
// use today's date; local time is fine
$date = date("Y-m-d");
} else {
throw new \Exception("CHANGELOG: Date at line $a is incomplete");
}
} else {
$date = $m[2];
}
if ($entry) {
$out[] = $entry;
}
$entry = ['version' => $version, 'date' => $date, 'features' => [], 'fixes' => [], 'changes' => []];
$expected = ["separator"];
} elseif (in_array("separator", $expected) && preg_match('/^=+/', $l)) {
$length = strlen($lines[$a - 2]);
if (strlen($l) !== $length) {
throw new \Exception("CHANGELOG: Separator at line $a is of incorrect length");
}
$expected = ["blank line"];
$section = "";
} elseif (in_array("blank line", $expected) && $l === "") {
$expected = [
'' => ["features section", "fixes section", "changes section"],
'features' => ["fixes section", "changes section", "version"],
'fixes' => ["changes section", "version"],
'changes' => ["version"],
][$section];
$expected[] = "end-of-file";
} elseif (in_array("features section", $expected) && $l === "New features:") {
$section = "features";
$expected = ["item"];
} elseif (in_array("fixes section", $expected) && $l === "Bug fixes:") {
$section = "fixes";
$expected = ["item"];
} elseif (in_array("changes section", $expected) && $l === "Changes:") {
$section = "changes";
$expected = ["item"];
} elseif (in_array("item", $expected) && preg_match('/^- (\w.*)$/D', $l, $m)) {
$entry[$section][] = $m[1];
$expected = ["item", "continuation", "blank line"];
} elseif (in_array("continuation", $expected) && preg_match('/^ (\w.*)$/D', $l, $m)) {
$last = sizeof($entry[$section]) - 1;
$entry[$section][$last] .= "\n".$m[1];
} else {
if (sizeof($expected) > 1) {
throw new \Exception("CHANGELOG: Expected one of [".implode(", ", $expected)."] at line $a");
} else {
throw new \Exception("CHANGELOG: Expected ".$expected[0]." at line $a");
}
}
}
if (!in_array("end-of-file", $expected)) {
if (sizeof($expected) > 1) {
throw new \Exception("CHANGELOG: Expected one of [".implode(", ", $expected)."] at end of file");
} else {
throw new \Exception("CHANGELOG: Expected ".$expected[0]." at end of file");
}
}
$out[] = $entry;
return $out;
}
protected function changelogDebian(array $log, string $targetVersion): string {
$latest = $log[0]['version'];
$baseVersion = preg_replace('/^(\d+(?:\.\d+)*).*/', "$1", $targetVersion);
if ($baseVersion !== $targetVersion && version_compare($latest, $baseVersion, ">")) {
// if the changelog contains an entry for a future version, change its version number to match the target version instead of using the future version
$log[0]['version'] = $targetVersion;
$log[0]['distribution'] = "UNRELEASED";
} elseif ($baseVersion !== $targetVersion) {
// otherwise synthesize a changelog entry for the changes since the last tag
array_unshift($log, ['version' => $targetVersion, 'date' => date("Y-m-d"), 'features' => [], 'fixes' => [], 'changes' => ["Unspecified changes"], 'distribution' => "UNRELEASED"]);
}
$out = "";
foreach ($log as $entry) {
// normalize the version string
preg_match('/^(\d+(?:\.\d+)*)(?:-(\d+)-.+)?$/D', $entry['version'], $m);
$version = $m[1]."-".($m[2] ?: "1");
// output the entry
$out .= "arsse ($version) ".($entry['distribution'] ?? "unstable")."; urgency=low\n";
if ($entry['features']) {
$out .= "\n";
foreach ($entry['features'] as $item) {
$out .= " * ".trim(preg_replace("/^/m", " ", $item))."\n";
}
}
if ($entry['fixes']) {
$out .= "\n";
foreach ($entry['fixes'] as $item) {
$out .= " * ".trim(preg_replace("/^/m", " ", $item))."\n";
}
}
if ($entry['changes']) {
$out .= "\n";
foreach ($entry['changes'] as $item) {
$out .= " * ".trim(preg_replace("/^/m", " ", $item))."\n";
}
}
$out .= "\n -- J. King <jking@jkingweb.ca> ".\DateTimeImmutable::createFromFormat("Y-m-d", $entry['date'], new \DateTimeZone("UTC"))->format("D, d M Y")." 00:00:00 +0000\n\n";
}
return $out;
}
protected function generateDebianSourceControl(string $dir, string $version, array $tarballs): string {
// read in control file
if (!$control = @file_get_contents($dir."control")) {
throw new \Exception("Unable to read Debian control file");
}
// read the format
if (!$format = @file_get_contents($dir."source/format")) {
throw new \Exception("Unable to read source format in Debian files");
}
// read the binary packages from the control file
if (preg_match_all('/^Package:\s*(\S+)/m', $control, $m)) {
$binary = [];
foreach ($m[1] as $pkg) {
$binary[] = $pkg;
}
} else {
throw new \Exception("No packages defined in Debian control file");
}
// read the package architectures from the control file
if (preg_match_all('/^Architecture:\s*(\S+)/m', $control, $m) || sizeof($m[1]) != sizeof($binary)) {
$architecture = [];
foreach ($m[1] as $pkg) {
$architecture[] = preg_replace('/\s/', "", $pkg);
}
} else {
throw new \Exception("Number of architectures defined in Debian control file does not match number of packages");
}
// read the package sections from the control file
if (preg_match_all('/^Section:\s*(\S+)/m', $control, $m) || sizeof($m[1]) != sizeof($binary)) {
$section = [];
foreach ($m[1] as $pkg) {
$section[] = $pkg;
}
} else {
throw new \Exception("Number of sections defined in Debian control file does not match number of packages");
}
// read the package priorities from the control file
if (preg_match_all('/^Priority:\s*(\S+)/m', $control, $m) || sizeof($m[1]) != sizeof($binary)) {
$priority = [];
foreach ($m[1] as $pkg) {
$priority[] = $pkg;
}
} else {
throw new \Exception("Number of priorities defined in Debian control file does not match number of packages");
}
// read simple metadata from the control file
$metadata = [];
foreach (["Source", "Maintainer", "Homepage", "Standards-Version", "Vcs-Browser", "Vcs-Git"] as $meta) {
if (preg_match('/^'.$meta.':\s*(.+)/m', $control, $m)) {
$metadata[$meta] = $m[1];
} else {
throw new \Exception("$meta is not defined in Debian control file");
}
}
// read build dependencies from control file
if (preg_match('/(?:^|\n)Build-Depends:\s*((?:[^\n]|\n(?= ))+)/s', $control, $m)) {
$buildDepends = preg_replace('/\s/', "", $m[1]);
} else {
$buildDepends = "";
}
// trim format
$format = trim($format);
// consolidate binaries and package list
$packageList = [];
for ($a = 0; $a < sizeof($binary); $a++) {
$packageList[] = "$binary[$a] deb $section[$a] $priority[$a] arch=$architecture[$a]";
}
$packageList = implode("\n ", $packageList);
// consolidate package names
$binary = implode(",", $binary);
// consolidate architectures
$architecture = implode(",", array_unique($architecture));
// calculate checksums for files
$fMeta = [];
foreach ($tarballs as $f) {
$fMeta[$f] = [
'name' => basename($f),
'size' => filesize($f),
'sha1' => hash_file("sha1", $f),
'sha256' => hash_file("sha256", $f),
'md5' => hash_file("md5", $f),
];
}
// consolidate SHA-1 checksums
$sums = [];
foreach ($fMeta as $data) {
$sums[] = $data['sha1']." ".$data['size']." ".$data['name'];
}
$sumsSha1 = implode("\n ", $sums);
// consolidate SHA-256 checksums
$sums = [];
foreach ($fMeta as $data) {
$sums[] = $data['sha256']." ".$data['size']." ".$data['name'];
}
$sumsSha256 = implode("\n ", $sums);
// consolidate MD5 checksums
$sums = [];
foreach ($fMeta as $data) {
$sums[] = $data['md5']." ".$data['size']." ".$data['name'];
}
$sumsMd5 = implode("\n ", $sums);
// return complete file
return <<< DSC_FILE
Format: $format
Source: {$metadata['Source']}
Binary: $binary
Architecture: $architecture
Version: $version
Maintainer: {$metadata['Maintainer']}
Homepage: {$metadata['Homepage']}
Standards-Version: {$metadata['Standards-Version']}
Vcs-Browser: {$metadata['Vcs-Browser']}
Vcs-Git: {$metadata['Vcs-Git']}
Build-Depends: $buildDepends
Package-List:
$packageList
Checksums-Sha1:
$sumsSha1
Checksums-Sha256:
$sumsSha256
Files:
$sumsMd5
DSC_FILE;
}
}

3
arsse.php

@ -25,8 +25,7 @@ if (\PHP_SAPI === "cli") {
exit($exitStatus);
} else {
// load configuration
$conf = file_exists(BASE."config.php") ? new Conf(BASE."config.php") : new Conf;
Arsse::load($conf);
Arsse::bootstrap();
// handle Web requests
$emitter = new \Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
$response = (new REST)->dispatch();

4
composer.json

@ -22,6 +22,7 @@
"ext-intl": "*",
"ext-json": "*",
"ext-hash": "*",
"ext-filter": "*",
"ext-dom": "*",
"nicolus/picofeed": "^0.1.43",
"hosteurope/password-generator": "1.*",
@ -33,6 +34,9 @@
"require-dev": {
"bamarni/composer-bin-plugin": "*"
},
"suggest": {
"ext-pcntl": "To respond to signals, particular to reload configuration via SIGHUP"
},
"config": {
"platform": {
"php": "7.1.33"

85
composer.lock

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2a87797422ae569bafcbb6476461ac38",
"content-hash": "c658930fbc56b2b2cf646e34c6a8d8d3",
"packages": [
{
"name": "docopt/docopt",
@ -129,16 +129,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.4.0",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "60d379c243457e073cff02bc323a2a86cb355631"
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
"reference": "60d379c243457e073cff02bc323a2a86cb355631",
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"shasum": ""
},
"require": {
@ -178,22 +178,22 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.0"
"source": "https://github.com/guzzle/promises/tree/1.4.1"
},
"time": "2020-09-30T07:37:28+00:00"
"time": "2021-03-07T09:25:29+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.7.0",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3"
"reference": "dc960a912984efb74d0a90222870c72c87f10c91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3",
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"shasum": ""
},
"require": {
@ -253,9 +253,9 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.7.0"
"source": "https://github.com/guzzle/psr7/tree/1.8.2"
},
"time": "2020-09-30T07:37:11+00:00"
"time": "2021-04-26T09:17:50+00:00"
},
{
"name": "hosteurope/password-generator",
@ -951,16 +951,16 @@
},
{
"name": "psr/log",
"version": "1.1.3",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
@ -984,7 +984,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
@ -995,9 +995,9 @@
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.3"
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2020-03-23T09:12:05+00:00"
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "ralouphie/getallheaders",
@ -1045,16 +1045,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.22.1",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "2d63434d922daf7da8dd863e7907e67ee3031483"
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483",
"reference": "2d63434d922daf7da8dd863e7907e67ee3031483",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65",
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65",
"shasum": ""
},
"require": {
@ -1068,7 +1068,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1112,7 +1112,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0"
},
"funding": [
{
@ -1128,20 +1128,20 @@
"type": "tidelift"
}
],
"time": "2021-01-22T09:19:47+00:00"
"time": "2021-05-27T09:27:20+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.22.1",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248"
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248",
"reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8",
"reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8",
"shasum": ""
},
"require": {
@ -1153,7 +1153,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1196,7 +1196,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0"
},
"funding": [
{
@ -1212,20 +1212,20 @@
"type": "tidelift"
}
],
"time": "2021-01-22T09:19:47+00:00"
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.22.1",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9"
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9",
"reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976",
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976",
"shasum": ""
},
"require": {
@ -1234,7 +1234,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1272,7 +1272,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0"
},
"funding": [
{
@ -1288,7 +1288,7 @@
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
"time": "2021-05-27T09:17:38+00:00"
}
],
"packages-dev": [
@ -1353,11 +1353,12 @@
"ext-intl": "*",
"ext-json": "*",
"ext-hash": "*",
"ext-filter": "*",
"ext-dom": "*"
},
"platform-dev": [],
"platform-overrides": {
"php": "7.1.33"
},
"plugin-api-version": "2.0.0"
"plugin-api-version": "2.1.0"
}

23
dist/apache.conf

@ -1,23 +0,0 @@
# N.B. the unix:/var/run/php/php7.2-fpm.sock path used repeatedly below will
# vary from system to system and will be probably need to be changed
<VirtualHost *:80>
ServerName localhost
# adjust according to your installation path
DocumentRoot /usr/share/arsse/www
# adjust according to your installation path
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/usr/share/arsse/arsse.php"
ProxyPreserveHost On
# Nextcloud News v1.2, Tiny Tiny RSS API, TT-RSS newsfeed icons, Miniflux API
<LocationMatch "(/index\.php/apps/news/api/?.+|/tt-rss/(api|feed-icons)|/v1/)">
ProxyPass "unix:/var/run/php/php7.2-fpm.sock|fcgi://localhost/usr/share/arsse"
</LocationMatch>