Compare commits

...

133 Commits

Author SHA1 Message Date
731a36d700 Remove the installed command
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 10m37s
Build / release (push) Successful in 10m8s
Since it is out of scope for this project.
2025-03-14 00:35:53 +01:00
8908b8ae93 Add a printer for HttpExceptionContent
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 11m5s
Build / release (push) Successful in 10m19s
2025-03-02 21:20:09 +01:00
1d81fea1a3 Remove extensions unused with GHC2024
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 12m13s
Build / release (push) Successful in 11m45s
2025-01-16 17:57:07 +01:00
e2debec6d7 Update to GHC 9.10
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 17m11s
Build / release (push) Successful in 16m37s
2025-01-08 23:44:49 +01:00
d043ba8844 Print shorter http exceptions
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 15m14s
2024-12-13 19:44:30 +01:00
e1ece39147 Show updatable local packages
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 14m18s
2024-11-29 21:46:59 +01:00
15cf346c61 Parse package names with a period
All checks were successful
Build / audit (push) Successful in 9s
Build / test (push) Successful in 14m10s
2024-11-27 22:41:03 +01:00
468852410e List installed packages from a repository
All checks were successful
Build / audit (push) Successful in 9s
Build / test (push) Successful in 16m24s
2024-11-25 17:08:28 +01:00
b5e6e3a2d6 Move package configuration to the configuration file
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 15m6s
2024-11-15 17:03:23 +01:00
2f46303a6d Support VCS clone configuration
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m32s
2024-11-14 22:58:14 +01:00
c7e300dc91 Unify the generation of gh package descriptions
All checks were successful
Build / audit (push) Successful in 9s
Build / test (push) Successful in 14m28s
2024-11-13 22:20:19 +01:00
bb0748b400 Replace deprecated cryptonite with crypton
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 13m20s
2024-10-30 22:46:07 +01:00
6290be859d Wrap common downloader fields into a record
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 15m2s
2024-10-01 19:54:32 +02:00
f395d57b33 Add version filter to the configuration
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 15m9s
2024-09-30 14:39:38 +02:00
8168804d71 Include repackaging command into configuration
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 15m0s
2024-09-29 21:24:40 +02:00
d9bfd2941c Filter versions in latestText
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m39s
2024-09-28 15:43:18 +02:00
ebbdb6f0f7 Make version picker a command
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 15m28s
2024-09-27 12:20:34 +02:00
f758ea7904 Implement experimental version picking command
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 14m39s
... for webex.
2024-09-24 21:28:01 +02:00
00cc58f87e Mix configuration and PackageDescription
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m41s
2024-09-22 18:07:22 +02:00
2a78256933 Add package tables to the configuration file
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 15m14s
2024-09-20 22:34:17 +02:00
ae63ff0cc0 Support HTTP and HTTPS URLs
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m19s
2024-09-20 17:52:09 +02:00
5b4caa8ff7 Generalize handleException
All checks were successful
Build / audit (push) Successful in 6s
Build / test (push) Successful in 14m55s
2024-09-14 11:32:34 +02:00
3dde41e0d4 Introduce a matcher for one or more matched digits
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 16m3s
2024-09-13 21:58:13 +02:00
74da0eb391 Consume tokens matching 0 characters at the end
Some checks failed
Build / audit (push) Failing after 1s
Build / test (push) Successful in 16m52s
2024-09-10 11:33:31 +02:00
6ead225e88 Add nginx
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m54s
2024-09-09 16:47:44 +02:00
1418e0ae46 Pretty print settings parsing errors
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 1h3m30s
2024-09-08 16:44:57 +02:00
4f74c2ec10 Support text based placeholders
All checks were successful
Build / audit (push) Successful in 9s
Build / test (push) Successful in 14m17s
2024-09-01 17:34:24 +02:00
14cc805dcf Display error descriptions
All checks were successful
Build / audit (push) Successful in 8s
Build / test (push) Successful in 14m18s
2024-08-20 22:36:43 +02:00
42b9b671e1 Fix GHC 9.8 warnings
All checks were successful
Build / audit (push) Successful in 7s
Build / test (push) Successful in 14m5s
2024-08-11 13:00:01 +02:00
e0ca80db32 Switch to buildenv for test builds
All checks were successful
Build / audit (push) Successful in 6s
Build / test (push) Successful in 15m27s
2024-08-09 10:04:40 +02:00
4ce20e3dd9 Provide own lzma conduit adapters
Some checks failed
Build / audit (push) Failing after 48s
Build / test (push) Failing after 16s
2024-08-08 11:03:02 +02:00
6d0248b4f8 Fix archive name generation
Some checks failed
Build / audit (push) Failing after 20s
Build / test (push) Failing after 19s
2024-05-25 07:54:05 +02:00
c81cabfcbf Replace extern rm rf call with a function
All checks were successful
Build / audit (push) Successful in 13m18s
Build / test (push) Successful in 14m23s
2024-05-14 19:05:41 +02:00
3b7b15f381 Fix filename of the reuploaded sources
All checks were successful
Build / audit (push) Successful in 13m13s
Build / test (push) Successful in 14m21s
2024-05-13 18:26:23 +02:00
f8ef93fde7 Support a custom upload command
All checks were successful
Build / audit (push) Successful in 13m47s
Build / test (push) Successful in 14m16s
2024-05-11 19:01:41 +02:00
6ba319c3b6 Describe features
All checks were successful
Build / audit (push) Successful in 14m9s
Build / test (push) Successful in 14m42s
2024-04-01 21:31:41 +02:00
ddda240e40 Describe configuration options
All checks were successful
Build / audit (push) Successful in 13m52s
Build / test (push) Successful in 14m33s
2024-03-31 17:06:54 +02:00
8351be053c Add a README
All checks were successful
Build / audit (push) Successful in 13m51s
Build / test (push) Successful in 14m42s
2024-03-27 20:01:08 +01:00
a98a6f8574 Add SIMD everywhere
All checks were successful
Build / audit (push) Successful in 16m0s
Build / test (push) Successful in 15m51s
2024-03-26 11:52:16 +01:00
47f27394de Reduce number of fetched tags by using a prefix
All checks were successful
Build / audit (push) Successful in 14m17s
Build / test (push) Successful in 14m20s
2024-03-25 18:36:15 +01:00
7c9c890056 Extern tag matcher with digit and dot patterns
All checks were successful
Build / audit (push) Successful in 14m36s
Build / test (push) Successful in 15m5s
2024-03-24 13:20:22 +01:00
7e59a8460d Add match function for simple tag globbing
All checks were successful
Build / audit (push) Successful in 14m54s
Build / test (push) Successful in 14m46s
2024-03-21 17:52:37 +01:00
bc3ba48d85 Recognize + in sematnic tags
All checks were successful
Build / audit (push) Successful in 14m54s
Build / test (push) Successful in 14m20s
2024-03-19 11:34:19 +01:00
3d81917627 Collect hash during creating an archive
All checks were successful
Build / audit (push) Successful in 13m45s
Build / test (push) Successful in 13m48s
2024-03-17 11:00:13 +01:00
cd28e6fb90 Switch to the haskell image
All checks were successful
Build / audit (push) Successful in 14m3s
Build / test (push) Successful in 13m54s
2024-03-06 15:08:01 +01:00
16c7063224 Make local paths relative to cwd
Some checks failed
Build / test (push) Failing after 5m55s
Build / audit (push) Successful in 13m8s
2024-03-05 23:06:32 +01:00
cd15b25db1 Read the dispositon header when downloading
Some checks failed
Build / audit (push) Successful in 14m57s
Build / test (push) Failing after 5m51s
2024-03-04 17:29:25 +01:00
e5bde183a5 Support extracting gzip on the fly
Some checks failed
Build / audit (push) Successful in 14m44s
Build / test (push) Failing after 5m47s
2024-03-03 17:12:29 +01:00
4c06ae274b Find the package category automatically
Some checks failed
Build / audit (push) Successful in 14m21s
Build / test (push) Failing after 5m36s
2024-02-18 18:28:27 +01:00
c8643a2fd4 Remove the source directory after repackaing
Some checks failed
Build / audit (push) Successful in 15m1s
Build / test (push) Failing after 6m29s
2024-01-28 13:35:53 +01:00
45472a9088 Get the checksum after repackaging
Some checks failed
Build / audit (push) Successful in 15m45s
Build / test (push) Failing after 6m19s
2024-01-24 14:34:58 +01:00
2802194063 Make is64 property part of the updater
All checks were successful
Build / audit (push) Successful in 14m26s
Build / test (push) Successful in 14m35s
2024-01-19 09:57:58 +01:00
7edb811dc2 Use consistent directory for cloning repositories
All checks were successful
Build / audit (push) Successful in 16m35s
Build / test (push) Successful in 16m41s
... with submodules.
2024-01-04 09:36:11 +01:00
a25655c2b2 Move latest version checker to a separate module
All checks were successful
Build / audit (push) Successful in 15m42s
Build / test (push) Successful in 15m43s
2024-01-01 19:44:45 +01:00
34d7dbd68f Add license information to all files
All checks were successful
Build / audit (push) Successful in 14m48s
Build / test (push) Successful in 15m54s
2023-12-23 22:15:10 +01:00
49cbda6027 Move newline after resetting the colour
All checks were successful
Build / audit (push) Successful in 14m52s
Build / test (push) Successful in 15m12s
2023-12-19 22:53:24 +01:00
eb68629653 Support x86-64 only downloads
All checks were successful
Build / audit (push) Successful in 16m16s
Build / test (push) Successful in 15m47s
2023-12-12 18:51:44 +01:00
6a063b2cc4 Accept up2date package parameter
All checks were successful
Build / audit (push) Successful in 16m10s
Build / test (push) Successful in 16m35s
2023-12-11 08:14:55 +01:00
e9504fb8e5 Replace clone command with the check command
All checks were successful
Build / audit (push) Successful in 15m55s
Build / test (push) Successful in 16m57s
2023-12-09 21:44:48 +01:00
ef0a5b5958 Add a linter action
Some checks failed
Build / audit (push) Successful in 15m51s
Build / test (push) Failing after 16m41s
2023-12-09 20:46:36 +01:00
49d6718fee Remove private build scripts and functions 2023-12-08 14:36:52 +01:00
3414a69bc8 Support GHC 9.4 2023-11-07 19:36:40 +01:00
9770cc8829 Remove gem and rake support files 2023-11-04 14:13:59 +01:00
0023fe0337 Remove unused tasks 2023-11-03 18:09:36 +01:00
24e62c3439 Update additional download versions in slackbuild 2023-11-01 19:07:49 +01:00
64233c4c63 Provide a name for additional downloads 2023-11-01 17:05:16 +01:00
396a536b3a d-tools: Migrate source downloads with git clone 2023-10-28 21:24:21 +02:00
f51a0418ff Support cloning downloads 2023-10-28 04:04:52 +02:00
fa6d93c5ca Allow updater save a function for each download
There are source that can be downloaded as archive, for example cloning
repositories with submodules. So how source are downloaded should be
changable per download.
2023-10-28 03:32:39 +02:00
6c0e2c2d24 Fix hardcoded repository path in the scp call 2023-10-26 19:40:47 +02:00
58a1b8864c Support additional downloads in the package 2023-10-24 21:06:37 +02:00
8a69240d88 Add librsync and dmd 2023-10-20 19:23:21 +02:00
3a6d17952b Allow looking on the text page for the latest version 2023-10-20 15:53:48 +02:00
4105ffa91f rdiff-backup: Migrated 2023-10-13 19:34:02 +02:00
5e161c3dad Support modifying reuploaded tarballs 2023-10-08 12:28:46 +02:00
f3beee3e19 Combine info file structures 2023-10-05 19:24:42 +02:00
7b5598a02e Validate the .info file 2023-10-04 22:36:19 +02:00
d5df676df7 Add module with an info file parser 2023-10-03 18:53:41 +02:00
f4b7883cf2 Migrate composer updater 2023-10-01 17:19:06 +02:00
69b24c6cfa universal-ctags: Finish migrating the updater 2023-09-27 19:58:16 +02:00
7c499bd3f7 universal-ctags: Add version path segment
… to the download URL.
2023-09-25 10:18:00 +02:00
ec704e267b Fix renderDownloadWithVersion concatenation order 2023-09-22 07:47:46 +02:00
840290491f Split the code into library and application 2023-09-22 07:33:02 +02:00
a7114618c1 Combine test and application dependencies 2023-09-21 23:51:02 +02:00
77c9a2ab54 Add a test module 2023-09-03 10:26:43 +02:00
c2b98ba395 Reimplement the info file printer 2023-08-28 21:05:47 +02:00
2126488066 Implement clone command in the binary 2023-08-25 10:30:24 +02:00
6983304b9d Download and determine the digest 2023-08-21 13:38:20 +02:00
258604f22d Support repository directory in the clone function 2023-08-18 07:50:18 +02:00
fd649b66f5 Implement remote file check as Haskell command 2023-08-17 22:07:09 +02:00
6b15ccd0f5 Support repository path in commits 2023-08-15 10:33:19 +02:00
5a9e87cd5f Move gh check to the Haskell binary 2023-08-10 12:47:43 +02:00
43ebbc5e67 Use TOML configuration 2023-08-09 20:59:42 +02:00
69ba04a731 Move text URL check to the Haskell binary 2023-08-06 14:25:19 +02:00
028f64d25a Move packagist check to a Haskell binary 2023-08-04 21:33:21 +02:00
1bc410d86d Add PHP updater 2023-08-01 18:03:00 +02:00
868f6c36a5 Update jitsi-meet-desktop automatically 2023-07-20 07:50:00 +02:00
bed90e3e02 rdiff-backup: Fix version detection 2023-07-13 18:03:02 +02:00
a0788d2f3a Ask for updating packages 2023-07-06 21:59:25 +02:00
df4c9b4ae9 Check the latest version from the LATEST text file 2023-06-30 11:02:20 +02:00
e0b98189eb Make v prefix default for tags 2023-06-28 23:47:21 +02:00
47e6c49ae2 Parse SET_HHVM_THIRD_PARTY_SOURCE_ARGS 2023-06-22 14:24:19 +02:00
d63e657948 Support version transformation for GitHub tags 2023-06-17 21:41:52 +02:00
6e313e2272 Make version output colorful 2023-05-29 22:17:35 +02:00
6a81f0959d Query packagist for the latest version 2023-05-24 12:56:55 +02:00
341eafcbf2 Parse package from the info file 2023-05-23 20:36:19 +02:00
f564676cb6 Add function to request latest github tag 2023-05-22 13:04:45 +02:00
04b24eeb99 Fix dmd calls to SlackBuilder module functions 2023-05-18 21:40:59 +02:00
bae3b8e90e Fix passing hhvm version as rake argument 2023-05-07 00:07:58 +02:00
6f5eaf9650 gcc-latest: Removed
There were still problems with this build. For example LibreOffice
cannot be built if GCC is installed.
2023-04-23 10:53:25 +02:00
691ddba017 Pull up the dependencies 2023-04-23 10:45:53 +02:00
79bdca04e2 Remove SBo differ experiment 2023-04-17 15:05:20 +02:00
34b10f41aa Retrieve updatable packages 2023-04-15 08:43:30 +02:00
dbf14caee2 ragel: Removed 2023-04-08 15:49:12 +02:00
b64a66a20c colm: Removed 2023-04-05 21:47:04 +02:00
ae0048ef3d Add command to clone the source repository 2023-04-02 12:46:44 +02:00
f46a16b4a0 Add an utility to list all installed packages 2023-04-01 14:17:08 +02:00
0385dbbe53 colm: Remove config.log
All checks were successful
test Test.
2023-03-30 08:48:44 +02:00
9c85c52599 ragel: Patch to link against shared colm
All checks were successful
test Test.
2023-03-30 08:46:51 +02:00
484d170b24 colm: patch to build a shared library
All checks were successful
test Test.
2023-03-29 17:18:43 +02:00
7becd04148 gcc-latest: Add the second linker error patch
All checks were successful
test Test.
2023-03-22 18:13:25 +01:00
c7a527e010 gcc-latest: Added a patch for immutable structs 2023-03-22 10:58:37 +01:00
6b634b4055 Replace eol ioncube with php82
Some checks reported warnings
test Test.
2023-03-18 13:15:12 +01:00
a24f1b436e gcc-latest: Updated for version 12.2.0 2023-02-20 10:49:27 +01:00
bd84f6bbf0 Revert "gcc-latest: Removed"
This reverts commit 729946afaf.
2023-02-20 08:57:04 +01:00
ad02a3fa38 php82: Removed 2023-02-18 09:48:36 +01:00
d07825f081 php82: Updated for version 8.2.3 2023-02-15 13:17:34 +01:00
49cb7d27eb php82: Updated to 8.2.2 2023-02-04 10:55:21 +01:00
6719d2d81d php81: Removed since same as php82 2023-01-31 18:36:21 +01:00
70a636a804 mysql: Removed 2023-01-21 11:27:09 +01:00
13d0def37a php81 and php82: Updated to 8.1.14 and 8.2.1
…respectively.
2023-01-20 12:32:13 +01:00
ef9942fe99 Move download functions into a module 2023-01-04 10:51:08 +01:00
5b26e7dca8 Support webex updates 2022-12-23 17:47:14 +01:00
58 changed files with 2127 additions and 1884 deletions

View File

