mirror of
https://github.com/qfpl/applied-fp-course.git
synced 2024-11-22 02:55:57 +03:00
Full Course Layout Change with a shuffle. (#54)
* Restructure entire course into a single library with multiple executable definitions. Makes working through the course a bit easier with respect to sandboxes, nix shells, and stack caching. Should be a side benefit of giving editor tooling a bit of an easier time. Lowers switch time between course levels. * Readme updates to suit new structure. Add comment to cabal file. * Syntax error in Travis yml file. Not sure where yet. * Applied some linting suggestions to travis file * Fixed missing comments in travis yml, removed duplicate executable entry in the cabal file * Added changelog file, vcs entry to cabal file * Fixing travis file, WIP. * Still trying * Added cabal.project file * Still trying (Travis) * Moved var declaration to higher level in travis.yml file. * Forgo the complexity of hvrs script and go low-tech. * Remove Haddocks from stack build. Add extra-deps because what was a working stack build is now failing for some reason, despite having the same version bounds and using the same LTS as before. * Added more deps to extra-deps to appease the stackbeast. * Updated base README * Readme tweaks, level 03 test updates * Moved Level07 to Level05, bumped other levels accordingly. * Moved 'Main' to 'Core'. Updated READMEs, first pass. Updated Cabal file. Updated Tests to handle change of Main to Core. * Proof read #3616 Lots of small fixes for file paths, wording, some additional exercises. Fixed up the tests to be more consistent as they've been reordered a few times and mostly left to rot. Readmes updated where needed. New exercise added to level07 for using the general `ExceptT` type. * Fix up some tests and avoid any more dynamic linking errors, I think * Fix up cabal config for doctests, missing packages and some exposed-modules * Removed use of Semigroup in tests to avoid CPP in cabal file for including semigroups package. Added bounds to base dependency for doctests test-suite
This commit is contained in:
parent
10612052be
commit
dd907523ba
228
.travis.yml
228
.travis.yml
@ -1,61 +1,56 @@
|
||||
# This is the complex Travis configuration, which is intended for use
|
||||
# on open source libraries which need compatibility across multiple GHC
|
||||
# versions, must work with cabal-install, and should be
|
||||
# cross-platform. For more information and other options, see:
|
||||
# This Travis job script has been generated by a script via
|
||||
#
|
||||
# https://docs.haskellstack.org/en/stable/travis_ci/
|
||||
# runghc make_travis_yml_2.hs 'applied-fp-course.cabal'
|
||||
#
|
||||
# Copy these contents into the root directory of your Github project in a file
|
||||
# named .travis.yml
|
||||
|
||||
# Use new container infrastructure to enable caching
|
||||
# For more information, see https://github.com/hvr/multi-ghc-travis
|
||||
#
|
||||
language: c
|
||||
sudo: false
|
||||
|
||||
# Do not choose a language; we provide our own build tools.
|
||||
language: generic
|
||||
git:
|
||||
submodules: false # whether to recursively clone submodules
|
||||
|
||||
# Caching so the next build will be fast too.
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.ghc
|
||||
- $HOME/.cabal
|
||||
- $HOME/.stack
|
||||
- $HOME/.cabal/packages
|
||||
- $HOME/.cabal/store
|
||||
- $HOME/.ghc
|
||||
- $HOME/.stack
|
||||
|
||||
before_cache:
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
|
||||
# remove files that are regenerated by 'cabal update'
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
|
||||
- rm -rfv $HOME/.cabal/packages/head.hackage
|
||||
|
||||
# The different configurations we want to test. We have BUILD=cabal which uses
|
||||
# cabal-install, and BUILD=stack which uses Stack. More documentation on each
|
||||
# of those below.
|
||||
#
|
||||
# We set the compiler values here to tell Travis to use a different
|
||||
# cache file per set of arguments.
|
||||
#
|
||||
# If you need to have different apt packages for each combination in the
|
||||
# matrix, you can use a line such as:
|
||||
# addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}}
|
||||
matrix:
|
||||
include:
|
||||
# We grab the appropriate GHC and cabal-install versions from hvr's PPA. See:
|
||||
# https://github.com/hvr/multi-ghc-travis
|
||||
- env: BUILD=cabal GHCVER=7.10.3 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
compiler: ": #GHC 7.10.3"
|
||||
addons: {apt: {packages: [cabal-install-2.0,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||
- env: BUILD=cabal GHCVER=8.0.2 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
compiler: ": #GHC 8.0.2"
|
||||
addons: {apt: {packages: [cabal-install-2.0,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||
- env: BUILD=cabal GHCVER=8.2.2 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
compiler: ": #GHC 8.2.2"
|
||||
addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||
- env: BUILD=cabal GHCVER=8.4.1 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
compiler: ": #GHC 8.4.1"
|
||||
addons: {apt: {packages: [cabal-install-2.0,ghc-8.4.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||
- env: BUILD=cabal
|
||||
compiler: "ghc-7.10.3"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.3], sources: [hvr-ghc]}}
|
||||
|
||||
# Build with the newest GHC and cabal-install. This is an accepted failure,
|
||||
# see below.
|
||||
- env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
compiler: ": #GHC HEAD"
|
||||
addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
|
||||
- env: BUILD=cabal
|
||||
compiler: "ghc-8.0.2"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
|
||||
|
||||
# The Stack builds. We can pass in arbitrary Stack arguments via the ARGS
|
||||
# variable, such as using --stack-yaml to point to a different file.
|
||||
- env: BUILD=cabal
|
||||
compiler: "ghc-8.2.2"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
|
||||
|
||||
- env: BUILD=cabal
|
||||
compiler: "ghc-8.4.1"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}
|
||||
|
||||
# The Stack builds. We can pass in arbitrary Stack arguments via the ARGS
|
||||
# variable, such as using --stack-yaml to point to a different file.
|
||||
- env: BUILD=stack ARGS=""
|
||||
compiler: ": #stack default"
|
||||
addons: {apt: {packages: [libgmp-dev]}}
|
||||
@ -100,102 +95,63 @@ matrix:
|
||||
os: osx
|
||||
|
||||
allow_failures:
|
||||
- env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7
|
||||
#- env: BUILD=stack ARGS="--resolver lts-6"
|
||||
- env: BUILD=stack ARGS="--resolver nightly"
|
||||
|
||||
before_install:
|
||||
# Using compiler above sets CC to an invalid value, so unset it
|
||||
- unset CC
|
||||
|
||||
# Store the list of levels
|
||||
- LEVELS=$(ls -1d level*)
|
||||
|
||||
# We want to always allow newer versions of packages when building on GHC HEAD
|
||||
- CABALARGS=""
|
||||
- if [ "x$GHCVER" = "xhead" ]; then CABALARGS=--allow-newer; fi
|
||||
|
||||
# Download and unpack the stack executable
|
||||
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin:/opt/alex/$ALEXVER/bin:/opt/happy/$HAPPYVER/bin:$HOME/.cabal/bin:$PATH
|
||||
- mkdir -p ~/.local/bin
|
||||
- |
|
||||
if [ `uname` = "Darwin" ]
|
||||
then
|
||||
travis_retry curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin
|
||||
else
|
||||
travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
|
||||
fi
|
||||
|
||||
# Use the more reliable S3 mirror of Hackage
|
||||
mkdir -p $HOME/.cabal
|
||||
echo 'remote-repo: hackage.haskell.org:http://hackage.fpcomplete.com/' > $HOME/.cabal/config
|
||||
echo 'remote-repo-cache: $HOME/.cabal/packages' >> $HOME/.cabal/config
|
||||
|
||||
if [ "$CABALVER" != "1.16" ]
|
||||
then
|
||||
echo 'jobs: $ncpus' >> $HOME/.cabal/config
|
||||
fi
|
||||
- HC=${CC}
|
||||
- HCPKG=${HC/ghc/ghc-pkg}
|
||||
- unset CC
|
||||
- ROOTDIR=$(pwd)
|
||||
- mkdir -p $HOME/.local/bin
|
||||
- "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"
|
||||
- HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
|
||||
- echo $HCNUMVER
|
||||
# Download and unpack the stack executable
|
||||
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin:/opt/alex/$ALEXVER/bin:/opt/happy/$HAPPYVER/bin:$HOME/.cabal/bin:$PATH
|
||||
- mkdir -p ~/.local/bin
|
||||
- |
|
||||
if [ `uname` = "Darwin" ]
|
||||
then
|
||||
travis_retry curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin
|
||||
else
|
||||
travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
|
||||
fi
|
||||
|
||||
install:
|
||||
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||
- if [ -f configure.ac ]; then autoreconf -i; fi
|
||||
- |
|
||||
set -x
|
||||
case "$BUILD" in
|
||||
stack)
|
||||
# Add in extra-deps for older snapshots, as necessary
|
||||
stack --no-terminal --install-ghc $ARGS build --bench --dry-run || ( \
|
||||
stack --no-terminal $ARGS build cabal-install && \
|
||||
stack --no-terminal $ARGS solver --update-config)
|
||||
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||
- BENCH=${BENCH---enable-benchmarks}
|
||||
- TEST=${TEST---enable-tests}
|
||||
- HADDOCK=${HADDOCK-true}
|
||||
- INSTALLED=${INSTALLED-true}
|
||||
- GHCHEAD=${GHCHEAD-false}
|
||||
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
|
||||
- |
|
||||
case "$BUILD" in
|
||||
stack)
|
||||
# Add in extra-deps for older snapshots, as necessary
|
||||
stack --no-terminal --install-ghc $ARGS build --bench --dry-run || ( \
|
||||
stack --no-terminal $ARGS build cabal-install && \
|
||||
stack --no-terminal $ARGS solver --update-config)
|
||||
|
||||
# Build the dependencies
|
||||
stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies
|
||||
;;
|
||||
cabal)
|
||||
cabal --version
|
||||
travis_retry cabal update
|
||||
|
||||
# Get the list of packages from the stack.yaml file. Note that
|
||||
# this will also implicitly run hpack as necessary to generate
|
||||
# the .cabal files needed by cabal-install.
|
||||
PACKAGES=$(stack --install-ghc query locals | grep '^ *path' | sed 's@^ *path:@@')
|
||||
|
||||
;;
|
||||
esac
|
||||
set +ex
|
||||
# Build the dependencies
|
||||
stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies
|
||||
;;
|
||||
cabal)
|
||||
cabal --version
|
||||
travis_retry cabal update -v
|
||||
;;
|
||||
esac
|
||||
|
||||
# Here starts the actual work to be performed for the package under test;
|
||||
# any command which exits with a non-zero exit code causes the build to fail.
|
||||
script:
|
||||
- |
|
||||
set -ex
|
||||
case "$BUILD" in
|
||||
stack)
|
||||
stack --no-terminal $ARGS build --no-run-benchmarks --haddock --no-haddock-deps
|
||||
;;
|
||||
cabal)
|
||||
# Build with stack
|
||||
- if [[ "$BUILD" == "stack" ]]; then stack --no-terminal $ARGS build --no-run-benchmarks; fi
|
||||
# Build with cabal, using individual commands so we can see which part failed.
|
||||
- if [[ "$BUILD" == "cabal" ]]; then cabal new-configure -w ${HC} --enable-tests --ghc-options -O0; fi
|
||||
- if [[ "$BUILD" == "cabal" ]]; then cabal new-build -w ${HC} all; fi
|
||||
- if [[ "$BUILD" == "cabal" ]]; then rm -rf ./dist-newstyle; fi
|
||||
|
||||
ORIGDIR=$(pwd)
|
||||
|
||||
if [ $CABALVER != "2.0" ]
|
||||
then
|
||||
|
||||
cabal sandbox init
|
||||
|
||||
for dir in $PACKAGES
|
||||
do
|
||||
cd $dir
|
||||
echo "Processing $dir"
|
||||
travis_retry cabal update
|
||||
PKGVER=$(cabal info . | awk '{print $2;exit}')
|
||||
|
||||
cabal install --only-dependencies --enable-tests
|
||||
cabal configure --enable-tests --ghc-options -O0
|
||||
cabal build
|
||||
|
||||
cd $ORIGDIR
|
||||
done
|
||||
else
|
||||
cabal new-configure --project-file="cabal.project" --enable-tests --ghc-options -O0
|
||||
cabal new-build --project-file="cabal.project" all
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
set +ex
|
||||
# REGENDATA ["applied-fp-course.cabal"]
|
||||
# EOF
|
||||
|
63
README.md
63
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
[![Build Status](https://travis-ci.org/qfpl/applied-fp-course.svg?branch=master)](https://travis-ci.org/qfpl/applied-fp-course)
|
||||
|
||||
<img src="https://i.imgur.com/0h9dFhl.png" height="400" width="640" />
|
||||
<img src="https://i.imgur.com/0h9dFhl.png" height="200" width="320" />
|
||||
|
||||
This is a brand new course, so there are going to be rough edges. We invite you to submit issues or
|
||||
pull requests if you find errors or have suggestions on how to improve it.
|
||||
@ -21,6 +21,7 @@ IRC on [Freenode](https://freenode.net/) in #qfpl or #fp-course.
|
||||
* Have a few months self-study to your name.
|
||||
* Want to know how to build larger applications with statically typed FP.
|
||||
* Are willing to accept that a web application is a sufficient choice.
|
||||
* Can write the canonical function of type: ``Applicative f => [f a] -> f [a]``
|
||||
|
||||
### We:
|
||||
|
||||
@ -39,30 +40,45 @@ IRC on [Freenode](https://freenode.net/) in #qfpl or #fp-course.
|
||||
|
||||
### Setup build tools:
|
||||
|
||||
Each level is a self-contained Haskell application, containing incomplete, or as
|
||||
yet undefined, data types and functions. There is a Cabal and Nix file for each
|
||||
level, so you can use either cabal sandboxes or a ``nix-shell``, depending on
|
||||
your preference.
|
||||
Each level is a self-contained Haskell module, containing incomplete, or as yet
|
||||
undefined, data types and functions.
|
||||
|
||||
We recommend using either a cabal sandbox, or a ``nix-shell``, depending on your
|
||||
preference.
|
||||
|
||||
To use a sandbox:
|
||||
|
||||
```bash
|
||||
$ cd <levelN>
|
||||
$ cd path/to/applied-fp-course
|
||||
$ cabal sandbox init
|
||||
$ cabal install --only-dependencies
|
||||
$ cabal install --only-dependencies --enable-tests
|
||||
$ cabal build
|
||||
$ $EDITOR README.md
|
||||
```
|
||||
The normal cabal build commands should then work as expected. We do recommend
|
||||
using cabal sandboxes as they provide a contained Haskell environment for a
|
||||
given project. Easy to clean up, and package versions won't conflict with any
|
||||
other sandboxed project you may be working on.
|
||||
|
||||
We do recommend using cabal sandboxes as they provide a contained Haskell
|
||||
environment for a given project. Easy to clean up, and package versions won't
|
||||
conflict with any other sandboxed project you may be working on.
|
||||
|
||||
If you're using a version of Cabal that is >=2.0 (use ``cabal --version`` to
|
||||
find out), then you can use the ``new-*`` commands and you don't need a sandbox:
|
||||
|
||||
```bash
|
||||
$ cd path/to/applied-fp-course
|
||||
$ cabal new-configure --enable-tests
|
||||
$ cabal new-build <levelN>-exe
|
||||
$ $EDITOR src/<LevelN>/README.md
|
||||
```
|
||||
|
||||
The normal cabal build commands should then work as expected.
|
||||
|
||||
To use the Nix Shell:
|
||||
```bash
|
||||
$ cd <levelN>
|
||||
$ cd path/to/applied-fp-course
|
||||
$ nix-shell
|
||||
$ cabal build
|
||||
$ $EDITOR README.md
|
||||
$ cabal new-build <levelN>-exe
|
||||
$ $EDITOR src/<LevelN>/README.md
|
||||
|
||||
```
|
||||
Once that completes you will be in a ``nix-shell`` environment with all the
|
||||
tools required to build the application for that level. Note that the
|
||||
@ -70,7 +86,13 @@ levels build on each other, so you can go to the highest level and enter a
|
||||
nix-shell there, you will then have all the required tools for every level.
|
||||
|
||||
The ``shell.nix`` is not provided, so if you have a different work-flow you can
|
||||
utilise the derivation from the respective ``levelN.nix``.
|
||||
utilise the derivation from the ``applied-fp-course.nix``.
|
||||
|
||||
##### Stack
|
||||
|
||||
Stack yaml configuration is provided and checked by our CI system for successful
|
||||
builds. However the authors do not use stack, so we cannot promise to be able to
|
||||
resolve stack related issues that may arise. Though we will do our best. :)
|
||||
|
||||
##### Please note...
|
||||
|
||||
@ -83,16 +105,16 @@ free [WebChat client](https://webchat.freenode.net).
|
||||
|
||||
#### Subsequent lessons may contain spoilers, don't cheat yourself out of the experience!
|
||||
|
||||
There is a ``README.md`` file in each Level project that will provide instructions about
|
||||
what the goal is for that specific level.
|
||||
There is a ``README.md`` file in each Level module folder that will provide
|
||||
instructions about what the goal is for that specific level.
|
||||
|
||||
* Level 01 : Simple Hello World web app.
|
||||
* Level 02 : Define our application spec with types!
|
||||
* Level 03 : Testing & Tools (hspec & ghcid)
|
||||
* Level 04 : Database layer (sqlite-simple)
|
||||
* Level 05 : Add some flexible configuration
|
||||
* Level 06 : ReaderT & Refactoring
|
||||
* Level 07 : ExceptT & Refactoring
|
||||
* Level 05 : Better Error Handling Through ExceptT
|
||||
* Level 06 : Add some flexible configuration
|
||||
* Level 07 : ReaderT & Refactoring
|
||||
|
||||
-- Coming Soon...
|
||||
* Level 08 : (Bonus Round) Lenses & Refactoring
|
||||
@ -101,4 +123,3 @@ what the goal is for that specific level.
|
||||
* Level 09 : Add session controls (login, logout) and a protected route. So we
|
||||
can have something that resembles application state. For the purposes of
|
||||
modelling the state machine and implementing some property based tests.
|
||||
|
||||
|
253
applied-fp-course.cabal
Normal file
253
applied-fp-course.cabal
Normal file
@ -0,0 +1,253 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: applied-fp-course
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps for educational purposes.
|
||||
|
||||
-- A longer description of the package.
|
||||
description: Haskell course for people looking to start building larger applications.
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a README.
|
||||
extra-source-files: changelog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.4.1
|
||||
, GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/qfpl/applied-fp-course
|
||||
|
||||
library
|
||||
-- Modules included in this executable, other than Main.
|
||||
exposed-modules:
|
||||
Level01.Core
|
||||
, Level02.Core
|
||||
, Level02.Types
|
||||
, Level03.Core
|
||||
, Level03.Types
|
||||
, Level04.Conf
|
||||
, Level04.DB
|
||||
, Level04.DB.Types
|
||||
, Level04.Core
|
||||
, Level04.Types
|
||||
, Level04.Types.CommentText
|
||||
, Level04.Types.Error
|
||||
, Level04.Types.Topic
|
||||
, Level05.AppM
|
||||
, Level05.Conf
|
||||
, Level05.DB
|
||||
, Level05.DB.Types
|
||||
, Level05.Core
|
||||
, Level05.Types
|
||||
, Level05.Types.CommentText
|
||||
, Level05.Types.Error
|
||||
, Level05.Types.Topic
|
||||
, Level06.AppM
|
||||
, Level06.Conf
|
||||
, Level06.Conf.CommandLine
|
||||
, Level06.Conf.File
|
||||
, Level06.DB
|
||||
, Level06.DB.Types
|
||||
, Level06.Core
|
||||
, Level06.Types
|
||||
, Level06.Types.CommentText
|
||||
, Level06.Types.Error
|
||||
, Level06.Types.Topic
|
||||
, Level07.AppM
|
||||
, Level07.Conf
|
||||
, Level07.Conf.CommandLine
|
||||
, Level07.Conf.File
|
||||
, Level07.DB
|
||||
, Level07.DB.Types
|
||||
, Level07.Core
|
||||
, Level07.Responses
|
||||
, Level07.Types
|
||||
, Level07.Types.CommentText
|
||||
, Level07.Types.Error
|
||||
, Level07.Types.Topic
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, optparse-applicative >= 0.13 && < 0.15
|
||||
, aeson == 1.*
|
||||
, mtl == 2.2.*
|
||||
, time >= 1.4 && < 1.10
|
||||
, sqlite-simple == 0.4.*
|
||||
, sqlite-simple-errors == 0.6.*
|
||||
, semigroups == 0.18.*
|
||||
, transformers >= 0.4 && < 0.6
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite app-fp-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
|
||||
other-modules: Level03Tests
|
||||
, Level04Tests
|
||||
, Level05Tests
|
||||
, Level06Tests
|
||||
, Level07Tests
|
||||
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, applied-fp-course
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, mtl == 2.2.*
|
||||
|
||||
test-suite doctests
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
|
||||
other-modules: Level04Tests
|
||||
, Level05Tests
|
||||
, Level06Tests
|
||||
, Level07Tests
|
||||
|
||||
ghc-options: -threaded
|
||||
main-is: doctests.hs
|
||||
hs-source-dirs: tests
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, applied-fp-course
|
||||
, mtl == 2.2.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, doctest >= 0.11 && < 0.16
|
||||
|
||||
-- Level Executables
|
||||
executable level01-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level01.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level02-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level02.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level03-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level03.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level04-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level04.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level05-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level05.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level06-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level06.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level07-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Level07.hs
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: exe
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, applied-fp-course
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
23
applied-fp-course.nix
Normal file
23
applied-fp-course.nix
Normal file
@ -0,0 +1,23 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, mtl, optparse-applicative, semigroups, sqlite-simple
|
||||
, sqlite-simple-errors, stdenv, text, time, transformers, wai
|
||||
, wai-extra, warp
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "applied-fp-course";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types mtl optparse-applicative
|
||||
semigroups sqlite-simple sqlite-simple-errors text time
|
||||
transformers wai warp
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai mtl text wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps for educational purposes";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
# This Travis job script has been generated by a script via
|
||||
#
|
||||
# runghc make_travis_yml_2.hs 'cabal.project'
|
||||
#
|
||||
# For more information, see https://github.com/hvr/multi-ghc-travis
|
||||
#
|
||||
language: c
|
||||
sudo: false
|
||||
|
||||
git:
|
||||
submodules: false # whether to recursively clone submodules
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cabal/packages
|
||||
- $HOME/.cabal/store
|
||||
|
||||
before_cache:
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
|
||||
# remove files that are regenerated by 'cabal update'
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
|
||||
- rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
|
||||
|
||||
- rm -rfv $HOME/.cabal/packages/head.hackage
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: "ghc-7.10.3"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.3], sources: [hvr-ghc]}}
|
||||
- compiler: "ghc-8.0.2"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
|
||||
- compiler: "ghc-8.2.2"
|
||||
# env: TEST=--disable-tests BENCH=--disable-benchmarks
|
||||
addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
|
||||
|
||||
before_install:
|
||||
- HC=${CC}
|
||||
- HCPKG=${HC/ghc/ghc-pkg}
|
||||
- unset CC
|
||||
- ROOTDIR=$(pwd)
|
||||
- mkdir -p $HOME/.local/bin
|
||||
- "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"
|
||||
- HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))
|
||||
- echo $HCNUMVER
|
||||
|
||||
install:
|
||||
- cabal --version
|
||||
- echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
|
||||
- BENCH=${BENCH---enable-benchmarks}
|
||||
- TEST=${TEST---enable-tests}
|
||||
- HADDOCK=${HADDOCK-true}
|
||||
- INSTALLED=${INSTALLED-true}
|
||||
- GHCHEAD=${GHCHEAD-false}
|
||||
- travis_retry cabal update -v
|
||||
- "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"
|
||||
- rm -fv cabal.project cabal.project.local
|
||||
- grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'
|
||||
- "printf 'packages: \"level01\" \"level02\" \"level03\" \"level04\" \"level05\" \"level06\" \"level07\"\\n' > cabal.project"
|
||||
- cat cabal.project
|
||||
- if [ -f "level01/configure.ac" ]; then
|
||||
(cd "level01" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level02/configure.ac" ]; then
|
||||
(cd "level02" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level03/configure.ac" ]; then
|
||||
(cd "level03" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level04/configure.ac" ]; then
|
||||
(cd "level04" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level05/configure.ac" ]; then
|
||||
(cd "level05" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level06/configure.ac" ]; then
|
||||
(cd "level06" && autoreconf -i);
|
||||
fi
|
||||
- if [ -f "level07/configure.ac" ]; then
|
||||
(cd "level07" && autoreconf -i);
|
||||
fi
|
||||
- rm -f cabal.project.freeze
|
||||
- cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all
|
||||
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all
|
||||
- rm -rf "level01"/.ghc.environment.* "level02"/.ghc.environment.* "level03"/.ghc.environment.* "level04"/.ghc.environment.* "level05"/.ghc.environment.* "level06"/.ghc.environment.* "level07"/.ghc.environment.* "level01"/dist "level02"/dist "level03"/dist "level04"/dist "level05"/dist "level06"/dist "level07"/dist
|
||||
- DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
|
||||
|
||||
# Here starts the actual work to be performed for the package under test;
|
||||
# any command which exits with a non-zero exit code causes the build to fail.
|
||||
script:
|
||||
# test that source-distributions can be generated
|
||||
# - (cd "level01" && cabal sdist)
|
||||
# - (cd "level02" && cabal sdist)
|
||||
# - (cd "level03" && cabal sdist)
|
||||
# - (cd "level04" && cabal sdist)
|
||||
# - (cd "level05" && cabal sdist)
|
||||
# - (cd "level06" && cabal sdist)
|
||||
# - (cd "level07" && cabal sdist)
|
||||
# - mv "level01"/dist/level01-*.tar.gz "level02"/dist/level02-*.tar.gz "level03"/dist/level03-*.tar.gz "level04"/dist/level04-*.tar.gz "level05"/dist/level05-*.tar.gz "level06"/dist/level06-*.tar.gz "level07"/dist/level07-*.tar.gz ${DISTDIR}/
|
||||
# - cd ${DISTDIR} || false
|
||||
# - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;
|
||||
- "printf 'packages: level01/level01.cabal level02/level02.cabal level03/level03.cabal level04/level04.cabal level05/level05.cabal level06/level06.cabal level07/level07.cabal\\n' > cabal.project"
|
||||
- cat cabal.project
|
||||
# this builds all libraries and executables (without tests/benchmarks)
|
||||
- cabal new-build -w ${HC} --disable-tests --disable-benchmarks all
|
||||
|
||||
# Build with installed constraints for packages in global-db
|
||||
- if $INSTALLED; then echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks $(${HCPKG} list --global --simple-output --names-only | sed 's/\([a-zA-Z0-9-]\{1,\}\) */--constraint="\1 installed" /g') all | sh; else echo "Not building with installed constraints"; fi
|
||||
|
||||
# build & run tests, build benchmarks
|
||||
- cabal new-build -w ${HC} ${TEST} ${BENCH} all
|
||||
# - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi
|
||||
|
||||
# cabal check
|
||||
# - (cd level01 && cabal check)
|
||||
# - (cd level02 && cabal check)
|
||||
# - (cd level03 && cabal check)
|
||||
# - (cd level04 && cabal check)
|
||||
# - (cd level05 && cabal check)
|
||||
# - (cd level06 && cabal check)
|
||||
# - (cd level07 && cabal check)
|
||||
|
||||
# haddock
|
||||
- rm -rf ./dist-newstyle
|
||||
- if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi
|
||||
|
||||
# REGENDATA ["cabal.project"]
|
||||
# EOF
|
@ -1,8 +1 @@
|
||||
packages:
|
||||
level01/
|
||||
level02/
|
||||
level03/
|
||||
level04/
|
||||
level05/
|
||||
level06/
|
||||
level07/
|
||||
packages: .
|
0
changelog.md
Normal file
0
changelog.md
Normal file
@ -1,5 +1,6 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
{ nixpkgs ? import <nixpkgs> {}
|
||||
, compiler ? "default"
|
||||
}:
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
@ -7,7 +8,7 @@ let
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level04.nix {};
|
||||
drv = haskellPackages.callPackage ./applied-fp-course.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
9
exe/Level01.hs
Normal file
9
exe/Level01.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level01.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level02.hs
Normal file
9
exe/Level02.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level02.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level03.hs
Normal file
9
exe/Level03.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level03.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level04.hs
Normal file
9
exe/Level04.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level04.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Level04.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level05.hs
Normal file
9
exe/Level05.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level05.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Level05.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level06.hs
Normal file
9
exe/Level06.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level06.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
9
exe/Level07.hs
Normal file
9
exe/Level07.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module Main where
|
||||
|
||||
import qualified Level07.Core as Core
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``exe/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair.
|
||||
main :: IO ()
|
||||
main = Core.runApp
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,9 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as Main
|
||||
|
||||
-- Our application will be built as a library that will be included in an
|
||||
-- executable. So our ``bin/Main.hs`` is a straightforward and unremarkable
|
||||
-- affair. We won't be updating this file.
|
||||
main :: IO ()
|
||||
main = Main.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level01
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level01.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,93 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level01
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
exposed-modules: FirstApp.Main
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level01-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Modules included in this executable, other than Main.
|
||||
-- other-modules:
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level01
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -1,13 +0,0 @@
|
||||
{ mkDerivation, stdenv, base, wai, warp, http-types }:
|
||||
|
||||
mkDerivation {
|
||||
pname = "level01";
|
||||
src = ./.;
|
||||
version = "0.1.0.0";
|
||||
sha256 = "0";
|
||||
isLibrary = false;
|
||||
isExecutable = true;
|
||||
executableHaskellDepends = [ base wai warp http-types ];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as Main
|
||||
|
||||
main :: IO ()
|
||||
main = Main.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level02
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level02.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,97 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level02
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
library
|
||||
exposed-modules: FirstApp.Types
|
||||
, FirstApp.Main
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-fwarn-missing-import-lists
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
|
||||
executable level02-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Modules included in this executable, other than Main.
|
||||
-- other-modules:
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level02
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
@ -1,13 +0,0 @@
|
||||
{ mkDerivation, base, wai, warp, http-types, stdenv }:
|
||||
mkDerivation {
|
||||
pname = "level02";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = false;
|
||||
isExecutable = true;
|
||||
executableHaskellDepends = [
|
||||
base wai warp http-types
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as M
|
||||
|
||||
main :: IO ()
|
||||
main = M.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level03
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level03.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,113 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level03
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
-- Modules included in this executable, other than Main.
|
||||
exposed-modules: FirstApp.Types
|
||||
, FirstApp.Main
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-fwarn-missing-import-lists
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level03-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Modules included in this executable, other than Main.
|
||||
-- other-modules:
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level03
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
-- This is the declaration of a test-suite for your application. You may have
|
||||
-- multiple test suites in a single application, provided they are named
|
||||
-- differently.
|
||||
test-suite level03-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, level03
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
@ -1,20 +0,0 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, optparse-applicative, stdenv, text, wai, wai-extra
|
||||
, warp
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "level03";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types optparse-applicative text wai warp
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1,9 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Test.DocTest (doctest)
|
||||
|
||||
main :: IO ()
|
||||
main = doctest
|
||||
[ "-isrc"
|
||||
, "src/FirstApp/Conf.hs"
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as M
|
||||
|
||||
main :: IO ()
|
||||
main = M.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level04
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,132 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level04
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
-- Modules included in this executable, other than Main.
|
||||
exposed-modules: FirstApp.Conf
|
||||
, FirstApp.DB
|
||||
, FirstApp.DB.Types
|
||||
, FirstApp.Main
|
||||
, FirstApp.Types
|
||||
, FirstApp.Types.CommentText
|
||||
, FirstApp.Types.Error
|
||||
, FirstApp.Types.Topic
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-fwarn-missing-import-lists
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, optparse-applicative >= 0.13 && < 0.15
|
||||
, aeson == 1.*
|
||||
, mtl == 2.2.*
|
||||
, time >= 1.4 && < 1.10
|
||||
, sqlite-simple == 0.4.*
|
||||
, sqlite-simple-errors == 0.6.*
|
||||
, semigroups == 0.18.*
|
||||
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level04-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level04
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite level04-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, level04
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
||||
|
||||
test-suite doctests
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
ghc-options: -threaded
|
||||
main-is: doctests.hs
|
||||
hs-source-dirs: tests
|
||||
build-depends: base
|
||||
, doctest >= 0.11 && < 0.16
|
||||
, semigroups == 0.18.*
|
@ -1,21 +0,0 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, mtl, optparse-applicative, sqlite-simple, semigroups
|
||||
, sqlite-simple-errors, stdenv, text, time, wai, wai-extra, warp
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "level04";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types mtl optparse-applicative
|
||||
sqlite-simple sqlite-simple-errors text time wai warp semigroups
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1 +0,0 @@
|
||||
{"foo":33}
|
@ -1,11 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Test.DocTest (doctest)
|
||||
|
||||
main :: IO ()
|
||||
main = doctest
|
||||
[ "-isrc"
|
||||
, "src/FirstApp/Conf.hs"
|
||||
, "src/FirstApp/DB.hs"
|
||||
, "src/FirstApp/Types.hs"
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,33 +0,0 @@
|
||||
# Level 05
|
||||
|
||||
In this exercise we build some configuration capabilities into our application.
|
||||
|
||||
This exercise will require a combination of building the right types to guide
|
||||
your development, plus consulting plenty of documentation to leverage the chosen
|
||||
packages. There may also be, depending on your level of interest, some external
|
||||
reading for later as well.
|
||||
|
||||
The steps for this level:
|
||||
1) ``src/FirstApp/Types.hs``
|
||||
2) ``src/FirstApp/Conf/File.hs``
|
||||
3) ``src/FirstApp/Conf.hs``
|
||||
4) ``src/FirstApp/Main.hs``
|
||||
|
||||
The packages we will use for this are:
|
||||
|
||||
- [Aeson](http://hackage.haskell.org/package/aeson)
|
||||
- [Optparse Applicative](http://hackage.haskell.org/package/optparse-applicative)
|
||||
|
||||
#### Aside: Tool Introduction - doctest
|
||||
|
||||
This level utilises the [doctest](https://hackage.haskell.org/package/doctest)
|
||||
tool to help us ensure our functions comply with some quick tests that are
|
||||
written as comments in the source file. This is a port of the same technology
|
||||
that exists in Python.
|
||||
|
||||
You can see the new entry in the Cabal file as another ``test-suite``. The
|
||||
``doctests.hs`` lists the files that have doctests that we want to run. The
|
||||
``src/FirstApp/Conf/File.hs`` file contains some tests that you need to update
|
||||
as part of the level.
|
||||
|
||||
For details on running and writing doctests, refer to the documentation.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"dbFileName": "app_db.db"
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as Main
|
||||
|
||||
main :: IO ()
|
||||
main = Main.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level05
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level05.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,126 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level05
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
exposed-modules: FirstApp.Conf
|
||||
, FirstApp.Conf.CommandLine
|
||||
, FirstApp.Conf.File
|
||||
, FirstApp.DB
|
||||
, FirstApp.DB.Types
|
||||
, FirstApp.Main
|
||||
, FirstApp.Types
|
||||
, FirstApp.Types.CommentText
|
||||
, FirstApp.Types.Error
|
||||
, FirstApp.Types.Topic
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, optparse-applicative >= 0.13 && < 0.15
|
||||
, aeson == 1.*
|
||||
, time >= 1.4 && < 1.10
|
||||
, sqlite-simple == 0.4.*
|
||||
, sqlite-simple-errors == 0.6.*
|
||||
, semigroups == 0.18.*
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level05-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level05
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite level05-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, level05
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
||||
test-suite doctests
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
ghc-options: -threaded
|
||||
main-is: doctests.hs
|
||||
hs-source-dirs: tests
|
||||
build-depends: base
|
||||
, level05
|
||||
, doctest >= 0.11 && < 0.16
|
@ -1,21 +0,0 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, mtl, optparse-applicative, sqlite-simple, semigroups
|
||||
, sqlite-simple-errors, stdenv, text, time, wai, wai-extra, warp
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "level05";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types mtl optparse-applicative
|
||||
sqlite-simple sqlite-simple-errors text time wai warp semigroups
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"foo": 33
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Main where
|
||||
|
||||
import Control.Monad (join)
|
||||
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
|
||||
import qualified System.Exit as Exit
|
||||
|
||||
import qualified FirstApp.DB as DB
|
||||
import qualified FirstApp.Main as Main
|
||||
import qualified FirstApp.Types as Types
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let dieWith m = print m >> Exit.exitFailure
|
||||
|
||||
reqsE <- Main.prepareAppReqs
|
||||
case reqsE of
|
||||
|
||||
Left err -> dieWith err
|
||||
|
||||
Right ( cfg, db ) -> do
|
||||
let app' = pure ( Main.app cfg db )
|
||||
|
||||
flushTopic =
|
||||
-- Clean up and yell about our errors
|
||||
fmap ( either dieWith pure . join ) .
|
||||
-- Purge all of the comments for this topic for our tests
|
||||
traverse ( DB.deleteTopic db )
|
||||
-- We don't export the constructor so even for known values we have
|
||||
-- to play by the rules. There is no - "Oh just this one time.", do it right.
|
||||
$ Types.mkTopic "fudge"
|
||||
|
||||
-- Run the tests with a DB topic flush between each spec
|
||||
hspec . with ( flushTopic >> app' ) $ do
|
||||
|
||||
-- AddRq Spec
|
||||
describe "POST /topic/add" $ do
|
||||
|
||||
it "Should return 200 with well formed request" $ do
|
||||
post "/fudge/add" "Fred" `shouldRespondWith` "Success"
|
||||
|
||||
it "Should 400 on empty input" $
|
||||
post "/fudge/add" "" `shouldRespondWith` 400
|
||||
|
||||
-- ViewRq Spec
|
||||
describe "GET /topic/view" $ do
|
||||
it "Should return 200 with content" $ do
|
||||
post "/fudge/add" "Is super tasty."
|
||||
get "/fudge/view" `shouldRespondWith` 200
|
||||
|
||||
-- ListRq Spec
|
||||
describe "GET /list" $ do
|
||||
it "Should return 200 with content" $ do
|
||||
post "/fudge/add" "Is super tasty."
|
||||
get "/list" `shouldRespondWith` "[\"fudge\"]"
|
@ -1,9 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Test.DocTest (doctest)
|
||||
|
||||
main :: IO ()
|
||||
main = doctest
|
||||
[ "-isrc"
|
||||
, "src/FirstApp/Conf.hs"
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as M
|
||||
|
||||
main :: IO ()
|
||||
main = M.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level06
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level06.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,136 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level06
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
-- Modules included in this executable, other than Main.
|
||||
exposed-modules: FirstApp.AppM
|
||||
, FirstApp.Conf
|
||||
, FirstApp.Conf.CommandLine
|
||||
, FirstApp.Conf.File
|
||||
, FirstApp.DB
|
||||
, FirstApp.DB.Types
|
||||
, FirstApp.Main
|
||||
, FirstApp.Responses
|
||||
, FirstApp.Types
|
||||
, FirstApp.Types.CommentText
|
||||
, FirstApp.Types.Error
|
||||
, FirstApp.Types.Topic
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, optparse-applicative >= 0.13 && < 0.15
|
||||
, aeson == 1.*
|
||||
, mtl == 2.2.*
|
||||
, time >= 1.4 && < 1.10
|
||||
, sqlite-simple == 0.4.*
|
||||
, sqlite-simple-errors == 0.6.*
|
||||
, semigroups == 0.18.*
|
||||
, transformers >= 0.4 && < 0.6
|
||||
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level06-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level06
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite level06-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, level06
|
||||
, mtl == 2.2.*
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
||||
|
||||
test-suite doctests
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
ghc-options: -threaded
|
||||
main-is: doctests.hs
|
||||
hs-source-dirs: tests
|
||||
build-depends: base
|
||||
, doctest >= 0.11 && < 0.16
|
@ -1,23 +0,0 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, mtl, optparse-applicative, sqlite-simple, semigroups
|
||||
, sqlite-simple-errors, stdenv, text, time, wai, wai-extra, warp
|
||||
, transformers
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "level06";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types mtl optparse-applicative
|
||||
sqlite-simple sqlite-simple-errors text time wai warp semigroups
|
||||
transformers
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# OPTIONS_GHC -fno-warn-missing-methods #-}
|
||||
module FirstApp.Conf
|
||||
( parseOptions
|
||||
) where
|
||||
|
||||
import GHC.Word (Word16)
|
||||
|
||||
import Data.Bifunctor (first)
|
||||
import Data.Monoid (Last (..), (<>))
|
||||
|
||||
import FirstApp.Types (Conf (..), ConfigError (..),
|
||||
DBFilePath (DBFilePath),
|
||||
PartialConf (..), Port (Port))
|
||||
|
||||
import FirstApp.Conf.CommandLine (commandLineParser)
|
||||
import FirstApp.Conf.File (parseJSONConfigFile)
|
||||
|
||||
-- We have some sane defaults that we can always rely on, so define them using
|
||||
-- our PartialConf.
|
||||
defaultConf
|
||||
:: PartialConf
|
||||
defaultConf = PartialConf
|
||||
(pure (Port 3000))
|
||||
(pure (DBFilePath "app_db.db"))
|
||||
|
||||
-- We need something that will take our PartialConf and see if can finally build
|
||||
-- a complete Conf record. Also we need to highlight any missing config values
|
||||
-- by providing the relevant error.
|
||||
makeConfig
|
||||
:: PartialConf
|
||||
-> Either ConfigError Conf
|
||||
makeConfig pc = Conf
|
||||
<$> lastToEither MissingPort pcPort
|
||||
<*> lastToEither MissingDBFilePath pcDBFilePath
|
||||
where
|
||||
-- You don't need to provide type signatures for most functions in where/let
|
||||
-- sections. Sometimes the compiler might need a bit of help, or you would
|
||||
-- like to be explicit in your intentions.
|
||||
lastToEither
|
||||
:: ConfigError
|
||||
-> (PartialConf -> Last b)
|
||||
-> Either ConfigError b
|
||||
lastToEither e g =
|
||||
(maybe (Left e) Right . getLast . g) pc
|
||||
|
||||
-- This is the function we'll actually export for building our configuration.
|
||||
-- Since it wraps all our efforts to read information from the command line, and
|
||||
-- the file, before combining it all and returning the required information.
|
||||
parseOptions
|
||||
:: FilePath
|
||||
-> IO (Either ConfigError Conf)
|
||||
parseOptions fp =
|
||||
let mkCfg cli file = makeConfig (defaultConf <> file <> cli)
|
||||
in do
|
||||
cli' <- commandLineParser
|
||||
( >>= mkCfg cli' ) <$> parseJSONConfigFile fp
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1 +0,0 @@
|
||||
{"foo":33}
|
@ -1,89 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module Main where
|
||||
|
||||
import Control.Monad.Reader (ask, reader)
|
||||
|
||||
import Control.Monad (join)
|
||||
|
||||
import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
|
||||
import qualified System.Exit as Exit
|
||||
|
||||
import FirstApp.AppM (Env)
|
||||
import qualified FirstApp.AppM as AppM
|
||||
|
||||
import qualified FirstApp.DB as DB
|
||||
import qualified FirstApp.Main as Main
|
||||
import qualified FirstApp.Types as Types
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
let dieWith m = print m >> Exit.exitFailure
|
||||
|
||||
-- Keeping everything in sync with out larger application changes.
|
||||
reqsE <- Main.prepareAppReqs
|
||||
case reqsE of
|
||||
|
||||
Left err -> dieWith err
|
||||
|
||||
Right env -> do
|
||||
let app' = pure ( Main.app env )
|
||||
|
||||
flushTopic :: IO ()
|
||||
flushTopic = AppM.runAppM (do
|
||||
r <- traverse DB.deleteTopic ( Types.mkTopic "fudge" )
|
||||
either ( liftIO . dieWith ) pure $ join r
|
||||
) env
|
||||
|
||||
-- We can't run the tests for our AppM in the same stage as our
|
||||
-- application, because of the use of the 'with' function. As it expects
|
||||
-- to be able to execute our tests by applying it to our 'Application'.
|
||||
hspec $ appMTests env
|
||||
|
||||
-- Run the tests with a DB topic flush between each spec
|
||||
hspec . with ( flushTopic >> app' ) $ do
|
||||
|
||||
-- AddRq Spec
|
||||
describe "POST /topic/add" $ do
|
||||
|
||||
it "Should return 200 with well formed request" $
|
||||
post "/fudge/add" "Fred" `shouldRespondWith` "Success"
|
||||
|
||||
it "Should 400 on empty input" $
|
||||
post "/fudge/add" "" `shouldRespondWith` 400
|
||||
|
||||
-- ViewRq Spec
|
||||
describe "GET /topic/view" $
|
||||
it "Should return 200 with content" $ do
|
||||
post "/fudge/add" "Is super tasty."
|
||||
get "/fudge/view" `shouldRespondWith` 200
|
||||
|
||||
-- ListRq Spec
|
||||
describe "GET /list" $
|
||||
it "Should return 200 with content" $ do
|
||||
post "/fudge/add" "Is super tasty."
|
||||
get "/list" `shouldRespondWith` "[\"fudge\"]"
|
||||
|
||||
|
||||
-- These tests ensure that our AppM will do we want it to, with respect to the
|
||||
-- behaviour of 'ask', 'reader', and use in a Monad.
|
||||
appMTests :: Env -> Spec
|
||||
appMTests env = describe "AppM Tests" $ do
|
||||
|
||||
it "ask should retrieve the Env" $ do
|
||||
r <- AppM.runAppM ask env
|
||||
( AppM.envConfig r == AppM.envConfig env ) `shouldBe` True
|
||||
|
||||
it "reader should run a function on the Env" $ do
|
||||
let getDBfilepath = Types.dbFilePath . AppM.envConfig
|
||||
|
||||
r <- AppM.runAppM ( reader getDBfilepath ) env
|
||||
r `shouldBe` (getDBfilepath env)
|
||||
|
||||
it "should let us run IO functions" $ do
|
||||
let fn = do
|
||||
e <- ask
|
||||
AppM.envLoggingFn e "In a test!"
|
||||
r <- AppM.runAppM fn env
|
||||
r `shouldBe` ()
|
@ -1,11 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Test.DocTest (doctest)
|
||||
|
||||
main :: IO ()
|
||||
main = doctest
|
||||
[ "-isrc"
|
||||
, "src/FirstApp/Conf.hs"
|
||||
, "src/FirstApp/DB.hs"
|
||||
, "src/FirstApp/Types.hs"
|
||||
]
|
@ -1,31 +0,0 @@
|
||||
Copyright (c) 2017, Commonwealth Scientific and Industrial Research Organisation
|
||||
(CSIRO) ABN 41 687 119 230.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of QFPL nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -1,8 +0,0 @@
|
||||
# Level 07
|
||||
|
||||
Handling those `Either` values everywhere is a bit awkward, this exercise
|
||||
introduces another monad transformer, ``ExceptT``. As well as the concept of a
|
||||
'transformer stack' and what benefits it can provide.
|
||||
|
||||
Start in ``src/FirstApp/AppM.hs``.
|
||||
|
@ -1,2 +0,0 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"port": 3000,
|
||||
"helloMsg": "Functional Programming is neat.",
|
||||
"tableName": "comments",
|
||||
"dbName": "firstapp"
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import qualified FirstApp.Main as M
|
||||
|
||||
main :: IO ()
|
||||
main = M.runApp
|
@ -1,5 +0,0 @@
|
||||
# Revision history for level07
|
||||
|
||||
## 0.1.0.0 -- YYYY-mm-dd
|
||||
|
||||
* First version. Released on an unsuspecting world.
|
@ -1,13 +0,0 @@
|
||||
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default" }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) pkgs;
|
||||
|
||||
haskellPackages = if compiler == "default"
|
||||
then pkgs.haskellPackages
|
||||
else pkgs.haskell.packages.${compiler};
|
||||
|
||||
drv = haskellPackages.callPackage ./level07.nix {};
|
||||
|
||||
in
|
||||
if pkgs.lib.inNixShell then drv.env else drv
|
@ -1,136 +0,0 @@
|
||||
-- Initial level01.cabal generated by cabal init. For further
|
||||
-- documentation, see http://haskell.org/cabal/users-guide/
|
||||
|
||||
-- The name of the package.
|
||||
name: level07
|
||||
|
||||
-- The package version. See the Haskell package versioning policy (PVP)
|
||||
-- for standards guiding when and how versions should be incremented.
|
||||
-- https://wiki.haskell.org/Package_versioning_policy
|
||||
-- PVP summary: +-+------- breaking API changes
|
||||
-- | | +----- non-breaking API additions
|
||||
-- | | | +--- code changes with no API change
|
||||
version: 0.1.0.0
|
||||
|
||||
-- A short (one-line) description of the package.
|
||||
synopsis: Simplest of web apps
|
||||
|
||||
-- A longer description of the package.
|
||||
-- description:
|
||||
|
||||
-- The license under which the package is released.
|
||||
license: BSD3
|
||||
|
||||
-- The file containing the license text.
|
||||
license-file: LICENCE
|
||||
|
||||
-- The package author(s).
|
||||
author: QFPL @ Data61
|
||||
|
||||
-- An email address to which users can send suggestions, bug reports, and
|
||||
-- patches.
|
||||
maintainer: sean.chalmers@data61.csiro.au
|
||||
|
||||
-- A copyright notice.
|
||||
copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)
|
||||
|
||||
category: Education
|
||||
|
||||
build-type: Simple
|
||||
|
||||
-- Extra files to be distributed with the package, such as examples or a
|
||||
-- README.
|
||||
extra-source-files: ChangeLog.md
|
||||
|
||||
-- Constraint on the version of Cabal needed to build this package.
|
||||
cabal-version: >=1.10
|
||||
|
||||
tested-with: GHC==8.2.2
|
||||
, GHC==8.0.2
|
||||
, GHC==7.10.3
|
||||
|
||||
library
|
||||
-- Modules included in this executable, other than Main.
|
||||
exposed-modules: FirstApp.AppM
|
||||
, FirstApp.Conf
|
||||
, FirstApp.Conf.CommandLine
|
||||
, FirstApp.Conf.File
|
||||
, FirstApp.DB
|
||||
, FirstApp.DB.Types
|
||||
, FirstApp.Main
|
||||
, FirstApp.Responses
|
||||
, FirstApp.Types
|
||||
, FirstApp.Types.CommentText
|
||||
, FirstApp.Types.Error
|
||||
, FirstApp.Types.Topic
|
||||
|
||||
ghc-options: -Wall
|
||||
-fno-warn-unused-binds
|
||||
-fno-warn-unused-do-bind
|
||||
-fno-warn-unused-imports
|
||||
-fno-warn-type-defaults
|
||||
-ferror-spans
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, wai == 3.2.*
|
||||
, warp == 3.2.*
|
||||
, http-types >= 0.9 && < 0.13
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, optparse-applicative >= 0.13 && < 0.15
|
||||
, aeson == 1.*
|
||||
, mtl == 2.2.*
|
||||
, time >= 1.4 && < 1.10
|
||||
, sqlite-simple == 0.4.*
|
||||
, sqlite-simple-errors == 0.6.*
|
||||
, semigroups == 0.18.*
|
||||
, transformers >= 0.4 && < 0.6
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: src
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
executable level07-exe
|
||||
-- .hs or .lhs file containing the Main module.
|
||||
main-is: Main.hs
|
||||
|
||||
-- Directories containing source files.
|
||||
hs-source-dirs: bin
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
|
||||
-- Other library packages from which modules are imported.
|
||||
build-depends: base >=4.8 && <4.12
|
||||
, level07
|
||||
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite level07-tests
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: tests
|
||||
main-is: Test.hs
|
||||
build-depends: base >= 4.8 && <4.12
|
||||
, level07
|
||||
, wai == 3.2.*
|
||||
, wai-extra == 3.0.*
|
||||
, hspec >= 2.2 && < 3.0
|
||||
, hspec-wai >= 0.6 && < 0.10
|
||||
, bytestring == 0.10.*
|
||||
, text == 1.2.*
|
||||
, mtl == 2.2.*
|
||||
|
||||
test-suite doctests
|
||||
-- Base language which the package is written in.
|
||||
default-language: Haskell2010
|
||||
type: exitcode-stdio-1.0
|
||||
ghc-options: -threaded
|
||||
main-is: doctests.hs
|
||||
hs-source-dirs: tests
|
||||
build-depends: base
|
||||
, doctest >= 0.11 && < 0.16
|
@ -1,23 +0,0 @@
|
||||
{ mkDerivation, aeson, base, bytestring, doctest, hspec, hspec-wai
|
||||
, http-types, mtl, optparse-applicative, sqlite-simple, semigroups
|
||||
, sqlite-simple-errors, stdenv, text, time, wai, wai-extra, warp
|
||||
, transformers
|
||||
}:
|
||||
mkDerivation {
|
||||
pname = "level07";
|
||||
version = "0.1.0.0";
|
||||
src = ./.;
|
||||
isLibrary = true;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring http-types mtl optparse-applicative
|
||||
sqlite-simple sqlite-simple-errors text time wai warp semigroups
|
||||
transformers
|
||||
];
|
||||
executableHaskellDepends = [ base ];
|
||||
testHaskellDepends = [
|
||||
base bytestring doctest hspec hspec-wai text wai wai-extra
|
||||
];
|
||||
description = "Simplest of web apps";
|
||||
license = stdenv.lib.licenses.bsd3;
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
module FirstApp.Conf.CommandLine
|
||||
( commandLineParser
|
||||
) where
|
||||
|
||||
import Data.Monoid (Last (Last), (<>))
|
||||
|
||||
import Options.Applicative (Parser, eitherReader, execParser,
|
||||
fullDesc, header, help, helper, info,
|
||||
long, metavar, option, optional, progDesc,
|
||||
short, strOption)
|
||||
|
||||
import Text.Read (readEither)
|
||||
|
||||
import FirstApp.Types (DBFilePath (DBFilePath),
|
||||
PartialConf (PartialConf), Port (Port))
|
||||
|
||||
-- | Command Line Parsing
|
||||
|
||||
-- This is an example of using the ``optparse-applicative`` package to build our command line
|
||||
-- parser. As this particular problem is fraught with silly dangers and we appreciate someone else
|
||||
-- having eaten this gremlin on our behalf.
|
||||
commandLineParser
|
||||
:: IO PartialConf
|
||||
commandLineParser =
|
||||
let mods = fullDesc
|
||||
<> progDesc "Manage comments for something"
|
||||
<> header "Your first Haskell app!"
|
||||
in
|
||||
execParser $ info (helper <*> partialConfParser) mods
|
||||
|
||||
-- Combine the smaller parsers into our larger ``PartialConf`` type.
|
||||
partialConfParser
|
||||
:: Parser PartialConf
|
||||
partialConfParser =
|
||||
PartialConf <$> portParser <*> dbFilePathParser
|
||||
|
||||
-- Parse the Port value off the command line args and into a Last wrapper.
|
||||
portParser
|
||||
:: Parser (Last Port)
|
||||
portParser =
|
||||
let
|
||||
mods = long "port"
|
||||
<> short 'p'
|
||||
<> metavar "PORT"
|
||||
<> help "TCP Port to accept requests on"
|
||||
-- A custom parser to turn a String into a Word16, before putting it into a Port
|
||||
portReader = eitherReader (fmap Port . readEither)
|
||||
in
|
||||
Last <$> optional (option portReader mods)
|
||||
|
||||
-- Parse the DBFilePath from the input string into our type and into a Last wrapper.
|
||||
dbFilePathParser
|
||||
:: Parser (Last DBFilePath)
|
||||
dbFilePathParser =
|
||||
let
|
||||
mods = long "db-filepath"
|
||||
<> short 'd'
|
||||
<> metavar "DBFILEPATH"
|
||||
<> help "File path for our SQLite Database file."
|
||||
in
|
||||
Last <$> optional (DBFilePath <$> strOption mods)
|
@ -1,39 +0,0 @@
|
||||
module FirstApp.Conf.File where
|
||||
|
||||
import Data.ByteString.Lazy (ByteString)
|
||||
import qualified Data.ByteString.Lazy.Char8 as LBS
|
||||
|
||||
import Data.Bifunctor (first)
|
||||
|
||||
import Control.Exception (try)
|
||||
|
||||
import qualified Data.Aeson as Aeson
|
||||
|
||||
import FirstApp.Types (ConfigError (..), PartialConf)
|
||||
|
||||
-- Doctest setup section
|
||||
-- $setup
|
||||
-- >>> :set -XOverloadedStrings
|
||||
|
||||
-- | Update these tests when you've completed this function.
|
||||
--
|
||||
-- | readConfFile
|
||||
-- >>> readConfFile "badFileName.no"
|
||||
-- Left (ConfigFileReadError badFileName.no: openBinaryFile: does not exist (No such file or directory))
|
||||
-- >>> readConfFile "test.json"
|
||||
-- Right "{\"foo\":33}\n"
|
||||
--
|
||||
readConfFile
|
||||
:: FilePath
|
||||
-> IO ( Either ConfigError ByteString )
|
||||
readConfFile fp =
|
||||
first ConfigFileReadError <$> try (LBS.readFile fp)
|
||||
|
||||
-- Construct the function that will take a ``FilePath``, read it in, decode it,
|
||||
-- and construct our ``PartialConf``.
|
||||
parseJSONConfigFile
|
||||
:: FilePath
|
||||
-> IO ( Either ConfigError PartialConf )
|
||||
parseJSONConfigFile fp =
|
||||
(first JSONDecodeError . Aeson.eitherDecode =<<) <$> readConfFile fp
|
||||
|
@ -1,176 +0,0 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module FirstApp.Main
|
||||
( runApp
|
||||
, prepareAppReqs
|
||||
, app
|
||||
) where
|
||||
|
||||
import Control.Monad.Except (ExceptT (ExceptT),
|
||||
runExceptT)
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
|
||||
import Network.Wai (Application, Request,
|
||||
Response, pathInfo,
|
||||
requestMethod,
|
||||
strictRequestBody)
|
||||
import Network.Wai.Handler.Warp (run)
|
||||
|
||||
import Data.Bifunctor (first)
|
||||
import Data.Either (Either (Left, Right),
|
||||
either)
|
||||
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as Text
|
||||
import Data.Text.Encoding (decodeUtf8)
|
||||
import Data.Text.IO (hPutStrLn)
|
||||
|
||||
import qualified Data.ByteString.Lazy.Char8 as LBS
|
||||
|
||||
import Database.SQLite.SimpleErrors.Types (SQLiteResponse)
|
||||
|
||||
import System.IO (stderr)
|
||||
|
||||
import qualified FirstApp.DB as DB
|
||||
|
||||
import qualified FirstApp.Conf as Conf
|
||||
import qualified FirstApp.Responses as Res
|
||||
import FirstApp.Types (Conf (..),
|
||||
ConfigError (..),
|
||||
Error (DBError, EmptyCommentText, EmptyTopic, UnknownRoute),
|
||||
RqType (AddRq, ListRq, ViewRq),
|
||||
confPortToWai,
|
||||
mkCommentText, mkTopic)
|
||||
|
||||
import FirstApp.AppM (AppM,
|
||||
Env (Env, envConfig, envDB),
|
||||
runAppM, liftEither)
|
||||
|
||||
-- Our start-up process is becoming more complicated and could fail in new and
|
||||
-- interesting ways. But we also want to be able to capture these errors in a
|
||||
-- single type so that we can deal with the entire start-up process as a whole.
|
||||
data StartUpError
|
||||
= ConfErr ConfigError
|
||||
| DbInitErr SQLiteResponse
|
||||
deriving Show
|
||||
|
||||
runApp
|
||||
:: IO ()
|
||||
runApp = do
|
||||
appE <- prepareAppReqs
|
||||
either print runWithDbConn appE
|
||||
where
|
||||
runWithDbConn env =
|
||||
appWithDb env >> DB.closeDB (envDB env)
|
||||
|
||||
appWithDb env =
|
||||
run ( confPortToWai $ envConfig env ) (app env)
|
||||
|
||||
-- Monad transformers can be used without needing to write the newtype. The
|
||||
-- constructor for ExceptT has a type of :: m (Either e a). So if you have
|
||||
-- multiple functions that match that pattern and you don't want to have to
|
||||
-- thread the error handling needle yourself. You can apply the constructor to
|
||||
-- the functions and work directly on the values, knowing that the error
|
||||
-- handling will work as expected. Then you `runExceptT` and produce the final
|
||||
-- Either value.
|
||||
prepareAppReqs
|
||||
:: IO (Either StartUpError Env)
|
||||
prepareAppReqs =
|
||||
error "Copy your completed 'prepareAppReqs' and refactor to match the new type signature"
|
||||
where
|
||||
logToErr :: Text -> AppM ()
|
||||
logToErr = liftIO . hPutStrLn stderr
|
||||
|
||||
toStartUpErr :: (a -> StartUpError) -> IO (Either a c) -> ExceptT StartUpError IO c
|
||||
toStartUpErr = error "toStartUpErr not reimplemented"
|
||||
|
||||
-- Take our possibly failing configuration/db functions with their unique
|
||||
-- error types and turn them into a consistently typed ExceptT. We can then
|
||||
-- use them in a `do` block as if the Either isn't there. Extracting the
|
||||
-- final result before returning.
|
||||
initConf :: ExceptT StartUpError IO Conf
|
||||
initConf = toStartUpErr ConfErr $ Conf.parseOptions "appconfig.json"
|
||||
|
||||
initDB :: Conf -> ExceptT StartUpError IO DB.FirstAppDB
|
||||
initDB cfg = toStartUpErr DbInitErr $ DB.initDB (dbFilePath cfg)
|
||||
|
||||
app
|
||||
:: Env
|
||||
-> Application
|
||||
app env rq cb = do
|
||||
e <- requestToResponse
|
||||
resp <- either handleError pure e
|
||||
cb resp
|
||||
where
|
||||
logToErr :: Text -> IO ()
|
||||
logToErr = liftIO . hPutStrLn stderr
|
||||
|
||||
requestToResponse :: IO (Either Error Response)
|
||||
requestToResponse = runAppM ( mkRequest rq >>= handleRequest ) env
|
||||
|
||||
handleError :: Error -> IO Response
|
||||
handleError e = mkErrorResponse e <$ ( logToErr . Text.pack . show ) e
|
||||
|
||||
-- This function has changed quite a bit since we changed our DB functions to be
|
||||
-- part of AppM. We no longer have to deal with the extra layer of the returned
|
||||
-- Either and these functions share the same Monad, AppM.
|
||||
handleRequest
|
||||
:: RqType
|
||||
-> AppM Response
|
||||
handleRequest ( AddRq t c ) =
|
||||
-- We've cleaned this branch up a bit more by dropping our use of `const` as
|
||||
-- we can use the Functor operator that ignores the result on the right hand
|
||||
-- side and returns the result of the function on the left.
|
||||
Res.resp200 "Success" <$ DB.addCommentToTopic t c
|
||||
handleRequest ( ViewRq t ) =
|
||||
Res.resp200Json <$> DB.getComments t
|
||||
handleRequest ListRq =
|
||||
Res.resp200Json <$> DB.getTopics
|
||||
|
||||
mkRequest
|
||||
:: Request
|
||||
-> AppM RqType
|
||||
mkRequest rq =
|
||||
liftEither =<< case ( pathInfo rq, requestMethod rq ) of
|
||||
-- Commenting on a given topic
|
||||
( [t, "add"], "POST" ) ->
|
||||
liftIO $ mkAddRequest t <$> strictRequestBody rq
|
||||
-- View the comments on a given topic
|
||||
( [t, "view"], "GET" ) ->
|
||||
pure ( mkViewRequest t )
|
||||
-- List the current topics
|
||||
( ["list"], "GET" ) ->
|
||||
pure mkListRequest
|
||||
-- We don't care about any other requests so throw your hands in the air
|
||||
_ ->
|
||||
pure ( Left UnknownRoute )
|
||||
|
||||
mkAddRequest
|
||||
:: Text
|
||||
-> LBS.ByteString
|
||||
-> Either Error RqType
|
||||
mkAddRequest ti c = AddRq
|
||||
<$> mkTopic ti
|
||||
<*> (mkCommentText . decodeUtf8 . LBS.toStrict) c
|
||||
|
||||
mkViewRequest
|
||||
:: Text
|
||||
-> Either Error RqType
|
||||
mkViewRequest =
|
||||
fmap ViewRq . mkTopic
|
||||
|
||||
mkListRequest
|
||||
:: Either Error RqType
|
||||
mkListRequest =
|
||||
Right ListRq
|
||||
|
||||
mkErrorResponse
|
||||
:: Error
|
||||
-> Response
|
||||
mkErrorResponse UnknownRoute =
|
||||
Res.resp404 "Unknown Route"
|
||||
mkErrorResponse EmptyCommentText =
|
||||
Res.resp400 "Empty Comment"
|
||||
mkErrorResponse EmptyTopic =
|
||||
Res.resp400 "Empty Topic"
|
||||
mkErrorResponse ( DBError _ ) =
|
||||
Res.resp500 "OH NOES"
|
@ -1,53 +0,0 @@
|
||||
module FirstApp.Responses where
|
||||
|
||||
import Network.Wai (Response, responseLBS)
|
||||
|
||||
import Network.HTTP.Types (Status, hContentType, status200,
|
||||
status400, status404, status500)
|
||||
|
||||
import qualified Data.ByteString.Lazy.Char8 as LBS
|
||||
|
||||
import Data.Aeson (ToJSON)
|
||||
import qualified Data.Aeson as A
|
||||
import FirstApp.Types (ContentType (JSON, PlainText),
|
||||
renderContentType)
|
||||
|
||||
mkResponse
|
||||
:: Status
|
||||
-> ContentType
|
||||
-> LBS.ByteString
|
||||
-> Response
|
||||
mkResponse sts ct msg =
|
||||
responseLBS sts [(hContentType, renderContentType ct)] msg
|
||||
|
||||
resp200
|
||||
:: LBS.ByteString
|
||||
-> Response
|
||||
resp200 =
|
||||
mkResponse status200 PlainText
|
||||
|
||||
resp404
|
||||
:: LBS.ByteString
|
||||
-> Response
|
||||
resp404 =
|
||||
mkResponse status404 PlainText
|
||||
|
||||
resp400
|
||||
:: LBS.ByteString
|
||||
-> Response
|
||||
resp400 =
|
||||
mkResponse status400 PlainText
|
||||
|
||||
-- Some new helpers for different statuses and content types
|
||||
resp500
|
||||
:: LBS.ByteString
|
||||
-> Response
|
||||
resp500 =
|
||||
mkResponse status500 PlainText
|
||||
|
||||
resp200Json
|
||||
:: ToJSON a
|
||||
=> a
|
||||
-> Response
|
||||
resp200Json =
|
||||
mkResponse status200 JSON . A.encode
|
@ -1,248 +0,0 @@
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module FirstApp.Types
|
||||
( Error (..)
|
||||
, ConfigError (..)
|
||||
, PartialConf (..)
|
||||
, Port (..)
|
||||
, DBFilePath (..)
|
||||
, Conf (..)
|
||||
, FirstAppDB (..)
|
||||
, RqType (..)
|
||||
, ContentType (..)
|
||||
, Comment (..)
|
||||
, Topic
|
||||
, CommentText
|
||||
, mkTopic
|
||||
, getTopic
|
||||
, mkCommentText
|
||||
, getCommentText
|
||||
, renderContentType
|
||||
, fromDbComment
|
||||
, confPortToWai
|
||||
) where
|
||||
|
||||
import System.IO.Error (IOError)
|
||||
|
||||
import GHC.Generics (Generic)
|
||||
import GHC.Word (Word16)
|
||||
|
||||
import Data.ByteString (ByteString)
|
||||
import Data.Text (Text)
|
||||
|
||||
import Data.List (stripPrefix)
|
||||
import Data.Maybe (fromMaybe)
|
||||
import Data.Monoid (Last (..))
|
||||
import Data.Semigroup (Semigroup ((<>)))
|
||||
|
||||
import Data.Aeson (ToJSON, FromJSON (..), (.:?))
|
||||
import qualified Data.Aeson as A
|
||||
import qualified Data.Aeson.Types as A
|
||||
|
||||
import Data.Time (UTCTime)
|
||||
|
||||
import Database.SQLite.Simple (Connection)
|
||||
import Database.SQLite.SimpleErrors.Types (SQLiteResponse)
|
||||
|
||||
import FirstApp.DB.Types (DbComment (..))
|
||||
import FirstApp.Types.Error (Error ( UnknownRoute
|
||||
, EmptyCommentText
|
||||
, EmptyTopic
|
||||
, DBError
|
||||
))
|
||||
import FirstApp.Types.CommentText ( CommentText
|
||||
, mkCommentText
|
||||
, getCommentText
|
||||
)
|
||||
import FirstApp.Types.Topic (Topic, mkTopic, getTopic)
|
||||
|
||||
newtype CommentId = CommentId Int
|
||||
deriving (Show, ToJSON)
|
||||
|
||||
data Comment = Comment
|
||||
{ commentId :: CommentId
|
||||
, commentTopic :: Topic
|
||||
, commentText :: CommentText
|
||||
, commentTime :: UTCTime
|
||||
}
|
||||
-- Generic has been added to our deriving list.
|
||||
deriving ( Show, Generic )
|
||||
|
||||
-- Strip the prefix (which may fail if the prefix isn't present), fall
|
||||
-- back to the original label if need be, then camel-case the name.
|
||||
|
||||
-- | modFieldLabel
|
||||
-- >>> modFieldLabel "commentId"
|
||||
-- "id"
|
||||
-- >>> modFieldLabel "topic"
|
||||
-- "topic"
|
||||
-- >>> modFieldLabel ""
|
||||
-- ""
|
||||
modFieldLabel
|
||||
:: String
|
||||
-> String
|
||||
modFieldLabel l =
|
||||
A.camelTo2 '_'
|
||||
. fromMaybe l
|
||||
$ stripPrefix "comment" l
|
||||
|
||||
instance ToJSON Comment where
|
||||
-- This is one place where we can take advantage of our Generic instance. Aeson
|
||||
-- already has the encoding functions written for anything that implements the
|
||||
-- Generic typeclass. So we don't have to write our encoding, we tell Aeson to
|
||||
-- build it.
|
||||
toEncoding = A.genericToEncoding opts
|
||||
where
|
||||
-- These options let us make some minor adjustments to how Aeson treats
|
||||
-- our type. Our only adjustment is to alter the field names a little, to
|
||||
-- remove the 'comment' prefix and use an Aeson function to handle the
|
||||
-- rest of the name. This accepts any 'String -> String' function but it's
|
||||
-- wise to keep the modifications simple.
|
||||
opts = A.defaultOptions
|
||||
{ A.fieldLabelModifier = modFieldLabel
|
||||
}
|
||||
|
||||
-- For safety we take our stored DbComment and try to construct a Comment that
|
||||
-- we would be okay with showing someone. However unlikely it may be, this is a
|
||||
-- nice method for separating out the back and front end of a web app and
|
||||
-- providing greater guarantees about data cleanliness.
|
||||
fromDbComment
|
||||
:: DbComment
|
||||
-> Either Error Comment
|
||||
fromDbComment dbc =
|
||||
Comment (CommentId $ dbCommentId dbc)
|
||||
<$> (mkTopic $ dbCommentTopic dbc)
|
||||
<*> (mkCommentText $ dbCommentComment dbc)
|
||||
<*> (pure $ dbCommentTime dbc)
|
||||
|
||||
data RqType
|
||||
= AddRq Topic CommentText
|
||||
| ViewRq Topic
|
||||
| ListRq
|
||||
|
||||
-- Provide a type to list our response content types so we don't try to
|
||||
-- do the wrong thing with what we meant to be used as text or JSON etc.
|
||||
data ContentType
|
||||
= PlainText
|
||||
| JSON
|
||||
|
||||
renderContentType
|
||||
:: ContentType
|
||||
-> ByteString
|
||||
renderContentType PlainText = "text/plain"
|
||||
renderContentType JSON = "application/json"
|
||||
|
||||
-----------------
|
||||
-- Config Types
|
||||
-----------------
|
||||
|
||||
-- This is an alternative way of defining a `newtype`. You define it as a simple
|
||||
-- record and this lets you specify an unwrapping function at the same time. Which
|
||||
-- technique you choose is a matter for your specific needs and preference.
|
||||
--
|
||||
newtype Port = Port
|
||||
{ getPort :: Word16 }
|
||||
deriving (Eq, Show)
|
||||
|
||||
newtype DBFilePath = DBFilePath
|
||||
{ getDBFilePath :: FilePath }
|
||||
deriving (Eq, Show)
|
||||
|
||||
-- The ``Conf`` type will need:
|
||||
-- - A customisable port number: ``Port``
|
||||
-- - A filepath for our SQLite database: ``DBFilePath``
|
||||
data Conf = Conf
|
||||
{ port :: Port
|
||||
, dbFilePath :: DBFilePath
|
||||
}
|
||||
deriving Eq
|
||||
|
||||
-- We're storing our Port as a Word16 to be more precise and prevent invalid
|
||||
-- values from being used in our application. However Wai is not so stringent.
|
||||
-- To accommodate this and make our lives a bit easier, we will write this
|
||||
-- helper function to take ``Conf`` value and convert it to an ``Int``.
|
||||
confPortToWai
|
||||
:: Conf
|
||||
-> Int
|
||||
confPortToWai =
|
||||
fromIntegral . getPort . port
|
||||
|
||||
-- Similar to when we were considering our application types, leave this empty
|
||||
-- for now and add to it as you go.
|
||||
data ConfigError
|
||||
= MissingPort
|
||||
| MissingDBFilePath
|
||||
| JSONDecodeError String
|
||||
| ConfigFileReadError IOError
|
||||
deriving Show
|
||||
|
||||
-- Our application will be able to load configuration from both a file and
|
||||
-- command line input. We want to be able to use the command line to temporarily
|
||||
-- override the configuration from our file. How do we combine the different
|
||||
-- inputs to enable this property?
|
||||
|
||||
-- We want the command line configuration to take precedence over the File
|
||||
-- configuration, so if we think about combining each of our ``Conf`` records,
|
||||
-- we want to be able to write something like this:
|
||||
|
||||
-- ``defaults <> file <> commandLine``
|
||||
|
||||
-- We can use the ``Monoid`` typeclass to handle combining the ``Conf`` records
|
||||
-- together, and the ``Last`` type to wrap up our values to handle the desired
|
||||
-- precedence. The ``Last`` type is a wrapper for Maybe that when used with its
|
||||
-- ``Monoid`` instance will always preference the last ``Just`` value that it
|
||||
-- has:
|
||||
|
||||
-- Last (Just 3) <> Last (Just 1) = Last (Just 1)
|
||||
-- Last Nothing <> Last (Just 1) = Last (Just 1)
|
||||
-- Last (Just 1) <> Last Nothing = Last (Just 1)
|
||||
|
||||
-- To make this easier, we'll make a new type ``PartialConf`` that will have our
|
||||
-- ``Last`` wrapped values. We can then define a ``Monoid`` instance for it and
|
||||
-- have our ``Conf`` be a known good configuration.
|
||||
data PartialConf = PartialConf
|
||||
{ pcPort :: Last Port
|
||||
, pcDBFilePath :: Last DBFilePath
|
||||
}
|
||||
|
||||
-- Before we can define our ``Monoid`` instance for ``PartialConf``, we'll have
|
||||
-- to define a Semigroup instance. We define our ``(<>)`` function to lean
|
||||
-- on the ``Semigroup`` instance for Last to always get the last value.
|
||||
instance Semigroup PartialConf where
|
||||
_a <> _b = PartialConf
|
||||
{ pcPort = error "pcPort (<>) not implemented"
|
||||
, pcDBFilePath = error "pcDBFilePath (<>) not implemented"
|
||||
}
|
||||
|
||||
-- We now define our ``Monoid`` instance for ``PartialConf``. Allowing us to
|
||||
-- define our always empty configuration, which would always fail our
|
||||
-- requirements. We just define `mappend` to be an alias of ``(<>)``
|
||||
instance Monoid PartialConf where
|
||||
mempty = PartialConf mempty mempty
|
||||
mappend = (<>)
|
||||
|
||||
-- When it comes to reading the configuration options from the command-line, we
|
||||
-- use the 'optparse-applicative' package. This part of the exercise has already
|
||||
-- been completed for you, feel free to have a look through the 'CommandLine'
|
||||
-- module and see how it works.
|
||||
--
|
||||
-- For reading the configuration from the file, we're going to use the aeson
|
||||
-- library to handle the parsing and decoding for us. In order to do this, we
|
||||
-- have to tell aeson how to go about converting the JSON into our PartialConf
|
||||
-- data structure.
|
||||
instance FromJSON PartialConf where
|
||||
parseJSON = A.withObject "PartialConf" $ \o -> PartialConf
|
||||
<$> parseToLast "port" Port o
|
||||
<*> parseToLast "dbFilePath" DBFilePath o
|
||||
where
|
||||
parseToLast k c o =
|
||||
Last . fmap c <$> o .:? k
|
||||
|
||||
-- We have a data type to simplify passing around the information we need to run
|
||||
-- our database queries. This also allows things to change over time without
|
||||
-- having to rewrite all of the functions that need to interact with DB related
|
||||
-- things in different ways.
|
||||
newtype FirstAppDB = FirstAppDB
|
||||
{ dbConn :: Connection
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
||||
# resolver:
|
||||
# name: custom-snapshot
|
||||
# location: "./custom-snapshot.yaml"
|
||||
resolver: lts-10.4
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# - location:
|
||||
# git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
# extra-dep: true
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
#
|
||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
||||
# will not be run. This is useful for tweaking upstream packages.
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||
# (e.g., acme-missiles-0.3)
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=1.6"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
@ -1 +0,0 @@
|
||||
{"foo":33}
|
@ -1,11 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Test.DocTest (doctest)
|
||||
|
||||
main :: IO ()
|
||||
main = doctest
|
||||
[ "-isrc"
|
||||
, "src/FirstApp/Conf.hs"
|
||||
, "src/FirstApp/DB.hs"
|
||||
, "src/FirstApp/Types.hs"
|
||||
]
|
@ -1,6 +1,6 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
|
||||
module FirstApp.Main (runApp) where
|
||||
module Level01.Core (runApp) where
|
||||
|
||||
import Network.Wai (Application, Request, Response,
|
||||
ResponseReceived, responseLBS)
|
||||
@ -42,4 +42,3 @@ app _ cb =
|
||||
-- executable Main.hs.
|
||||
runApp :: IO ()
|
||||
runApp = run undefined undefined
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
The purpose of this exercise is to whet our appetite by creating a basic web
|
||||
app. The focus will be on reading the [Hackage] documentation for the [Wai]
|
||||
framework. Consult the ``src/FirstApp/Main.hs`` to find the parts that are
|
||||
framework. Consult the ``src/Level01/Core.hs`` to find the parts that are
|
||||
missing and what we need from the [Wai] package to build our "Hello, World!"
|
||||
application.
|
||||
|
@ -1,5 +1,5 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module FirstApp.Main (runApp) where
|
||||
module Level02.Core (runApp) where
|
||||
|
||||
import Network.Wai (Application, Request, Response,
|
||||
pathInfo, requestMethod, responseLBS,
|
||||
@ -16,12 +16,12 @@ import Data.Either (either)
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Encoding (decodeUtf8)
|
||||
|
||||
import FirstApp.Types (ContentType, Error, RqType,
|
||||
import Level02.Types (ContentType, Error, RqType,
|
||||
mkCommentText, mkTopic,
|
||||
renderContentType)
|
||||
|
||||
-- --------------------------------------------
|
||||
-- - Don't start here, go to FirstApp.Types! -
|
||||
-- - Don't start here, go to Level02.Types! -
|
||||
-- --------------------------------------------
|
||||
|
||||
-- | Some helper functions to make our lives a little more DRY.
|
@ -38,7 +38,7 @@ GET /<topic>/view
|
||||
GET /list
|
||||
```
|
||||
|
||||
The starting point for this exercise is the ``src/FirstApp/Types.hs``.
|
||||
The starting point for this exercise is the ``src/Level02/Types.hs``.
|
||||
|
||||
### Running the program:
|
||||
|
@ -1,6 +1,6 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# OPTIONS_GHC -fno-warn-dodgy-exports #-}
|
||||
module FirstApp.Types
|
||||
module Level02.Types
|
||||
( Topic
|
||||
, CommentText
|
||||
, ContentType (..)
|
||||
@ -122,3 +122,5 @@ getCommentText
|
||||
-> Text
|
||||
getCommentText =
|
||||
error "getCommentText not implemented"
|
||||
|
||||
---- Go to `src/Level02/Core.hs` next
|
@ -1,5 +1,5 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
module FirstApp.Main (runApp, app) where
|
||||
module Level03.Core (runApp, app) where
|
||||
|
||||
import Network.Wai (Application, Request, Response,
|
||||
pathInfo, requestMethod, responseLBS,
|
||||
@ -16,7 +16,7 @@ import Data.Either (either)
|
||||
import Data.Text (Text)
|
||||
import Data.Text.Encoding (decodeUtf8)
|
||||
|
||||
import FirstApp.Types (ContentType (PlainText), Error (EmptyCommentText, EmptyTopic, UnknownRoute),
|
||||
import Level03.Types (ContentType (PlainText), Error (EmptyCommentText, EmptyTopic, UnknownRoute),
|
||||
RqType (AddRq, ListRq, ViewRq),
|
||||
mkCommentText, mkTopic,
|
||||
renderContentType)
|
||||
@ -83,17 +83,13 @@ mkRequest
|
||||
mkRequest rq =
|
||||
case ( pathInfo rq, requestMethod rq ) of
|
||||
-- Commenting on a given topic
|
||||
( [t, "add"], "POST" ) ->
|
||||
mkAddRequest t <$> strictRequestBody rq
|
||||
( [t, "add"], "POST" ) -> mkAddRequest t <$> strictRequestBody rq
|
||||
-- View the comments on a given topic
|
||||
( [t, "view"], "GET" ) ->
|
||||
pure ( mkViewRequest t )
|
||||
( [t, "view"], "GET" ) -> pure ( mkViewRequest t )
|
||||
-- List the current topics
|
||||
( ["list"], "GET" ) ->
|
||||
pure mkListRequest
|
||||
( ["list"], "GET" ) -> pure mkListRequest
|
||||
-- Finally we don't care about any other requests so throw your hands in the air
|
||||
_ ->
|
||||
pure ( Left UnknownRoute )
|
||||
_ -> pure ( Left UnknownRoute )
|
||||
|
||||
mkAddRequest
|
||||
:: Text
|
@ -23,6 +23,14 @@ $ cabal configure --enable-tests
|
||||
$ cabal test
|
||||
```
|
||||
|
||||
If you're using Cabal 2.0 or greater (You can check your cabal version with `$ cabal --version`):
|
||||
|
||||
```shell
|
||||
$ cabal new-configure --enable-tests
|
||||
$ cabal new-build --enable-tests
|
||||
$ cabal new-test
|
||||
```
|
||||
|
||||
For a stack environment:
|
||||
|
||||
```shell
|
||||
@ -33,10 +41,10 @@ To load the tests in the REPL:
|
||||
|
||||
```shell
|
||||
# Cabal
|
||||
$ cabal repl level03-tests
|
||||
$ cabal new-repl app-fp-tests
|
||||
|
||||
# Stack
|
||||
$ stack ghci level03:test:level03-tests
|
||||
$ stack ghci applied-fp-course:test:app-fp-tests
|
||||
```
|
||||
|
||||
To run the tests in the repl:
|
||||
@ -45,7 +53,7 @@ To run the tests in the repl:
|
||||
*Main> :main
|
||||
```
|
||||
|
||||
Start in ``tests/Test.hs``.
|
||||
Start in ``tests/Level03Tests.hs``.
|
||||
|
||||
[HSpec]: (http://hspec.github.io/)
|
||||
[hspec-wai]: (https://hackage.haskell.org/package/hspec-wai)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user