Update things for 2023 (#81)

This commit is contained in:
Taylor Fausak 2023-02-12 14:55:05 -05:00 committed by GitHub
parent cb6d96e949
commit 6e1a255e31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 293 additions and 340 deletions

6
.devcontainer.json Normal file
View File

@ -0,0 +1,6 @@
{
"dockerComposeFile": "compose.yaml",
"initializeCommand": "docker volume create cabal-store",
"service": "devcontainer",
"workspaceFolder": "/workspaces/witch"
}

View File

@ -1,9 +0,0 @@
#! /usr/bin/env sh
set -o errexit -o xtrace
if ! command -v "$1" >&2
then
cabal install "$1" >&2
fi
exec "$@"

View File

@ -1,14 +0,0 @@
services:
devcontainer:
command: sh -c 'while sleep 1; do :; done'
image: public.ecr.aws/acilearning/haskell:9.2.5-7bd251ac55c29968002b10e3d012562e86d3f218
init: true
volumes:
- ..:/workspaces/witch
- cabal:/home/haskell/.cabal
- cabal-store:/cabal-store
working_dir: /workspaces/witch
volumes:
cabal: null
cabal-store:
external: true

View File

@ -1,16 +0,0 @@
{
"dockerComposeFile": "compose.yaml",
"extensions": [
"taylorfausak.purple-yolk"
],
"initializeCommand": ".devcontainer/initialize.sh",
"onCreateCommand": ".devcontainer/on-create.sh",
"service": "devcontainer",
"settings": {
"editor.formatOnSave": true,
"purple-yolk.haskell.formatter.command": ".devcontainer/cabal-shim.sh ormolu --no-cabal",
"purple-yolk.haskell.linter.command": ".devcontainer/cabal-shim.sh hlint --json --no-exit-code -",
"purple-yolk.haskell.linter.onSave": true
},
"workspaceFolder": "/workspaces/witch"
}

View File

@ -1,8 +0,0 @@
#! /usr/bin/env sh
set -o errexit -o xtrace
volume=cabal-store
if ! docker volume inspect "$volume"
then
docker volume create "$volume"
fi

View File

@ -1,9 +0,0 @@
#! /usr/bin/env sh
set -o errexit -o xtrace
cabal update
if ! test -f cabal.project.local
then
cabal configure --enable-tests --jobs --test-show-details direct
fi

View File

@ -1,6 +1,12 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: daily
{
"updates": [
{
"directory": "/",
"package-ecosystem": "github-actions",
"schedule": {
"interval": "daily"
}
}
],
"version": 2
}

View File

@ -1,131 +1,193 @@
name: Workflow
on:
push: null
release:
types:
- created
jobs:
cabal:
runs-on: ubuntu-latest
name: Cabal
steps:
- uses: actions/checkout@v3
- run: cabal check
hlint:
runs-on: ubuntu-latest
name: HLint
steps:
- uses: actions/checkout@v3
- uses: haskell/actions/hlint-setup@v2
- uses: haskell/actions/hlint-run@v2
with:
fail-on: status
ormolu:
runs-on: ubuntu-latest
name: Ormolu
steps:
- uses: actions/checkout@v3
- uses: mrkkrp/ormolu-action@v9
build:
strategy:
matrix:
include:
- { platform: ubuntu, ghc: 9.4.2 }
- { platform: ubuntu, ghc: 9.2.5 }
- { platform: ubuntu, ghc: 9.0.2 }
- { platform: macos, ghc: 9.4.2 }
- { platform: windows, ghc: 9.4.2 }
- { platform: ubuntu, ghc: 8.10.7 }
- { platform: ubuntu, ghc: 8.8.4 }
- { platform: ubuntu, ghc: 8.6.5 }
- { platform: ubuntu, ghc: 8.4.4 }
- { platform: ubuntu, ghc: 8.2.2 }
runs-on: ${{ matrix.platform }}-latest
name: GHC ${{ matrix.ghc }} on ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
- run: mkdir artifact
- id: artifact
run: echo '::set-output name=directory::artifact/${{ matrix.platform }}-${{ matrix.ghc }}'
- run: mkdir ${{ steps.artifact.outputs.directory }}
# https://discourse.haskell.org/t/incident-github-actions-ci-failure-ghcup/5761
- if: matrix.platform == 'ubuntu'
run: sudo chown -R $USER /usr/local/.ghcup
- id: setup-haskell
uses: haskell/actions/setup@v2
with:
ghc-version: ${{ matrix.ghc }}
- run: cabal configure --enable-tests --flags pedantic --jobs
- run: cat cabal.project.local
- run: cp cabal.project.local ${{ steps.artifact.outputs.directory }}
- run: cabal freeze
- run: cat cabal.project.freeze
- run: cp cabal.project.freeze ${{ steps.artifact.outputs.directory }}
- uses: actions/cache@v3
with:
path: ${{ steps.setup-haskell.outputs.cabal-store }}
key: ${{ matrix.platform }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
restore-keys: ${{ matrix.platform }}-${{ matrix.ghc }}-
- run: cabal build --only-download
- run: cabal build --only-dependencies
- run: cabal build
- run: cabal run -- witch-test-suite
- run: cabal sdist --output-dir ${{ steps.artifact.outputs.directory }}
- uses: actions/upload-artifact@v3
with:
path: artifact
name: witch-${{ github.sha }}
release:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: witch-${{ github.sha }}
path: artifact
- uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_content_type: application/gzip
asset_name: witch-${{ github.event.release.tag_name }}.tar.gz
asset_path: artifact/ubuntu-9.4.2/witch-${{ github.event.release.tag_name }}.tar.gz
upload_url: ${{ github.event.release.upload_url }}
- run: cabal upload --publish --username '${{ secrets.HACKAGE_USERNAME }}' --password '${{ secrets.HACKAGE_PASSWORD }}' artifact/ubuntu-9.4.2/witch-${{ github.event.release.tag_name }}.tar.gz
i386:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: docker run --rm --user 0 --volume "$PWD:$PWD" --workdir "$PWD" taylorfausak/i386-haskell@sha256:450720742fa69258c0a8589dcac28c3c6d5d34718172d935b385520f4ee9128e sh -c 'cabal update && cabal test --test-show-details direct'
{
"jobs": {
"build": {
"name": "Build on ${{ matrix.platform }} with GHC ${{ matrix.ghc }}",
"runs-on": "${{ matrix.platform }}-${{ matrix.version }}",
"steps": [
{
"uses": "actions/checkout@v3"
},
{
"run": "mkdir artifact"
},
{
"id": "artifact",
"run": "echo 'directory=artifact/${{ matrix.platform }}-${{ matrix.ghc }}' >> $GITHUB_OUTPUT",
"shell": "bash"
},
{
"run": "mkdir ${{ steps.artifact.outputs.directory }}"
},
{
"id": "haskell",
"uses": "haskell/actions/setup@v2",
"with": {
"cabal-version": "3.8.1.0",
"ghc-version": "${{ matrix.ghc }}"
}
},
{
"run": "cabal sdist --output-dir ${{ steps.artifact.outputs.directory }}"
},
{
"run": "cabal configure --enable-optimization=2 --flags pedantic --jobs"
},
{
"run": "cat cabal.project.local"
},
{
"run": "cp cabal.project.local ${{ steps.artifact.outputs.directory }}"
},
{
"run": "cabal freeze"
},
{
"run": "cat cabal.project.freeze"
},
{
"run": "cp cabal.project.freeze ${{ steps.artifact.outputs.directory }}"
},
{
"run": "cabal outdated --v2-freeze-file cabal.project.freeze"
},
{
"uses": "actions/cache@v3",
"with": {
"key": "${{ matrix.platform }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}",
"path": "${{ steps.haskell.outputs.cabal-store }}",
"restore-keys": "${{ matrix.platform }}-${{ matrix.ghc }}-"
}
},
{
"run": "cabal build --only-download"
},
{
"run": "cabal build --only-dependencies"
},
{
"run": "cabal build"
},
{
"uses": "actions/upload-artifact@v3",
"with": {
"name": "witch-${{ github.sha }}",
"path": "artifact"
}
},
{
"run": "cabal run witch-test-suite"
}
],
"strategy": {
"matrix": {
"include": [
{
"ghc": "9.4.4",
"platform": "macos",
"version": "12"
},
{
"ghc": "9.0.2",
"platform": "ubuntu",
"version": "22.04"
},
{
"ghc": "9.2.5",
"platform": "ubuntu",
"version": "22.04"
},
{
"ghc": "9.4.4",
"platform": "ubuntu",
"version": "22.04"
},
{
"extension": ".exe",
"ghc": "9.4.4",
"platform": "windows",
"version": "2022"
}
]
}
}
},
"cabal": {
"name": "Cabal",
"runs-on": "ubuntu-22.04",
"steps": [
{
"uses": "actions/checkout@v3"
},
{
"run": "cabal check"
}
]
},
"hlint": {
"name": "HLint",
"runs-on": "ubuntu-22.04",
"steps": [
{
"uses": "actions/checkout@v3"
},
{
"uses": "haskell/actions/hlint-setup@v2",
"with": {
"version": 3.5
}
}
]
},
"ormolu": {
"name": "Ormolu",
"runs-on": "ubuntu-22.04",
"steps": [
{
"uses": "actions/checkout@v3"
},
{
"uses": "mrkkrp/ormolu-action@v10"
}
]
},
"release": {
"if": "github.event_name == 'release'",
"name": "Release",
"needs": "build",
"runs-on": "ubuntu-22.04",
"steps": [
{
"uses": "actions/download-artifact@v3",
"with": {
"name": "witch-${{ github.sha }}",
"path": "artifact"
}
},
{
"uses": "svenstaro/upload-release-action@v2",
"with": {
"asset_name": "witch-${{ github.event.release.tag_name }}.tar.gz",
"file": "artifact/ubuntu-9.4.4/witch-${{ github.event.release.tag_name }}.tar.gz"
}
},
{
"run": "cabal upload --publish --username '${{ secrets.HACKAGE_USERNAME }}' --password '${{ secrets.HACKAGE_PASSWORD }}' artifact/ubuntu-9.4.4/witch-${{ github.event.release.tag_name }}.tar.gz"
}
]
}
},
"name": "Workflow",
"on": {
"push": null,
"release": {
"types": [
"created"
]
},
"schedule": [
{
"cron": "0 0 * * *"
}
]
}
}

View File

@ -1,3 +1,29 @@
- group: { name: dollar, enabled: true }
- ignore: { name: Use lambda-case }
- ignore: { name: Use tuple-section }
[
{
"group": {
"enabled": true,
"name": "dollar"
}
},
{
"group": {
"enabled": true,
"name": "generalise"
}
},
{
"ignore": {
"name": "Use lambda-case"
}
},
{
"ignore": {
"name": "Use tuple-section"
}
},
{
"ignore": {
"name": "Redundant bracket"
}
}
]

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 Taylor Fausak
Copyright (c) 2023 Taylor Fausak
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,6 +1,6 @@
# Witch
[![CI](https://github.com/tfausak/witch/workflows/Workflow/badge.svg)](https://github.com/tfausak/witch/actions)
[![Workflow](https://github.com/tfausak/witch/actions/workflows/workflow.yaml/badge.svg)](https://github.com/tfausak/witch/actions/workflows/workflow.yaml)
[![Hackage](https://img.shields.io/hackage/v/witch)](https://hackage.haskell.org/package/witch)
[![Stackage](https://www.stackage.org/package/witch/badge/nightly?label=stackage)](https://www.stackage.org/package/witch)

21
compose.yaml Normal file
View File

@ -0,0 +1,21 @@
{
"services": {
"devcontainer": {
"command": "sh -c 'while sleep 1; do :; done'",
"image": "public.ecr.aws/acilearning/haskell:9.4.4",
"init": true,
"volumes": [
".:/workspaces/witch",
"cabal:/home/haskell/.cabal",
"cabal-store:/cabal-store"
],
"working_dir": "/workspaces/witch"
}
},
"volumes": {
"cabal": null,
"cabal-store": {
"external": true
}
}
}

View File

@ -1,48 +0,0 @@
{-# LANGUAGE ExplicitForAll #-}
module Witch.Lift where
import qualified Data.Typeable as Typeable
import qualified Language.Haskell.TH.Syntax as TH
import qualified Witch.TryFrom as TryFrom
import qualified Witch.Utility as Utility
-- | This is like 'Utility.unsafeFrom' except that it works at compile time
-- rather than runtime.
--
-- > -- Avoid this:
-- > unsafeFrom @s "some literal"
-- >
-- > -- Prefer this:
-- > $$(liftedFrom @s "some literal")
liftedFrom ::
forall source target.
( TryFrom.TryFrom source target,
TH.Lift target,
Show source,
Typeable.Typeable source,
Typeable.Typeable target
) =>
source ->
TH.Q (TH.TExp target)
liftedFrom = TH.liftTyped . Utility.unsafeFrom
-- | This is like 'Utility.unsafeInto' except that it works at compile time
-- rather than runtime.
--
-- > -- Avoid this:
-- > unsafeInto @t "some literal"
-- >
-- > -- Prefer this:
-- > $$(liftedInto @t "some literal")
liftedInto ::
forall target source.
( TryFrom.TryFrom source target,
TH.Lift target,
Show source,
Typeable.Typeable source,
Typeable.Typeable target
) =>
source ->
TH.Q (TH.TExp target)
liftedInto = liftedFrom

View File

@ -1,48 +0,0 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Witch.Lift where
import qualified Data.Typeable as Typeable
import qualified Language.Haskell.TH.Syntax as TH
import qualified Witch.TryFrom as TryFrom
import qualified Witch.Utility as Utility
-- | This is like 'Utility.unsafeFrom' except that it works at compile time
-- rather than runtime.
--
-- > -- Avoid this:
-- > unsafeFrom @s "some literal"
-- >
-- > -- Prefer this:
-- > $$(liftedFrom @s "some literal")
liftedFrom ::
forall source target.
( TryFrom.TryFrom source target,
TH.Lift target,
Show source,
Typeable.Typeable source,
Typeable.Typeable target
) =>
source ->
TH.Q (TH.TExp target)
liftedFrom s = TH.unsafeTExpCoerce $ TH.lift (Utility.unsafeFrom s :: target)
-- | This is like 'Utility.unsafeInto' except that it works at compile time
-- rather than runtime.
--
-- > -- Avoid this:
-- > unsafeInto @t "some literal"
-- >
-- > -- Prefer this:
-- > $$(liftedInto @t "some literal")
liftedInto ::
forall target source.
( TryFrom.TryFrom source target,
TH.Lift target,
Show source,
Typeable.Typeable source,
Typeable.Typeable target
) =>
source ->
TH.Q (TH.TExp target)
liftedInto = liftedFrom

View File

@ -31,5 +31,5 @@ class From source target where
-- >>> instance From Name String
-- >>> instance From String Name
from :: source -> target
default from :: Coerce.Coercible source target => source -> target
default from :: (Coerce.Coercible source target) => source -> target
from = Coerce.coerce

View File

@ -911,7 +911,7 @@ instance From.From Double Float where
-- Ratio
-- | Uses '(Ratio.%)' with a denominator of 1.
instance Integral a => From.From a (Ratio.Ratio a) where
instance (Integral a) => From.From a (Ratio.Ratio a) where
from = (Ratio.% 1)
-- | Uses 'Ratio.numerator' when the denominator is 1.
@ -930,7 +930,7 @@ instance From.From Rational Double where
from = fromRational
-- | Uses `fromRational` as long as there isn't a loss of precision.
instance Fixed.HasResolution a => TryFrom.TryFrom Rational (Fixed.Fixed a) where
instance (Fixed.HasResolution a) => TryFrom.TryFrom Rational (Fixed.Fixed a) where
tryFrom = Utility.eitherTryFrom $ \s ->
let t :: Fixed.Fixed a
t = fromRational s
@ -949,13 +949,13 @@ instance From.From (Fixed.Fixed a) Integer where
from (Fixed.MkFixed t) = t
-- | Uses 'toRational'.
instance Fixed.HasResolution a => From.From (Fixed.Fixed a) Rational where
instance (Fixed.HasResolution a) => From.From (Fixed.Fixed a) Rational where
from = toRational
-- Complex
-- | Uses '(Complex.:+)' with an imaginary part of 0.
instance Num a => From.From a (Complex.Complex a) where
instance (Num a) => From.From a (Complex.Complex a) where
from = (Complex.:+ 0)
-- | Uses 'Complex.realPart' when the imaginary part is 0.
@ -978,7 +978,7 @@ instance From.From (NonEmpty.NonEmpty a) [a] where
-- Set
-- | Uses 'Set.fromList'.
instance Ord a => From.From [a] (Set.Set a) where
instance (Ord a) => From.From [a] (Set.Set a) where
from = Set.fromList
-- | Uses 'Set.toAscList'.
@ -999,7 +999,7 @@ instance From.From IntSet.IntSet [Int] where
-- | Uses 'Map.fromList'. If there are duplicate keys, later values will
-- overwrite earlier ones.
instance Ord k => From.From [(k, v)] (Map.Map k v) where
instance (Ord k) => From.From [(k, v)] (Map.Map k v) where
from = Map.fromList
-- | Uses 'Map.toAscList'.
@ -1539,7 +1539,7 @@ instance From.From String (Encoding.UTF_32BE LazyByteString.ByteString) where
--
realFloatToRational ::
RealFloat s => s -> Either Exception.ArithException Rational
(RealFloat s) => s -> Either Exception.ArithException Rational
realFloatToRational s
| isNaN s = Left Exception.LossOfPrecision
| isInfinite s =
@ -1569,13 +1569,13 @@ fromNonNegativeIntegral x =
-- | The maximum integral value that can be unambiguously represented as a
-- 'Float'. Equal to 16,777,215.
maxFloat :: Num a => a
maxFloat :: (Num a) => a
maxFloat = 16777215
-- | The maximum integral value that can be unambiguously represented as a
-- 'Double'. Equal to 9,007,199,254,740,991.
maxDouble :: Num a => a
maxDouble :: (Num a) => a
maxDouble = 9007199254740991
tryEvaluate :: Exception.Exception e => a -> Either e a
tryEvaluate :: (Exception.Exception e) => a -> Either e a
tryEvaluate = Unsafe.unsafePerformIO . Exception.try . Exception.evaluate

View File

@ -30,7 +30,7 @@ as = id
-- >
-- > -- Prefer this:
-- > into @t x
into :: forall target source. From.From source target => source -> target
into :: forall target source. (From.From source target) => source -> target
into = From.from
-- | This function converts from some @source@ type into some @target@ type,
@ -78,7 +78,7 @@ via = From.from . (\x -> x :: through) . From.from
-- > tryInto @t x
tryInto ::
forall target source.
TryFrom.TryFrom source target =>
(TryFrom.TryFrom source target) =>
source ->
Either (TryFromException.TryFromException source target) target
tryInto = TryFrom.tryFrom
@ -136,7 +136,7 @@ maybeTryFrom f s = case f s of
-- > -- Prefer this:
-- > tryFrom = eitherTryFrom f
eitherTryFrom ::
Exception.Exception exception =>
(Exception.Exception exception) =>
(source -> Either exception target) ->
source ->
Either (TryFromException.TryFromException source target) target

View File

@ -2453,32 +2453,32 @@ type Spec = Writer.Writer (Seq.Seq HUnit.Test) ()
anyTryFromException :: Selector (Witch.TryFromException s t)
anyTryFromException = const True
describe :: Stack.HasCallStack => String -> Spec -> Spec
describe :: (Stack.HasCallStack) => String -> Spec -> Spec
describe label = testToSpec . HUnit.TestLabel label . specToTest
hush :: Either x a -> Maybe a
hush = either (const Nothing) Just
it :: Stack.HasCallStack => String -> HUnit.Assertion -> Spec
it :: (Stack.HasCallStack) => String -> HUnit.Assertion -> Spec
it label = testToSpec . HUnit.TestLabel label . HUnit.TestCase
shouldBe :: (Stack.HasCallStack, Eq a, Show a) => a -> a -> HUnit.Assertion
shouldBe = (HUnit.@?=)
shouldSatisfy :: (Stack.HasCallStack, Show a) => a -> (a -> Bool) -> HUnit.Assertion
shouldSatisfy value predicate = HUnit.assertBool ("predicate failed on: " ++ show value) $ predicate value
shouldSatisfy value predicate = HUnit.assertBool ("predicate failed on: " <> show value) $ predicate value
shouldThrow :: (Stack.HasCallStack, Exception.Exception e) => IO a -> Selector e -> HUnit.Assertion
shouldThrow action predicate = do
result <- Exception.try action
case result of
Right _ -> HUnit.assertFailure "did not get expected exception"
Left exception -> HUnit.assertBool ("predicate failed on expected exception: " ++ show exception) $ predicate exception
Left exception -> HUnit.assertBool ("predicate failed on expected exception: " <> show exception) $ predicate exception
specToTest :: Stack.HasCallStack => Spec -> HUnit.Test
specToTest :: (Stack.HasCallStack) => Spec -> HUnit.Test
specToTest = HUnit.TestList . Foldable.toList . Writer.execWriter
testToSpec :: Stack.HasCallStack => HUnit.Test -> Spec
testToSpec :: (Stack.HasCallStack) => HUnit.Test -> Spec
testToSpec = Writer.tell . Seq.singleton
unixEpoch :: Time.UTCTime

View File

@ -23,36 +23,27 @@ flag pedantic
common library
build-depends:
, base >= 4.10 && < 4.18
, bytestring >= 0.10.8 && < 0.12
, containers >= 0.5.10 && < 0.7
, base >= 4.15 && < 4.18
, bytestring >= 0.10.12 && < 0.12
, containers >= 0.6.4 && < 0.7
, tagged >= 0.8.6 && < 0.9
, text >= 1.2.3 && < 1.3 || >= 2.0 && < 2.1
, time >= 1.9.1 && < 1.13
, text >= 1.2.5 && < 1.3 || >= 2.0 && < 2.1
, time >= 1.9.3 && < 1.13
default-language: Haskell2010
ghc-options:
-Weverything
-Wno-all-missed-specialisations
-Wno-implicit-prelude
-Wno-missed-specialisations
-Wno-missing-deriving-strategies
-Wno-missing-export-lists
-Wno-missing-exported-signatures
-Wno-missing-safe-haskell-mode
-Wno-prepositive-qualified-module
-Wno-redundant-constraints
-Wno-safe
-Wno-unsafe
if impl(ghc >= 8.4)
ghc-options:
-Wno-missing-export-lists
if impl(ghc >= 8.8)
ghc-options:
-Wno-missing-deriving-strategies
if impl(ghc >= 8.10)
ghc-options:
-Wno-missing-safe-haskell-mode
-Wno-prepositive-qualified-module
if impl(ghc >= 9.2)
ghc-options:
-Wno-missing-kind-signatures
@ -73,7 +64,7 @@ library
import: library
build-depends:
, template-haskell >= 2.12 && < 2.20
, template-haskell >= 2.17 && < 2.20
exposed-modules:
Witch
Witch.Encoding
@ -85,13 +76,6 @@ library
Witch.Utility
hs-source-dirs: source/library
if impl(ghc >= 9.0)
hs-source-dirs: source/ghc-9.0
elif impl(ghc >= 8.10)
hs-source-dirs: source/ghc-8.10
else
hs-source-dirs: source/ghc-8.8
test-suite witch-test-suite
import: executable