@ -0,0 +1,37 @@
name: Build
on:
push:
pull_request:
branches: [master]
jobs:
audit:
runs-on: buildenv
steps:
- uses: actions/checkout@v4
- run: hlint src lib tests
test:
runs-on: buildenv
steps:
- name: Set up environment
run: |
apt-get update -y
apt-get upgrade -y
apt-get install -y pkg-config liblzma-dev
- uses: actions/checkout@v4
- run: cabal update
- run: cabal test --test-show-details=streaming
release:
runs-on: buildenv
steps:
- name: Set up environment
run: |
apt-get update -y
apt-get upgrade -y
apt-get install -y pkg-config liblzma-dev
- uses: actions/checkout@v4
- run: cabal update
- run: cabal build

View File

@ -0,0 +1,29 @@
name: Deploy
on:
push:
tags:
- '**'
jobs:
release:
runs-on: buildenv
steps:
- name: Set up environment
run: |
apt-get update -y
apt-get upgrade -y
apt-get install -y pkg-config liblzma-dev
- uses: actions/checkout@v4
- run: cabal update
- run: cabal build
- name: Archive
run: |
DISTRIBUTION=$(echo $GITHUB_REF_NAME | awk '{ gsub(/^v/, "slackbuilder-"); print $0 }')
cabal install --installdir=$DISTRIBUTION/bin --install-method=copy
strip $DISTRIBUTION/bin/slackbuilder
tar Jcvf $DISTRIBUTION.tar.xz $DISTRIBUTION
- uses: akkuman/gitea-release-action@v1
with:
files: "*.tar.xz"
token: ${{ secrets.API_KEY }}

4
.gitignore vendored
View File

@ -14,15 +14,15 @@
*.lz *.lz
*.pk3 *.pk3
*.run *.run
*.Z
*.deb *.deb
*.jar
*~ *~
.directory .directory
*.phar *.phar
/slackbuilds/ /slackbuilds/
/config/config.toml
/config/config.rb /config/config.rb
/vendor/ /vendor/
/.bundle/ /.bundle/
/pkg/ /pkg/
/dist-newstyle/

2
.hlint.yaml Normal file
View File

@ -0,0 +1,2 @@
arguments:
- -XQuasiQuotes

View File

@ -1,41 +0,0 @@
AllCops:
Exclude:
- 'vendor/**/*'
- '.git/**/*'
- 'slackbuilds/**/*'
- 'bin/bundle'
- 'bin/cap*'
- 'bin/rake'
- 'bin/rspec'
- 'bin/rubocop'
- 'bin/setup'
- 'bin/spring'
- 'bin/update'
- 'pkg/**/*'
TargetRubyVersion: '3.0'
NewCops: enable
SuggestExtensions: false
Style/Documentation:
Enabled: false
# False-Positive: non-string-variable + 'some string'
Style/StringConcatenation:
Enabled: false
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented
Layout/MultilineOperationIndentation:
EnforcedStyle: indented
Layout/ArgumentAlignment:
EnforcedStyle: with_fixed_indentation
Layout/EndAlignment:
EnforcedStyleAlignWith: variable
Metrics/BlockLength:
AllowedMethods:
- namespace

5
CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
# Revision history for slackbuilder
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

15
Gemfile
View File

@ -1,15 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
gem 'rake', '~> 13.0'
gem 'rubocop', '~> 1.7', require: false
gem 'progressbar', '~> 1.11'
gem 'term-ansicolor', '~> 1.7'

View File

@ -1,44 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
json (2.6.2)
parallel (1.22.1)
parser (3.1.2.1)
ast (~> 2.4.1)
progressbar (1.11.0)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.6.0)
rexml (3.2.5)
rubocop (1.38.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.1.2.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.23.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.23.0)
parser (>= 3.1.1.0)
ruby-progressbar (1.11.0)
sync (0.5.0)
term-ansicolor (1.7.1)
tins (~> 1.0)
tins (1.32.1)
sync
unicode-display_width (2.3.0)
PLATFORMS
ruby
DEPENDENCIES
progressbar (~> 1.11)
rake (~> 13.0)
rubocop (~> 1.7)
term-ansicolor (~> 1.7)
BUNDLED WITH
2.2.33

79
README.md Normal file
View File

@ -0,0 +1,79 @@
# SlackBuilder
SlackBuilder is a tool which aims to help to update Slackware packages.
It checks for the latest version of an upstream package and can modify
SlackBuild meta information accordingly.
## Features
- Querying various sources (like registries) for the latest upstream version.
Currently supported sources are:
- GitHub
- Packagist
- Remote text file containing a version number (like the LATEST file).
- Updating package version and checksum in the .info file;
Updating version variables in the .SlackBuild
- Updating packages with multiple sources. One source is assumed to be the main
source and match the version of the package. Other sources are just updated to
the latest version available for them.
- Modifying or just reuploading source tarballs to a different destination.
SlackBuilder can download the original source tarball, optionally extract and
modify its contents, and upload it to another server. It can be used for
example to download package dependencies to ship them all within a single
archive, so the package can be built offline.
## Build instructions
SlackBuilder is a Haskell program and can be built and run using the
Cabal build tool and package manager:
```sh
cabal build
```
After that you can run slackbuilder using Cabal and `cabal run slackbuilder`.
Or you can install the program locally with `cabal install` and run it just
as `slackbuilder` assuming `~/.cabal/bin` is on your PATH.
# Usage
## Configuration
There is a sample configuration file under `config/config.toml.example`.
The sample contains comments describing each supported option.
Just copy this file to `config/config.toml` and modify as needed.
Each package that should be updated automatically needs a special
description which contains links to the upstream repositories and
instructions how the sources should be prepared.
Unfortunately the only format currently supported for the package
descriptions is Haskell source code. But I'm planning to make it
possible to describe the packages without recompiling the slackbuilder
itself.
For the time being `src/Main.hs` contains descriptions of my
slackbuilds, that can be used as an example and a start point.
## Command line options
SlackBuilder is called with a command as its first argument:
```sh
slackbuilder COMMAND
```
Currently supported commands are listed below.
### check
`check` checks whether there are updates available. It prints the name of each
known package together with its version. If the package version is not the
latest known version, the version the package can be updated to is printed as
well.
### up2date
Performs the package updates for packages the can be updated. `up2date` accepts
an optional argument specifying the package that should be updated if only one
package should be updated and not all.

107
Rakefile
View File

@ -1,107 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
require 'digest/md5'
require 'net/http'
require_relative 'config/config'
require_relative 'lib/package'
require_relative 'lib/download'
task :dmd, [:version] do |_, arguments|
raise 'Version is not specified.' unless arguments.key? :version
dub_version = '1.30.0'
dscanner_version = '0.12.2'
dcd_version = '0.13.6'
SlackBuilder::DmdTools.update_dmd arguments[:version]
SlackBuilder::DmdTools.update_tools arguments[:version], dub_version, dscanner_version, dcd_version
end
task :composer, [:version] do |_, arguments|
raise 'Version is not specified.' unless arguments.key? :version
package = Package.new 'development/composer',
version: arguments[:version],
homepage: 'https://getcomposer.org/'
uri = "https://getcomposer.org/download/#{arguments[:version]}/composer.phar"
checksum = download URI(uri), 'slackbuilds/development/composer/composer.phar'
write_info package, downloads: [Download.new(uri, checksum.hexdigest)]
update_slackbuild_version 'development/composer', arguments[:version]
commit 'development/composer', arguments[:version]
end
task 'universal-ctags', [:version] do |_, arguments|
raise 'Version is not specified.' unless arguments.key? :version
package = Package.new 'development/universal-ctags',
version: arguments[:version],
homepage: 'https://ctags.io/',
requires: ['%README%']
uri = "https://github.com/universal-ctags/ctags/archive/#{arguments[:version]}/ctags-#{arguments[:version]}.tar.gz"
tarball = "slackbuilds/development/universal-ctags/ctags-#{arguments[:version]}.tar.gz"
checksum = download URI(uri), tarball
download = "https://download.dlackware.com/hosted-sources/universal-ctags/ctags-#{arguments[:version]}.tar.gz"
write_info package,
downloads: [Download.new(download, checksum.hexdigest)]
update_slackbuild_version 'development/universal-ctags', arguments[:version]
sh 'scp', tarball, "#{CONFIG[:remote_path]}/universal-ctags"
commit 'development/universal-ctags', arguments[:version]
end
task :hhvm do
raise 'Version is not specified.' unless arguments.key? :version
checksum = {}
checksum[:hhvm] = clone 'https://github.com/facebook/hhvm.git',
"development/hhvm/hhvm-#{arguments[:version]}.tar.xz", 'HHVM-'
package = Package.new 'development/hhvm',
version: arguments[:version],
homepage: 'https://hhvm.com/',
requires: %w[tbb glog libdwarf libmemcached dobule-conversion]
write_info package,
downloads: [
Download.new(hosted_sources("/hhvm/hhvm-#{package.version}.tar.xz"), checksum[:hhvm], is64: true)
]
update_slackbuild_version 'development/hhvm', package.version
end
task :ioncube do
raise 'Version is not specified.' unless arguments.key? :version
tarball_name = {
'32' => "ioncube_loaders_lin_x86_#{arguments[:version]}.tar.gz",
'64' => "ioncube_loaders_lin_x86-64_#{arguments[:version]}.tar.gz"
}
uri = {
'32' => URI("http://downloads3.ioncube.com/loader_downloads/#{tarball_name['32']}"),
'64' => URI("http://downloads3.ioncube.com/loader_downloads/#{tarball_name['64']}")
}
checksum = {
'32' => download(uri['32'], "slackbuilds/development/ioncube-loader/#{tarball_name['32']}").hexdigest,
'64' => download(uri['64'], "slackbuilds/development/ioncube-loader/#{tarball_name['64']}").hexdigest
}
package = Package.new 'development/ioncube-loader',
version: arguments[:version],
homepage: 'https://www.ioncube.com'
write_info package,
downloads: [
Download.new(uri['32'], checksum['32']),
Download.new(uri['64'], checksum['64'], is64: true)
]
update_slackbuild_version 'development/ioncube-loader', package.version
commit 'development/ioncube-loader', package.version
end

View File

