Compare commits

...

157 Commits

Author SHA1 Message Date
J. King 2557c22410 Update dependencies 3 days ago
J. King 4ca7b65a65 Update dependencies 2 weeks ago
J. King 4d37ae30ae Update dependencies 3 weeks ago
J. King d1da6fbe5e Use cases rather than casting bools to int in SQL 4 weeks ago
J. King d54733ad98 Update link to Nextcloud News documentation again 2 months ago
J. King a0c31fac5d Merge branch 'reader' 2 months ago
J. King 59358ec35b More PHP 7 fixes 2 months ago
J. King 90b66241b3 Fixes for PHP 7 2 months ago
J. King 761b3d5333 Return removed articles correctly in Miniflux 2 months ago
J. King d64dc751f9 Tests for query filters 2 months ago
J. King f51acb4264 Build exceptions correctly in Miniflux for clarity 2 months ago
J. King 300225439c Fix trivial error in Miniflux 2 months ago
J. King c6cc2a1a42 Restore coverage for Query class 2 months ago
J. King a44fe103d8 Prototype for nesting query filters 2 months ago
J. King 630536d789 Tests for union context 2 months ago
J. King 206c5c0012 Fill in union context 2 months ago
J. King 0c8f33c37c Remove setCTE and pushCTE from query builder 2 months ago
J. King 26e431b1a5 Simplify more queries 2 months ago
J. King 336207741d Add missing API documentation 2 months ago
J. King 6863c182d7 Update reference to the "Reeder" client 2 months ago
J. King f2aad7188c Update links to TT-RSS documentation 2 months ago
J. King 65b1bb4fcd Allow multiple dates in TT-RSS searches 2 months ago
J. King 2c5b9a6768 Fix missing TTRSS coverage 2 months ago
J. King 17832ac63e Allow timezone in TT-RSS search queries 2 months ago
J. King e65069885b Clean up obsolete FIXMEs 2 months ago
J. King 7e5d8494c4 Tests for selecting arrays of ranges 2 months ago
J. King e6505a5fda Work around possible MySQL bug 2 months ago
J. King 2acacd2647 Implement handling for arrays of ranges 2 months ago
J. King f6799e2ab1 Tests for date ranges in contexts 2 months ago
J. King 33a3478a58 Avoid use of PHP 7.4 feature 2 months ago
J. King 2489743d0f Further simplifications 2 months ago
J. King 0bd01849bb Remove unnecessary in() clause 2 months ago
J. King 895c045c9b Simplify folder selection in article queries 2 months ago
J. King fe02613214 Fix coverage 2 months ago
J. King 427bddd3b7 Allow multiple date ranges 2 months ago
J. King 53ba591720 Finish up article selection refactor 2 months ago
J. King 97dfef3267 Fix typos 2 months ago
J. King 396ca86482 Start on removal of conditional CTEs 2 months ago
J. King 4a87926dd5 Fix up context tests 2 months ago
J. King 6f1332c559 Start to shore up testing 2 months ago
J. King 308b592b18 Clean up coontext classes 2 months ago
J. King 983fa58ec8 Convert article and edition ranges to atomic 2 months ago
J. King 2c2bb4a856 Retrofits dates to use ranges 2 months ago
J. King c993168002 Update URL of Nextcloud News documentation 2 months ago
J. King 73497688fc Break contexts up into traits 2 months ago
J. King 1b0256d6ce Abandon automation of binary packaging for now 3 months ago
J. King 144a41e061 Prepare new version 3 months ago
J. King 60b4002329 Revert "Document that we actually emulate Miniflux 2.0.29" 3 months ago
J. King f24ec8b00b Address security vulnerability in Guzzle's PSR-7 3 months ago
J. King d379aa2253 Document that we actually emulate Miniflux 2.0.29 3 months ago
J. King b707ecc942 Tag new version 5 months ago
J. King afe26fb8e1 Style fixes 5 months ago
J. King 3a219a591d Update dependencies 5 months ago
J. King b5579d6e43 Support PHP 8.1 5 months ago
J. King b660508009 Improve MySQL test performance 6 months ago
J. King 3c884f521b Update dependencies 8 months ago
J. King 70b063e028 Make parts of generic packaging conditional 11 months ago
J. King cf3d270077 Merge branch 'deb' 11 months ago
J. King 1fa75aba4a Generate Debian source package without deb tooling 11 months ago
J. King 317d23c1bb Fix copy-paste error in manual 12 months ago
J. King 75dbe380ba Add Pandoc to AUR arsse-git build dependencies 12 months ago
J. King 08250841a0 Don't sign packages 12 months ago
J. King 2452264893 Date release 12 months ago
J. King c1e57eb01f Add manual installation instructions 12 months ago
J. King e75e0dfd2f Clarify exactly what "older Debians" is 12 months ago
J. King 6c11c9e485 Fix Debian bugs 12 months ago
J. King 40a2856ae8 Use correct PHP_FPM socket paths for Debian 12 months ago
J. King c7dcc36ba1 Update version 12 months ago
J. King a31fb896d9 Update changelog 12 months ago
J. King def4a3bc77 Move Debian adaptations to Debian packaging rules 12 months ago
J. King cd89472575 Fix up Debian documentation 12 months ago
J. King beea98040c Initial documentation for Debian packages 12 months ago
J. King 59ff88f3b6 Add all-in-one packaging task 12 months ago
J. King 4070870421 Enforce external tooling requirements 12 months ago
J. King 5ab9dc3840 Add missing pbuilder script 12 months ago
J. King 20ffb2484a Simply Robo input for Arch and Deb packaging 12 months ago
J. King f91b3c0120 Output packages to a "release" directory 12 months ago
J. King 4121fc3e21 Database server ports must be integers 12 months ago
J. King 7ad3611a84 Set up configuration file for Debian properly 12 months ago
J. King 5412eb348f Clean up maintainer scripts 12 months ago
J. King c936ecc1af Fix another typo 12 months ago
J. King 99c923b1b1 Fix typos 12 months ago
J. King c2237532eb Add glue for dbconfig-common configuration 12 months ago
J. King 9687ce026e Add MySQL back to Debian depeendencies 12 months ago
J. King 30bed8a9d5 Typo 12 months ago
J. King cf9059c2b0 Update tooling 12 months ago
J. King 93bcf93685 Prototype Debian maintainer scripts 12 months ago
J. King 46e20be983 Test for service reloading 12 months ago
J. King ad32bf3340 Style fixes 12 months ago
J. King b8ac646d22 Fix up hangup signal handling 12 months ago
J. King 37c58e186a Handle hangup signal 12 months ago
J. King 88fe3e76cb Fix up missing-extension message 12 months ago
J. King 3c8ee42666 Basic tests for exception checking 12 months ago
J. King 04adc3b997 Document forking in the manpage 12 months ago
J. King c49cb72528 Fail gracefully when extensions are missing 12 months ago
J. King c9a2393a4e Note requirement for filter extension 12 months ago
J. King 75e87f31a0 Prototype code to check for missing extensions 12 months ago
J. King 3b51d4daea Fix license for Debian package 12 months ago
J. King ce9dfc3f30 Add init script to Debian files 12 months ago
J. King cbc7cd8ea7 Add an explicit path to init script 12 months ago
J. King 2e29f3f76e Correct typo 12 months ago
J. King 8a1a1eee42 Prototype init script 12 months ago
J. King e160189224 Handle exceptions from child processes 12 months ago
J. King e9394e8599 More forking tweaks 1 year ago
J. King 577356cd3d Fork error test 1 year ago
J. King 514cb0a351 Ow 1 year ago
J. King 0bb5e916d2 Test PID writing 1 year ago
J. King 2767ab755e Use D modifier in pattern 1 year ago
J. King a4036afbf8 Partial tests for PID file reading 1 year ago
J. King 32c9d761c3 Clean up more exceptions 1 year ago
J. King 5b3e8fbef0 Refine some exceptions 1 year ago
J. King b9fd9ac32e Tweaks 1 year ago
J. King 23749b51aa Tests for path resolution 1 year ago
J. King dfaf44ac68 Basic path resolution tests 1 year ago
J. King bab64add9b Separate PID conflict checking from PID claiming 1 year ago
J. King 822158d1bd Update dependencies 1 year ago
J. King f1c29c99c7 Finish testing PID file path checking 1 year ago
J. King 59cf27089a More daemon cleanup 1 year ago
J. King 4e1193bab2 Move forking daemon support code to own class 1 year ago
J. King 32e04e3938 Move forking and related to Service class 1 year ago
J. King 55acb87577 Start on PI(D file resolution tests 1 year ago
J. King e8cab78bd6 Handle last possible PID failures 1 year ago
J. King 9595c4f019 Start filling out PID file exceptions 1 year ago
J. King 372bf9f630 Exclude code from coverage 1 year ago
J. King 4ffc29781d Remove references to oldpass param 1 year ago
J. King 47af739e47 Catch more PID path failures 1 year ago
J. King 2c7b16ed27 Respond to termination signals and delete PID file 1 year ago
J. King 410310282f Load configuration after forking 1 year ago
J. King 29b83b4453 Prototype forking daemon 1 year ago
J. King fc2abc1203 Use D modifier for all patterns with $ anchors 1 year ago
J. King 59c5c2eb14 Oops 1 year ago
J. King 3cd3ac4a51 Correct filename conflict 1 year ago
J. King 837895fd6a Adapt dist files for Debian 1 year ago
J. King b4c9413130 Update README 1 year ago
J. King bafb788b02 Correct errors in manual 1 year ago
J. King 68e3cd82ca Don't include section number in title 1 year ago
J. King c3fa4788d6 Use proper metadata block for manpage 1 year ago
J. King 3567f294a6 Merge branch 'manpage' 1 year ago
J. King 8c0f047747 Update HTML manual to mention man page 1 year ago
J. King fd76b1b611 Add examples to manual page 1 year ago
J. King 4317a96db1 Work around double spacing 1 year ago
J. King 62d49e0d3c Fill out most of the manual page 1 year ago
J. King 88487d27a2 Expand manual page 1 year ago
J. King 46c88f584f Fix copying of man page in PKGBUILDs 1 year ago
J. King 92823d5bc2 Create directories before executing Pandoc 1 year ago
J. King 3e55ab3849 Move man pages to their own directory 1 year ago
J. King 2ec7acc50b Turn off "smart" character substitution in Pandoc 1 year ago
J. King d3a983e7f0 Move the markdown manpage 1 year ago
J. King 176aac0ad7 Fix stupid typo properly 1 year ago
J. King e439dd8277 Fix manpage in Arch PKGBUILD 1 year ago
J. King 6cc9f96728 Prototype manual page 1 year ago
J. King d4569c77a9 Add database location to tmpfiles 1 year ago
J. King add1acc87a Fix more lintian complaints 1 year ago
J. King 14d3cdfe58 Hopefully fix some Debian problems 1 year ago
J. King 281760be71 Address some lintian complaints 1 year ago
J. King 758a02d667 Move generic configuration file 1 year ago
J. King 18846c19cb Add install list for Debian package 1 year ago
  1. 8
      .gitignore
  2. 32
      CHANGELOG
  3. 27
      README.md
  4. 411
      RoboFile.php
  5. 5
      arsse.php
  6. 7
      composer.json
  7. 257
      composer.lock
  8. 7
      dist/arch/PKGBUILD
  9. 10
      dist/arch/PKGBUILD-git
  10. 2
      dist/arsse
  11. 0
      dist/config.php
  12. 16
      dist/debian/arsse.config
  13. 1
      dist/debian/arsse.dirs
  14. 18
      dist/debian/arsse.install
  15. 1
      dist/debian/arsse.links
  16. 29
      dist/debian/arsse.postinst
  17. 20
      dist/debian/arsse.postrm
  18. 16
      dist/debian/arsse.prerm
  19. 15
      dist/debian/config.php
  20. 8
      dist/debian/control
  21. 1
      dist/debian/copyright
  22. 44
      dist/debian/dbconfig-common.php
  23. 6
      dist/debian/lintian-overrides
  24. 40
      dist/debian/pbuilder.sh
  25. 19
      dist/debian/rules
  26. 2
      dist/debian/source/lintian-overrides
  27. 78
      dist/init.sh
  28. 2
      dist/systemd/arsse-fetch.service
  29. 7
      dist/tmpfiles.conf
  30. 6
      docs/en/020_Getting_Started/020_Download_and_Installation/010_On_Arch_Linux.md
  31. 72
      docs/en/020_Getting_Started/020_Download_and_Installation/020_On_Debian_and_Derivatives.md
  32. 83
      docs/en/020_Getting_Started/020_Download_and_Installation/020_On_Debian_and_Ubuntu.md
  33. 53
      docs/en/020_Getting_Started/020_Download_and_Installation/999_ On_Other_Systems.md
  34. 16
      docs/en/020_Getting_Started/020_Download_and_Installation/index.md
  35. 12
      docs/en/020_Getting_Started/040_Database_Setup/000_SQLite.md
  36. 14
      docs/en/020_Getting_Started/050_Configuration.md
  37. 20
      docs/en/020_Getting_Started/index.md
  38. 4
      docs/en/025_Using_The_Arsse/030_Other_Topics.md
  39. 2
      docs/en/025_Using_The_Arsse/index.md
  40. 1
      docs/en/030_Supported_Protocols/005_Miniflux.md
  41. 2
      docs/en/030_Supported_Protocols/010_Nextcloud_News.md
  42. 4
      docs/en/030_Supported_Protocols/020_Tiny_Tiny_RSS.md
  43. 4
      docs/en/040_Compatible_Clients.md
  44. 13
      lib/AbstractException.php
  45. 32
      lib/Arsse.php
  46. 251
      lib/CLI.php
  47. 27
      lib/Context/AbstractContext.php
  48. 35
      lib/Context/BooleanMembers.php
  49. 40
      lib/Context/Context.php
  50. 250
      lib/Context/ExclusionContext.php
  51. 262
      lib/Context/ExclusionMembers.php
  52. 20
      lib/Context/RootContext.php
  53. 50
      lib/Context/UnionContext.php
  54. 610
      lib/Database.php
  55. 8
      lib/Db/MySQL/Driver.php
  56. 3
      lib/Db/MySQL/PDODriver.php
  57. 2
      lib/Db/MySQL/Statement.php
  58. 2
      lib/Db/PDOStatement.php
  59. 2
      lib/Db/PostgreSQL/Driver.php
  60. 4
      lib/Db/PostgreSQL/Statement.php
  61. 5
      lib/Db/Result.php
  62. 2
      lib/Db/SQLite3/Driver.php
  63. 3
      lib/Db/SQLite3/PDODriver.php
  64. 2
      lib/Db/SQLite3/Statement.php
  65. 2
      lib/Misc/HTTP.php
  66. 75
      lib/Misc/Query.php
  67. 75
      lib/Misc/QueryFilter.php
  68. 2
      lib/Misc/URL.php
  69. 10
      lib/Misc/ValueInfo.php
  70. 16
      lib/REST.php
  71. 8
      lib/REST/Fever/API.php
  72. 2
      lib/REST/Miniflux/Token.php
  73. 31
      lib/REST/Miniflux/V1.php
  74. 12
      lib/REST/NextcloudNews/V1_2.php
  75. 2
      lib/REST/NextcloudNews/Versions.php
  76. 27
      lib/REST/TinyTinyRSS/API.php
  77. 2
      lib/REST/TinyTinyRSS/Icon.php
  78. 42
      lib/REST/TinyTinyRSS/Search.php
  79. 51
      lib/Service.php
  80. 226
      lib/Service/Daemon.php
  81. 10
      lib/Service/Exception.php
  82. 21
      locale/en.php
  83. 226
      manpages/en.md
  84. 2
      sql/SQLite3/0.sql
  85. 2
      sql/SQLite3/2.sql
  86. 2
      tests/bootstrap.php
  87. 36
      tests/cases/CLI/TestCLI.php
  88. 64
      tests/cases/Database/SeriesArticle.php
  89. 4
      tests/cases/Database/SeriesSubscription.php
  90. 4
      tests/cases/Db/BaseDriver.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. 2
      tests/cases/Db/SQLite3/TestCreation.php
  96. 1
      tests/cases/ImportExport/TestOPML.php
  97. 182
      tests/cases/Misc/TestContext.php
  98. 61
      tests/cases/Misc/TestQuery.php
  99. 173
      tests/cases/Misc/TestValueInfo.php
  100. 13
      tests/cases/REST/Fever/TestAPI.php

8
.gitignore

@ -1,11 +1,13 @@
# Temporary files
/release/
/documentation/
/manual/
/tests/coverage/
/dist/arch/arsse
/dist/arch/src
/dist/arch/pkg
/dist/arch/arsse/
/dist/arch/src/
/dist/arch/pkg/
/dist/man/
/arsse.db*
/config.php
/.php_cs.cache

32
CHANGELOG

@ -1,3 +1,35 @@
Version 0.1?.? (2022-??-??)
===========================
Bug fixes:
- Return all removed articles when multiple statuses are requested in Miniflux
- Allow multiple date ranges in search strings in Tiny Tiny RSS
- Honour user time zone when interpreting search strings in Tiny Tiny RSS
- Perform MySQL table maintenance more reliably
Version 0.10.2 (2022-04-04)
===========================
Changes:
- Update Guzzle PSR-7 due to CVE-2022-24775
Version 0.10.1 (2022-01-17)
===========================
Changes:
- Support PHP 8.1
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)
==========================

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

