Compare commits

...

268 Commits

Author SHA1 Message Date
J. King 1ae3c33344 Be more specific about coverage of Database class 2 months ago
J. King aed3749da8 Shore up coverage 2 months ago
J. King b68a68b500 Update changelog 2 months ago
J. King ade1c79361 Fix language-loading loop by applying incrementally 2 months ago
J. King 0170ec19c7 Fix language-loading infinite loop when throwing exceptions 2 months ago
J. King 8834a65e4c Address case where user is already arsse 8 months ago
J. King b1154359e4 Prepare release 8 months ago
J. King 3838cdc0af Merge branch 'arch2' 8 months ago
J. King 1f9beb85a5 Fix socket path 8 months ago
J. King 2670ed4ab8 Typo 8 months ago
J. King 4df97eefcb Oops 8 months ago
J. King 82f94d1dae Remove obsolete systemd patching 8 months ago
J. King 7f6b36d4da Remove references to Pandoc 8 months ago
J. King 06ec67816a Update arsse-git PKGBUILD 9 months ago
J. King e647d79e1e Update dependencies 9 months ago
J. King f853851568 Run with the correct executable name visible to PHP 9 months ago
J. King 4131531bff Tweaks 9 months ago
J. King 9086a5d9b1 Add interpreter adaptation for service, with documentation 9 months ago
J. King cce48878e7 Add pool for php-legacy 9 months ago
J. King 185ae88ba3 Correct outdated documentation 9 months ago
J. King 29fb134633 First steps in supporting php-legacy in Arc 9 months ago
J. King 9951b44932 Update changelog 11 months ago
J. King 692af39768 Use mdoc manual directly without any preprocessing 11 months ago
J. King 73446887f5 Editorial tweak 11 months ago
J. King e20937f98f The rest of the mdoc manual 11 months ago
J. King 2ff3286aa9 More work on mdoc manual 11 months ago
J. King 174ed544b2 Start on an mdoc-format manual 11 months ago
J. King 5579144fee Complete native groff manual 11 months ago
J. King 7613142221 Start on a native groff manual 11 months ago
J. King d9b90390e7 Update style rules 1 year ago
J. King 59a9329032 Upgrade dependencies where possible with PHP 7.3 2 years ago
J. King be3adf7026 Document RoboFile better 2 years ago
J. King eb371b75fe Fix documentation errors 2 years ago
J. King 1b80ad37bc Merge branch 'csfixer3' 2 years ago
J. King 3c83fc9139 Update php-cs-fixer rules 2 years ago
J. King 711f87aad8 Housekeeping 2 years ago
J. King 0a8d19d37d Require PHP 7.3 2 years ago
J. King fe06ffc176 Avoid dynamic property creation with PicoFeed 2 years ago
J. King 0d6f8d2921 Avoid most deprecation warnings 2 years ago
J. King 92b1a840a1 Support PHP 8.2 properly 2 years ago
J. King a25e777ec6 Version bump 2 years ago
J. King 44e2c9c13e Update documentation 2 years ago
J. King 866800dcc5 Finish last Guzzle-related tests 2 years ago
J. King 136d3782e3 Update changelog 2 years ago
J. King 3be3f43bab Start on tests for response wrappers 2 years ago
J. King d2f3f19128 Fix failures 2 years ago
J. King 459e44e041 Address remaining errors 2 years ago
J. King 56f015bfb9 More Guzzle conversion 2 years ago
J. King 64ec3f6ae4 Use unused variable 2 years ago
J. King 4d18bf27e2 Adjust most uses of Diactoros to Guzzle PSR-7 2 years ago
J. King e588a52e88 Replace ServerRequestFactory 2 years ago
J. King 6c0183faea Replace instances of Diactoros' EmptyResponse 2 years ago
J. King 560d4db139 Remove Diactoros in favour of Guzzle PSR-7 2 years ago
J. King 2557c22410 Update dependencies 2 years ago
J. King 4ca7b65a65 Update dependencies 2 years ago
J. King 4d37ae30ae Update dependencies 2 years ago
J. King d1da6fbe5e Use cases rather than casting bools to int in SQL 2 years ago
J. King d54733ad98 Update link to Nextcloud News documentation again 2 years ago
J. King a0c31fac5d Merge branch 'reader' 2 years ago
J. King 59358ec35b More PHP 7 fixes 2 years ago
J. King 90b66241b3 Fixes for PHP 7 2 years ago
J. King 761b3d5333 Return removed articles correctly in Miniflux 2 years ago
J. King d64dc751f9 Tests for query filters 2 years ago
J. King f51acb4264 Build exceptions correctly in Miniflux for clarity 2 years ago
J. King 300225439c Fix trivial error in Miniflux 2 years ago
J. King c6cc2a1a42 Restore coverage for Query class 2 years ago
J. King a44fe103d8 Prototype for nesting query filters 2 years ago
J. King 630536d789 Tests for union context 2 years ago
J. King 206c5c0012 Fill in union context 2 years ago
J. King 0c8f33c37c Remove setCTE and pushCTE from query builder 2 years ago
J. King 26e431b1a5 Simplify more queries 2 years ago
J. King 336207741d Add missing API documentation 2 years ago
J. King 6863c182d7 Update reference to the "Reeder" client 2 years ago
J. King f2aad7188c Update links to TT-RSS documentation 2 years ago
J. King 65b1bb4fcd Allow multiple dates in TT-RSS searches 2 years ago
J. King 2c5b9a6768 Fix missing TTRSS coverage 2 years ago
J. King 17832ac63e Allow timezone in TT-RSS search queries 2 years ago
J. King e65069885b Clean up obsolete FIXMEs 2 years ago
J. King 7e5d8494c4 Tests for selecting arrays of ranges 2 years ago
J. King e6505a5fda Work around possible MySQL bug 2 years ago
J. King 2acacd2647 Implement handling for arrays of ranges 2 years ago
J. King f6799e2ab1 Tests for date ranges in contexts 2 years ago
J. King 33a3478a58 Avoid use of PHP 7.4 feature 2 years ago
J. King 2489743d0f Further simplifications 2 years ago
J. King 0bd01849bb Remove unnecessary in() clause 2 years ago
J. King 895c045c9b Simplify folder selection in article queries 2 years ago
J. King fe02613214 Fix coverage 2 years ago
J. King 427bddd3b7 Allow multiple date ranges 2 years ago
J. King 53ba591720 Finish up article selection refactor 2 years ago
J. King 97dfef3267 Fix typos 2 years ago
J. King 396ca86482 Start on removal of conditional CTEs 2 years ago
J. King 4a87926dd5 Fix up context tests 2 years ago
J. King 6f1332c559 Start to shore up testing 2 years ago
J. King 308b592b18 Clean up coontext classes 2 years ago
J. King 983fa58ec8 Convert article and edition ranges to atomic 2 years ago
J. King 2c2bb4a856 Retrofits dates to use ranges 2 years ago
J. King c993168002 Update URL of Nextcloud News documentation 2 years ago
J. King 73497688fc Break contexts up into traits 2 years ago
J. King 1b0256d6ce Abandon automation of binary packaging for now 2 years ago
J. King 144a41e061 Prepare new version 2 years ago
J. King 60b4002329 Revert "Document that we actually emulate Miniflux 2.0.29" 2 years ago
J. King f24ec8b00b Address security vulnerability in Guzzle's PSR-7 2 years ago
J. King d379aa2253 Document that we actually emulate Miniflux 2.0.29 3 years ago
J. King b707ecc942 Tag new version 3 years ago
J. King afe26fb8e1 Style fixes 3 years ago
J. King 3a219a591d Update dependencies 3 years ago
J. King b5579d6e43 Support PHP 8.1 3 years ago
J. King b660508009 Improve MySQL test performance 3 years ago
J. King 3c884f521b Update dependencies 3 years ago
J. King 70b063e028 Make parts of generic packaging conditional 3 years ago
J. King cf3d270077 Merge branch 'deb' 3 years ago
J. King 1fa75aba4a Generate Debian source package without deb tooling 3 years ago
J. King 317d23c1bb Fix copy-paste error in manual 3 years ago
J. King 75dbe380ba Add Pandoc to AUR arsse-git build dependencies 3 years ago
J. King 08250841a0 Don't sign packages 3 years ago
J. King 2452264893 Date release 3 years ago
J. King c1e57eb01f Add manual installation instructions 3 years ago
J. King e75e0dfd2f Clarify exactly what "older Debians" is 3 years ago
J. King 6c11c9e485 Fix Debian bugs 3 years ago
J. King 40a2856ae8 Use correct PHP_FPM socket paths for Debian 3 years ago
J. King c7dcc36ba1 Update version 3 years ago
J. King a31fb896d9 Update changelog 3 years ago
J. King def4a3bc77 Move Debian adaptations to Debian packaging rules 3 years ago
J. King cd89472575 Fix up Debian documentation 3 years ago
J. King beea98040c Initial documentation for Debian packages 3 years ago
J. King 59ff88f3b6 Add all-in-one packaging task 3 years ago
J. King 4070870421 Enforce external tooling requirements 3 years ago
J. King 5ab9dc3840 Add missing pbuilder script 3 years ago
J. King 20ffb2484a Simply Robo input for Arch and Deb packaging 3 years ago
J. King f91b3c0120 Output packages to a "release" directory 3 years ago
J. King 4121fc3e21 Database server ports must be integers 3 years ago
J. King 7ad3611a84 Set up configuration file for Debian properly 3 years ago
J. King 5412eb348f Clean up maintainer scripts 3 years ago
J. King c936ecc1af Fix another typo 3 years ago
J. King 99c923b1b1 Fix typos 3 years ago
J. King c2237532eb Add glue for dbconfig-common configuration 3 years ago
J. King 9687ce026e Add MySQL back to Debian depeendencies 3 years ago
J. King 30bed8a9d5 Typo 3 years ago
J. King cf9059c2b0 Update tooling 3 years ago
J. King 93bcf93685 Prototype Debian maintainer scripts 3 years ago
J. King 46e20be983 Test for service reloading 3 years ago
J. King ad32bf3340 Style fixes 3 years ago
J. King b8ac646d22 Fix up hangup signal handling 3 years ago
J. King 37c58e186a Handle hangup signal 3 years ago
J. King 88fe3e76cb Fix up missing-extension message 3 years ago
J. King 3c8ee42666 Basic tests for exception checking 3 years ago
J. King 04adc3b997 Document forking in the manpage 3 years ago
J. King c49cb72528 Fail gracefully when extensions are missing 3 years ago
J. King c9a2393a4e Note requirement for filter extension 3 years ago
J. King 75e87f31a0 Prototype code to check for missing extensions 3 years ago
J. King 3b51d4daea Fix license for Debian package 3 years ago
J. King ce9dfc3f30 Add init script to Debian files 3 years ago
J. King cbc7cd8ea7 Add an explicit path to init script 3 years ago
J. King 2e29f3f76e Correct typo 3 years ago
J. King 8a1a1eee42 Prototype init script 3 years ago
J. King e160189224 Handle exceptions from child processes 3 years ago
J. King e9394e8599 More forking tweaks 3 years ago
J. King 577356cd3d Fork error test 3 years ago
J. King 514cb0a351 Ow 3 years ago
J. King 0bb5e916d2 Test PID writing 3 years ago
J. King 2767ab755e Use D modifier in pattern 3 years ago
J. King a4036afbf8 Partial tests for PID file reading 3 years ago
J. King 32c9d761c3 Clean up more exceptions 3 years ago
J. King 5b3e8fbef0 Refine some exceptions 3 years ago
J. King b9fd9ac32e Tweaks 3 years ago
J. King 23749b51aa Tests for path resolution 3 years ago
J. King dfaf44ac68 Basic path resolution tests 3 years ago
J. King bab64add9b Separate PID conflict checking from PID claiming 3 years ago
J. King 822158d1bd Update dependencies 3 years ago
J. King f1c29c99c7 Finish testing PID file path checking 3 years ago
J. King 59cf27089a More daemon cleanup 3 years ago
J. King 4e1193bab2 Move forking daemon support code to own class 3 years ago
J. King 32e04e3938 Move forking and related to Service class 3 years ago
J. King 55acb87577 Start on PI(D file resolution tests 3 years ago
J. King e8cab78bd6 Handle last possible PID failures 3 years ago
J. King 9595c4f019 Start filling out PID file exceptions 3 years ago
J. King 372bf9f630 Exclude code from coverage 3 years ago
J. King 4ffc29781d Remove references to oldpass param 3 years ago
J. King 47af739e47 Catch more PID path failures 3 years ago
J. King 2c7b16ed27 Respond to termination signals and delete PID file 3 years ago
J. King 410310282f Load configuration after forking 3 years ago
J. King 29b83b4453 Prototype forking daemon 3 years ago
J. King fc2abc1203 Use D modifier for all patterns with $ anchors 3 years ago
J. King 59c5c2eb14 Oops 3 years ago
J. King 3cd3ac4a51 Correct filename conflict 3 years ago
J. King 837895fd6a Adapt dist files for Debian 3 years ago
J. King b4c9413130 Update README 3 years ago
J. King bafb788b02 Correct errors in manual 3 years ago
J. King 68e3cd82ca Don't include section number in title 3 years ago
J. King c3fa4788d6 Use proper metadata block for manpage 3 years ago
J. King 3567f294a6 Merge branch 'manpage' 3 years ago
J. King 8c0f047747 Update HTML manual to mention man page 3 years ago
J. King fd76b1b611 Add examples to manual page 3 years ago
J. King 4317a96db1 Work around double spacing 3 years ago
J. King 62d49e0d3c Fill out most of the manual page 3 years ago
J. King 88487d27a2 Expand manual page 3 years ago
J. King 46c88f584f Fix copying of man page in PKGBUILDs 3 years ago
J. King 92823d5bc2 Create directories before executing Pandoc 3 years ago
J. King 3e55ab3849 Move man pages to their own directory 3 years ago
J. King 2ec7acc50b Turn off "smart" character substitution in Pandoc 3 years ago
J. King d3a983e7f0 Move the markdown manpage 3 years ago
J. King 176aac0ad7 Fix stupid typo properly 3 years ago
J. King e439dd8277 Fix manpage in Arch PKGBUILD 3 years ago
J. King 6cc9f96728 Prototype manual page 3 years ago
J. King d4569c77a9 Add database location to tmpfiles 3 years ago
J. King add1acc87a Fix more lintian complaints 3 years ago
J. King 14d3cdfe58 Hopefully fix some Debian problems 3 years ago
J. King 281760be71 Address some lintian complaints 3 years ago
J. King 758a02d667 Move generic configuration file 3 years ago
J. King 18846c19cb Add install list for Debian package 3 years ago
J. King b5bbdc2bc6 Date release 3 years ago
J. King 3be6c9984d Update Apache documentation in manual 3 years ago
J. King 6c84b2199e More Apache fixes 3 years ago
J. King f9cbac2c31 Hopefully fix Apache configuration 3 years ago
J. King 32ca0c3fe4 Appease GitHub once and for all 3 years ago
J. King a81bd0e45c Add whitespace 3 years ago
J. King 86d82a2586 Use global flag when replacing with sed 3 years ago
J. King f0bf55f9cf Add ExecStart to parent systemd unit 3 years ago
J. King 1055611940 Add version constraints to Arch dependencies 3 years ago
J. King 2ccfb1fd33 Fix packaging process 3 years ago
J. King 9eabfd0f27 Fix up sed usage in PKGBUILD 3 years ago
J. King 0236b42052 Use tmpfiles to create link to config file 3 years ago
J. King 8aa9d81fd1 Update changelog 3 years ago
J. King 11fc83da60 Significant edits to the manual 3 years ago
J. King de55290746 Fix build dependencies for Deb package 3 years ago
J. King f844c17a94 More Debian fixes 3 years ago
J. King 0de9647809 Add compat file 3 years ago
J. King e653fb3f73 Enhancements to Debian files 3 years ago
J. King b7909d7cd3 Downgrade tool dependencies for Ubuntu 3 years ago
J. King 3c9f4dd66f Prototype Debian rules file 3 years ago
J. King 3537e74d49 Update dependencies 3 years ago
J. King d031d931a5 Tidy up the Robo file further 3 years ago
J. King 38cb1059b2 Shorten output of packaging task 3 years ago
J. King 16174f11b6 Add changelog parsing to packaging task 3 years ago
J. King 073f6b3c39 Prototype Debian control file and other changes 3 years ago
J. King 3f3f449da1 Re-organize manual 3 years ago
J. King 2260b7cc50 Back up all Web server configuration 3 years ago
J. King 61eb4a252e Fix doc URLs 3 years ago
J. King 3f401f1cfa Fix typo 3 years ago
J. King 6c750d2dc0 Documentation for installing on Arch 3 years ago
J. King 6d790c5efd Add prototype for new Apache configuration 3 years ago
J. King 3a3b9231df Use generic configuration where possible 3 years ago
J. King fbe03a2534 Use chmod instead of touch 3 years ago
J. King e75f8cebfb Add Arch packaging to Robo file 3 years ago
J. King 79391446cd Start moving Arch build responsibility to Robo 3 years ago
J. King 19ab9df063 Fix more bugs 3 years ago
J. King 568b12600b Drop privileges when executing CLI 3 years ago
J. King 488af80a85 Update changelog 3 years ago
J. King 44612cfe8f Add tmpfiles 3 years ago
J. King d1fd6e9653 Correct permissions 3 years ago
J. King a97ca23631 Don't try to enable extensions 3 years ago
J. King e2b182ebe6 Fix errors in Arch config file 3 years ago
J. King 3eab5aad5d Fix adding users to a blank database 3 years ago
J. King 805a508ea6 Use correct state path 3 years ago
J. King 3ebc23ab13 Tweaks 3 years ago
J. King 7abdf05b7f Make package from local files for now 3 years ago
J. King 971c12ff9f Rename sample to example 3 years ago
J. King febc7c7ca4 Add configuration for Nginx 3 years ago
J. King edb146b826 Use PHP-FPM instead of uWSGI 3 years ago
J. King 7ba4cabdde Prototype Arch PKGBUILD and supporting files 3 years ago
J. King 4080b2d09d Apply new rules 3 years ago
J. King 73731fa9db Fix up CS config file 3 years ago
J. King 18d296dcd6 Clean up CS fixer rules 3 years ago
J. King 114dcc568f Update dependencies 3 years ago
Dustin Wilson 1331b14a04 Reverting for now 3 years ago
Dustin Wilson 035feae0ce Removed postcss in favor of sass for building manual theme 3 years ago
J. King 8e063bea2f Appease GitHub again 3 years ago
J. King 4a9e66d872 Fix inconsistent grammar 4 years ago
  1. 20
      .gitignore
  2. 33
      .php-cs-fixer.dist.php
  3. 75
      CHANGELOG
  4. 46
      README.md
  5. 602
      RoboFile.php
  6. 16
      UPGRADING
  7. 6
      arsse.php
  8. 33
      composer.json
  9. 830
      composer.lock
  10. 23
      dist/apache.conf
  11. 5
      dist/apache/arsse-fcgi.conf
  12. 34
      dist/apache/arsse-loc.conf
  13. 6
      dist/apache/arsse.conf
  14. 9
      dist/apache/example.conf
  15. 64
      dist/arch/PKGBUILD
  16. 79
      dist/arch/PKGBUILD-git
  17. 6
      dist/arch/apache-arsse-fcgi.conf
  18. 28
      dist/arch/arsse
  19. 37
      dist/arch/arsse-fetch.service
  20. 13
      dist/arch/arsse.service
  21. 16
      dist/arch/nginx-arsse-fcgi.conf
  22. 1
      dist/arch/systemd-environment
  23. 10
      dist/arsse
  24. 15
      dist/arsse.service
  25. 8
      dist/config.php
  26. 16
      dist/debian/arsse.config
  27. 1
      dist/debian/arsse.dirs
  28. 18
      dist/debian/arsse.install
  29. 1
      dist/debian/arsse.links
  30. 29
      dist/debian/arsse.postinst
  31. 20
      dist/debian/arsse.postrm
  32. 16
      dist/debian/arsse.prerm
  33. 1
      dist/debian/compat
  34. 15
      dist/debian/config.php
  35. 32
      dist/debian/control
  36. 34
      dist/debian/copyright
  37. 44
      dist/debian/dbconfig-common.php
  38. 6
      dist/debian/lintian-overrides
  39. 40
      dist/debian/pbuilder.sh
  40. 26
      dist/debian/rules
  41. 1
      dist/debian/source/format
  42. 2
      dist/debian/source/lintian-overrides
  43. 78
      dist/init.sh
  44. 342
      dist/man/man1/arsse.1
  45. 75
      dist/nginx.conf
  46. 15
      dist/nginx/arsse-fcgi.conf
  47. 49
      dist/nginx/arsse-loc.conf
  48. 13
      dist/nginx/arsse.conf
  49. 13
      dist/nginx/example.conf
  50. 11
      dist/php-fpm.conf
  51. 36
      dist/systemd/arsse-fetch.service
  52. 14
      dist/systemd/arsse.service
  53. 1
      dist/sysuser.conf
  54. 5
      dist/tmpfiles.conf
  55. 16
      docs/en/020_Getting_Started/010_Requirements.md
  56. 41
      docs/en/020_Getting_Started/020_Download_and_Installation.md
  57. 71
      docs/en/020_Getting_Started/020_Download_and_Installation/010_On_Arch_Linux.md
  58. 72
      docs/en/020_Getting_Started/020_Download_and_Installation/020_On_Debian_and_Derivatives.md
  59. 53
      docs/en/020_Getting_Started/020_Download_and_Installation/999_ On_Other_Systems.md
  60. 16
      docs/en/020_Getting_Started/020_Download_and_Installation/index.md
  61. 124
      docs/en/020_Getting_Started/030_Web_Server_Configuration.md
  62. 14
      docs/en/020_Getting_Started/040_Database_Setup/000_SQLite.md
  63. 2
      docs/en/020_Getting_Started/040_Database_Setup/010_PostgreSQL.md
  64. 2
      docs/en/020_Getting_Started/040_Database_Setup/020_MySQL.md
  65. 18
      docs/en/020_Getting_Started/050_Configuration.md
  66. 3
      docs/en/020_Getting_Started/index.md
  67. 22
      docs/en/025_Using_The_Arsse/010_Managing_Users.md
  68. 8
      docs/en/025_Using_The_Arsse/020_Importing_and_Exporting.md
  69. 49
      docs/en/025_Using_The_Arsse/030_Keeping_Newsfeeds_Up_to_Date.md
  70. 34
      docs/en/025_Using_The_Arsse/030_Other_Topics.md
  71. 12
      docs/en/025_Using_The_Arsse/040_Upgrading_to_a_New_Version.md
  72. 15
      docs/en/025_Using_The_Arsse/index.md
  73. 1
      docs/en/030_Supported_Protocols/005_Miniflux.md
  74. 2
      docs/en/030_Supported_Protocols/010_Nextcloud_News.md
  75. 4
      docs/en/030_Supported_Protocols/020_Tiny_Tiny_RSS.md
  76. 4
      docs/en/040_Compatible_Clients.md
  77. 14
      lib/AbstractException.php
  78. 33
      lib/Arsse.php
  79. 252
      lib/CLI.php
  80. 5
      lib/Conf.php
  81. 1
      lib/Conf/Exception.php
  82. 28
      lib/Context/AbstractContext.php
  83. 36
      lib/Context/BooleanMembers.php
  84. 41
      lib/Context/Context.php
  85. 251
      lib/Context/ExclusionContext.php
  86. 262
      lib/Context/ExclusionMembers.php
  87. 21
      lib/Context/RootContext.php
  88. 51
      lib/Context/UnionContext.php
  89. 634
      lib/Database.php
  90. 1
      lib/Db/AbstractDriver.php
  91. 1
      lib/Db/AbstractResult.php
  92. 1
      lib/Db/AbstractStatement.php
  93. 1
      lib/Db/Driver.php
  94. 1
      lib/Db/Exception.php
  95. 1
      lib/Db/ExceptionInput.php
  96. 1
      lib/Db/ExceptionRetry.php
  97. 1
      lib/Db/ExceptionTimeout.php
  98. 9
      lib/Db/MySQL/Driver.php
  99. 5
      lib/Db/MySQL/ExceptionBuilder.php
  100. 4
      lib/Db/MySQL/PDODriver.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/
/arsse.db*
/config.php
/.php_cs.cache
/yarn-error.log
/.php-cs-fixer.cache
/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

33
.php_cs.dist → .php-cs-fixer.dist.php

@ -4,6 +4,7 @@
* See LICENSE and AUTHORS files for details */
declare(strict_types=1);
namespace JKingWeb\Arsse;
const BASE = __DIR__.DIRECTORY_SEPARATOR;
@ -13,7 +14,10 @@ $paths = [
BASE."arsse.php",
BASE."RoboFile.php",
BASE."lib",
BASE."tests",
BASE."tests/cases",
BASE."tests/lib",
BASE."tests/bootstrap.php",
BASE."tests/server.php",
];
$rules = [
// house rules where PSR series is silent
@ -35,6 +39,7 @@ $rules = [
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true, // this could probably use more configuration
'no_mixed_echo_print' => ['use' => "echo"],
'no_short_bool_cast' => true,
@ -48,28 +53,16 @@ $rules = [
'pow_to_exponentiation' => true,
'set_type_to_cast' => true,
'standardize_not_equals' => true,
'trailing_comma_in_multiline_array' => true,
'trailing_comma_in_multiline' => ['elements' => ["arrays"]],
'unary_operator_spaces' => true,
'yoda_style' => false,
// PSR standard to apply
'@PSR2' => true,
// PSR-12 rules; php-cs-fixer does not yet support PSR-12 natively
'compact_nullable_typehint' => true,
'declare_equal_normalize' => ['space' => "none"],
'function_typehint_space' => true,
'lowercase_cast' => true,
'lowercase_static_reference' => true,
'no_alternative_syntax' => true,
'no_empty_statement' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_whitespace_in_blank_line' => true,
'return_type_declaration' => ['space_before' => "none"],
'single_trait_insert_per_statement' => true,
'short_scalar_cast' => true,
'visibility_required' => ['elements' => ["const", "property", "method"]],
'@PSR12' => true,
// house exceptions to PSR rules
'braces' => ['position_after_functions_and_oop_constructs' => "same"],
'curly_braces_position' => [
'functions_opening_brace' => "same_line",
'classes_opening_brace' => "same_line",
],
'function_declaration' => ['closure_function_spacing' => "none"],
'new_with_braces' => false, // no option to specify absence of braces
];
@ -82,4 +75,4 @@ foreach ($paths as $path) {
$finder = $finder->in($path);
}
}
return \PhpCsFixer\Config::create()->setRiskyAllowed(true)->setRules($rules)->setFinder($finder);
return (new \PhpCsFixer\Config)->setRiskyAllowed(true)->setRules($rules)->setFinder($finder);

75
CHANGELOG

@ -1,3 +1,69 @@
Version 0.??.? (2024-??-??)
===========================
Bug fixes:
- Do not hang when language files are missing or corrupted
Version 0.10.5 (2024-01-10)
===========================
Changes:
- Require PHP 7.3
- Adapt the Arch package to make using alternative PHP interpreters easier
(see manual for details)
- Multiple editorial and stylistic changes to the UNIX manual page
Version 0.10.4 (2023-01-24)
===========================
Changes:
- Support PHP 8.2
Version 0.10.3 (2022-09-14)
===========================
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
- Address CVE-2022-31090, CVE-2022-31091, CVE-2022-29248, and CVE-2022-31109
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)
==========================
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)
==========================
@ -5,7 +71,7 @@ Bug fixes:
- Respond to PUT requests with 201 rather than 200 in Miniflux
Changes:
- Corrected Web server configuration in manual
- Correct Web server configuration in manual
Version 0.9.0 (2021-03-06)
==========================
@ -21,7 +87,7 @@ Bug fixes:
- Further relax Fever HTTP correctness, to fix more clients
- Use icons specified in Atom feeds when available
- Do not return null as subscription unread count
- Explicitly forbid U+003A COLON and control characters in usernames, for
- Explicitly forbid U+003A COLON and control characters in usernames, for
compatibility with RFC 7617
- Never return 401 in response to an OPTIONS request
- Accept "t" and "f" as booleans in Tiny Tiny RSS
@ -118,7 +184,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
@ -238,4 +304,5 @@ Bug fixes:
Version 0.1.0 (2017-08-29)
==========================
Initial release
New features:
- Initial release

