# arch-hs [![GitHub CI](https://github.com/berberman/arch-hs/workflows/CI/badge.svg)](https://github.com/berberman/arch-hs/actions) [![Build Status](https://travis-ci.com/berberman/arch-hs.svg?branch=master)](https://travis-ci.com/berberman/arch-hs) [![Hackage](https://img.shields.io/hackage/v/arch-hs.svg?logo=haskell)](https://hackage.haskell.org/package/arch-hs) [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) A program generating PKGBUILD for hackage packages. Special thanks to [felixonmars](https://github.com/felixonmars/). **Notice that `arch-hs` will always support only the latest GHC version.** ## Introduction Given the name of a package in hackage, `arch-hs` can generate PKGBUILD files, not only for the package whose name is given, but also for all dependencies missing in [community](https://www.archlinux.org/packages/). `arch-hs` has a naive built-in dependency solver, which can fetch those dependencies and find out which are required to be packaged. During the dependency calculation, all version constraints will be discarded due to the arch haskell packaging strategy, thus there is no guarantee of dependencies' version consistency. ## Prerequisite `arch-hs` is a PKGBUILD text file generator, which is not integrated with `pacman`(See [Alpm Support](#Alpm-Support)), depending on nothing than: * Pacman database (`community.db`) * Hackage index tarball (`01-index.tar`, or `00-index.tar` previously) -- usually provided by `cabal-install` ## Installation `arch-hs` is portable, which means it's not restricted to Arch Linux. However, `arch-hs` can use libalpm to load pacman database on Arch Linux, and if you want to run them on other systems, you have to build it from source. ### Install the latest release ``` # pacman -S arch-hs ``` `arch-hs` is available in [community](https://www.archlinux.org/packages/community/x86_64/arch-hs/), so you can install it using `pacman`. ### Install the development version ``` # pacman -S arch-hs-git ``` The `-git` version is available in [archlinuxcn](https://github.com/archlinuxcn/repo), following the latest git commit. ## Build ``` $ git clone https://github.com/berberman/arch-hs ``` Then build it via stack or cabal. #### Stack ``` $ stack build ``` #### Cabal (dynamic) ``` $ cabal configure --disable-library-vanilla --enable-shared --enable-executable-dynamic --ghc-options=-dynamic $ cabal build ``` ## Usage Just run `arch-hs` in command line with options and a target. Here is an example: we will create the archlinux package of [accelerate](https://hackage.haskell.org/package/accelerate): ``` $ arch-hs -o ~/test accelerate ...... ⓘ Recommended package order (from topological sort): 1. unique 2. tasty-kat 3. accelerate ...... ⓘ Write file: /home/berberman/test/haskell-accelerate/PKGBUILD ⓘ Write file: /home/berberman/test/haskell-unique/PKGBUILD ⓘ Write file: /home/berberman/test/haskell-tasty-kat/PKGBUILD ✔ Success! ``` This message tells us that in order to package `accelerate`, we must package `unique` and `tasty-kat` first sequentially, because `accelerate` dependents on them to build or test, whereas they are not present in archlinux community repo. ``` $ tree ~/test /home/berberman/Desktop/test ├── haskell-accelerate │ └── PKGBUILD ├── haskell-tasty-kat │ └── PKGBUILD └── haskell-unique └── PKGBUILD ``` `arch-hs` will generate PKGBUILD for each package. Let's see what we have in `./haskell-accelerate/PKGBUILD`: ``` bash # This file was generated by arch-hs, please check it manually. # Maintainer: Your Name _hkgname=accelerate pkgname=haskell-accelerate pkgver=1.3.0.0 pkgrel=1 pkgdesc="An embedded language for accelerated array processing" url="https://github.com/AccelerateHS/accelerate/" license=("custom:BSD3") arch=('x86_64') depends=('ghc-libs' 'haskell-ansi-terminal' 'haskell-base-orphans' 'haskell-cryptonite' 'haskell-half' 'haskell-hashable' 'haskell-hashtables' 'haskell-hedgehog' 'haskell-lens' 'haskell-prettyprinter' 'haskell-prettyprinter-ansi-terminal' 'haskell-primitive' 'haskell-tasty' 'haskell-terminal-size' 'haskell-unique' 'haskell-unordered-containers' 'haskell-vector') makedepends=('ghc' 'haskell-doctest') source=("https://hackage.haskell.org/packages/archive/$_hkgname/$pkgver/$_hkgname-$pkgver.tar.gz") sha256sums=('4b97161f145c81f7554679802059598587e06d49b2c153e7bafc4dd6974bad92') build() { cd $_hkgname-$pkgver runhaskell Setup configure -O --enable-shared --enable-executable-dynamic --disable-library-vanilla \ --prefix=/usr --docdir=/usr/share/doc/$pkgname --enable-tests \ --dynlibdir=/usr/lib --libsubdir=\$compiler/site-local/\$pkgid \ --ghc-option=-optl-Wl\,-z\,relro\,-z\,now \ --ghc-option='-pie' runhaskell Setup build runhaskell Setup register --gen-script runhaskell Setup unregister --gen-script sed -i -r -e "s|ghc-pkg.*update[^ ]* |&'--force' |" register.sh sed -i -r -e "s|ghc-pkg.*unregister[^ ]* |&'--force' |" unregister.sh } check() { cd $_hkgname-$pkgver runhaskell Setup test } package() { cd $_hkgname-$pkgver install -D -m744 register.sh "$pkgdir"/usr/share/haskell/register/$pkgname.sh install -D -m744 unregister.sh "$pkgdir"/usr/share/haskell/unregister/$pkgname.sh runhaskell Setup copy --destdir="$pkgdir" install -D -m644 LICENSE -t "$pkgdir"/usr/share/licenses/$pkgname/ rm -f "$pkgdir"/usr/share/doc/$pkgname/LICENSE } ``` `arch-hs` will collect the information from hackage db, and apply it into a fixed template after some processing steps including renaming, matching license, and filling out dependencies etc. However, packaging haven't been done so far. `arch-hs` may does well statically, but we should guarantee that this package can be built by ghc with the latest dependencies; hence some patchs may be required in `prepare()`, such as [uusi](#Uusi). ## Options ### Output ``` $ arch-hs -o ~/test TARGET ``` Using `-o` can generate a series of PKGBUILD including `TARGET` with its dependencies into the output dir. If you don't pass it, only dependency calculation will occur. ### Flag Assignments ``` $ arch-hs -f TARGET:FLAG_A:true TARGET ``` Using `-f` can pass flags, which may affect the results of resolving. ### AUR Searching ``` $ arch-hs -a TARGET ``` With `-a`, `arch-hs` will regard AUR as another package provider, and it will try to search missing packages in AUR as well. ### Skipping Components ``` $ arch-hs -s COMPONENT_A TARGET ``` Using `-s` can force skip runnable components in dependency resolving. This is useful when a package doesn't provide flag to disable its runnables, which will be built by default but are trivial in system level packaging. Notice that this only makes sense in the lifetime of `arch-hs`, whereas generated PKGBUILD and actual build processes will not be affected. ### Extra Cabal Files ``` $ arch-hs -e ~/TARGET/TARGET.cabal TARGET ``` **For Testing Purposes Only** Using `-e` can include extra `.cabal` files as supplementary. Useful when the `TARGET` hasn't been released to hackage. ### Trace ``` $ arch-hs --trace TARGET ``` With `--trace`, `arch-hs` can print the process of dependency resolving into stdout. ``` $ arch-hs --trace-file foo.log TARGET ``` Similar to `--trace`, but the log will be written into a file. ### Uusi ``` $ arch-hs -o ~/test --uusi TARGET ``` With `--uusi`, `arch-hs` will generate following snippet for each package: ```bash prepare() { uusi $_hkgname-$pkgver/$_hkgname.cabal } ``` See [uusi](https://hackage.haskell.org/package/uusi) for details. ### Alpm ``` $ arch-hs --alpm TARGET ``` See [Alpm Support](#Alpm-Support). ## [Name preset](https://github.com/berberman/arch-hs/blob/master/data/NAME_PRESET.json) To distribute a haskell package to archlinux, the name of package should be changed according to the naming convention: * for haskell libraries, their names must have `haskell-` prefix * for programs, it depends on circumstances * names should always be in lower case However, it's not enough to prefix the string with `haskell-` and transform to lower case; in some special situations, the hackage name may have `haskell-` prefix already, or the case is irregular, thus we have to a name preset manually. Once a package distributed to archlinux, whose name conform to above-mentioned situation, the name preset should be upgraded correspondingly. ## Diff `arch-hs` also provides a component called `arch-hs-diff`. `arch-hs-diff` can show the differences of package description between two versions of a package. This is useful in the subsequent maintenance of a package. Example: ``` $ arch-hs-diff HTTP 4000.3.14 4000.3.15 ▶ You didn't pass -f, different flag values may make difference in dependency resolving. ⓘ Start running... ⓘ Downloading cabal file from https://hackage.haskell.org/package/HTTP-4000.3.14/revision/0.cabal... ⓘ Downloading cabal file from https://hackage.haskell.org/package/HTTP-4000.3.15/revision/0.cabal... Package: HTTP Version: 4000.3.14 ⇒ 4000.3.15 Synopsis: A library for client-side HTTP URL: https://github.com/haskell/HTTP Depends: base >=4.3.0.0 && <4.14 time >=1.1.2.3 && <1.10 array >=0.3.0.2 && <0.6 bytestring >=0.9.1.5 && <0.11 mtl >=2.0 && <2.3 network >=2.6 && <3.2 network-uri ==2.6.* parsec >=2.0 && <3.2 -------------------------------------- base >=4.3.0.0 && <4.15 time >=1.1.2.3 && <1.11 array >=0.3.0.2 && <0.6 bytestring >=0.9.1.5 && <0.11 mtl >=2.0 && <2.3 network >=2.6 && <3.2 network-uri ==2.6.* parsec >=2.0 && <3.2 MakeDepends: HUnit >=1.2.0.1 && <1.7 deepseq >=1.3.0.0 && <1.5 httpd-shed >=0.4 && <0.5 mtl >=1.1.1.0 && <2.3 pureMD5 >=0.2.4 && <2.2 split >=0.1.3 && <0.3 test-framework >=0.2.0 && <0.9 test-framework-hunit >=0.3.0 && <0.4 Flags: HTTP ⚐ mtl1: description: Use the old mtl version 1. default: False isManual: False ⚐ warn-as-error: description: Build with warnings-as-errors default: False isManual: True ⚐ conduit10: description: Use version 1.0.x or below of the conduit package (for the test suite) default: False isManual: False ⚐ warp-tests: description: Test against warp default: False isManual: True ⚐ network-uri: description: Get Network.URI from the network-uri package default: True isManual: False ✔ Success! ``` `arch-hs-diff` does not require hackage db, it downloads cabal files from hackage server instead. ## Submit For hackage distribution maintainers only. ## Limitations * The dependency solver will **ONLY** expand the dependencies of *executables* , *libraries* and *sub-libraries* recursively, because circular dependency lies ubiquitously involving *test suites* and their *buildTools*. `arch-hs` is not able to handle with complicated situations: the libraries of a package partially exist in hackage, some libraries include external sources, etc. * Currently, `arch-hs`'s functionality is limited to dependency processing, whereas necessary procedures like file patches, loose of version constraints, etc. are need to be done manually, so **DO NOT** give too much trust in generated PKGBUILD files. ## Alpm Support [alpm](https://www.archlinux.org/pacman/libalpm.3.html) is Arch Linux Package Management library. When running on Arch Linux, loading `community.db` through this library is slightly faster than using the internal parser of `arch-hs`. Thus, `arch-hs` provides a flag `alpm` to enable this feature: ``` cabal build -f alpm ``` This flag is enabled by default in `arch-hs` Arch Linux package. Compiled with `alpm`, `arch-hs` can accpet runtime flag `--alpm`. **That said, if you want to use alpm to boost `arch-hs`, you need compile `arch-hs` with cabal flag `alpm`, and pass `--aplm` to `arch-hs` when running.** > When `alpm` is enabled, `arch-hs` will lose the capability of specifying the path of `community.db`. ## ToDoList - [ ] **Standardized pretty printing**. - [x] AUR support. - [x] Working with given `.cabal` files which haven't been released to hackage. - [ ] Using `hackage-security` to manage hackage index tarball. ## Contributing Issues and PRs are always welcome. **\_(:з」∠)\_**