411
RoboFile.php

@ -6,6 +6,7 @@ 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,9 +146,34 @@ 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".
*
@ -155,45 +181,75 @@ class RoboFile extends \Robo\Tasks {
* 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
$commit = $version ?? $this->askDefault("Commit to package:", "HEAD");
[$commit, $version] = $this->commitVersion($commit);
preg_match('/^([^-]+)(?:-(\d+)-(\w+))?$/', $version, $m);
$archVersion = $m[1].($m[2] ? ".r$m[2].$m[3]" : "");
$baseVersion = $m[1];
$release = $m[2];
// 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
$result = $this->taskExec("git worktree add ".escapeshellarg($dir)." ".escapeshellarg($commit))->dir(BASE)->run();
$result = $this->taskExec("git worktree add ".escapeshellarg($dir)." ".escapeshellarg($version))->dir(BASE)->run();
if ($result->getExitCode() > 0) {
return $result;
}
try {
// get useable version strings from Git
$version = trim(`git -C "$dir" describe --tags`);
$archVersion = preg_replace('/^([^-]+)-(\d+)-(\w+)$/', "$1.r$2.$3", $version);
// name the generic release tarball
$tarball = "arsse-$version.tar.gz";
// generate the Debian changelog; this also validates our original changelog
$debianChangelog = $this->changelogDebian($this->changelogParse(file_get_contents($dir."CHANGELOG"), $version), $version);
// save commit description to VERSION file for use by packaging
// Perform Arch-specific tasks
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).'")'));
}
// perform Debian-specific tasks
if (file_exists($dir."dist/debian")) {
// generate the Debian changelog; this also validates our original changelog
$changelog = $this->changelogParse(file_get_contents($dir."CHANGELOG"), $version);
$debianChangelog = $this->changelogDebian($changelog, $version);
// save the Debian-format changelog
$t->addTask($this->taskWriteToFile($dir."dist/debian/changelog")->text($debianChangelog));
}
// perform RPM-specific tasks
if (file_exists($dir."dist/rpm")) {
// patch the spec file with the correct version and release
$t->addTask($this->taskReplaceInFile($dir."dist/rpm/arsse.spec")->regex('/^Version: .*$/m')->to("Version: $baseVersion"));
$t->addTask($this->taskReplaceInFile($dir."dist/rpm/arsse.spec")->regex('/^Release: .*$/m')->to("Release: $release"));
// patch the spec file with the correct tarball name
$t->addTask($this->taskReplaceInFile($dir."dist/rpm/arsse.spec")->regex('/^Source0: .*$/m')->to("Source0: arsse-$version.tar.gz"));
// append the RPM changelog to the spec file
$t->addTask($this->taskWriteToFile($dir."dist/rpm/arsse.spec")->append(true)->text("\n\n%changelog\n".$this->changelogRPM($changelog, $version)));
}
// save commit description to VERSION file for reference
$t->addTask($this->taskWriteToFile($dir."VERSION")->text($version));
// save the Debian changelog
$t->addTask($this->taskWriteToFile($dir."dist/debian/changelog")->text($debianChangelog));
// 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).'")'));
// perform Composer installation in the temp location with dev dependencies
$t->addTask($this->taskComposerInstall()->arg("-q")->dir($dir));
// generate the manual
$t->addTask($this->taskExec("./robo manual -q")->dir($dir));
if (file_exists($dir."docs") || file_exists($dir."manpages")) {
// perform Composer installation in the temp location with dev dependencies to include Robo and Daux
$t->addTask($this->taskExec("composer install")->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"));
$t->addTask($this->taskExec("composer install")->dir($dir)->arg("--no-dev")->arg("-o")->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",
@ -202,6 +258,7 @@ class RoboFile extends \Robo\Tasks {
$dir."RoboFile.php",
$dir."CONTRIBUTING.md",
$dir."docs",
$dir."manpages",
$dir."tests",
$dir."vendor-bin",
$dir."vendor/bin",
@ -211,11 +268,22 @@ class RoboFile extends \Robo\Tasks {
$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();
@ -227,34 +295,27 @@ class RoboFile extends \Robo\Tasks {
return $result;
}
/** Packages a release tarball into an Arch package */
public function packageArch(string $tarball): Result {
$dir = dirname($tarball).\DIRECTORY_SEPARATOR;
// start a collection
$t = $this->collectionBuilder();
// 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 release tarball into a Debian package */
public function packageDeb(string $tarball): Result {
// determine the "upstream" (tagged) version
if (preg_match('/^arsse-(\d+(?:\.\d+)*)/', basename($tarball), $m)) {
$version = $m[1];
} else {
throw new \Exception("Tarball is not named correctly");
}
/** 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) {
@ -262,11 +323,80 @@ class RoboFile extends \Robo\Tasks {
(new \Archive_Tar($tarball))->extract($dir, false);
return $this->taskFilesystemStack()->rename($dir."arsse", $base)->run();
});
// re-pack the tarball using specific names special to debuild
$t->addTask($this->taskPack($dir."arsse_$version.orig.tar.gz")->addDir("arsse-$version", $base));
// copy Debian files to lower down in the tree
$t->addTask($this->taskFilesystemStack()->mirror($base."dist/debian", $base."debian"));
$t->addTask($this->taskExec("deber")->dir($dir));
// 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/debian"));
// 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", BASE."release/$version/arsse_$debVersion.debian.tar.gz", BASE."release/$version/arsse_$debVersion.dsc"]));
// copy the new files over
$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();
}
/** Packages a given commit of the software and produces all relevant release files
*
* 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".
*
* In addition to the release tarball, a Debian source package, Arch PKGBUILD,
* and RPM spec file are output as well. These are suitable for use with Open
* Build Service instances and with slight modification the Arch User Repository.
* Use for Launchpad PPAs has not been tested.
*/
public function package(string $commit = null): Result {
if (!$this->toolExists("git")) {
throw new \Exception("Git is required in PATH to produce packages");
}
[$commit, $version] = $this->commitVersion($commit);
$tarball = BASE."release/$version/arsse-$version.tar.gz";
// build the generic release tarball
$result = $this->taskExec(BASE."robo package:generic $commit")->run();
if (!$result->wasSuccessful()) {
return $result;
}
// if the generic tarball could be built, try to produce Arch, Debian, and RPM files; these might legitimately not exist in old releases
// start by getting the list of files from the tarball
$archive = new \Archive_Tar($tarball);
$filelist = array_flip(array_column($archive->listContent(), "filename"));
// start a collection
$t = $this->collectionBuilder();
// Produce an Arch PKGBUILD if appropriate
if (isset($filelist['arsse/dist/arch/PKGBUILD'])) {
$t->addCode(function() use ($tarball, $archive) {
$dir = dirname($tarball).\DIRECTORY_SEPARATOR;
$archive->extractList("arsse/dist/arch/PKGBUILD", $dir, "arsse/dist/arch/", false);
// update the tarball's checksum
$sums = [
'md5' => hash_file("md5", $tarball),
];
return $this->taskReplaceInFile($dir."PKGBUILD")->regex('/^md5sums=\("SKIP"\)$/m')->to('md5sums=("'.$sums['md5'].'")')->run();
});
}
// Produce a Debian source package if appropriate
if (isset($filelist['arsse/dist/debian/control']) && isset($filelist['arsse/dist/debian/source/format'])) {
$t->addTask($this->taskExec(BASE."robo package:debsrc $commit"));
}
// Produce an RPM spec file if appropriate
if (isset($filelist['arsse/dist/rpm/arsse.spec'])) {
$t->addCode(function() use ($tarball, $archive) {
$dir = dirname($tarball).\DIRECTORY_SEPARATOR;
$archive->extractList("arsse/dist/rpm/arsse.spec", $dir, "arsse/dist/rpm/", false);
// perform a do-nothing filesystem operation since we need a Robo task result
return $this->taskFilesystemStack()->chmod($dir."arsse.spec", 0644)->run();
});
}
return $t->run();
}
@ -296,6 +426,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;
@ -314,6 +447,29 @@ class RoboFile extends \Robo\Tasks {
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 = "";
@ -323,9 +479,9 @@ class RoboFile extends \Robo\Tasks {
$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*$/', $l, $m)) {
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}$/', $m[2])) {
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
@ -338,7 +494,7 @@ class RoboFile extends \Robo\Tasks {
}
if ($entry) {
$out[] = $entry;
}
}
$entry = ['version' => $version, 'date' => $date, 'features' => [], 'fixes' => [], 'changes' => []];
$expected = ["separator"];
} elseif (in_array("separator", $expected) && preg_match('/^=+/', $l)) {
@ -365,10 +521,10 @@ class RoboFile extends \Robo\Tasks {
} elseif (in_array("changes section", $expected) && $l === "Changes:") {
$section = "changes";
$expected = ["item"];
} elseif (in_array("item", $expected) && preg_match('/^- (\w.*)$/', $l, $m)) {
} 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.*)$/', $l, $m)) {
} elseif (in_array("continuation", $expected) && preg_match('/^ (\w.*)$/D', $l, $m)) {
$last = sizeof($entry[$section]) - 1;
$entry[$section][$last] .= "\n".$m[1];
} else {
@ -389,24 +545,25 @@ class RoboFile extends \Robo\Tasks {
$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;
} else {
$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"]]);
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+)-.+)?$/', $entry['version'], $m);
preg_match('/^(\d+(?:\.\d+)*)(?:-(\d+)-.+)?$/D', $entry['version'], $m);
$version = $m[1]."-".($m[2] ?: "1");
// output the entry
$out .= "arsse ($version) UNRELEASED; urgency=low\n";
$out .= "arsse ($version) ".($entry['distribution'] ?? "unstable")."; urgency=low\n";
if ($entry['features']) {
$out .= "\n";
foreach ($entry['features'] as $item) {
@ -425,8 +582,134 @@ class RoboFile extends \Robo\Tasks {
$out .= " * ".trim(preg_replace("/^/m", " ", $item))."\n";
}
}
$out .= "\n -- The Arsse team <no-contact@code.mensbeam.com> ".\DateTimeImmutable::createFromFormat("Y-m-d", $entry['date'], new \DateTimeZone("UTC"))->format("D, d M Y")." 00:00:00 +0000\n\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;
}
}

5
arsse.php

@ -13,7 +13,7 @@ require_once BASE."vendor".DIRECTORY_SEPARATOR."autoload.php";
ignore_user_abort(true);
ini_set("memory_limit", "-1");
ini_set("max_execution_time", "0");
// FIXME: This is required by a dependency of Picofeed
// FIXME: This is required because various dependencies have yet to adjust to PHP 8.1
error_reporting(\E_ALL & ~\E_DEPRECATED);
if (\PHP_SAPI === "cli") {
@ -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();

7
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,9 +34,15 @@
"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"
},
"allow-plugins": {
"bamarni/composer-bin-plugin": true
}
},
"scripts": {

257
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",
@ -58,24 +58,24 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.5",
"version": "6.5.8",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e"
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981",
"reference": "a52f0440530b54fa079ce76e8c5d196a42cad981",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.6.1",
"guzzlehttp/psr7": "^1.9",
"php": ">=5.5",
"symfony/polyfill-intl-idn": "^1.17.0"
"symfony/polyfill-intl-idn": "^1.17"
},
"require-dev": {
"ext-curl": "*",
@ -92,22 +92,52 @@
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
@ -123,22 +153,36 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/6.5"
"source": "https://github.com/guzzle/guzzle/tree/6.5.8"
},
"time": "2020-06-16T21:01:06+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2022-06-20T22:16:07+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "1.4.1",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"shasum": ""
},
"require": {
@ -150,26 +194,41 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
"dev-master": "1.5-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
@ -178,22 +237,36 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.1"
"source": "https://github.com/guzzle/promises/tree/1.5.1"
},
"time": "2021-03-07T09:25:29+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"time": "2021-10-22T20:56:57+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.8.2",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91"
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"shasum": ""
},
"require": {
@ -214,29 +287,50 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
],
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
@ -253,9 +347,23 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.8.2"
"source": "https://github.com/guzzle/psr7/tree/1.9.0"
},
"time": "2021-04-26T09:17:50+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2022-06-20T21:43:03+00:00"
},
{
"name": "hosteurope/password-generator",
@ -1045,16 +1153,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.22.1",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "2d63434d922daf7da8dd863e7907e67ee3031483"
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
},
"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/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"shasum": ""
},
"require": {
@ -1068,7 +1176,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1076,12 +1184,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Idn\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1112,7 +1220,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.26.0"
},
"funding": [
{
@ -1128,20 +1236,20 @@
"type": "tidelift"
}
],
"time": "2021-01-22T09:19:47+00:00"
"time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.22.1",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248"
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
},
"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/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"shasum": ""
},
"require": {
@ -1153,7 +1261,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1161,12 +1269,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"classmap": [
"Resources/stubs"
]
@ -1196,7 +1304,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.26.0"
},
"funding": [
{
@ -1212,20 +1320,20 @@
"type": "tidelift"
}
],
"time": "2021-01-22T09:19:47+00:00"
"time": "2022-05-24T11:49:31+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.22.1",
"version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9"
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
},
"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/bf44a9fd41feaac72b074de600314a93e2ae78e2",
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
"shasum": ""
},
"require": {
@ -1234,7 +1342,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.26-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1242,12 +1350,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
},
"files": [
"bootstrap.php"
]
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@ -1272,7 +1380,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0"
},
"funding": [
{
@ -1288,22 +1396,22 @@
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
"time": "2022-05-24T11:49:31+00:00"
}
],
"packages-dev": [
{
"name": "bamarni/composer-bin-plugin",
"version": "1.4.1",
"version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/bamarni/composer-bin-plugin.git",
"reference": "9329fb0fbe29e0e1b2db8f4639a193e4f5406225"
"reference": "49934ffea764864788334c1485fbb08a4b852031"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/9329fb0fbe29e0e1b2db8f4639a193e4f5406225",
"reference": "9329fb0fbe29e0e1b2db8f4639a193e4f5406225",
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/49934ffea764864788334c1485fbb08a4b852031",
"reference": "49934ffea764864788334c1485fbb08a4b852031",
"shasum": ""
},
"require": {
@ -1338,9 +1446,9 @@
],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
"source": "https://github.com/bamarni/composer-bin-plugin/tree/master"
"source": "https://github.com/bamarni/composer-bin-plugin/tree/v1.5.0"
},
"time": "2020-05-03T08:27:20+00:00"
"time": "2022-02-22T21:01:25+00:00"
}
],
"aliases": [],
@ -1353,11 +1461,12 @@
"ext-intl": "*",
"ext-json": "*",
"ext-hash": "*",
"ext-filter": "*",
"ext-dom": "*"
},
"platform-dev": [],