46
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, manual pages, 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 written in [mdoc](https://man.archlinux.org/man/extra/mandoc/mandoc_mdoc.7.en) format, which can be found 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 |
@ -62,19 +64,19 @@ PHPUnit's configuration can be customized by copying its configuration file to `
The `/vendor-bin/` directory houses the files needed for the tools used in The Arsse's programming environment. These are managed by the Composer ["bin" plugin](https://github.com/bamarni/composer-bin-plugin) and are not used by The Arsse itself. The following files are also related to various programming tools:
| Path | Description |
|-------------------|----------------------------------------------------------|
| `/.gitattributes` | Git settings for handling files |
| `/.gitignore` | Git file exclusion patterns |
| `/.php_cs.dist` | Configuration for [php-cs-fixer](https://cs.symfony.com) |
| `/.php_cs.cache` | Cache for php-cs-fixer |
| `/composer.json` | Configuration for Composer |
| `/composer.lock` | Version synchronization data for Composer |
| `/RoboFile.php` | Task definitions for [Robo](https://robo.li/) |
| `/robo` | Simple wrapper for executing Robo on POSIX systems |
| `/robo.bat` | Simple wrapper for executing Robo on Windows |
| Path | Description |
|---------------------------|----------------------------------------------------------|
| `/.gitattributes` | Git settings for handling files |
| `/.gitignore` | Git file exclusion patterns |
| `/.php-cs-fixer.dist.php` | Configuration for [php-cs-fixer](https://cs.symfony.com) |
| `/.php-cs-fixer.cache` | Cache for php-cs-fixer |
| `/composer.json` | Configuration for Composer |
| `/composer.lock` | Version synchronization data for Composer |
| `/RoboFile.php` | Task definitions for [Robo](https://robo.li/) |
| `/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
@ -88,11 +90,11 @@ There is also a `test:quick` Robo task which excludes slower tests, and a `test:
### Test coverage
Computing the coverage of tests can be done by running `./robo coverage`, after which an HTML-format coverage report will be written to `/tests/coverage/`. Either [PCOV](https://github.com/krakjoe/pcov), [Xdebug](https://xdebug.org), or [phpdbg](https://php.net/manual/en/book.phpdbg.php) is required for this. PCOV is generally recommended as it is faster than Xdebug; phpdbg is faster still, but less accurate. If using either PCOV or Xdebug, the extension need not be enabled globally; PHPUnit will enable it when needed.
Computing the coverage of tests can be done by running `./robo coverage`, after which an HTML-format coverage report will be written to `/tests/coverage/`. Either [PCOV](https://github.com/krakjoe/pcov) or [Xdebug](https://xdebug.org) is required for this. PCOV is generally recommended as it is faster than Xdebug. Neither extension need be enabled globally; Robo will enable it when needed.
## Enforcing coding style
The [php-cs-fixer](https://cs.symfony.com) tool, executed via `./robo clean`, can be used to rewrite code to adhere to The Arsse's coding style. The style largely follows [PSR-2](https://www.php-fig.org/psr/psr-2/) with some exceptions:
The [php-cs-fixer](https://cs.symfony.com) tool, executed via `./robo clean`, can be used to rewrite code to adhere to The Arsse's coding style. The style largely follows [PSR-12](https://www.php-fig.org/psr/psr-12/) with some exceptions:
- Classes, methods, and functions should have their opening brace on the same line as the signature
- Anonymous functions should have no space before the parameter list
@ -107,13 +109,11 @@ The manual employs a custom theme derived from the standard Daux theme. If the s
## 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 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.

602
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 {
@ -54,8 +55,8 @@ class RoboFile extends \Robo\Tasks {
* tests/coverage/. Additional reports may be produced by passing
* arguments to this task as one would to PHPUnit.
*
* Robo first tries to use pcov and will fall back first to xdebug then
* phpdbg. Neither pcov nor xdebug need to be enabled to be used; they
* Robo first tries to use pcov and will fall back to xdebug.
* Neither pcov nor xdebug need to be enabled to be used; they
* only need to be present in the extension load path to be used.
*/
public function coverage(array $args): Result {
@ -79,9 +80,9 @@ class RoboFile extends \Robo\Tasks {
return $this->runTests($exec, "typical", array_merge(["--coverage-html", BASE_TEST."coverage"], $args));
}
/** Runs the coding standards fixer */
/** Runs the coding-style fixer */
public function clean($opts = ['demo|d' => false]): Result {
$t = $this->taskExec(norm(BASE."vendor/bin/php-cs-fixer"));
$t = $this->taskExec(norm(BASE."vendor-bin/csfixer/vendor/bin/php-cs-fixer"));
$t->arg("fix");
if ($opts['demo']) {
$t->args("--dry-run", "--diff")->option("--diff-format", "udiff");
@ -89,9 +90,10 @@ class RoboFile extends \Robo\Tasks {
return $t->run();
}
/** Finds the first suitable means of computing code coverage, either pcov or xdebug. */
protected function findCoverageEngine(): string {
$dir = rtrim(ini_get("extension_dir"), "/").\DIRECTORY_SEPARATOR;
$ext = IS_WIN ? "dll" : (IS_MAC ? "dylib" : "so");
$ext = IS_WIN ? "dll" : "so";
$php = escapeshellarg(\PHP_BINARY);
$code = escapeshellarg(BASE."lib");
if (extension_loaded("pcov")) {
@ -103,25 +105,27 @@ class RoboFile extends \Robo\Tasks {
} elseif (file_exists($dir."xdebug.$ext")) {
return "$php -d zend_extension=xdebug.$ext -d xdebug.mode=coverage";
} else {
if (IS_WIN) {
$dbg = dirname(\PHP_BINARY)."\\phpdbg.exe";
$dbg = file_exists($dbg) ? $dbg : "";
} else {
$dbg = trim(`which phpdbg 2>/dev/null`);
}
if ($dbg) {
return escapeshellarg($dbg)." -qrr";
} else {
return $php;
}
return $php;
}
}
/** Returns the necessary shell arguments to print error output or all output to the bitbucket
*
* @param bool $all Whether all output (true) or only error output (false) should be suppressed
*/
protected function blackhole(bool $all = false): string {
$hole = IS_WIN ? "nul" : "/dev/null";
return $all ? ">$hole 2>&1" : "2>$hole";
}
/** Executes PHPUnit, used by the test and coverage tasks.
*
* This also executes the built-in PHP Web server, which is required to fetch some newsfeeds during tests
*
* @param string $executor The path to the PHP binary to execute with any required extra arguments. Normally this is either "php" or the result of findCoverageEngine()
* @param string $set The set of tests to run, either "typical" (excludes redundant tests), "quick" (excludes redundant and slow tests), "coverage" (excludes tests not needed for coverage), or "full" (all tests)
* @param array $args Extra arguments passed by Robo from the command line
*/
protected function runTests(string $executor, string $set, array $args): Result {
switch ($set) {
case "typical":
@ -145,71 +149,270 @@ 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();
}
/** Returns a Git version string for a given Git tree-ish ID
*
* Returns an array containing the tree-ish string and the version string.
*
* @param string|null $commit The tree-ish ID. If not supplied the user will be prompted
*/
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];
}
/** Checks whether all the supplied terminal commands are available in path */
protected function toolExists(string ...$binary): bool {
$blackhole = $this->blackhole(IS_WIN);
foreach ($binary as $bin) {
if (!exec(escapeshellarg($bin)." --help $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")) {
throw new \Exception("Git is 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);
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
$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
$out = $t->run();
// clean the Git worktree list
$this->_exec("git worktree prune");
return $out;
$result = $this->taskExec("git worktree add ".escapeshellarg($dir)." ".escapeshellarg($version))->dir(BASE)->run();
if ($result->getExitCode() > 0) {
return $result;
}
try {
// 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));
if (file_exists($dir."docs") || file_exists($dir."manpages/en.md")) {
// 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."docs")) {
// generate the HTML manual
$t->addTask($this->taskExec("./robo manual -q")->dir($dir));
}
if (file_exists($dir."manpages/en.md")) {
// generate manpages (NOTE: obsolete process)
$t->addTask($this->taskExec("./robo manpage")->dir($dir));
}
}
// perform Composer installation in the temp location for final output
$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",
$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 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/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();
}
/** Generates static manual pages in the "manual" directory
/** 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();
}
/** Generates static HTML manual pages in the "manual" directory
*
* The resultant files are suitable for offline viewing and inclusion into release builds
*/
public function manual(array $args): Result {
$execpath = escapeshellarg(norm(BASE."vendor/bin/daux"));
$execpath = escapeshellarg(norm(BASE."vendor-bin/daux/vendor/bin/daux"));
$t = $this->collectionBuilder();
$t->taskExec($execpath)->arg("generate")->option("-d", BASE."manual")->args($args);
$t->taskDeleteDir(BASE."manual/daux_libraries");
@ -220,7 +423,7 @@ class RoboFile extends \Robo\Tasks {
/** Serves a live view of the manual using the built-in Web server */
public function manualLive(array $args): Result {
$execpath = escapeshellarg(norm(BASE."vendor/bin/daux"));
$execpath = escapeshellarg(norm(BASE."vendor-bin/daux/vendor/bin/daux"));
return $this->taskExec($execpath)->arg("serve")->args($args)->run();
}
@ -230,6 +433,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 +453,276 @@ class RoboFile extends \Robo\Tasks {
// execute the collection
return $t->run();
}
/** Parses the contents of the CHANGELOG file into an array structure
*
* This is done line-by-line and tends to be quite strict.
* The parsed output can be used to generate changelogs in other formats,
* such as a Debian changelog or RPM changelog.
*
* @param string $text The text of the CHANGELOG file
* @param string $targetVersion The x.y.z version number of the latest release. This is used to check that version numbers and dates have been updated when preparing a release
*/
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('/^ (\S.*)$/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;
}
/** Produce a Debian changelog from a parsed CHANGELOG file
*
* The Debian changelog format is extremely specific with certain tokens
* having special meaning and leading whitespace also being significant.
* Modifying this function should be done with extreme care.
*
* @param array $log The parsed chaneglog, output by changelogParse()
* @param string $targetVersion The second output of commitVersion()
*/
protected function changelogDebian(array $log, string $targetVersion): string {
$authorName = "J. King";
$authorMail = "jking@jkingweb.ca";
$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 -- $authorName <$authorMail> ".\DateTimeImmutable::createFromFormat("Y-m-d", $entry['date'], new \DateTimeZone("UTC"))->format("D, d M Y")." 00:00:00 +0000\n\n";
}
return $out;
}
/** Produces a Debian "source control" file from various bits of data
*
* As with a Debian changelog, the output is of a very exacting format,
* and this function should be modified with care.
*
* @param string $dir The path to Debian-specific files, with trailing slash
* @param string $version The Debian version string, in the format x.y.z-a
* @param array $tarballs An array of paths to the "orig" and "debian" tarball files
*/
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;
}
}

16
UPGRADING

@ -9,6 +9,22 @@ usually prudent:
- Check for any changes to sample systemd unit or other init files
- If installing from source, update dependencies with:
`composer install -o --no-dev`
Upgrading from 0.10.4 to 0.10.5
=============================
- PHP 7.3 is now required
- Web server configuration in the Arch Linux package has been modified to ease
the use of alternative PHP interpreters; please review the sample
configuration files for changes
Upgrading from 0.10.2 to 0.10.3
=============================
- The following Composer dependencies have been removed:
- laminas/laminas-diactoros
Upgrading from 0.8.5 to 0.9.0

6
arsse.php

@ -4,6 +4,7 @@
* See LICENSE and AUTHORS files for details */
declare(strict_types=1);
namespace JKingWeb\Arsse;
const BASE = __DIR__.DIRECTORY_SEPARATOR;
@ -13,7 +14,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
// NOTE: While running in the wild we don't want to spew deprecation warnings if users are ahead of us in PHP versions
error_reporting(\E_ALL & ~\E_DEPRECATED);
if (\PHP_SAPI === "cli") {
@ -25,8 +26,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();

33
composer.json