@ -1,29 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'rubocop' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
bundle_binstub = File.expand_path("../bundle", __FILE__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("rubocop", "rubocop")

View File

@ -1,7 +0,0 @@
# frozen_string_literal: true
CONFIG = {
remote_path: 'example.com:/srv/httpd/some/path',
download_url: 'https://example.com/some/path',
branch: 'user/nick/updates'
}.freeze

View File

@ -0,0 +1,35 @@
## Global options
# Accessing GitHub APIs is only possible using a personal access token. The
# token doesn't need any scopes set since it is used to query public
# repositories.
gh_token = ""
# Relative path to a cloned SBo repository.
repository = "./slackbuilds"
# After one package is updated a commit is created on this branch. The branch is
# not pushed or reset automatically.
branch = "user/nick/updates"
# If some packages use custom sources and these sources a generated during the
# update, this option specifies the base URL where the sources can be downloaded
# afterwads. The full URL written into the .info file contains download_url,
# followed by the package name and source file name. This option should probably
# be configured consistently with the remote_path.
download_url = "https://example.com/some/path"
# If a package updater generates a source tarball, the tarball is uploaded with
# a command given in this parameter. The parameter is a array where the first
# element is the command with the following elements being the command
# arguments. The command supports 2 placeholders:
# %s - Path to the source archive.
# %c - Package category.
upload_command = ["scp", "%s", "example.com:/srv/httpd/some/path/%c"]
## Maintainer specific options
[maintainer]
# Whether the git commits should be signed with a GPG signature using the
# default key.
signature = false

View File

@ -0,0 +1,95 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Configuration file.
module SlackBuilder.Config
( CloneSettings(..)
, DownloaderSettings(..)
, Settings(..)
, MaintainerSettings(..)
, PackageSettings(..)
, settingsCodec
) where
import Data.List.NonEmpty (NonEmpty(..))
import Data.Text (Text)
import Toml ((.=))
import qualified Toml
import GHC.Records (HasField(..))
data Settings = Settings
{ ghToken :: !Text
, repository :: !FilePath
, branch :: Text
, downloadURL :: Text
, uploadCommand :: NonEmpty Text
, maintainer :: MaintainerSettings
, packages :: [PackageSettings]
} deriving (Eq, Show)
newtype MaintainerSettings = MaintainerSettings
{ signature :: Bool
} deriving (Eq, Show)
data DownloaderSettings = DownloaderSettings
{ name :: Text
, is64 :: Bool
, version :: Text
, template :: Maybe Text
, clone :: Maybe CloneSettings
, github :: Maybe (Text, Text)
, packagist :: Maybe (Text, Text)
, text :: Maybe (Text, [String])
, repackage :: Maybe [String]
} deriving (Eq, Show)
data PackageSettings = PackageSettings
{ downloader :: DownloaderSettings
, downloaders :: [DownloaderSettings]
} deriving (Eq, Show)
data CloneSettings = CloneSettings
{ remote :: Text
, tagTemplate :: Text
} deriving (Eq, Show)
settingsCodec :: Toml.TomlCodec Settings
settingsCodec = Settings
<$> Toml.text "gh_token" .= ghToken
<*> Toml.string "repository" .= repository
<*> Toml.text "branch" .= branch
<*> Toml.text "download_url" .= downloadURL
<*> Toml.arrayNonEmptyOf Toml._Text "upload_command" .= uploadCommand
<*> Toml.table maintainerSettingsCodec "maintainer" .= maintainer
<*> Toml.list packageSettingsCodec "package" .= packages
maintainerSettingsCodec :: Toml.TomlCodec MaintainerSettings
maintainerSettingsCodec = MaintainerSettings
<$> Toml.bool "signature" .= signature
downloaderSettingsCodec :: Toml.TomlCodec DownloaderSettings
downloaderSettingsCodec = DownloaderSettings
<$> Toml.text "name" .= name
<*> Toml.bool "is64" .= is64
<*> Toml.text "version" .= version
<*> Toml.dioptional (Toml.text "template") .= template
<*> Toml.dioptional (Toml.table cloneSettingsCodec "clone") .= clone
<*> Toml.dioptional (Toml.table githubCodec "github") .= github
<*> Toml.dioptional (Toml.table packagistCodec "packagist") .= packagist
<*> Toml.dioptional (Toml.table textCodec "text") .= text
<*> Toml.dioptional (Toml.arrayOf Toml._String "repackage") .= repackage
where
githubCodec = Toml.pair (Toml.text "owner") (Toml.text "name")
packagistCodec = Toml.pair (Toml.text "owner") (Toml.text "name")
textCodec = Toml.pair (Toml.text "url") (Toml.arrayOf Toml._String "picker")
packageSettingsCodec :: Toml.TomlCodec PackageSettings
packageSettingsCodec = PackageSettings
<$> downloaderSettingsCodec .= getField @"downloader"
<*> Toml.list downloaderSettingsCodec "downloader" .= downloaders
cloneSettingsCodec :: Toml.TomlCodec CloneSettings
cloneSettingsCodec = CloneSettings
<$> Toml.text "remote" .= remote
<*> Toml.text "tag_template" .= tagTemplate

View File

@ -0,0 +1,360 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Contains routines for downloading, cloning and uploading sources.
module SlackBuilder.Download
( cloneAndUpload
, extractRemote
, commit
, createLzmaTarball
, download
, hostedSources
, remoteFileExists
, responseBodySource
, reqGet
, sinkFileAndHash
, sinkHash
, updateSlackBuildVersion
, uploadSource
) where
import qualified Codec.Compression.Lzma as Lzma
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Char8
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.NonNull (toNullable)
import Data.Foldable (find)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text.IO
import SlackBuilder.Config
import SlackBuilder.Trans
import Control.Monad.Trans.Reader (asks)
import Control.Monad.IO.Class (MonadIO(liftIO))
import System.Directory (createDirectory, removePathForcibly)
import System.IO (IOMode(..), withFile)
import System.FilePath ((</>), (<.>), takeFileName, takeDirectory, stripExtension)
import System.Process
( CreateProcess(..)
, StdStream(..)
, proc
, readCreateProcessWithExitCode
, callProcess
)
import System.Exit (ExitCode(..))
import Control.Monad (unless, void)
import Text.URI (URI(..))
import qualified Text.URI as URI
import Network.HTTP.Req
( useHttpsURI
, useURI
, HEAD(..)
, NoReqBody(..)
, req
, runReq
, defaultHttpConfig
, ignoreResponse
, responseStatusCode
, MonadHttp
, HttpConfig(..)
, GET(..)
, reqBr
)
import Data.Functor ((<&>))
import Network.HTTP.Client (BodyReader, Response(..), brRead)
import Conduit
( ConduitT
, MonadResource
, yield
, runConduitRes
, sinkFile
, (.|)
, ZipSink(..)
, await
, sourceFile
, leftover
, awaitNonNull
)
import Data.Conduit.Tar (FileInfo(..), tarFilePath, untar)
import Crypto.Hash (Digest, MD5, hashInit, hashFinalize, hashUpdate)
import Data.Void (Void)
import qualified Data.Conduit.Zlib as Zlib
import Control.Monad.Catch (MonadThrow(..))
import Data.Maybe (fromMaybe)
updateSlackBuildVersion :: Text -> Text -> Map Text Text -> SlackBuilderT ()
updateSlackBuildVersion packagePath version additionalDownloads = do
repository' <- SlackBuilderT $ asks repository
let name = Text.unpack $ snd $ Text.breakOnEnd "/" packagePath
slackbuildFilename = repository'
</> Text.unpack packagePath
</> (name <.> "SlackBuild")
slackbuildContents <- liftIO $ Text.IO.readFile slackbuildFilename
let slackbuildLines = replaceLine . updateLineVariable "VERSION" version
<$> Text.lines slackbuildContents
liftIO $ Text.IO.writeFile slackbuildFilename $ Text.unlines slackbuildLines
where
replaceLine line = Map.foldrWithKey updateLineDependencyVersion line additionalDownloads
updateLineDependencyVersion dependencyName = updateLineVariable
$ dependencyName <> "_VERSION"
updateLineVariable variableName variableValue line
| Text.isPrefixOf (variableName <> "=") line =
variableName <> "=${" <> variableName <> ":-" <> variableValue <> "}"
| otherwise = line
commit :: Text -> Text -> SlackBuilderT ()
commit packagePath version = do
branch' <- SlackBuilderT $ Text.unpack <$> asks branch
repository' <- SlackBuilderT $ asks repository
signature' <- SlackBuilderT $ asks $ signature . maintainer
let message = Text.unpack
$ packagePath <> ": Updated for version " <> version
mainCommitArguments = ["-C", repository', "commit", "-m", message]
commitArguments =
if signature'
then mainCommitArguments <> ["-S"]
else mainCommitArguments
(checkoutExitCode, _, _) <- liftIO
$ withFile "/dev/null" WriteMode
$ testCheckout repository' branch'
unless (checkoutExitCode == ExitSuccess)
$ liftIO
$ callProcess "git" ["-C", repository', "checkout", "-b", branch', "master"]
liftIO
$ callProcess "git" ["-C", repository', "add", Text.unpack packagePath]
>> callProcess "git" commitArguments
where
testCheckout repository' branch' nullHandle =
let createCheckoutProcess = (proc "git" ["-C", repository', "checkout", branch'])
{ std_in = NoStream
, std_err = UseHandle nullHandle
}
in readCreateProcessWithExitCode createCheckoutProcess ""
hostedSources :: NonEmpty Text -> SlackBuilderT URI
hostedSources urlPathPieces = do
downloadURL' <- SlackBuilderT (asks downloadURL) >>= URI.mkURI
urlPathPieces' <- traverse URI.mkPathPiece urlPathPieces
let updatedPath = case URI.uriPath downloadURL' of
Just (_, existingPath) ->
NonEmpty.append existingPath urlPathPieces'
Nothing -> urlPathPieces'
pure $ downloadURL'{ uriPath = Just (False, updatedPath) }
remoteFileExists :: NonEmpty Text -> SlackBuilderT Bool
remoteFileExists urlPathPieces = hostedSources urlPathPieces
>>= traverse (runReq httpConfig . go . fst) . useHttpsURI
<&> maybe False ((== 200) . responseStatusCode)
where
httpConfig = defaultHttpConfig
{ httpConfigCheckResponse = const $ const $ const Nothing
}
go uri = req HEAD uri NoReqBody ignoreResponse mempty
cloneAndArchive :: Text -> FilePath -> Text -> SlackBuilderT ()
cloneAndArchive repo tarballPath tagPrefix = do
let version = snd $ Text.breakOnEnd "-"
$ Text.pack $ takeFileName tarballPath
repositoryTarballPath <- relativeToRepository tarballPath
repositoryArchivePath <- relativeToRepository $ tarballPath <.> "tar.xz"
liftIO
$ removePathForcibly repositoryTarballPath
>> callProcess "git"
[ "clone"
, Text.unpack repo
, repositoryTarballPath
]
>> callProcess "git"
[ "-C"
, repositoryTarballPath
, "checkout"
, Text.unpack $ tagPrefix <> version
]
>> callProcess "git"
[ "-C"
, repositoryTarballPath
, "submodule"
, "update"
, "--init"
, "--recursive"
]
>> createLzmaTarball repositoryTarballPath repositoryArchivePath
>> removePathForcibly repositoryTarballPath
-- | Takes a directory as input and a file name as output and creates a tar.xz
-- archive from the given directory.
createLzmaTarball :: FilePath -> FilePath -> IO (Digest MD5)
createLzmaTarball input output = runConduitRes $ yield input
.| void tarFilePath
.| compressLzma
.| sinkFileAndHash output
responseBodySource :: MonadIO m => Response BodyReader -> ConduitT i ByteString m ()
responseBodySource = bodyReaderSource . responseBody
where
bodyReaderSource br = liftIO (brRead br) >>= go br
go br bs = unless (ByteString.null bs) $ yield bs >> bodyReaderSource br
sinkHash :: Monad m => ConduitT ByteString Void m (Digest MD5)
sinkHash = sink hashInit
where
sink ctx = await
>>= maybe (pure $ hashFinalize ctx) (sink . hashUpdate ctx)
cloneAndUpload :: Text -> FilePath -> Text -> SlackBuilderT (URI, Digest MD5)
cloneAndUpload repo tarballPath tagPrefix = do
let tarballFileName = takeFileName tarballPath <.> "tar.xz"
packageName = takeFileName $ takeDirectory tarballPath
remoteArchivePath = Text.pack $ packageName </> tarballFileName
urlPathPieces = Text.pack <$> packageName :| [tarballFileName]
localPath <- relativeToRepository tarballFileName
remoteResultURI <- hostedSources urlPathPieces
remoteFileExists' <- remoteFileExists urlPathPieces
if remoteFileExists'
then (remoteResultURI,) . snd
<$> download remoteResultURI (takeDirectory localPath)
else
let go = sourceFile localPath .| sinkHash
in cloneAndArchive repo tarballPath tagPrefix
>> uploadSource localPath remoteArchivePath
>> liftIO (runConduitRes go) <&> (remoteResultURI,)
-- | Given a path to a local file and a remote path uploads the file using
-- the settings given in the configuration file.
--
-- The remote path is given relative to the path in the configuration.
uploadSource :: FilePath -> Text -> SlackBuilderT ()
uploadSource localPath remotePath' = do
uploadCommand' :| uploadArguments <- SlackBuilderT $ asks uploadCommand
let uploadArguments' = Text.unpack
. Text.replace "%s" (Text.pack localPath)
. Text.replace "%c" remotePath'
<$> uploadArguments
liftIO $ callProcess (Text.unpack uploadCommand') uploadArguments'
-- | Downlaods a file into the directory. Returns name of the downloaded file
-- and checksum.
--
-- The filename is read from the disposition header or from the URL if the
-- Content-Disposition is missing.
download :: URI -> FilePath -> SlackBuilderT (FilePath, Digest MD5)
download uri packagePath = runReq defaultHttpConfig go
where
go
| Just uriPath <- URI.uriPath uri =
reqGet uri
$ readResponse
$ Text.unpack
$ URI.unRText
$ NonEmpty.last
$ snd uriPath
| otherwise = throwM $ UnsupportedUrlType uri
readResponse :: FilePath -> Response BodyReader -> IO (FilePath, Digest MD5)
readResponse downloadFileName response = do
let attachmentName = dispositionAttachment response
targetFileName = fromMaybe downloadFileName attachmentName
target = packagePath </> fromMaybe downloadFileName attachmentName
digest <- runConduitRes
$ responseBodySource response
.| sinkFileAndHash target
pure (targetFileName, digest)
-- | Writes a file to the destination path and accumulates its MD5 checksum.
sinkFileAndHash :: MonadResource m => FilePath -> ConduitT ByteString Void m (Digest MD5)
sinkFileAndHash target = getZipSink
$ ZipSink (sinkFile target) *> ZipSink sinkHash
compressLzma :: MonadIO m => ConduitT ByteString ByteString m ()
compressLzma = liftIO (Lzma.compressIO Lzma.defaultCompressParams) >>= go
where
go (Lzma.CompressInputRequired flush supplyInput) = do
next <- await
result <- case next of
Just input
| ByteString.null input -> liftIO flush
| otherwise -> liftIO $ supplyInput input
Nothing -> liftIO $ supplyInput mempty
go result
go (Lzma.CompressOutputAvailable output stream) = yield output
>> liftIO stream >>= go
go Lzma.CompressStreamEnd = pure ()
decompressLzma :: (MonadThrow m, MonadIO m) => ConduitT ByteString ByteString m ()
decompressLzma = liftIO (Lzma.decompressIO Lzma.defaultDecompressParams) >>= go
where
go (Lzma.DecompressInputRequired processor) = do
next <- awaitNonNull
result <- case next of
Just input -> liftIO $ processor (toNullable input)
Nothing -> liftIO $ processor mempty
go result
go (Lzma.DecompressOutputAvailable output stream) = yield output
>> liftIO stream
>>= go
go (Lzma.DecompressStreamEnd output) = leftover output
go (Lzma.DecompressStreamError lzmaReturn) = throwM
$ LzmaDecompressionFailed lzmaReturn
-- | Downloads a compressed tar archive and extracts its contents on the fly to
-- a directory.
--
-- If the download contains the disposition header and the attachment type was
-- recognized as tar archive, returns the attachment name from the
-- disposition header without the extension. So if the disposition header
-- is "attachment; filename=package-1.2.3.tar.gz", returns "package-1.2.3".
extractRemote :: URI -> FilePath -> SlackBuilderT (Maybe FilePath)
extractRemote uri' packagePath =
runReq defaultHttpConfig $ go packagePath
where
go toTarget = reqGet uri' $ readResponse toTarget
readResponse :: FilePath -> Response BodyReader -> IO (Maybe FilePath)
readResponse toTarget response = do
let attachmentName = dispositionAttachment response
(decompress, attachmentDirectory) =
case attachmentName of
Just attachmentName'
| Just directoryName' <- stripExtension ".tar.gz" attachmentName' ->
(Zlib.ungzip, Just directoryName')
| Just directoryName' <- stripExtension ".tar.xz" attachmentName' ->
(decompressLzma, Just directoryName')
_ -> (pure (), Nothing)
runConduitRes $ responseBodySource response
.| decompress
.| untar (withDecompressedFile toTarget)
pure attachmentDirectory
withDecompressedFile toTarget FileInfo{..}
| Char8.last filePath /= '/' =
sinkFile (toTarget </> Char8.unpack filePath)
| otherwise = liftIO (createDirectory (toTarget </> Char8.unpack filePath))
dispositionAttachment :: Response BodyReader -> Maybe FilePath
dispositionAttachment response
= fmap (Char8.unpack . snd . Char8.breakEnd (== '=') . snd)
$ find ((== "Content-Disposition") . fst)
$ responseHeaders response
reqGet :: (MonadThrow m, MonadHttp m)
=> URI
-> (Response BodyReader -> IO a)
-> m a
reqGet uri bodyReader =
case useURI uri of
Just urlWithOptions
| Left (httpsURI, httpsOptions) <- urlWithOptions ->
reqBr GET httpsURI NoReqBody httpsOptions bodyReader
| Right (httpsURI, httpsOptions) <- urlWithOptions ->
reqBr GET httpsURI NoReqBody httpsOptions bodyReader
_ -> throwM $ UnsupportedUrlType uri

166
lib/SlackBuilder/Info.hs Normal file
View File

@ -0,0 +1,166 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Info file parsing and printing.
module SlackBuilder.Info
( PackageInfo(..)
, generate
, parseInfoFile
, readInfoFile
) where
import Control.Applicative (Alternative(..))
import Control.Monad.Combinators (sepBy)
import qualified Data.ByteArray as ByteArray
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Char8
import Data.Maybe (mapMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.Text.Lazy as Lazy.Text
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Data.Text.Lazy.Builder as Text (Builder)
import Crypto.Hash (Digest, MD5, digestFromByteString)
import Data.Void (Void)
import Data.Word (Word8)
import Numeric (readHex, showHex)
import Text.Megaparsec (Parsec, count, eof, parse, takeWhile1P)
import Text.Megaparsec.Byte (hspace1, space, string, hexDigitChar)
import Text.URI
( URI(..)
, parserBs
, render
)
import qualified Data.Word8 as Word8
import SlackBuilder.Trans
( SlackBuilderT(..)
, SlackBuilderException(..)
, relativeToRepository
)
import System.FilePath ((</>), (<.>))
import Control.Monad.IO.Class (MonadIO(..))
import Conduit (MonadThrow(throwM))
import Control.Monad (void)
type GenParser = Parsec Void ByteString
-- | Data used to generate an .info file.
data PackageInfo = PackageInfo
{ pkgname :: String
, version :: Text
, homepage :: Text
, downloads :: [URI]
, checksums :: [Digest MD5]
, downloadX64 :: [URI]
, checksumX64 :: [Digest MD5]
, requires :: [ByteString]
, maintainer :: Text
, email :: Text
} deriving (Eq, Show)
variableEntry :: ByteString -> GenParser ByteString
variableEntry variable = string (Char8.append variable "=\"")
*> takeWhile1P Nothing (0x22 /=)
<* string "\"\n"
variableSeparator :: GenParser ()
variableSeparator = void $ some $ hspace1 <|> void (string "\\\n")
packageDownloads :: ByteString -> GenParser [URI]
packageDownloads variableName = string (variableName <> "=\"")
*> sepBy parserBs variableSeparator
<* string "\"\n"
hexDigit :: GenParser Word8
hexDigit = count 2 hexDigitChar
>>= extractNumber . readHex . fmap (toEnum . fromIntegral)
where
extractNumber [(number, "")] = pure number
extractNumber _ = fail "Unable to convert a 2-digit hexadecimal number"
packageChecksum :: GenParser ByteString
packageChecksum = ByteString.pack <$> count 16 hexDigit
packageChecksums :: ByteString -> GenParser [ByteString]
packageChecksums variableName = string (variableName <> "=\"")
*> sepBy packageChecksum variableSeparator
<* string "\"\n"
packageRequires :: GenParser [ByteString]
packageRequires = string "REQUIRES=\""
*> sepBy (packageName <|> string "%README%") space
<* string "\"\n"
packageName :: GenParser ByteString
packageName = takeWhile1P Nothing isNameToken
where
isNameToken x = Word8.isAlphaNum x
|| x == Word8._hyphen
|| x == Word8._underscore
|| x == Word8._period
parseInfoFile :: GenParser PackageInfo
parseInfoFile = PackageInfo . Char8.unpack
<$> packagePrgnam
<*> (Text.decodeUtf8 <$> variableEntry "VERSION")
<*> (Text.decodeUtf8 <$> variableEntry "HOMEPAGE")
<*> packageDownloads "DOWNLOAD"
<*> (mapMaybe digestFromByteString <$> packageChecksums "MD5SUM")
<*> packageDownloads "DOWNLOAD_x86_64"
<*> (mapMaybe digestFromByteString <$> packageChecksums "MD5SUM_x86_64")
<*> packageRequires
<*> (Text.decodeUtf8 <$> variableEntry "MAINTAINER")
<*> (Text.decodeUtf8 <$> variableEntry "EMAIL")
<* eof
where
packagePrgnam = (string "PKGNAM" <|> string "PRGNAM")
>> string "=\""
*> packageName
<* "\"\n"
readInfoFile :: Text -> Text -> SlackBuilderT PackageInfo
readInfoFile category packageName' = do
let packageName'' = Text.unpack packageName'
infoPath <- relativeToRepository
$ Text.unpack category </> packageName'' </> packageName'' <.> "info"
infoContents <- liftIO $ ByteString.readFile infoPath
either (throwM . MalformedInfoFile) pure
$ parse parseInfoFile infoPath infoContents
generate :: PackageInfo -> Text
generate pkg = Lazy.Text.toStrict $ Text.Builder.toLazyText builder
where
digestToText = Text.pack . foldr hexAppender "" . ByteArray.unpack
hexAppender x acc
| x > 15 = showHex x acc
| otherwise = '0' : showHex x acc
builder = "PRGNAM=\"" <> Text.Builder.fromString (pkgname pkg) <> "\"\n"
<> "VERSION=\"" <> Text.Builder.fromText (version pkg) <> "\"\n"
<> "HOMEPAGE=\"" <> Text.Builder.fromText (homepage pkg) <> "\"\n"
<> downloadEntry
<> generateMultiEntry "MD5SUM" (digestToText <$> checksums pkg)
<> generateMultiEntry "DOWNLOAD_x86_64" (render <$> downloadX64 pkg)
<> generateMultiEntry "MD5SUM_x86_64" (digestToText <$> checksumX64 pkg)
<> "REQUIRES=\"" <> fromByteStringWords (requires pkg) <> "\"\n"
<> "MAINTAINER=\"" <> Text.Builder.fromText (maintainer pkg) <> "\"\n"
<> "EMAIL=\"" <> Text.Builder.fromText (email pkg) <> "\"\n"
fromByteStringWords = Text.Builder.fromText
. Text.unwords . fmap Text.decodeUtf8
downloadEntry
| null $ downloads pkg
, not $ null $ downloadX64 pkg = "DOWNLOAD=\"UNSUPPORTED\"\n"
| otherwise = generateMultiEntry "DOWNLOAD" $ render <$> downloads pkg
generateMultiEntry :: Text -> [Text] -> Text.Builder
generateMultiEntry name entries = Text.Builder.fromText name
<> "=\""
<> Text.Builder.fromText (Text.intercalate separator entries)
<> "\"\n"
where
padLength = Text.length name + 2
separator = " \\\n" <> Text.replicate padLength " "

View File

@ -0,0 +1,307 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | This module contains implementations to check the latest version of a
-- package hosted by a specific service.
module SlackBuilder.LatestVersionCheck
( PackageOwner(..)
, TextArguments(..)
, latestGitHub
, latestPackagist
, latestText
, match
) where
import SlackBuilder.Config
import qualified Data.Aeson as Aeson
import Data.Aeson ((.:))
import Data.Aeson.TH (defaultOptions, deriveJSON)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text.Encoding
import Data.Vector (Vector, (!?))
import qualified Data.Vector as Vector
import Network.HTTP.Req
( header
, runReq
, defaultHttpConfig
, req
, GET(..)
, https
, jsonResponse
, NoReqBody(..)
, (/:)
, responseBody
, POST(..)
, ReqBodyJson(..)
, JsonResponse
)
import Text.URI (mkURI)
import SlackBuilder.Trans
import qualified Data.Aeson.KeyMap as KeyMap
import GHC.Records (HasField(..))
import Control.Monad.Trans.Reader (asks)
import Data.Char (isAlpha)
import SlackBuilder.Download (responseBodySource, reqGet)
import Network.HTTP.Client (BodyReader, Response(..))
import Conduit (decodeUtf8C, (.|), linesUnboundedC, sinkNull, runConduit)
import qualified Data.Conduit.List as CL
import Data.Conduit.Process (sourceProcessWithStreams, proc)
import Data.Maybe (listToMaybe, mapMaybe)
data PackageOwner = PackageOwner
{ owner :: Text
, name :: Text
} deriving (Eq, Show)
data MatchState = MatchState
{ ignoring :: !Bool
, matched :: !Text
, pattern' :: ![MatchToken]
} deriving (Eq, Show)
data MatchToken
= OpenParenMatchToken
| CloseParenMatchToken
| SymbolMatchToken Char
| AtLeastMatchToken [Char]
| OneOfMatchToken [Char]
deriving (Eq, Show)
-- | Matches a string (for example a version name or CVS tag) against a pattern.
-- Returns the matched part of the string or 'Nothing' if there is not match.
--
-- The pattern is just a list of characters with some special characters and
-- sequences.
--
-- * ( ) - The text in parentheses is matched but no saved in the resulting
-- string.
-- * \\d - Matches zero or more digits.
-- * \\D - Matches one or more digits.
-- * \\. - Matches zero or more digits or dots.
-- * \\\\ - Matches a back slash.
-- * * - Matches everything.
-- * [ ] - Match one of the characters inbetween. The characters are
-- matched verbatim.
--
-- For example the following expression matches tags like @v1.2.3@, but returns
-- only @1.2.3@.
--
-- @
-- (v)\\.
-- @
match :: Text -> Text -> Maybe Text
match fullPattern = go startState
where
startState = MatchState
{ ignoring = False
, matched = mempty
, pattern' = parsePattern fullPattern
}
go :: MatchState -> Text -> Maybe Text
-- There is no input, look at the remaining tokens.
go MatchState{ pattern' = [], matched } "" = Just matched
go state@MatchState{ pattern' = OpenParenMatchToken : tokens } input' =
go (state{ ignoring = True, pattern' = tokens }) input'
go state@MatchState{ pattern' = CloseParenMatchToken : tokens } input' =
go (state{ ignoring = False, pattern' = tokens }) input'
go state@MatchState{ pattern' = SymbolMatchToken patternCharacter : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input'
, patternCharacter == nextCharacter =
go (matchSymbolToken state{ pattern' = tokens } nextCharacter) leftOver
| otherwise = Nothing
go state@MatchState{ pattern' = OneOfMatchToken chars : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input'
, nextCharacter `elem` chars =
go (matchSymbolToken state nextCharacter) leftOver
| otherwise =
go (state{ pattern' = tokens }) input'
go state@MatchState{ pattern' = AtLeastMatchToken chars : tokens } input'
| Just (nextCharacter, leftOver) <- Text.uncons input'
, nextCharacter `elem` chars =
go (matchSymbolToken state{ pattern' = OneOfMatchToken chars : tokens } nextCharacter) leftOver
| otherwise = Nothing
-- All tokens are processed, but there is still some input left.
go MatchState{ pattern' = [] } _ = Nothing
matchSymbolToken state nextCharacter
| getField @"ignoring" state = state
| otherwise = state
{ matched = Text.snoc (getField @"matched" state) nextCharacter
}
parsePattern :: Text -> [MatchToken]
parsePattern input'
| Just (firstChar, remaining) <- Text.uncons input'
, firstChar == '\\' =
case Text.uncons remaining of
Nothing -> []
Just ('d', remaining') -> OneOfMatchToken digits
: parsePattern remaining'
Just ('D', remaining') -> AtLeastMatchToken digits
: parsePattern remaining'
Just ('.', remaining') -> AtLeastMatchToken ('.' : digits)
: parsePattern remaining'
Just ('\\', remaining') -> SymbolMatchToken '\\'
: parsePattern remaining'
Just (_, remaining') -> parsePattern remaining'
| Just (firstChar, remaining) <- Text.uncons input'
, firstChar == '['
, Just lastBracket <- Text.findIndex (== ']') remaining
= OneOfMatchToken (Text.unpack $ Text.take lastBracket remaining)
: parsePattern (Text.drop (succ lastBracket) remaining)
| Just (firstChar, remaining) <- Text.uncons input' =
let token =
case firstChar of
'*' -> OneOfMatchToken (toEnum <$> [32 .. 127])
'(' -> OpenParenMatchToken
')' -> CloseParenMatchToken
s -> SymbolMatchToken s
in token : parsePattern remaining
| otherwise = []
where
digits = toEnum <$> [fromEnum '0' .. fromEnum '9']
-- * Packagist
newtype PackagistPackage = PackagistPackage
{ version :: Text
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''PackagistPackage)
newtype PackagistResponse = PackagistResponse
{ packages :: HashMap Text (Vector PackagistPackage)
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''PackagistResponse)
latestPackagist :: PackageOwner -> SlackBuilderT (Maybe Text)
latestPackagist PackageOwner{..} = do
packagistResponse <- runReq defaultHttpConfig $
let uri = https "repo.packagist.org" /: "p2"
/: owner
/: name <> ".json"
in req GET uri NoReqBody jsonResponse mempty
let packagistPackages = getField @"packages"
$ Network.HTTP.Req.responseBody (packagistResponse :: JsonResponse PackagistResponse)
fullName = Text.intercalate "/" [owner, name]
pure $ HashMap.lookup fullName packagistPackages
>>= fmap (getField @"version" . fst) . Vector.uncons
-- * Remote text file
data TextArguments = TextArguments
{ textURL :: Text
, versionPicker :: [String]
}
latestText :: TextArguments -> Text -> SlackBuilderT (Maybe Text)
latestText TextArguments{..} pattern' = do
uri' <- mkURI textURL
versions <- case versionPicker of
(command : arguments) ->
runReq defaultHttpConfig $ reqGet uri' $ readResponse command arguments
[] -> runReq defaultHttpConfig $ reqGet uri' go
pure $ listToMaybe $ mapMaybe (match pattern') versions
where
readResponse :: String -> [String] -> Response BodyReader -> IO [Text]
readResponse command arguments response = do
let createProcess' = proc command arguments
(_, stdout', _) <- sourceProcessWithStreams createProcess' (responseBodySource response) stdoutReader sinkNull
pure stdout'
stdoutReader = decodeUtf8C .| linesUnboundedC .| CL.consume
go response = runConduit $ responseBodySource response .| stdoutReader
-- * GitHub
newtype GhRefNode = GhRefNode
{ name :: Text
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRefNode)
newtype GhRef = GhRef
{ nodes :: Vector GhRefNode
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRef)
newtype GhRepository = GhRepository
{ refs :: GhRef
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhRepository)
newtype GhData = GhData
{ repository :: GhRepository
} deriving (Eq, Show)
instance Aeson.FromJSON GhData where
parseJSON (Aeson.Object keyMap)
| Just data' <- KeyMap.lookup "data" keyMap =
GhData <$> Aeson.withObject "GhData" (.: "repository") data'
parseJSON _ = fail "data key not found in the response"
data GhVariables = GhVariables
{ name :: Text
, owner :: Text
, prefix :: Maybe Text
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhVariables)
data GhQuery = GhQuery
{ query :: Text
, variables :: GhVariables
} deriving (Eq, Show)
$(deriveJSON defaultOptions ''GhQuery)
latestGitHub
:: PackageOwner
-> Text
-> SlackBuilderT (Maybe Text)
latestGitHub PackageOwner{..} pattern' = do
ghToken' <- SlackBuilderT $ asks ghToken
ghResponse <- runReq defaultHttpConfig $
let uri = https "api.github.com" /: "graphql"
prefix = Text.takeWhile isAlpha
$ Text.filter (liftA2 (&&) (/= ')') (/= '(')) pattern'
query = GhQuery
{ query = githubQuery
, variables = GhVariables
{ owner = owner
, name = name
, prefix = if Text.null prefix then Nothing else Just $ prefix <> "*"
}
}
authorizationHeader = header "authorization"
$ Text.Encoding.encodeUtf8
$ "Bearer " <> ghToken'
in req POST uri (ReqBodyJson query) jsonResponse
$ authorizationHeader <> header "User-Agent" "SlackBuilder"
let ghNodes = nodes
$ refs
$ (getField @"repository" :: GhData -> GhRepository)
$ Network.HTTP.Req.responseBody ghResponse
refs' = Vector.catMaybes
$ match pattern' . getField @"name" <$> ghNodes
pure $ refs' !? 0
where
githubQuery =
"query ($name: String!, $owner: String!, $prefix: String) {\n\
\ repository(name: $name, owner: $owner) {\n\
\ refs(first: 10, query: $prefix, refPrefix: \"refs/tags/\", orderBy: {\n\
\ field: TAG_COMMIT_DATE, direction: DESC\n\
\ }) {\n\
\ nodes {\n\
\ id,\n\
\ name\n\
\ }\n\
\ }\n\
\ }\n\
\}"

View File

@ -0,0 +1,81 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Contains data describing packages, methods to update them and to request
-- information about them.
module SlackBuilder.Package
( DataBaseEntry(..)
, Download(..)
, DownloadTemplate(..)
, PackageDescription(..)
, PackageUpdateData(..)
, Updater(..)
, renderDownloadWithVersion
, renderTextWithVersion
) where
import Data.Text (Text)
import qualified Data.Text as Text
import Text.URI (URI(..))
import qualified Text.URI as URI
import Crypto.Hash (Digest, MD5)
import SlackBuilder.Trans
import Control.Monad.Catch (MonadThrow)
import Data.Map (Map)
-- | Contains information how a package can be updated.
data PackageDescription = PackageDescription
{ latest :: Updater
, downloaders :: Map Text Updater
, name :: Text
}
data PackageUpdateData = PackageUpdateData
{ description :: PackageDescription
, category :: Text
, version :: Text
}
-- | Download URI with the MD5 checksum of the target.
data Download = Download
{ download :: URI
, md5sum :: Digest MD5
} deriving (Eq, Show)
-- | List of URI components, including version placeholders.
newtype DownloadTemplate = DownloadTemplate
{ unDownloadTemplate :: Text
} deriving Eq
instance Show DownloadTemplate
where
show = Text.unpack . unDownloadTemplate
-- | Replaces placeholders in the URL template with the given version.
renderDownloadWithVersion :: MonadThrow m => DownloadTemplate -> Text -> m URI
renderDownloadWithVersion (DownloadTemplate template) version =
URI.mkURI $ renderTextWithVersion template version
-- | Replaces placeholders in the text with the given version.
renderTextWithVersion :: Text -> Text -> Text
renderTextWithVersion template version = Text.replace "{version}" version template
-- | Function used to get the latest version of a source.
data Updater = Updater
{ detectLatest :: SlackBuilderT (Maybe Text)
, is64 :: Bool
, getVersion :: Text -> Text -> SlackBuilderT Download
}
data DataBaseEntry = DataBaseEntry
{ name :: Text
, version :: Text
, arch :: Text
, build :: Text
} deriving Eq
instance Show DataBaseEntry
where
show DataBaseEntry{..} = Text.unpack
$ Text.intercalate "-" [name, version, arch, build]

98
lib/SlackBuilder/Trans.hs Normal file
View File

@ -0,0 +1,98 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Transformers and exceptions.
module SlackBuilder.Trans
( SlackBuilderException(..)
, SlackBuilderT(..)
, relativeToRepository
) where
import Control.Monad.Trans.Reader (ReaderT(..), asks)
import Data.ByteString (ByteString)
import Data.Text (Text)
import qualified Data.Text as Text
import SlackBuilder.Config
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Catch (MonadCatch(..), MonadThrow(..))
import Control.Exception (Exception(..))
import System.FilePath ((</>))
import Text.URI (URI)
import qualified Text.URI as URI
import qualified Codec.Compression.Lzma as Lzma
import Text.Megaparsec (ParseErrorBundle(..), errorBundlePretty)
import Conduit (Void)
data SlackBuilderException
= UpdaterNotFound Text
| UnsupportedUrlType URI
| LzmaDecompressionFailed Lzma.LzmaRet
| MalformedInfoFile (ParseErrorBundle ByteString Void)
deriving Show
instance Exception SlackBuilderException
where
displayException (UpdaterNotFound updateName) = Text.unpack
$ Text.concat ["Requested package \"", updateName, "\" was not found"]
displayException (UnsupportedUrlType givenURI) = Text.unpack
$ "Only https URLs are supported, got: " <> URI.render givenURI
displayException (LzmaDecompressionFailed Lzma.LzmaRetOK) =
"Operation completed successfully"
displayException (LzmaDecompressionFailed Lzma.LzmaRetStreamEnd) =
"End of stream was reached"
displayException (LzmaDecompressionFailed Lzma.LzmaRetUnsupportedCheck) =
"Cannot calculate the integrity check"
displayException (LzmaDecompressionFailed Lzma.LzmaRetGetCheck) =
"Integrity check type is now available"
displayException (LzmaDecompressionFailed Lzma.LzmaRetMemError) =
"Cannot allocate memory"
displayException (LzmaDecompressionFailed Lzma.LzmaRetMemlimitError) =
"Memory usage limit was reached"
displayException (LzmaDecompressionFailed Lzma.LzmaRetFormatError) =
"File format not recognized"
displayException (LzmaDecompressionFailed Lzma.LzmaRetOptionsError) =
"Invalid or unsupported options"
displayException (LzmaDecompressionFailed Lzma.LzmaRetDataError) =
"Data is corrupt"
displayException (LzmaDecompressionFailed Lzma.LzmaRetBufError) =
"No progress is possible"
displayException (LzmaDecompressionFailed Lzma.LzmaRetProgError) =
"Programming error"
displayException (MalformedInfoFile errorBundle) =
errorBundlePretty errorBundle
newtype SlackBuilderT a = SlackBuilderT
{ runSlackBuilderT :: ReaderT Settings IO a
}
relativeToRepository :: FilePath -> SlackBuilderT FilePath
relativeToRepository filePath =
(</> filePath) <$> SlackBuilderT (asks repository)
instance Functor SlackBuilderT
where
fmap f (SlackBuilderT slackBuilderT) = SlackBuilderT $ f <$> slackBuilderT
instance Applicative SlackBuilderT
where
pure = SlackBuilderT . pure
(SlackBuilderT f) <*> (SlackBuilderT x) = SlackBuilderT $ f <*> x
instance Monad SlackBuilderT
where
return = pure
(SlackBuilderT x) >>= f = SlackBuilderT $ x >>= runSlackBuilderT . f
instance MonadIO SlackBuilderT
where
liftIO = SlackBuilderT . liftIO
instance MonadThrow SlackBuilderT
where
throwM = SlackBuilderT . throwM
instance MonadCatch SlackBuilderT
where
catch (SlackBuilderT action) handler =
SlackBuilderT $ catch action $ runSlackBuilderT . handler

View File

@ -1,170 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
require_relative '../config/config'
require_relative 'package'
require 'net/http'
require 'pathname'
require 'progressbar'
require 'term/ansicolor'
module SlackBuilder
extend Rake::FileUtilsExt
def self.clone(repo, package, tag_prefix = 'v')
repository = Pathname.new('pkg') + package.name_version
if repository.directory?
sh 'git', '-C', repository.to_path, 'remote', 'update', '--prune'
else
sh 'git', 'clone', repo, repository.to_path
end
sh 'git', '-C', repository.to_path, 'checkout', "#{tag_prefix}#{package.version}"
sh 'git', '-C', repository.to_path, 'submodule', 'update', '--init', '--recursive'
repository
end
end
def write_chunk(response, checksum, progressbar, io)
response.read_body do |chunk|
progressbar.progress += chunk.length
io << chunk
checksum << chunk
end
end
def write_download(target, response)
checksum = Digest::MD5.new
progressbar = ProgressBar.create title: target, total: response.header.content_length
File.open target, 'w' do |io|
write_chunk response, checksum, progressbar, io
end
progressbar.finish
checksum
end
def redirect_download(location, target)
puts 'redirecting...'
new_location = URI location
download new_location, target
end
def start_download(uri, target, http)
request = Net::HTTP::Get.new uri
http.request request do |response|
case response
when Net::HTTPRedirection
return redirect_download response['location'], target
else
return write_download target, response
end
end
end
def download(uri, target)
print Term::ANSIColor.green "Downloading #{uri} "
checksum = nil
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
checksum = start_download uri, target, http
end
puts
checksum
end
def hosted_sources(absolute_url)
CONFIG[:download_url] + absolute_url
end
def remote_file_exists?(url)
uri = URI hosted_sources(url)
request = Net::HTTP.new uri.host, uri.port
request.use_ssl = true
response = request.request_head uri.path
response.code.to_i == 200
end
def upload_command(local_path, remote_path)
['scp', "slackbuilds/#{local_path}", CONFIG[:remote_path] + remote_path]
end
def clone_and_archive(repo, name_version, tarball, tag_prefix = 'v')
_, _, version = name_version.rpartition '-'
rm_rf name_version
sh 'git', 'clone', repo, name_version
sh 'git', '-C', name_version, 'checkout', "#{tag_prefix}#{version}"
sh 'git', '-C', name_version, 'submodule', 'update', '--init', '--recursive'
sh 'tar', 'Jcvf', "slackbuilds/#{tarball}", name_version
rm_rf name_version
end
def clone(repo, tarball, tag_prefix = 'v')
name_version = File.basename tarball, '.tar.xz'
remote_path = tarball[tarball.index('/')..]
if remote_file_exists?(remote_path)
uri = URI hosted_sources(remote_path)
return download(uri, "slackbuilds/#{tarball}").hexdigest
end
clone_and_archive repo, name_version, tarball, tag_prefix
sh(*upload_command(tarball, remote_path))
Digest::MD5.hexdigest File.read("slackbuilds/#{tarball}")
end
def download_and_deploy(uri, tarball)
remote_path = tarball[tarball.index('/')..]
if remote_file_exists?(remote_path)
uri = URI hosted_sources(remote_path)
return download(uri, "slackbuilds/#{tarball}").hexdigest
end
checksum = download uri, "slackbuilds/#{tarball}"
sh(*upload_command(tarball, remote_path))
checksum.hexdigest
end
def write_info(package, downloads:)
File.write "slackbuilds/#{package.path}/#{package.name}.info",
info_template(package, downloads)
end
def update_slackbuild_version(package_path, version)
name = package_path.split('/').last
slackbuild_filename = "slackbuilds/#{package_path}/#{name}.SlackBuild"
slackbuild_contents = File.read(slackbuild_filename)
.gsub(/^VERSION=\${VERSION:-.+/, "VERSION=${VERSION:-#{version}}")
File.open(slackbuild_filename, 'w') { |file| file.puts slackbuild_contents }
end
def commit(package_path, version)
message = "#{package_path}: Updated for version #{version}"
unless system('git', '-C', 'slackbuilds', 'checkout', CONFIG[:branch],
err: '/dev/null')
sh 'git', '-C', 'slackbuilds', 'checkout', '-b', CONFIG[:branch], 'master'
end
sh 'git', '-C', 'slackbuilds', 'add', package_path
sh 'git', '-C', 'slackbuilds', 'commit', '-S', '-m', message
# sh 'git', '-C', 'slackbuilds', 'push', 'origin', CONFIG[:branch]
end

View File

@ -1,76 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
class Package
attr_reader :path, :version, :homepage, :requires
def initialize(path, version:, homepage:, requires: [])
@path = path
@version = version
@homepage = homepage
@requires = requires
end
def name
File.basename @path
end
def name_version
"#{name}-#{@version}"
end
end
class Download
attr_reader :download, :md5sum
def initialize(download, md5sum, is64: false)
@download = download
@md5sum = md5sum
@is64 = is64
end
def is64?
@is64
end
end
def info_template(package, downloads)
downloads64, downloads32 = downloads.partition(&:is64?)
download32, md5sum32, download64, md5sum64 = download_entries downloads64, downloads32
<<~INFO_FILE
PRGNAM="#{package.name}"
VERSION="#{package.version}"
HOMEPAGE="#{package.homepage}"
DOWNLOAD="#{download32}"
MD5SUM="#{md5sum32}"
DOWNLOAD_x86_64="#{download64}"
MD5SUM_x86_64="#{md5sum64}"
REQUIRES="#{requires_entry package.requires}"
MAINTAINER="Eugene Wissner"
EMAIL="belka@caraus.de"
INFO_FILE
end
private
def requires_entry(requires)
requires * ' '
end
def download_entries(downloads64, downloads32)
download32 =
if downloads32.empty? && !downloads64.empty?
'UNSUPPORTED'
else
downloads32.map(&:download) * " \\\n "
end
md5sum32 = downloads32.map(&:md5sum) * " \\\n "
download64 = downloads64.map(&:download) * " \\\n "
md5sum64 = downloads64.map(&:md5sum) * " \\\n "
[download32, md5sum32, download64, md5sum64]
end

View File

@ -1,4 +0,0 @@
Colm is a programming language designed for the analysis and
and transformation of computer languages.
Colm is influenced primarily by TXL.
It is in the family of program transformation languages.

View File

@ -1,112 +0,0 @@
#!/bin/bash
# Slackware build script for colm
# Copyright 2017-2019 Matteo Bernardini <ponce@slackbuilds.org>, Pisa, Italy
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=colm
VERSION=${VERSION:-0.14.7}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=${TMP:-/tmp/SBo}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
DOCS="COPYING README"
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
tar xvf $CWD/$PRGNAM-$VERSION.tar.?z*
cd $PRGNAM-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
autoreconf -fi
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/man \
--docdir=/usr/doc/$PRGNAM-$VERSION \
--build=$ARCH-slackware-linux
make
make install DESTDIR=$PKG
find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a $DOCS $PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -1,10 +0,0 @@
PRGNAM="colm"
VERSION="0.14.7"
HOMEPAGE="https://www.colm.net/open-source/colm/"
DOWNLOAD="https://www.colm.net/files/colm/colm-0.14.7.tar.gz"
MD5SUM="073b11234fe64a281874b4466c0c25ee"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES=""
MAINTAINER="Matteo Bernardini"
EMAIL="ponce@slackbuilds.org"

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description.
# Line up the first '|' above the ':' following the base package name, and
# the '|' on the right side marks the last column you can put a character in.
# You must make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':' except on otherwise blank lines.
|-----handy-ruler------------------------------------------------------|
colm: colm (Programming language)
colm:
colm: Colm is a programming language designed for the analysis and
colm: and transformation of computer languages.
colm: Colm is influenced primarily by TXL.
colm: It is in the family of program transformation languages.
colm:
colm: homepage: https://www.colm.net/open-source/colm/
colm:
colm:
colm:

View File

@ -1,182 +0,0 @@
#!/bin/bash
# Copyright 2008, 2009, 2010, 2012, 2013, 2014, 2017, 2018, 2020, 2021 Patrick J. Volkerding, Sebeka, Minnesota, USA
# Copyright 2011, 2012, 2013, 2014, 2017 Heinz Wiesinger, Amsterdam, The Netherlands
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Build and install MySQL on Slackware
# by: David Cantrell <david@slackware.com>
# MariaDB conversion by: Heinz Wiesinger <pprkut@liwjatan.at>
# Also maintained by: Patrick Volkerding <volkerdi@slackware.com>
cd $(dirname $0) ; CWD=$(pwd)
PKGNAM=mysql
VERSION=${VERSION:-8.0.30}
BUILD=${BUILD:-1}
# To reduce the package size, the embedded server may be omitted. Currently
# only amarok uses this. To build without embedded support, set this to NO.
EMBEDDED=${EMBEDDED:-YES}
# Add a description tag to the $BUILD. This is used by
# "build_embedded_package.sh" to mark packages containing the embedded server,
# but can optionally be used with any kind of custom tag desired.
TAG=${TAG:-}
# Automatically determine the architecture we're building on:
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) export ARCH=i586 ;;
arm*) export ARCH=arm ;;
# Unless $ARCH is already set, use uname -m for all other archs:
*) export ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PKGNAM-$VERSION-$ARCH-${BUILD}${TAG}.txz"
exit 0
fi
NUMJOBS=${NUMJOBS:-" -j$(expr $(nproc) + 1) "}
TMP=${TMP:-/tmp}
PKG=$TMP/package-${PKGNAM}
if [ "$ARCH" = "i486" ]; then
SLKCFLAGS="-O2 -march=i486 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
fi
rm -rf $PKG
mkdir -p $TMP $PKG
cd $TMP
rm -rf ${PKGNAM}-$VERSION
tar xvf $CWD/${PKGNAM}-boost-$VERSION.tar.?z || exit 1
cd ${PKGNAM}-$VERSION || exit 1
chown -R root:root .
find . \
\( -perm 777 -o -perm 775 -o -perm 711 -o -perm 555 -o -perm 511 \) \
-exec chmod 755 {} \+ -o \
\( -perm 666 -o -perm 664 -o -perm 600 -o -perm 444 -o -perm 440 -o -perm 400 \) \
-exec chmod 644 {} \+
mkdir build
cd build
cmake \
-DCMAKE_C_FLAGS="$SLKCFLAGS" \
-DCMAKE_CXX_FLAGS="$SLKCFLAGS" \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFEATURE_SET="community" \
-DINSTALL_LAYOUT="RPM" \
-DCMAKE_INSTALL_PREFIX=/usr \
-DINSTALL_LIBDIR="lib${LIBDIRSUFFIX}" \
-DINSTALL_SBINDIR=libexec \
-DINSTALL_INCLUDEDIR=include/mysql \
-DINSTALL_MYSQLSHAREDIR=/usr/share/mysql \
-DINSTALL_SQLBENCHDIR= \
-DINSTALL_MYSQLTESTDIR=mysql-test \
-DINSTALL_MANDIR=man \
-DINSTALL_PLUGINDIR="/usr/lib${LIBDIRSUFFIX}/mysql/plugin" \
-DINSTALL_SCRIPTDIR=bin \
-DINSTALL_SUPPORTFILESDIR=/usr/share/mysql \
-DINSTALL_MYSQLDATADIR="/var/lib/mysql" \
-DINSTALL_DOCREADMEDIR="doc/${PKGNAM}-$VERSION" \
-DINSTALL_DOCDIR="doc/${PKGNAM}-$VERSION" \
-DMYSQL_DATADIR="/var/lib/mysql" \
-DMYSQL_UNIX_ADDR="/var/run/mysql/mysql.sock" \
-DWITH_EXTRA_CHARSETS=complex \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=ON \
-DWITH_EMBEDDED_SERVER=${EMBEDDED} \
-DWITH_LIBARCHIVE=ON \
-DWITH_READLINE=ON \
-DWITH_ROCKSDB_JEMALLOC=ON \
-DWITH_ZLIB=system \
-DWITH_EXTERNAL_ZLIB=ON \
-DWITH_SSL=system \
-DWITH_BOOST="../boost" \
-DCONC_WITH_SSL=ON \
-DUSE_ARIA_FOR_TMP_TABLES=ON \
-DAWS_SDK_EXTERNAL_PROJECT=OFF \
.. || exit 1
# ruby mysql2 fails to run
# -DWITH_JEMALLOC=system \
make $NUMJOBS || make || exit 1
make install DESTDIR=$PKG || exit 1
# Sorry, I'm not going to put up with "/etc/systemd/" just for a config file
# that isn't really needed anyway:
rm -rf $PKG/etc/systemd
# Leave build directory:
cd ..
# Remove large static libraries:
rm -f $PKG/usr/lib${LIBDIRSUFFIX}/libmysqlclient.a
# Do not include the test suite:
rm -rf $PKG/usr/mysql-test
# The ./configure option to omit this has gone away, so we'll omit it
# the old-fashioned way. It's all in the source tarball if you need it.
rm -rf $PKG/usr/sql-bench
# This is the directory where databases are stored
mkdir -p $PKG/var/lib/mysql $PKG/var/lib/mysql-files
chown mysql.mysql $PKG/var/lib/mysql $PKG/var/lib/mysql-files
chmod 0750 $PKG/var/lib/mysql $PKG/var/lib/mysql-files
# This is where the socket is stored
mkdir -p $PKG/var/run/mysql
chown mysql.mysql $PKG/var/run/mysql
chmod 0755 $PKG/var/run/mysql
rm -rf $PKG/etc/init.d $PKG/usr/libexec/rcmysql
# Mark config files under /etc as .new
rm -rf $PKG/etc/logrotate.d
find $PKG | xargs file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
find $PKG/usr/man -type f -exec gzip -9 {} \+
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
/sbin/makepkg -l y -c n $TMP/${PKGNAM}-$VERSION-$ARCH-${BUILD}${TAG}.txz

View File

@ -1,10 +0,0 @@
PRGNAM="mysql"
VERSION="8.0.30"
HOMEPAGE="https://dev.mysql.com"
DOWNLOAD=""
MD5SUM=""
DOWNLOAD_x86_64="https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.30.tar.gz"
MD5SUM_x86_64="313d625fcaa932bd87b48f0cf9b40f1c"
REQUIRES=""
MAINTAINER="Eugene Wissner"
EMAIL="belka@caraus.de"

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|'
# on the right side marks the last column you can put a character in. You must
# make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':'.
|-----handy-ruler------------------------------------------------------|
mysql: mysql (The MySQL Database Server)
mysql:
mysql: MySQL Server, the world's most popular open source database, and
mysql: MySQL Cluster, a real-time, open source transactional database.
mysql:
mysql: Homepage: www.mysql.com/
mysql:
mysql:
mysql:
mysql:
mysql:

View File

@ -1,4 +0,0 @@
PackageKit is a DBUS abstraction layer that allows the session user to manage
packages in a secure way using a cross-distro, cross-architecture API.
The script requires bash-completion from extra.

View File

@ -1,11 +0,0 @@
--- a/meson.build 2022-12-01 19:47:48.000000000 +0100
+++ b/meson.build 2022-12-05 13:10:39.303777801 +0100
@@ -45,7 +45,7 @@
elogind = []
if get_option('elogind')
- elogind = dependency('elogind', version: '>=229.4')
+ elogind = dependency('libelogind', version: '>=229.4')
add_project_arguments ('-DHAVE_SYSTEMD_SD_LOGIN_H=1', language: 'c')
endif

View File

@ -1,120 +0,0 @@
#!/bin/bash
# Slackware build script for packagekit
#
# Copyright 2022 Eugene Wissner, Germany, Dachau
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=packagekit
VERSION=${VERSION:-1.2.6}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
SRCNAM=PackageKit
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=${TMP:-/tmp}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $SRCNAM-$VERSION
tar xvf $CWD/$SRCNAM-$VERSION.tar.xz
cd $SRCNAM-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
patch -p1 --verbose -i $CWD/meson_elogind.patch
mkdir build
cd build
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
meson .. \
--buildtype=release \
--infodir=/usr/info \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--localstatedir=/var \
--prefix=/usr \
--sysconfdir=/etc \
-Dstrip=true \
-Dsystemd=false \
-Doffline_update=false \
-Delogind=true \
-Dpackaging_backend=slack
"${NINJA:=ninja}"
DESTDIR=$PKG $NINJA install
cd ..
mv $PKG/usr/share/man $PKG/usr/man
find $PKG/usr/man -type f -exec gzip -9 {} \;
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a \
AUTHORS COPYING HACKING MAINTAINERS NEWS README RELEASE \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -1,11 +0,0 @@
PRGNAM="packagekit"
VERSION="1.2.6"
HOMEPAGE="https://www.freedesktop.org/software/PackageKit/"
DOWNLOAD="https://www.freedesktop.org/software/PackageKit/releases/PackageKit-1.2.6.tar.xz"
MD5SUM="71f855b4ac809b642ec911ce12dd8010"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES=""
MAINTAINER="Eugene Wissner"
EMAIL="belka@caraus.de"
PackageKit-1.2.6.tar.xz

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|'
# on the right side marks the last column you can put a character in. You must
# make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':'.
|-----handy-ruler------------------------------------------------------|
packagekit: PackageKit (A DBUS packaging abstraction layer)
packagekit:
packagekit: PackageKit is a DBUS abstraction layer that allows the session user to
packagekit: packages in a secure way using a cross-distro, cross-architecture API.
packagekit:
packagekit: Homepage: https://www.freedesktop.org/software/PackageKit/
packagekit:
packagekit:
packagekit:
packagekit:
packagekit:

View File

@ -1,7 +0,0 @@
PHP is an HTML-embedded scripting language. It shares syntax
characteristics with C, Java, and Perl. The primary objective behind
this language is to make a fast and easy-to-use scripting language for
dynamic web sites.
This installation is compatible with the official php package and
doesn't overwrit any stock files.

View File

@ -1,18 +0,0 @@
config() {
NEW="$1"
OLD="`dirname $NEW`/`basename $NEW .new`"
# If there's no config file by that name, mv it over:
if [ ! -r $OLD ]; then
mv $NEW $OLD
elif [ "`cat $OLD | md5sum`" = "`cat $NEW | md5sum`" ]; then # toss the redundant copy
rm $NEW
fi
# Otherwise, we leave the .new copy for the admin to consider...
}
# Keep same perms on rc.php-fpm.new:
if [ -e etc/rc.d/rc.php-fpm-8.1 ]; then
cp -a etc/rc.d/rc.php-fpm-8.1 etc/rc.d/rc.php-fpm-8.1.new.incoming
cat etc/rc.d/rc.php-fpm-8.1.new > etc/rc.d/rc.php-fpm-8.1.new.incoming
mv etc/rc.d/rc.php-fpm-8.1.new.incoming etc/rc.d/rc.php-fpm-8.1.new
fi
config etc/rc.d/rc.php-fpm-8.1.new

View File

@ -1,221 +0,0 @@
#!/bin/bash
# Build and package PHP FPM 8.1
# Copyright 2022 Eugene Wissner, Germany, Dachau
#
# by: David Cantrell <david@slackware.com>
# Modified for PHP 4-5 by volkerdi@slackware.com
# Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2017, 2019, 2020, 2021 Patrick Volkerding, Sebeka, MN, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=php81
VERSION=${VERSION:-8.1.13}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
VERSION_SUFFIX=8.1
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=${TMP:-/tmp}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf php-$VERSION
tar xvf $CWD/php-$VERSION.tar.xz
cd php-$VERSION
chown -R root:root .
# Sometimes they ship a few of these:
find . -name "*.orig" -delete
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
sed -i "s|build$|php/${VERSION_SUFFIX}/build|" scripts/Makefile.frag
sed -i "s|build\"$|php/${VERSION_SUFFIX}/build\"|" scripts/phpize.in
EXTENSION_DIR=/usr/lib${LIBDIRSUFFIX}/php/${VERSION_SUFFIX}/extensions \
CFLAGS="$SLKCFLAGS -DU_DEFINE_FALSE_AND_TRUE=1" \
CXXFLAGS="$SLKCFLAGS -DU_USING_ICU_NAMESPACE=1 -DU_DEFINE_FALSE_AND_TRUE=1" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--with-libdir=lib${LIBDIRSUFFIX} \
--localstatedir=/var \
--sysconfdir=/etc/php/${VERSION_SUFFIX} \
--datarootdir=/usr/share \
--datadir=/usr/share \
--infodir=/usr/info \
--mandir=/usr/man \
--program-suffix=-$VERSION_SUFFIX \
--without-apxs2 \
--enable-fpm \
--with-fpm-user=apache \
--with-fpm-group=apache \
--enable-zts \
--enable-pcntl \
--enable-mbregex \
--enable-tokenizer=shared \
--with-config-file-scan-dir=/etc/php/${VERSION_SUFFIX}/php.d \
--with-config-file-path=/etc/php/${VERSION_SUFFIX} \
--with-layout=PHP \
--disable-sigchild \
--with-libxml \
--with-expat \
--enable-simplexml \
--enable-xmlreader=shared \
--enable-dom=shared \
--enable-filter \
--disable-debug \
--with-openssl=shared \
--with-external-pcre \
--with-zlib=shared,/usr \
--enable-bcmath=shared \
--with-bz2=shared,/usr \
--enable-calendar=shared \
--enable-ctype=shared \
--with-curl=shared \
--enable-dba=shared \
--with-gdbm=/usr \
--with-db4=/usr \
--enable-exif=shared \
--enable-ftp=shared \
--enable-gd=shared \
--with-external-gd \
--with-jpeg \
--with-xpm \
--with-gettext=shared,/usr \
--with-gmp=shared,/usr \
--with-iconv=shared \
--with-imap-ssl=/usr \
--with-pdo-pgsql=shared,/usr/bin/pg_config \
--with-pgsql=shared,/usr/bin/pg_config \
--with-ldap=shared \
--enable-mbstring=shared \
--enable-mysqlnd=shared \
--with-mysqli=shared,mysqlnd \
--with-mysql-sock=/var/run/mysql/mysql.sock \
--with-iodbc=shared,/usr \
--enable-pdo=shared \
--with-pdo-mysql=shared,mysqlnd \
--with-pdo-sqlite=shared,/usr \
--with-pdo-odbc=shared,iODBC,/usr \
--with-pspell=shared,/usr \
--with-enchant=shared,/usr \
--enable-shmop=shared \
--with-snmp=shared,/usr \
--enable-soap=shared \
--enable-sockets \
--with-sqlite3=shared \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--with-xsl=shared,/usr \
--with-zip=shared \
--enable-intl=shared \
--enable-opcache \
--enable-shared=yes \
--enable-static=no \
--with-gnu-ld \
--with-pic \
--enable-phpdbg \
--with-sodium \
--with-password-argon2 \
--without-readline \
--with-libedit \
--with-pear=/usr/lib${LIBDIRSUFFIX}/php/${VERSION_SUFFIX} \
--includedir=/usr/include/php/${VERSION_SUFFIX} \
--with-tidy=shared \
--build=$ARCH-slackware-linux
make
make install INSTALL_ROOT=$PKG
mkdir -p $PKG/etc/rc.d
cp sapi/fpm/init.d.php-fpm $PKG/etc/rc.d/rc.php-fpm-${VERSION_SUFFIX}.new
chmod 644 $PKG/etc/rc.d/rc.php-fpm-${VERSION_SUFFIX}.new
# Strip ELF objects.
find $PKG | xargs file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
find $PKG/usr/man -type f -exec gzip -9 {} \;
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
# PHP sometimes puts junk in the root directory:
( cd $PKG
rm -rf .channels .depdb .depdblock .filemap .lock .registry
)
rm -r $PKG/usr/share/fpm $PKG/usr/bin/pear $PKG/usr/bin/peardev
mv $PKG/usr/bin/pecl $PKG/usr/bin/pecl-${VERSION_SUFFIX}
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a \
CODING_STANDARDS* CONTRIBUTING* EXTENSIONS* LICENSE* NEWS* README* UPGRADING* \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cat $CWD/doinst.sh > $PKG/install/doinst.sh
cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -1,10 +0,0 @@
PRGNAM="php81"
VERSION="8.1.13"
HOMEPAGE="https://www.php.net/"
DOWNLOAD="https://www.php.net/distributions/php-8.1.13.tar.xz"
MD5SUM="43302de3d2c064f2f23c9693a2f17aeb"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES="postgresql"
MAINTAINER="Eugene Wissner"
EMAIL="belka@caraus.de"

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|'
# on the right side marks the last column you can put a character in. You must
# make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':'.
|-----handy-ruler------------------------------------------------------|
php81: php81 (HTML-embedded scripting language)
php81:
php81: PHP is an HTML-embedded scripting language. It shares syntax
php81: characteristics with C, Java, and Perl. The primary objective behind
php81: this language is to make a fast and easy-to-use scripting language
php81: for dynamic web sites.
php81:
php81: Homepage: https://www.php.net/
php81:
php81:
php81:

View File

@ -1,7 +0,0 @@
PHP is an HTML-embedded scripting language. It shares syntax
characteristics with C, Java, and Perl. The primary objective behind
this language is to make a fast and easy-to-use scripting language for
dynamic web sites.
This installation is compatible with the official php package and
doesn't overwrit any stock files.

View File

@ -1,18 +0,0 @@
config() {
NEW="$1"
OLD="`dirname $NEW`/`basename $NEW .new`"
# If there's no config file by that name, mv it over:
if [ ! -r $OLD ]; then
mv $NEW $OLD
elif [ "`cat $OLD | md5sum`" = "`cat $NEW | md5sum`" ]; then # toss the redundant copy
rm $NEW
fi
# Otherwise, we leave the .new copy for the admin to consider...
}
# Keep same perms on rc.php-fpm.new:
if [ -e etc/rc.d/rc.php-fpm-8.2 ]; then
cp -a etc/rc.d/rc.php-fpm-8.2 etc/rc.d/rc.php-fpm-8.2.new.incoming
cat etc/rc.d/rc.php-fpm-8.2.new > etc/rc.d/rc.php-fpm-8.2.new.incoming
mv etc/rc.d/rc.php-fpm-8.2.new.incoming etc/rc.d/rc.php-fpm-8.2.new
fi
config etc/rc.d/rc.php-fpm-8.2.new

View File

@ -1,221 +0,0 @@
#!/bin/bash
# Build and package PHP FPM 8.2
# Copyright 2022 Eugene Wissner, Germany, Dachau
#
# by: David Cantrell <david@slackware.com>
# Modified for PHP 4-5 by volkerdi@slackware.com
# Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2017, 2019, 2020, 2021 Patrick Volkerding, Sebeka, MN, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=php82
VERSION=${VERSION:-8.2.0}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
VERSION_SUFFIX=8.2
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=${TMP:-/tmp}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf php-$VERSION
tar xvf $CWD/php-$VERSION.tar.xz
cd php-$VERSION
chown -R root:root .
# Sometimes they ship a few of these:
find . -name "*.orig" -delete
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \; -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \;
sed -i "s|build$|php/${VERSION_SUFFIX}/build|" scripts/Makefile.frag
sed -i "s|build\"$|php/${VERSION_SUFFIX}/build\"|" scripts/phpize.in
EXTENSION_DIR=/usr/lib${LIBDIRSUFFIX}/php/${VERSION_SUFFIX}/extensions \
CFLAGS="$SLKCFLAGS -DU_DEFINE_FALSE_AND_TRUE=1" \
CXXFLAGS="$SLKCFLAGS -DU_USING_ICU_NAMESPACE=1 -DU_DEFINE_FALSE_AND_TRUE=1" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--with-libdir=lib${LIBDIRSUFFIX} \
--localstatedir=/var \
--sysconfdir=/etc/php/${VERSION_SUFFIX} \
--datarootdir=/usr/share \
--datadir=/usr/share \
--infodir=/usr/info \
--mandir=/usr/man \
--program-suffix=-$VERSION_SUFFIX \
--without-apxs2 \
--enable-fpm \
--with-fpm-user=apache \
--with-fpm-group=apache \
--enable-zts \
--enable-pcntl \
--enable-mbregex \
--enable-tokenizer=shared \
--with-config-file-scan-dir=/etc/php/${VERSION_SUFFIX}/php.d \
--with-config-file-path=/etc/php/${VERSION_SUFFIX} \
--with-layout=PHP \
--disable-sigchild \
--with-libxml \
--with-expat \
--enable-simplexml \
--enable-xmlreader=shared \
--enable-dom=shared \
--enable-filter \
--disable-debug \
--with-openssl=shared \
--with-external-pcre \
--with-zlib=shared,/usr \
--enable-bcmath=shared \
--with-bz2=shared,/usr \
--enable-calendar=shared \
--enable-ctype=shared \
--with-curl=shared \
--enable-dba=shared \
--with-gdbm=/usr \
--with-db4=/usr \
--enable-exif=shared \
--enable-ftp=shared \
--enable-gd=shared \
--with-external-gd \
--with-jpeg \
--with-xpm \
--with-gettext=shared,/usr \
--with-gmp=shared,/usr \
--with-iconv=shared \
--with-imap-ssl=/usr \
--with-pdo-pgsql=shared,/usr/bin/pg_config \
--with-pgsql=shared,/usr/bin/pg_config \
--with-ldap=shared \
--enable-mbstring=shared \
--enable-mysqlnd=shared \
--with-mysqli=shared,mysqlnd \
--with-mysql-sock=/var/run/mysql/mysql.sock \
--with-iodbc=shared,/usr \
--enable-pdo=shared \
--with-pdo-mysql=shared,mysqlnd \
--with-pdo-sqlite=shared,/usr \
--with-pdo-odbc=shared,iODBC,/usr \
--with-pspell=shared,/usr \
--with-enchant=shared,/usr \
--enable-shmop=shared \
--with-snmp=shared,/usr \
--enable-soap=shared \
--enable-sockets \
--with-sqlite3=shared \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--with-xsl=shared,/usr \
--with-zip=shared \
--enable-intl=shared \
--enable-opcache \
--enable-shared=yes \
--enable-static=no \
--with-gnu-ld \
--with-pic \
--enable-phpdbg \
--with-sodium \
--with-password-argon2 \
--without-readline \
--with-libedit \
--with-pear=/usr/lib${LIBDIRSUFFIX}/php/${VERSION_SUFFIX} \
--includedir=/usr/include/php/${VERSION_SUFFIX} \
--with-tidy=shared \
--build=$ARCH-slackware-linux
make
make install INSTALL_ROOT=$PKG
mkdir -p $PKG/etc/rc.d
cp sapi/fpm/init.d.php-fpm $PKG/etc/rc.d/rc.php-fpm-${VERSION_SUFFIX}.new
chmod 644 $PKG/etc/rc.d/rc.php-fpm-${VERSION_SUFFIX}.new
# Strip ELF objects.
find $PKG | xargs file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null
find $PKG/usr/man -type f -exec gzip -9 {} \;
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
# PHP sometimes puts junk in the root directory:
( cd $PKG
rm -rf .channels .depdb .depdblock .filemap .lock .registry
)
rm -r $PKG/usr/share/fpm $PKG/usr/bin/pear $PKG/usr/bin/peardev
mv $PKG/usr/bin/pecl $PKG/usr/bin/pecl-${VERSION_SUFFIX}
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a \
CODING_STANDARDS* CONTRIBUTING* EXTENSIONS* LICENSE* NEWS* README* UPGRADING* \
$PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cat $CWD/doinst.sh > $PKG/install/doinst.sh
cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -1,10 +0,0 @@
PRGNAM="php82"
VERSION="8.2.0"
HOMEPAGE="https://www.php.net/"
DOWNLOAD="https://www.php.net/distributions/php-8.2.0.tar.xz"
MD5SUM="43302de3d2c064f2f23c9693a2f17aeb"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES="postgresql"
MAINTAINER="Eugene Wissner"
EMAIL="belka@caraus.de"

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description. Line
# up the first '|' above the ':' following the base package name, and the '|'
# on the right side marks the last column you can put a character in. You must
# make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':'.
|-----handy-ruler------------------------------------------------------|
php82: php82 (HTML-embedded scripting language)
php82:
php82: PHP is an HTML-embedded scripting language. It shares syntax
php82: characteristics with C, Java, and Perl. The primary objective behind
php82: this language is to make a fast and easy-to-use scripting language
php82: for dynamic web sites.
php82:
php82: Homepage: https://www.php.net/
php82:
php82:
php82:

View File

@ -1,9 +0,0 @@
Ragel compiles executable finite state machines from regular
languages. Ragel targets C, C++, Objective-C, D, Java and Ruby.
Ragel state machines can not only recognize byte sequences as regular
expression machines do, but can also execute code at arbitrary points
in the recognition of a regular language. Code embedding is done using
inline operators that do not disrupt the regular language syntax.
NOTE: before building this it's recommended to remove any previous
version you might have installed.

View File

@ -1,15 +0,0 @@
--- a/configure.ac 2021-02-15 20:45:20.000000000 +0100
+++ b/configure.ac 2021-02-21 17:59:13.593674832 +0100
@@ -46,9 +46,9 @@
COLM_WRAP="$withval/bin/colm-wrap"
CPPFLAGS="-I$withval/include ${CPPFLAGS}"
CPPFLAGS="-I$withval/include/aapl ${CPPFLAGS}"
- LDFLAGS="-L$withval/lib ${LDFLAGS}"
- LIBCOLM_LA="$withval/lib/libcolm.la"
- LIBFSM_LA="$withval/lib/libfsm.la"
+ LDFLAGS="-L$withval/lib64 ${LDFLAGS}"
+ LIBCOLM_LA="$withval/lib64/libcolm.la"
+ LIBFSM_LA="$withval/lib64/libfsm.la"
COLM_SHARE="$withval/share"
],
[]

View File

@ -1,119 +0,0 @@
#!/bin/bash
# Slackware build script for ragel
# Copyright 2012-2019 Matteo Bernardini <ponce@slackbuilds.org>, Pisa, Italy
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# 20220308 bkw: Modified by SlackBuilds.org:
# This build always fails if ragel is already installed. Add a check
# to make it fail quickly, with a useful error message (instead of a
# confusing link error, after compiling for several minutes).
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=ragel
VERSION=${VERSION:-7.0.4}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
i?86) ARCH=i586 ;;
arm*) ARCH=arm ;;
*) ARCH=$( uname -m ) ;;
esac
fi
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE"
exit 0
fi
TMP=${TMP:-/tmp/SBo}
PKG=$TMP/package-$PRGNAM
OUTPUT=${OUTPUT:-/tmp}
if [ "$ARCH" = "i586" ]; then
SLKCFLAGS="-O2 -march=i586 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
SLKCFLAGS="-O2 -march=i686 -mtune=i686"
LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
SLKCFLAGS="-O2 -fPIC"
LIBDIRSUFFIX="64"
else
SLKCFLAGS="-O2"
LIBDIRSUFFIX=""
fi
DOCS="COPYING README"
set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
rm -rf $PRGNAM-$VERSION
tar xvf $CWD/$PRGNAM-$VERSION.tar.gz
cd $PRGNAM-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
-o -perm 511 \) -exec chmod 755 {} \+ -o \
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \+
if [ "$LIBDIRSUFFIX" = "64" ]; then
patch --verbose -p1 -i $CWD/lib64.patch
fi
CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
--libdir=/usr/lib${LIBDIRSUFFIX} \
--sysconfdir=/etc \
--localstatedir=/var \
--mandir=/usr/man \
--docdir=/usr/doc/$PRGNAM-$VERSION \
--disable-static \
--with-colm=/usr \
--disable-manual \
--build=$ARCH-slackware-linux
make
make install-strip DESTDIR=$PKG
gzip -9 $PKG/usr/man/man*/*
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION
cp -a $DOCS $PKG/usr/doc/$PRGNAM-$VERSION
cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
rm -f $PKG/usr/lib*/*.la
mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE

View File

@ -1,10 +0,0 @@
PRGNAM="ragel"
VERSION="7.0.4"
HOMEPAGE="https://www.colm.net/open-source/ragel/"
DOWNLOAD="https://www.colm.net/files/ragel/ragel-7.0.4.tar.gz"
MD5SUM="2ca4f5507c1923bcf9a7909baa8254d3"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES="colm kelbt"
MAINTAINER="Matteo Bernardini"
EMAIL="ponce@slackbuilds.org"

View File

@ -1,19 +0,0 @@
# HOW TO EDIT THIS FILE:
# The "handy ruler" below makes it easier to edit a package description.
# Line up the first '|' above the ':' following the base package name, and
# the '|' on the right side marks the last column you can put a character in.
# You must make exactly 11 lines for the formatting to be correct. It's also
# customary to leave one space after the ':' except on otherwise blank lines.
|-----handy-ruler------------------------------------------------------|
ragel: ragel (State Machine Compiler)
ragel:
ragel: Ragel compiles executable finite state machines from regular
ragel: languages. Ragel targets C, C++, Objective-C, D, Java and Ruby.
ragel: Ragel state machines can not only recognize byte sequences as regular
ragel: expression machines do, but can also execute code at arbitrary points
ragel: in the recognition of a regular language. Code embedding is done using
ragel: inline operators that do not disrupt the regular language syntax.
ragel:
ragel: homepage: https://www.colm.net/open-source/ragel/
ragel:

View File

@ -1,83 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
require 'rake'
require_relative '../lib/download'
module SlackBuilder
module DmdTools
extend Rake::FileUtilsExt
def self.update_dmd(version)
tarball_name = "dmd.#{version}.linux.tar.xz"
uri = URI "http://downloads.dlang.org/releases/2.x/#{version}/#{tarball_name}"
checksum = download(uri, "slackbuilds/development/dmd/#{tarball_name}")
package = Package.new 'development/dmd', version: version,
homepage: 'https://dlang.org'
write_info package, downloads: [Download.new(uri.to_s, checksum.hexdigest)]
update_slackbuild_version 'development/dmd', package.version
commit 'development/dmd', version
end
def self.update_tools(version, dub_version, dscanner_version, dcd_version)
checksum = collect_checksums(version, dub_version, dscanner_version, dcd_version)
package = Package.new 'development/d-tools',
version: version,
homepage: 'https://dlang.org',
requires: ['dmd']
write_tools_info package, dub_version, dscanner_version, dcd_version, checksum
update_tools_versions dub_version, dscanner_version, dcd_version
update_slackbuild_version 'development/d-tools', package.version
commit 'development/d-tools', package.version
end
private_class_method def self.write_tools_info(package, dub_version, dscanner_version, dcd_version, checksum)
write_info package,
downloads: [
Download.new(hosted_sources("/d-tools/dub-#{dub_version}.tar.gz"), checksum[:dub]),
Download.new(hosted_sources("/d-tools/tools-#{package.version}.tar.gz"), checksum[:tools]),
Download.new(hosted_sources("/d-tools/D-Scanner-#{dscanner_version}.tar.xz"), checksum[:dscanner]),
Download.new(hosted_sources("/d-tools/DCD-#{dcd_version}.tar.xz"), checksum[:dcd])
]
end
private_class_method def self.collect_checksums(version, dub_version, dscanner_version, dcd_version)
checksum = {}
uri = URI "https://codeload.github.com/dlang/tools/tar.gz/v#{version}"
checksum[:tools] = download_and_deploy uri, "development/d-tools/tools-#{version}.tar.gz"
uri = URI "https://codeload.github.com/dlang/dub/tar.gz/v#{dub_version}"
checksum[:dub] = download_and_deploy uri, "development/d-tools/dub-#{dub_version}.tar.gz"
checksum[:dscanner] = clone 'https://github.com/dlang-community/D-Scanner.git',
"development/d-tools/D-Scanner-#{dscanner_version}.tar.xz"
checksum[:dcd] = clone 'https://github.com/dlang-community/DCD.git',
"development/d-tools/DCD-#{dcd_version}.tar.xz"
checksum
end
private_class_method def self.update_tools_versions(dub_version, dscanner_version, dcd_version)
slackbuild_filename = 'slackbuilds/development/d-tools/d-tools.SlackBuild'
slackbuild_contents = File.read(slackbuild_filename)
.gsub(/^DUB_VERSION=\${DUB_VERSION:-.+/,
"DUB_VERSION=${DUB_VERSION:-#{dub_version}}")
.gsub(/^DSCANNER_VERSION=\${DSCANNER_VERSION:-.+/,
"DSCANNER_VERSION=${DSCANNER_VERSION:-#{dscanner_version}}")
.gsub(/^DCD_VERSION=\${DCD_VERSION:-.+/,
"DCD_VERSION=${DCD_VERSION:-#{dcd_version}}")
File.open(slackbuild_filename, 'w') { |file| file.puts slackbuild_contents }
end
end
end

View File

@ -1,67 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# frozen_string_literal: true
namespace :hhvm do
desc 'Generates diffs with removed download URLs'
task :bundled_dependencies, [:version] do |_, arguments|
run_on_source arguments[:version] do |third_party|
c_make_lists = third_party + 'CMakeLists.txt'
next unless c_make_lists.exist?
contents = c_make_lists.read
set_hhvm_start = contents.index 'SET_HHVM_THIRD_PARTY_SOURCE_ARGS('
next if set_hhvm_start.nil?
line = contents[..set_hhvm_start].count "\n"
in_lines = contents.lines
4.times { in_lines.delete_at(line + 2) }
puts Open3.capture2('diff', '-Nur', c_make_lists.to_path, '-', stdin_data: in_lines.join).first
end
end
desc 'Generated SlackBuild code to prepare bundled dependencies'
task :bundled_code, [:version] do |_, arguments|
run_on_source arguments[:version] do |third_party|
c_make_lists = third_party + 'CMakeLists.txt'
next unless c_make_lists.exist?
contents = c_make_lists.read
set_hhvm_start = contents.index 'SET_HHVM_THIRD_PARTY_SOURCE_ARGS('
next if set_hhvm_start.nil?
set_hhvm_end = contents.index ')', set_hhvm_start
set_hhvm_start += 'SET_HHVM_THIRD_PARTY_SOURCE_ARGS('.length
set_hhvm_end -= 1
contents = contents[set_hhvm_start..set_hhvm_end].split[1..].map(&:strip)
src = Pathname.new('third-party') +
third_party.basename +
"bundled_#{third_party.basename}-prefix" + 'src'
bundled = src + "bundled_#{third_party.basename}"
archive_name = contents[1][contents[1].rindex('/') + 1..-2]
puts "mkdir -p #{bundled}"
puts "install -m 0644 -D $CWD/#{archive_name} #{src + archive_name}"
puts "tar -zxvf $CWD/#{archive_name} -C #{bundled}"
puts
end
end
end
private
def run_on_source(version, &block)
package = Package.new 'development/hhvm',
version: version,
homepage: 'https://hhvm.com/',
requires: %w[tbb glog libdwarf libmemcached dobule-conversion]
repository = SlackBuilder.clone 'https://github.com/facebook/hhvm.git', package, 'HHVM-'
(repository + 'third-party').each_child do |third_party|
block.call third_party
end
end

107
slackbuilder.cabal Normal file
View File

@ -0,0 +1,107 @@
cabal-version: 2.4
name: slackbuilder
version: 1.0
synopsis: Tool to automatically update Slackware build scripts.
bug-reports: https://git.caraus.tech/OSS/slackbuilder/issues
license: MPL-2.0
license-files: LICENSE
copyright: (c) 2023-2025 Eugen Wissner
author: Eugen Wissner
maintainer: belka@caraus.de
category: Build
extra-source-files:
CHANGELOG.md
README.md
source-repository head
type: git
location: https://git.caraus.tech/OSS/slackbuilder.git
common dependencies
build-depends:
aeson ^>= 2.2.0,
base >= 4.16 && < 5,
bytestring ^>= 0.12.0,
conduit ^>= 1.3.5,
conduit-extra ^>= 1.3,
http-client ^>= 0.7,
http-client-tls ^>= 0.3,
containers ^>= 0.7,
crypton ^>= 1.0,
directory ^>= 1.3.8,
exceptions >= 0.10,
filepath ^>= 1.5,
http-types ^>= 0.12.4,
megaparsec ^>= 9.7,
modern-uri ^>= 0.3.6,
memory ^>= 0.18,
parser-combinators ^>= 1.3,
process ^>= 1.6.18,
req ^>= 3.13,
tar-conduit ^>= 0.4,
lzma ^>= 0.0.1,
text ^>= 2.1,
tomland ^>= 1.3.3,
transformers ^>= 0.6.1,
unordered-containers ^>= 0.2.20,
vector ^>= 0.13.0,
word8 ^>= 0.1.3
default-language: GHC2024
default-extensions:
DuplicateRecordFields
OverloadedStrings
RecordWildCards
QuasiQuotes
TemplateHaskell
library
import: dependencies
exposed-modules:
SlackBuilder.Config
SlackBuilder.Download
SlackBuilder.Info
SlackBuilder.LatestVersionCheck
SlackBuilder.Package
SlackBuilder.Trans
hs-source-dirs: lib
ghc-options: -Wall
build-depends:
mono-traversable ^>= 1.0.17
executable slackbuilder
import: dependencies
main-is: Main.hs
other-modules:
SlackBuilder.CommandLine
SlackBuilder.Update
build-depends:
ansi-terminal ^>= 1.1,
optparse-applicative ^>= 0.18.1,
slackbuilder
hs-source-dirs: src
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
test-suite slackbuilder-test
import: dependencies
type: exitcode-stdio-1.0
main-is: Spec.hs
other-modules:
SlackBuilder.InfoSpec
SlackBuilder.LatestVersionCheckSpec
SlackBuilder.PackageSpec
hs-source-dirs: tests
build-depends:
hspec >= 2.10.9 && < 2.12,
hspec-megaparsec ^>= 2.2,
slackbuilder
ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-tool-depends:
hspec-discover:hspec-discover

118
src/Main.hs Normal file
View File

@ -0,0 +1,118 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
module Main
( main
) where
import Control.Monad.Catch (MonadThrow(..))
import Control.Monad.IO.Class (MonadIO(..))
import qualified Data.Map as Map
import Options.Applicative (execParser)
import SlackBuilder.CommandLine
import SlackBuilder.Config
import SlackBuilder.Trans
import SlackBuilder.LatestVersionCheck
import SlackBuilder.Update
import qualified Toml
import Data.Text (Text)
import qualified Data.Text.IO as Text
import Control.Monad.Trans.Reader (ReaderT(..), asks)
import SlackBuilder.Package (PackageDescription(..), renderTextWithVersion)
import qualified SlackBuilder.Package as Package
import Data.Foldable (find, traverse_)
import GHC.Records (HasField(..))
import System.Console.ANSI
( setSGR
, SGR(..)
, ColorIntensity(..)
, Color(..)
, ConsoleLayer(..)
)
import Data.Maybe (mapMaybe)
import qualified Text.URI as URI
autoUpdatable :: [PackageSettings] -> [PackageDescription]
autoUpdatable = mapMaybe go
where
go PackageSettings{ downloader = setting, downloaders } = do
latest' <- packageUpdaterFromSettings setting
pure $ PackageDescription
{ latest = latest'
, name = getField @"name" setting
, downloaders = Map.fromList $ mapMaybe forDownloader downloaders
}
forDownloader downloaderSettings@DownloaderSettings{ name } =
(name,) <$> packageUpdaterFromSettings downloaderSettings
packageUpdaterFromSettings :: DownloaderSettings -> Maybe Package.Updater
packageUpdaterFromSettings DownloaderSettings{..} = do
getVersion' <- getVersionSettings
detectLatest' <- detectLatestSettings
Just Package.Updater
{ detectLatest = detectLatest'
, getVersion = getVersion'
, is64 = is64
}
where
detectLatestSettings
| Just githubSettings <- github =
let ghArguments = uncurry PackageOwner githubSettings
in Just $ latestGitHub ghArguments version
| Just packagistSettings <- packagist =
let packagistArguments = uncurry PackageOwner packagistSettings
in Just $ latestPackagist packagistArguments
| Just textSettings <- text =
let textArguments = uncurry TextArguments textSettings
in Just $ latestText textArguments version
| otherwise = Nothing
getVersionSettings
| Just template' <- template =
Just $ repackageWithTemplate repackage $ Package.DownloadTemplate template'
| Just CloneSettings{..} <- clone
= flip cloneFromGit (renderTextWithVersion tagTemplate version)
<$> URI.mkURI remote
| otherwise = Nothing
up2Date :: Maybe Text -> SlackBuilderT ()
up2Date selectedPackage = do
packages' <- SlackBuilderT $ asks (getField @"packages")
case selectedPackage of
Nothing -> traverse_ (handleExceptions . go) $ autoUpdatable packages'
Just packageName
| Just foundPackage <- find ((packageName ==) . getField @"name") (autoUpdatable packages') ->
go foundPackage
| otherwise -> throwM $ UpdaterNotFound packageName
where
go package = getAndLogLatest package
>>= mapM_ updatePackageIfRequired
>> liftIO (putStrLn "")
check :: SlackBuilderT ()
check = SlackBuilderT (asks (getField @"packages"))
>>= traverse_ (handleExceptions . go) . autoUpdatable
where
go package = getAndLogLatest package
>>= mapM_ checkUpdateAvailability
>> liftIO (putStrLn "")
main :: IO ()
main = execParser slackBuilderParser
>>= handleExceptions . withCommandLine
where
withCommandLine programCommand = do
settingsResult <- Toml.decodeFileEither settingsCodec configurationFile
case settingsResult of
Right settings -> flip runReaderT settings
$ runSlackBuilderT
$ executeCommand programCommand
Left settingsErrors
-> setSGR [SetColor Foreground Dull Red]
>> putStrLn (configurationFile <> " parsing failed.")
>> setSGR [Reset]
>> Text.putStr (Toml.prettyTomlDecodeErrors settingsErrors)
configurationFile = "config/config.toml"
executeCommand = \case
CheckCommand -> check
Up2DateCommand packageName -> up2Date packageName

View File

@ -0,0 +1,43 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
-- | Command line parser.
module SlackBuilder.CommandLine
( SlackBuilderCommand(..)
, slackBuilderParser
) where
import Data.Text (Text)
import Options.Applicative
( Parser
, ParserInfo(..)
, metavar
, argument
, helper
, str
, info
, fullDesc
, subparser
, command
, optional, progDesc
)
data SlackBuilderCommand
= CheckCommand
| Up2DateCommand (Maybe Text)
slackBuilderParser :: ParserInfo SlackBuilderCommand
slackBuilderParser = info (helper <*> slackBuilderCommand) fullDesc
slackBuilderCommand :: Parser SlackBuilderCommand
slackBuilderCommand = subparser
$ command "check" checkCommand
<> command "up2date" up2DateCommand
where
checkCommand = info checkP $ progDesc "Check all configured slackbuilds for updates"
checkP = pure CheckCommand
up2DateP = Up2DateCommand
<$> optional (argument str (metavar "PKGNAM"))
up2DateCommand = info up2DateP
$ progDesc "Update a single or multiple slackbuild in the configured repository"

333
src/SlackBuilder/Update.hs Normal file
View File

@ -0,0 +1,333 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
module SlackBuilder.Update
( checkUpdateAvailability
, cloneFromGit
, downloadWithTemplate
, getAndLogLatest
, handleExceptions
, listRepository
, repackageWithTemplate
, reuploadWithTemplate
, updatePackageIfRequired
) where
import Control.Exception (Exception(..), SomeException(..))
import Control.Monad.Catch (MonadCatch(..), catches, Handler(..))
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Trans.Reader (asks)
import qualified Data.ByteString.Char8 as Char8
import Data.Foldable (Foldable(..), find)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.List.NonEmpty as NonEmpty
import Data.Maybe (fromJust, fromMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text.IO
import GHC.Records (HasField(..))
import qualified Network.HTTP.Req as Req
import Network.HTTP.Client (HttpException(..), HttpExceptionContent(..), responseStatus)
import System.FilePath
( (</>)
, (<.>)
, dropExtension
, takeBaseName
, splitFileName
, takeDirectory
, takeFileName
, dropTrailingPathSeparator
)
import System.Process
( CmdSpec(..)
, CreateProcess(..)
, StdStream(..)
, withCreateProcess
, waitForProcess
)
import SlackBuilder.Config
import SlackBuilder.Download
import SlackBuilder.Info
import SlackBuilder.Package (PackageDescription(..), PackageUpdateData(..))
import qualified SlackBuilder.Package as Package
import SlackBuilder.Trans
import Text.URI (URI(..))
import qualified Text.URI as URI
import System.Directory
( listDirectory
, doesDirectoryExist
, withCurrentDirectory
, removeDirectoryRecursive
)
import System.Console.ANSI
( setSGR
, SGR(..)
, ColorIntensity(..)
, Color(..)
, ConsoleLayer(..)
)
import Control.Monad (filterM, void)
import Data.List (isPrefixOf, isSuffixOf, partition)
import Data.Functor ((<&>))
import Data.Bifunctor (Bifunctor(..))
import Network.HTTP.Types (Status(..))
getAndLogLatest :: PackageDescription -> SlackBuilderT (Maybe PackageUpdateData)
getAndLogLatest description = do
let PackageDescription{ latest = Package.Updater{ detectLatest }, name } = description
liftIO (putStrLn $ Text.unpack name <> ": Retreiving the latest version.")
detectedVersion <- detectLatest
category <- HashMap.lookup name <$> listRepository
pure $ PackageUpdateData description
<$> category
<*> detectedVersion
checkUpdateAvailability :: PackageUpdateData -> SlackBuilderT (Maybe PackageInfo)
checkUpdateAvailability PackageUpdateData{..} = do
parsedInfoFile <- readInfoFile category $ getField @"name" description
if version == getField @"version" parsedInfoFile
then liftIO $ do
setSGR [SetColor Foreground Dull Green]
Text.IO.putStrLn
$ getField @"name" description <> " is up to date (Version " <> version <> ")."
setSGR [Reset]
pure Nothing
else liftIO $ do
setSGR [SetColor Foreground Dull Yellow]
Text.IO.putStr
$ "A new version of "
<> getField @"name" description
<> " " <> getField @"version" parsedInfoFile
<> " is available (" <> version <> ")."
setSGR [Reset]
putStrLn ""
pure $ Just parsedInfoFile
updatePackageIfRequired :: PackageUpdateData -> SlackBuilderT ()
updatePackageIfRequired updateData
= checkUpdateAvailability updateData
>>= mapM_ (updatePackage updateData)
data DownloadUpdated = DownloadUpdated
{ result :: Package.Download
, version :: Text
, is64 :: Bool
} deriving (Eq, Show)
updateDownload :: Text -> Package.Updater -> SlackBuilderT DownloadUpdated
updateDownload packagePath Package.Updater{..} = do
latestDownloadVersion <- fromJust <$> detectLatest
result <- getVersion packagePath latestDownloadVersion
pure $ DownloadUpdated
{ result = result
, version = latestDownloadVersion
, is64 = is64
}
cloneFromGit :: URI -> Text -> Text -> Text -> SlackBuilderT Package.Download
cloneFromGit repo tagPrefix packagePath version = do
let downloadFileName = URI.unRText
$ NonEmpty.last $ snd $ fromJust $ URI.uriPath repo
relativeTarball = Text.unpack packagePath
</> (dropExtension (Text.unpack downloadFileName) <> "-" <> Text.unpack version)
(uri', checksum) <- cloneAndUpload (URI.render repo) relativeTarball tagPrefix
pure $ Package.Download
{ md5sum = checksum
, download = uri'
}
repackageWithTemplate :: Maybe [String] -> Package.DownloadTemplate -> Text -> Text -> SlackBuilderT Package.Download
repackageWithTemplate Nothing template' = downloadWithTemplate template'
repackageWithTemplate (Just (cmd : arguments)) template' =
reuploadWithTemplate' template' (RawCommand cmd arguments)
repackageWithTemplate (Just []) template' = reuploadWithTemplate template'
downloadWithTemplate :: Package.DownloadTemplate -> Text -> Text -> SlackBuilderT Package.Download
downloadWithTemplate downloadTemplate packagePath version = do
repository' <- SlackBuilderT $ asks repository
uri' <- liftIO $ Package.renderDownloadWithVersion downloadTemplate version
checksum <- download uri' $ repository' </> Text.unpack packagePath
pure $ Package.Download uri' $ snd checksum
reuploadWithTemplate :: Package.DownloadTemplate -> Text -> Text -> SlackBuilderT Package.Download
reuploadWithTemplate downloadTemplate packagePath version = do
repository' <- SlackBuilderT $ asks repository
uri' <- liftIO $ Package.renderDownloadWithVersion downloadTemplate version
let packagePathRelativeToCurrent = repository' </> Text.unpack packagePath
(downloadedFileName, checksum) <- download uri' packagePathRelativeToCurrent
download' <- handleReupload packagePath
$ packagePathRelativeToCurrent </> downloadedFileName
pure $ Package.Download download' checksum
reuploadWithTemplate' :: Package.DownloadTemplate -> CmdSpec -> Text -> Text -> SlackBuilderT Package.Download
reuploadWithTemplate' downloadTemplate commands packagePath version = do
repository' <- SlackBuilderT $ asks repository
uri' <- liftIO $ Package.renderDownloadWithVersion downloadTemplate version
let downloadFileName = Text.unpack
$ URI.unRText
$ NonEmpty.last $ snd $ fromJust $ URI.uriPath uri'
packagePathRelativeToCurrent = repository' </> Text.unpack packagePath
changedArchiveRootName <- extractRemote uri' packagePathRelativeToCurrent
let relativeTarball = packagePathRelativeToCurrent
</> fromMaybe downloadFileName changedArchiveRootName
(relativeTarball', checksum) <- prepareSource relativeTarball
download' <- handleReupload packagePath relativeTarball'
pure $ Package.Download download' checksum
where
prepareSource tarballPath =
liftIO (defaultCreateProcess tarballPath commands)
>> liftIO (tarCompress tarballPath)
<* liftIO (removeDirectoryRecursive tarballPath)
tarCompress tarballPath =
let archiveBaseFilename = takeFileName tarballPath
appendTarExtension = (<.> "tar.xz")
in fmap (appendTarExtension tarballPath,)
$ withCurrentDirectory (takeDirectory tarballPath)
$ createLzmaTarball archiveBaseFilename (appendTarExtension archiveBaseFilename)
defaultCreateProcess cwd' cmdSpec
= flip withCreateProcess (const . const . const waitForProcess)
$ CreateProcess
{ use_process_jobs = False
, std_out = Inherit
, std_in = NoStream
, std_err = Inherit
, new_session = False
, env = Nothing
, detach_console = False
, delegate_ctlc = False
, cwd = Just cwd'
, create_new_console = False
, create_group = False
, cmdspec = cmdSpec
, close_fds = True
, child_user = Nothing
, child_group = Nothing
}
handleReupload :: Text -> String -> SlackBuilderT URI
handleReupload packagePath relativeTarball = do
liftIO $ putStrLn $ "Upload the source tarball " <> relativeTarball
uploadSource relativeTarball category'
hostedSources $ NonEmpty.cons category'
$ pure $ Text.pack $ takeFileName relativeTarball
where
category' = Text.pack $ takeBaseName $ Text.unpack packagePath
updatePackage :: PackageUpdateData -> PackageInfo -> SlackBuilderT ()
updatePackage PackageUpdateData{..} info = do
let packagePath = category <> "/" <> getField @"name" description
latest' = getField @"latest" description
repository' <- SlackBuilderT $ asks repository
mainDownload <- (, getField @"is64" latest')
<$> getField @"getVersion" latest' packagePath version
moreDownloads <- traverse (updateDownload packagePath)
$ getField @"downloaders" description
let (downloads64, allDownloads) = partition snd
$ mainDownload
: (liftA2 (,) (getField @"result") (getField @"is64") <$> toList moreDownloads)
let infoFilePath = repository' </> Text.unpack packagePath
</> (Text.unpack (getField @"name" description) <.> "info")
package' = info
{ version = version
, downloads = getField @"download" . fst <$> allDownloads
, checksums = getField @"md5sum" . fst <$> allDownloads
, downloadX64 = getField @"download" . fst <$> downloads64
, checksumX64 = getField @"md5sum" . fst <$> downloads64
}
liftIO $ Text.IO.writeFile infoFilePath $ generate package'
updateSlackBuildVersion packagePath version
$ getField @"version" <$> moreDownloads
commit packagePath version
listRepository :: SlackBuilderT (HashMap Text Text)
listRepository = do
repository' <- SlackBuilderT $ asks repository
listing <- go repository' [] ""
pure $ HashMap.fromList $ bimap Text.pack Text.pack <$> listing
where
go currentDirectory found accumulatedDirectory = do
let fullDirectory = currentDirectory </> accumulatedDirectory
contents <- liftIO $ listDirectory fullDirectory
case find (isSuffixOf ".info") contents of
Just _ ->
let (category, packageName) = first dropTrailingPathSeparator
$ splitFileName accumulatedDirectory
in pure $ (packageName, category) : found
Nothing ->
let accumulatedDirectories = (accumulatedDirectory </>)
<$> filter (not . isPrefixOf ".") contents
directoryFilter = liftIO . doesDirectoryExist
. (currentDirectory </>)
in filterM directoryFilter accumulatedDirectories
>>= traverse (go currentDirectory found) <&> concat
handleExceptions :: (MonadIO m, MonadCatch m) => forall a. m a -> m ()
handleExceptions action = catches (void action)
[ Handler handleHttp
, Handler handleSome
]
where
printException e
= liftIO (setSGR [SetColor Foreground Dull Red])
>> liftIO (putStrLn e)
>> liftIO (setSGR [Reset])
showStatus (Status code message) =
Char8.pack (show code) <> " \"" <> message <> "\""
showHttpExceptionContent (StatusCodeException response _) = Char8.unpack
$ "The server returned "
<> showStatus (responseStatus response)
<> " response status code."
showHttpExceptionContent (TooManyRedirects _) =
"The server responded with too many redirects for a request."
showHttpExceptionContent OverlongHeaders = "Too many total bytes in the HTTP header were returned by the server."
showHttpExceptionContent TooManyHeaderFields = "Too many HTTP header fields were returned by the server."
showHttpExceptionContent ResponseTimeout = "The server took too long to return a response."
showHttpExceptionContent ConnectionTimeout = "Attempting to connect to the server timed out"
showHttpExceptionContent (ConnectionFailure connectionException) = displayException connectionException
showHttpExceptionContent (InvalidStatusLine statusLine) = Char8.unpack
$ "The status line returned by the server could not be parsed: "
<> statusLine <> "."
showHttpExceptionContent (InvalidHeader headerLine) = Char8.unpack
$ "The given response header line could not be parsed: "
<> headerLine <> "."
showHttpExceptionContent (InvalidRequestHeader headerLine) = Char8.unpack
$ "The given request header is not compliant: "
<> headerLine <> "."
showHttpExceptionContent (InternalException interalException) = displayException interalException
showHttpExceptionContent (ProxyConnectException _ _ status) = Char8.unpack
$ showStatus status
<> " status code was returned when trying to connect to the proxy server on the given host and port."
showHttpExceptionContent NoResponseDataReceived = "No response data was received from the server at all."
showHttpExceptionContent TlsNotSupported = "This HTTP client does not have support for secure connections."
showHttpExceptionContent (WrongRequestBodyStreamSize _ _)
= "The request body provided did not match the expected size."
showHttpExceptionContent (ResponseBodyTooShort _ _) =
"The returned response body is too short. Provides the expected size and actual size."
showHttpExceptionContent InvalidChunkHeaders = "A chunked response body had invalid headers."
showHttpExceptionContent IncompleteHeaders = "An incomplete set of response headers were returned."
showHttpExceptionContent (InvalidDestinationHost hostLine) = Char8.unpack
$ "The host we tried to connect to is invalid"
<> hostLine <> "."
showHttpExceptionContent (HttpZlibException zlibException) = displayException zlibException
showHttpExceptionContent (InvalidProxyEnvironmentVariable environmentName environmentValue) = Text.unpack
$ "Values in the proxy environment variable were invalid: "
<> environmentName <> "=\"" <> environmentValue <> "\"."
showHttpExceptionContent ConnectionClosed = "Attempted to use a Connection which was already closed"
showHttpExceptionContent (InvalidProxySettings _) = "Proxy settings are not valid."
handleHttp :: (MonadIO m, MonadCatch m) => Req.HttpException -> m ()
handleHttp (Req.VanillaHttpException e)
| HttpExceptionRequest _ exceptionContent <- e = printException
$ showHttpExceptionContent exceptionContent
| InvalidUrlException url reason <- e = printException $ url <> ": " <> reason
handleHttp (Req.JsonHttpException e) = printException e
handleSome :: (MonadIO m, MonadCatch m) => SomeException -> m ()
handleSome = printException . show

View File

@ -0,0 +1,150 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
module SlackBuilder.InfoSpec
( spec
) where
import Crypto.Hash (Digest, MD5, digestFromByteString)
import qualified Data.ByteString as ByteString
import Data.ByteString.Char8 (ByteString)
import Data.Maybe (maybeToList)
import qualified Data.Text.Encoding as Text
import Data.Void (Void)
import SlackBuilder.Info
import Test.Hspec (Spec, describe, it, shouldBe)
import Test.Hspec.Megaparsec (parseSatisfies, shouldSucceedOn)
import Text.Megaparsec (parse)
import Text.Megaparsec.Error (ParseErrorBundle)
import Text.URI (mkURI)
parseInfoFile'
:: ByteString
-> Either (ParseErrorBundle ByteString Void) PackageInfo
parseInfoFile' = parse parseInfoFile ""
infoDownload0 :: ByteString
infoDownload0 = "PRGNAM=\"pkgnam\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"\"\n\
\MD5SUM=\"\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
infoDownload1 :: ByteString
infoDownload1 = "PRGNAM=\"pkgnam\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"https://dlackware.com/download.tar.gz\"\n\
\MD5SUM=\"0102030405060708090a0b0c0d0e0f10\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
maybeToDoubleList :: forall a. Maybe a -> [a]
maybeToDoubleList xs = [y | x <- maybeToList xs, y <- [x, x]]
checksumSample :: [Digest MD5]
checksumSample = maybeToList $ digestFromByteString (ByteString.pack [1 .. 16])
spec :: Spec
spec = do
describe "parseInfoFile" $ do
it "returns package on a valid input" $
parseInfoFile' `shouldSucceedOn` infoDownload1
it "returns an array with one element if one download is given" $
let condition = (== 1) . length . checksums
in parseInfoFile' infoDownload1 `parseSatisfies` condition
it "translates checksum characters into the binary format" $
let expected = ["0102030405060708090a0b0c0d0e0f10"]
condition = (== expected) . fmap show . checksums
in parseInfoFile' infoDownload1 `parseSatisfies` condition
it "accepts an empty downloads list" $
parseInfoFile' `shouldSucceedOn` infoDownload0
it "parses a package name with a dot" $
let given =
"PRGNAM=\"pkgnam.yaml\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"https://dlackware.com/download.tar.gz\"\n\
\MD5SUM=\"0102030405060708090a0b0c0d0e0f10\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
in parseInfoFile' `shouldSucceedOn` given
it "parses to downloads in a single line" $
let given =
"PRGNAM=\"pkgnam.yaml\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"https://dlackware.com/download1.tar.gz https://dlackware.com/download2.tar.gz\"\n\
\MD5SUM=\"0102030405060708090a0b0c0d0e0f10 0102030405060708090a0b0c0d0e0f11\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
in parseInfoFile' `shouldSucceedOn` given
it "parses downloads continuing on the next line" $
let given =
"PRGNAM=\"pkgnam.yaml\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"https://dlackware.com/download1.tar.gz \\\n\
\ https://dlackware.com/download2.tar.gz\"\n\
\MD5SUM=\"0102030405060708090a0b0c0d0e0f10 \\\n\
\ 0102030405060708090a0b0c0d0e0f11\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
in parseInfoFile' `shouldSucceedOn` given
describe "generate" $ do
it "generates an .info file without downloads" $
let given = PackageInfo "pkgnam" "1.2.3" "homepage" [] [] [] [] [] "Z" "test@example.com"
in generate given `shouldBe` Text.decodeUtf8 infoDownload0
it "splits multiple downloads into multiple lines" $
let downloads' = maybeToDoubleList
$ mkURI "https://dlackware.com/download.tar.gz"
checksums' = maybeToDoubleList
$ digestFromByteString (ByteString.pack [1.. 16])
given = PackageInfo
"pkgnam" "1.2.3" "homepage" downloads' checksums' [] [] [] "Z" "test@example.com"
expected = "PRGNAM=\"pkgnam\"\n\
\VERSION=\"1.2.3\"\n\
\HOMEPAGE=\"homepage\"\n\
\DOWNLOAD=\"https://dlackware.com/download.tar.gz \\\n\
\ https://dlackware.com/download.tar.gz\"\n\
\MD5SUM=\"0102030405060708090a0b0c0d0e0f10 \\\n\
\ 0102030405060708090a0b0c0d0e0f10\"\n\
\DOWNLOAD_x86_64=\"\"\n\
\MD5SUM_x86_64=\"\"\n\
\REQUIRES=\"\"\n\
\MAINTAINER=\"Z\"\n\
\EMAIL=\"test@example.com\"\n"
in generate given `shouldBe` expected
it "prints the checksum as a sequence of hexadecimal numbers" $
let downloads' = maybeToList
$ mkURI "https://dlackware.com/download.tar.gz"
given = PackageInfo
"pkgnam" "1.2.3" "homepage" downloads' checksumSample [] [] [] "Z" "test@example.com"
in generate given `shouldBe` Text.decodeUtf8 infoDownload1

View File

@ -0,0 +1,53 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
module SlackBuilder.LatestVersionCheckSpec
( spec
) where
import SlackBuilder.LatestVersionCheck
import Test.Hspec (Spec, describe, it, shouldBe)
spec :: Spec
spec = do
describe "match" $ do
it "matches an exact tag prefixed with v" $
let expected = Just "2.6.0"
actual = match "(v)2.6.0" "v2.6.0"
in actual `shouldBe` expected
it "matches a glob pattern prefixed with v" $
let expected = Just "2.6.0"
actual = match "(v)*" "v2.6.0"
in actual `shouldBe` expected
it "matches digits" $
let expected = Just "2.6.0"
actual = match "(v)2.6.\\d" "v2.6.0"
in actual `shouldBe` expected
it "matches digits and dots" $
let expected = Just "2.6.0"
actual = match "(v)\\." "v2.6.0"
in actual `shouldBe` expected
it "rejects unexpected suffix" $
let expected = Nothing
actual = match "(v)\\." "v2.6.0-rc1"
in actual `shouldBe` expected
it "rejects remaining umatched characters" $
let expected = Nothing
actual = match "2.6.0-rc1" "2.6.0"
in actual `shouldBe` expected
it "consumes the last token matching nothing" $
let expected = Just "abc"
actual = match "abc\\d\\d" "abc"
in actual `shouldBe` expected
it "matches at least one digit" $
let expected = Nothing
actual = match "1.\\D.3" "1..3"
in actual `shouldBe` expected

View File

@ -0,0 +1,26 @@
{- This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. -}
module SlackBuilder.PackageSpec
( spec
) where
import SlackBuilder.Package
import Test.Hspec (Spec, describe, it, shouldBe)
import Text.URI.QQ (uri)
spec :: Spec
spec = do
describe "renderDownloadWithVersion" $ do
it "renders text as URL" $
let given = DownloadTemplate "https://example.com"
actual = renderDownloadWithVersion given "1.2"
expected = Just [uri|https://example.com|]
in actual `shouldBe` expected
it "renders the components in order" $
let given = DownloadTemplate "https://example.com/{version}/segment"
actual = renderDownloadWithVersion given "1.2"
expected = Just [uri|https://example.com/1.2/segment|]
in actual `shouldBe` expected

1
tests/Spec.hs Normal file
View File

@ -0,0 +1 @@
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}