Halcyon tutorial
Halcyon is a system for installing apps and development tools, including and .
This tutorial shows how to develop a simple Haskell web app using Halcyon.
Set up
Halcyon can be installed by cloning the , or by running the , which also installs the necessary OS packages and sets up the environment.
The tutorial assumes you’re using a Linux system with at least 4 GB RAM and GNU bash 4 or newer.
Run the setup script to install Halcyon:
$ source <( curl -sL https://github.com/mietek/halcyon/raw/master/setup.sh )
-----> Welcome to Halcyon
[sudo] password for fnord:
-----> Creating base directory: /app
-----> Installing OS packages
...
-----> Installing Halcyon... done, 9d37342
-----> Installing bashmenot... done, 8bd8ea3
-----> Extending .bash_profile
Halcyon is now ready to use:
$ which halcyon
/app/halcyon/halcyon
Options
If you don’t want your .bash_profile
to be extended, set HALCYON_NO_MODIFY_HOME
to 1
before running the setup script. You’ll then need to activate Halcyon manually before each use:
$ source <( /app/halcyon/halcyon paths )
You can change where Halcyon is installed by setting the HALCYON_DIR
environment variable before running the setup script.
Halcyon installs development tools and other dependencies in the base directory, which defaults to /app
. Changing this path isn’t recommended, because it’ll require all dependencies to be built from scratch. If you still want to do it, set HALCYON_BASE
before running the setup script.
Install GHC and Cabal
Execute the Halcyon install
command to install GHC and Cabal:
$ halcyon install
-----> Installing GHC and Cabal
External storage: **public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Restoring GHC directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/halcyon-ghc-7.8.4.tar.gz... done
Extracting halcyon-ghc-7.8.4.tar.gz... done, 701MB
-----> Locating Cabal directories
Listing https://halcyon.global.ssl.fastly.net/... done
-----> Restoring Cabal directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... done
Extracting halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... done, 180MB
-----> GHC and Cabal installed
-----> Examining cache changes
+ halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
+ halcyon-ghc-7.8.4.tar.gz
Expected time: 20–30 seconds
In this step, Halcyon restores the GHC directory and the Cabal directory by extracting archives downloaded from public storage, which is an external cache for previously-built apps and dependencies.
All downloaded archives are cached in the Halcyon cache directory.
GHC and Cabal are now ready to use:
$ which ghc
/app/ghc/bin/ghc
$ which cabal
/app/cabal/bin/cabal
Options
All Halcyon options can be specified by setting an environment variable. You can also specify most options with a command-line argument.
By default, Halcyon installs GHC 7.8.4 and cabal-install 1.20.0.3. You can change this with the HALCYON_GHC_VERSION
and HALCYON_CABAL_VERSION
options.
The cache directory defaults to /var/tmp/halcyon-cache
, and can be changed with the HALCYON_CACHE
option.
Install the app
The is a simple web service for storing notes, built with .
The app includes a Cabal package description file, file, used to declare dependencies, and a Halcyon constraints file, file, used to declare version constraints.
Use the Halcyon install
command to install the app directly from the :
$ halcyon install https://github.com/mietek/halcyon-tutorial
-----> Examining cache contents
halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
halcyon-ghc-7.8.4.tar.gz
-----> Cloning https://github.com/mietek/halcyon-tutorial... done, af1461f
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **0c985ba**
External storage: **public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-0c985ba-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-install-0c985ba-halcyon-tutorial-1.0.tar.gz... done, 8.8MB
-----> Installing app to /app
-----> Installed halcyon-tutorial-1.0
-----> App installed: **halcyon-tutorial-1.0**
-----> Examining cache changes
+ halcyon-install-0c985ba-halcyon-tutorial-1.0.tar.gz
Expected time: 5–10 seconds
In this step, Halcyon restores the tutorial app’s install directory by using an archive from public storage.
The right archive to restore is determined by calculating a source hash of the app’s source directory.
Your app is now ready to run:
$ which halcyon-tutorial
/app/bin/halcyon-tutorial
Options
Some Halcyon options, such as HALCYON_CONSTRAINTS
, can be specified by including a magic file in your app’s source directory. Command-line arguments take precedence over environment variables, which in turn take precedence over magic files.
Using magic files is the recommended way of specifing options, as it doesn’t require the user to perform any additional actions when installing the app.
Halcyon installs apps in the prefix directory, which defaults to /app
. You can change this with the HALCYON_PREFIX
option.
Run the app
The tutorial app exposes one HTTP endpoint, /notes
, which accepts GET
and POST
requests.
Notes are JSON objects with a single text field, contents
. The app responds to each request with a list of all existing notes.
Start your app in one shell:
$ halcyon-tutorial
In another shell, make a GET
request to see an empty list of notes:
$ curl http://localhost:8080/notes
[]
Make a couple POST
requests to add some notes:
$ curl -X POST http://localhost:8080/notes -d '{ "contents": "Hello, world!" }'
[{"contents":"Hello, world!"}]
$ curl -X POST http://localhost:8080/notes -d '{ "contents": "Hello?" }'
[{"contents":"Hello?"},{"contents":"Hello, world!"}]
Incoming notes are logged in the original shell:
$ halcyon-tutorial
Hello, world!
Hello?
Press control-C
to stop your app.
Options
By default, the tutorial app listens on port 8080. You can change this by setting the PORT
environment variable:
$ PORT=4040 halcyon-tutorial
Make a change
Let’s change the tutorial app so that each note can contain a timestamp.
The version of the app includes a new dateTime
field in each note.
Clone the app:
$ git clone -q https://github.com/mietek/halcyon-tutorial
$ cd halcyon-tutorial
Check out step2
, and install it with the Halcyon install
command:
$ git checkout -q step2
$ halcyon install
-----> Examining cache contents
halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
halcyon-ghc-7.8.4.tar.gz
halcyon-install-0c985ba-halcyon-tutorial-1.0.tar.gz
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **56bdea7**
External storage: **public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Determining constraints
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **56bdea7**
Constraints hash: **becfd1b**
Magic hash: **c7b5b77**
External storage: **public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Using existing GHC directory
-----> Using existing Cabal directory
-----> Restoring sandbox directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done, 140MB
-----> Restoring build directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-build-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 9.4MB
-----> Examining source changes
* Main.hs
-----> Building app
Building halcyon-tutorial-1.0...
Preprocessing executable 'halcyon-tutorial' for halcyon-tutorial-1.0...
[1 of 1] Compiling Main ( Main.hs, dist/build/halcyon-tutorial/halcyon-tutorial-tmp/Main.o )
Linking dist/build/halcyon-tutorial/halcyon-tutorial ...
-----> App built, 12MB
Stripping app... done, 9.4MB
-----> Archiving build directory
Creating halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 2.1MB
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Preparing install directory
-----> Installing extra data files for dependencies
-----> Install directory prepared, 8.8MB
-----> Archiving install directory
Creating halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz... done, 2.0MB
-----> Installing app to /app
-----> Installed halcyon-tutorial-1.0
-----> App installed: **halcyon-tutorial-1.0**
-----> Examining cache changes
+ halcyon-build-halcyon-tutorial-1.0.tar.gz
- halcyon-install-0c985ba-halcyon-tutorial-1.0.tar.gz
+ halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz
+ halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz
Expected time: 30–40 seconds
In this step, Halcyon tries to restore the tutorial app’s install directory by using an archive from public storage. This fails, and so Halcyon falls back to building the app:
First, the existing GHC and Cabal directories are reused, and the app’s sandbox directory is restored from public storage.
Next, Halcyon restores the app’s build directory from public storage, and performs an incremental build.
Finally, the app’s new install directory is prepared and archived, and the app is installed.
Halcyon determines which sandbox archive to restore by calculating a constraints hash of the version constraints declared by your app. Similarly, the right version of GHC to use is implied by the base
package constraint:
$ grep -E '^base-' .halcyon/constraints
base-4.7.0.2
Your app is now ready to run again:
$ halcyon-tutorial
$ curl -X POST http://localhost:8080/notes -d '{ "contents": "Hello, world!" }'
[{"contents":"Hello, world!","dateTime":""}]
Declare a dependency
Now, let’s change the tutorial app so that it remembers the time each note is added.
The version of the app declares the standard Haskell and libraries as dependencies:
$ git diff step2 step3 halcyon-tutorial.cabal
...
**@@ -14,9 +14,11 @@** executable halcyon-tutorial
ghc-options: -O2 -Wall -threaded
build-depends: base,
aeson,
**+ old-locale,**
servant,
servant-server,
stm,
text,
**+ time,**
transformers,
warp
Check out and install step3
:
$ git checkout -q step3
$ halcyon install
-----> Examining cache contents
halcyon-build-halcyon-tutorial-1.0.tar.gz
halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
halcyon-ghc-7.8.4.tar.gz
halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz
halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **1382694**
External storage: **public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Determining constraints
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **1382694**
Constraints hash: **becfd1b**
Magic hash: **c7b5b77**
External storage: **public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Using existing GHC directory
-----> Using existing Cabal directory
-----> Using existing sandbox directory
-----> Restoring build directory
Extracting halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 9.4MB
-----> Examining source changes
* Main.hs
* halcyon-tutorial.cabal
-----> Configuring app
-----> Building app
Building halcyon-tutorial-1.0...
Preprocessing executable 'halcyon-tutorial' for halcyon-tutorial-1.0...
[1 of 1] Compiling Main ( Main.hs, dist/build/halcyon-tutorial/halcyon-tutorial-tmp/Main.o )
Linking dist/build/halcyon-tutorial/halcyon-tutorial ...
-----> App built, 12MB
Stripping app... done, 9.4MB
-----> Archiving build directory
Creating halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 2.1MB
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Preparing install directory
-----> Installing extra data files for dependencies
-----> Install directory prepared, 8.8MB
-----> Archiving install directory
Creating halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz... done, 2.0MB
-----> Installing app to /app
-----> Installed halcyon-tutorial-1.0
-----> App installed: **halcyon-tutorial-1.0**
-----> Examining cache changes
* halcyon-build-halcyon-tutorial-1.0.tar.gz
- halcyon-install-56bdea7-halcyon-tutorial-1.0.tar.gz
+ halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz
Expected time: 20–25 seconds
In this step, Halcyon reuses the existing GHC, Cabal, and sandbox directories, performs an incremental build, and installs the app.
The previously-restored sandbox directory can be used again, because version constraints for our new dependencies are already declared:
$ grep -E '^(old-locale|time)' .halcyon/constraints
old-locale-1.0.0.6
time-1.4.2
Your app is now ready to run again:
$ halcyon-tutorial
$ curl -X POST http://localhost:8080/notes -d '{ "contents": "Hello, world!" }'
[{"contents":"Hello, world!","dateTime":"2015-01-15T09:21:29Z"}]
Declare a constraint
Let’s try to simplify the code by using a third-party library.
The version of the app replaces old-locale and time with the library:
$ git diff step3 step4 halcyon-tutorial.cabal
...
**@@ -14,11 +14,10 @@** executable halcyon-tutorial
ghc-options: -O2 -Wall -threaded
build-depends: base,
aeson,
**- old-locale,**
**+ hourglass,**
servant,
servant-server,
stm,
text,
**- time,**
transformers,
warp
In order for Halcyon to provide the right sandbox directory, we need to declare version constraints for hourglass and all of its dependencies. You can determine these constraints using Halcyon.
Check out step4
, and try installing it:
$ git checkout -q step4
$ halcyon install
-----> Examining cache contents
halcyon-build-halcyon-tutorial-1.0.tar.gz
halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
halcyon-ghc-7.8.4.tar.gz
halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz
halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **bf9e916**
External storage: **public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-bf9e916-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Determining constraints
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **bf9e916**
Constraints hash: **becfd1b**
Magic hash: **c7b5b77**
External storage: **public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Using existing GHC directory
-----> Using existing Cabal directory
-----> Using existing sandbox directory
** *** WARNING: Unexpected constraints difference**
@@ -38,6 +38,7 @@
free-4.10.0.1
ghc-prim-0.3.1.0
hashable-1.2.3.1
+hourglass-0.2.8
http-date-0.0.4
http-types-0.8.5
integer-gmp-0.5.1.0
-----> Restoring build directory
Extracting halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 9.4MB
-----> Examining source changes
* Main.hs
* halcyon-tutorial.cabal
-----> Configuring app
...
Could not resolve dependencies:
trying: halcyon-tutorial-1.0 (user goal)
next goal: hourglass (dependency of halcyon-tutorial-1.0)
Dependency tree exhaustively searched.
Configuring halcyon-tutorial-1.0...
cabal: At least the following dependencies are missing:
hourglass -any
** *** ERROR: Failed to configure app**
Expected time: 10–15 seconds
In this step, Cabal fails to configure the app, because the hourglass library isn’t provided in the existing sandbox directory. Halcyon suggests adding a single version constraint, hourglass-0.2.8
.
The version of the app declares this constraint:
$ git diff -U1 step4 step5 .halcyon/constraints
...
**@@ -40,2 +40,3 @@** ghc-prim-0.3.1.0
hashable-1.2.3.1
**+hourglass-0.2.8**
http-date-0.0.4
Build the sandbox
Halcyon always provides a sandbox directory matching the declared version constraints. If needed, the sandbox directory is built on-the-fly — either from scratch, or based on a previously-built sandbox.
Check out and install step5
:
$ git checkout -q step5
$ halcyon install
-----> Examining cache contents
halcyon-build-halcyon-tutorial-1.0.tar.gz
halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
halcyon-ghc-7.8.4.tar.gz
halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz
halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **b28289b**
External storage: **public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Determining constraints
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **b28289b**
Constraints hash: **3ad1ba3**
Magic hash: **c23e21c**
External storage: **public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Using existing GHC directory
-----> Using existing Cabal directory
-----> Restoring sandbox directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Locating sandbox directories
Listing https://halcyon.global.ssl.fastly.net/... done
-----> Examining partially matching sandbox directories
...
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.constraints... done
-----> Scoring partially matching sandbox directories
Ignoring hello-miku-1.0 (3c81d66) as HUnit-1.2.5.2 is not needed
Ignoring hello-snap-1.0 (4af96d8) as HUnit-1.2.5.2 is not needed
Ignoring hello-wheb-1.0 (4c4bfdc) as SHA-1.6.4.1 is not needed
41 hello-wai-1.0 (028a0e6)
Ignoring hello-scotty-1.0 (33c011e) as data-default-0.5.3 is not needed
Ignoring hello-happstack-1.0 (47c3e8d) as base-unicode-symbols-0.2.2.4 is not needed
Ignoring hello-spock-1.0 (0331829) as QuickCheck-2.7.6 is not needed
101 halcyon-tutorial-1.0 (becfd1b)
Ignoring hello-yesod-1.0 (dac4ebf) as asn1-encoding-0.9.0 is not needed
-----> Using partially matching sandbox directory: halcyon-tutorial-1.0 (becfd1b)
-----> Restoring sandbox directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done, 140MB
-----> Building sandbox directory
-----> Building sandbox
Resolving dependencies...
Notice: installing into a sandbox located at /app/sandbox
Downloading hourglass-0.2.8...
Configuring hourglass-0.2.8...
Building hourglass-0.2.8...
Installed hourglass-0.2.8
-----> Sandbox built, 144MB
Removing documentation from sandbox directory... done, 144MB
Stripping sandbox directory... done, 143MB
-----> Archiving sandbox directory
Creating halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... done, 24MB
-----> Restoring build directory
Extracting halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 9.4MB
-----> Examining source changes
* .halcyon/constraints
* Main.hs
* cabal.config
* halcyon-tutorial.cabal
-----> Configuring app
-----> Building app
Building halcyon-tutorial-1.0...
Preprocessing executable 'halcyon-tutorial' for halcyon-tutorial-1.0...
[1 of 1] Compiling Main ( Main.hs, dist/build/halcyon-tutorial/halcyon-tutorial-tmp/Main.o )
Linking dist/build/halcyon-tutorial/halcyon-tutorial ...
-----> App built, 13MB
Stripping app... done, 9.8MB
-----> Archiving build directory
Creating halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 2.2MB
-----> Restoring install directory
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Preparing install directory
-----> Installing extra data files for dependencies
-----> Install directory prepared, 9.1MB
-----> Archiving install directory
Creating halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... done, 2.0MB
-----> Installing app to /app
-----> Installed halcyon-tutorial-1.0
-----> App installed: **halcyon-tutorial-1.0**
-----> Examining cache changes
* halcyon-build-halcyon-tutorial-1.0.tar.gz
- halcyon-install-1382694-halcyon-tutorial-1.0.tar.gz
+ halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz
+ halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz
Expected time: 60–90 seconds
In this step, Halcyon reuses the existing GHC and Cabal directories, and tries to locate the right sandbox directory for the current version of the app. This fails, and so Halcyon falls back to building the sandbox:
First, previously-built sandbox directories are located and assigned a score, which reflects the number of required dependencies within each sandbox.
Next, Halcyon builds and archives a new sandbox, based on the highest-scoring partially-matching sandbox directory.
Finally, an incremental build is performed, and the app is installed.
Your app is now ready to run again:
$ halcyon-tutorial
$ curl -X POST http://localhost:8080/notes -d '{ "contents": "Hello, world!" }'
[{"contents":"Hello, world!","dateTime":"2015-01-15T09:28:26+00:00"}]
Set up private storage
Halcyon can use private storage as well as public storage. Private storage is an external cache for the apps and dependencies you build.
By using private storage, you can share archives between multiple machines, and avoid running into resource limits on your installation targets.
To use private storage, you’ll need to:
Sign up for an account
Create an and an
Give the IAM user the S3 bucket
Once you’re done, configure private storage by setting HALCYON_AWS_ACCESS_KEY_ID
, HALCYON_AWS_SECRET_ACCESS_KEY
, and HALCYON_S3_BUCKET
:
$ export HALCYON_AWS_ACCESS_KEY_ID=example-access-key-id
$ export HALCYON_AWS_SECRET_ACCESS_KEY=example-secret-access-key
$ export HALCYON_S3_BUCKET=example-bucket
If your S3 bucket isn’t located in the Amazon US Standard region, set HALCYON_S3_ENDPOINT
to the address of the right :
$ export HALCYON_S3_ENDPOINT=s3-example-region.amazonaws.com
Options
By default, all uploads are assigned the private
. To make newly-uploaded files available to the public, set HALCYON_S3_ACL
to public-read
:
$ export HALCYON_S3_ACL=public-read
Use private storage
Let’s force Halcyon to build the sandbox directory again, in order to populate your private storage.
Remove the existing GHC, Cabal, and sandbox directories:
$ rm -rf /app/ghc /app/cabal /app/sandbox
Install the app again, using the HALCYON_PURGE_CACHE
option to empty the cache directory before building:
$ halcyon install --purge-cache
-----> Purging cache
-----> Installing halcyon-tutorial-1.0
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **b28289b**
External storage: **private and public**
GHC version: **7.8.4**
-----> Restoring install directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Determining constraints
Label: **halcyon-tutorial-1.0**
Prefix: **/app**
Source hash: **b28289b**
Constraints hash: **3ad1ba3**
Magic hash: **c23e21c**
External storage: **private and public**
GHC version: **7.8.4**
Cabal version: **1.20.0.3**
Cabal repository: **Hackage**
-----> Restoring GHC directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/halcyon-ghc-7.8.4.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/halcyon-ghc-7.8.4.tar.gz... done
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/halcyon-ghc-7.8.4.tar.gz... done
Extracting halcyon-ghc-7.8.4.tar.gz... done, 701MB
-----> Locating Cabal directories
Listing s3://example-bucket/?prefix=linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-... done
Listing https://halcyon.global.ssl.fastly.net/... done
-----> Restoring Cabal directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... done
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... done
Extracting halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz... done, 181MB
-----> Restoring sandbox directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Locating sandbox directories
Listing s3://example-bucket/?prefix=linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-... done
Listing https://halcyon.global.ssl.fastly.net/... done
-----> Examining partially matching sandbox directories
...
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.constraints... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.constraints... done
-----> Scoring partially matching sandbox directories
Ignoring hello-snap-1.0 (4af96d8) as HUnit-1.2.5.2 is not needed
41 hello-wai-1.0 (028a0e6)
Ignoring hello-happstack-1.0 (47c3e8d) as base-unicode-symbols-0.2.2.4 is not needed
101 halcyon-tutorial-1.0 (becfd1b)
Ignoring hello-yesod-1.0 (dac4ebf) as asn1-encoding-0.9.0 is not needed
-----> Using partially matching sandbox directory: halcyon-tutorial-1.0 (becfd1b)
-----> Restoring sandbox directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz... done, 140MB
-----> Building sandbox directory
-----> Building sandbox
Resolving dependencies...
Notice: installing into a sandbox located at /app/sandbox
Downloading hourglass-0.2.8...
Configuring hourglass-0.2.8...
Building hourglass-0.2.8...
Installed hourglass-0.2.8
-----> Sandbox built, 144MB
Removing documentation from sandbox directory... done, 144MB
Stripping sandbox directory... done, 143MB
-----> Archiving sandbox directory
Creating halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... done, 24MB
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz... done
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.constraints... done
Listing s3://example-bucket/?prefix=linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-... done
-----> Restoring build directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-build-halcyon-tutorial-1.0.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-build-halcyon-tutorial-1.0.tar.gz... done
Extracting halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 9.4MB
-----> Examining source changes
* .halcyon/constraints
* Main.hs
* cabal.config
* halcyon-tutorial.cabal
-----> Configuring app
-----> Building app
Building halcyon-tutorial-1.0...
Preprocessing executable 'halcyon-tutorial' for halcyon-tutorial-1.0...
[1 of 1] Compiling Main ( Main.hs, dist/build/halcyon-tutorial/halcyon-tutorial-tmp/Main.o )
Linking dist/build/halcyon-tutorial/halcyon-tutorial ...
-----> App built, 13MB
Stripping app... done, 9.8MB
-----> Archiving build directory
Creating halcyon-build-halcyon-tutorial-1.0.tar.gz... done, 2.2MB
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-build-halcyon-tutorial-1.0.tar.gz... done
-----> Restoring install directory
Downloading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
Downloading https://halcyon.global.ssl.fastly.net/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... 404 (not found)
-----> Preparing install directory
-----> Installing extra data files for dependencies
-----> Install directory prepared, 9.1MB
-----> Archiving install directory
Creating halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... done, 2.0MB
Uploading s3://example-bucket/linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz... done
Listing s3://example-bucket/?prefix=linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-... done
-----> Installing app to /app
-----> Installed halcyon-tutorial-1.0
-----> App installed: **halcyon-tutorial-1.0**
-----> Examining cache changes
+ halcyon-build-halcyon-tutorial-1.0.tar.gz
+ halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
+ halcyon-ghc-7.8.4.tar.gz
+ halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz
+ halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz
+ halcyon-sandbox-becfd1b-halcyon-tutorial-1.0.tar.gz
In this step, Halcyon restores the GHC and Cabal directories from public storage, builds and archives a sandbox based on a partially-matching sandbox directory, performs an incremental build, and installs the app again.
All downloaded and newly-created archives are uploaded to your private storage:
$ s3_list example-bucket linux-ubuntu-14
Listing s3://example-bucket/?prefix=linux-ubuntu-14... done
linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-build-halcyon-tutorial-1.0.tar.gz
linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-install-b28289b-halcyon-tutorial-1.0.tar.gz
linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.constraints
linux-ubuntu-14.04-x86_64/ghc-7.8.4/halcyon-sandbox-3ad1ba3-halcyon-tutorial-1.0.tar.gz
linux-ubuntu-14.04-x86_64/halcyon-cabal-1.20.0.3-hackage-2015-01-15.tar.gz
linux-ubuntu-14.04-x86_64/halcyon-ghc-7.8.4.tar.gz
Options
If you want to avoid downloading any archives from public storage, set HALCYON_NO_PUBLIC_STORAGE
to 1
before populating your private storage.
Next steps
You now know how to use Halcyon to develop Haskell apps. You have also developed a simple Haskell web service.
See the Halcyon reference for a complete list of available commands and options.
Read the to learn how to deploy Haskell web apps to .