README.md

# Castle

Hot-code upgrade support for Elixir Releases.

`Castle` provides build and runtime support for the generation of releases that correctly support hot-code upgrades. This includes:

  - Generation of runtime configuration into 
    [sys.config](https://www.erlang.org/doc/man/config.html#sys.config) prior to
    system boot.
  - Creation of the [RELEASES](https://www.erlang.org/doc/man/release_handler.html#description)
    file on first boot.
  - Support for [appup](https://www.erlang.org/doc/man/appup.html) and 
    [relup](https://www.erlang.org/doc/man/relup.html) files.
  - Shell-script support for managing upgrades.


## Installation

The package can be installed by adding `castle` to your list of dependencies in
`mix.exs`:

```elixir
def deps do
  [
    {:castle, "~> 0.2.0"}
  ]
end
```

## Integration

`Castle` integrates into the steps of the release assembly process. It requires
that the `Castle.pre_assemble/1` and `Castle.post_assemble/1` functions are
placed around the `:assemble` step, e.g.:

```elixir
defp releases do
  [
    myapp: [
      include_executables_for: [:unix],
      steps: [&Castle.pre_assemble/1, :assemble, &Castle.post_assemble/1, :tar]
    ]
  ]
end
```

## Build Time Support

The following steps shape the release at build-time:

### Pre-assembly

In the pre-assembly step:

  - The default evaluation of runtime configuration is disabled. `Castle` will
    do its own equivalent expansion into `sys.config` prior to system start,
    first with `runtime.exs` (if it exists) and then with any Config Providers.
  - A 'preboot' boot script is created that starts only `Castle` and its
    dependencies. This is used only during the aforementioned expansion.

The system is then assembled under the `:assemble` step as normal.

### Post-assembly

In the post-assembly step:

  - The `sys.config` generated from build-time configuration is copied to 
    `build.config`.
  - The shell-script in the `bin` folder is renamed from _name_ to _.name_, and
    a new script called _name_ is created in its place. This new script will
    ensure that the `sys.config` is correctly generated before the system is 
    started.
  - Any `runtime.exs` is copied into the version path of the release.
  - The generated _name.rel_ is copied into the `releases` folder as _name-vsn.rel_.
  - Any `relup` file is copied into the version path of the release.

## Runtime Support

At runtime, the script in the `bin` folder will intercept any calls to `start`,
`start_iex`, `daemon` and `daemon_iex` and bring up an ephemeral node to generate
`sys.config` by merging `build.config` with the results of evaluating `runtime.exs`
and any Config Providers.

Additionally, this ephemeral node will create the `RELEASES` file if it does not
already exist.

## Release Management

The script in the `bin` folder supports some extra commands to manage upgrades.
Releases, in their tarred-gzipped form, should first be copied to the `releases`
subfolder on the target system. The following commands can be used to manage
them:

  - `releases` - Lists the releases on the system and their status. Status can
    be one of the following:
    - permanent - the release the system will boot into on next restart.
    - current - if it exists, represents the current running release. Will be
      different from the permanent version if a new release has been installed
      but not yet committed. If no version is listed as current, the permanent
      version is the currently running version.
    - old - if it exists, a previously installed version.
    - unpacked - an unpacked version, but not yet installed.
  - `unpack <vsn>` - Unpacks the release called `<name>-<vsn>.tar.gz`.
  - `install <vsn>` - Installs the new release. This makes the release the
    current one, but not yet the permanent one. Prior to running the relup,
    `Castle` generates the version specific `sys.config` for the new version.
  - `commit <vsn>` - Makes the specified release the one the permanent one.
  - `remove <vsn>` - Remove an old version from the filesystem. Any files
    shared with remaining releases are left untouched.

## The Appup Compiler

You are responsible for writing the [appup](https://www.erlang.org/doc/man/appup.html)
scripts for your application, but `Castle` will copy the appup into the `ebin` folder
for you. The steps are as follows:

1. Write a file, in _Elixir form_, describing the application upgrade. e.g.:
   ```elixir
   # You can call the file what you like, e.g. appup.ex, 
   # but you should # keep it away from the compiler paths.
   {
    '0.1.1',
     [
      {'0.1.0', [
        {:update, MyApp.Server, {:advanced, []}}
      ]}
     ],
     [
      {'0.1.0', [
        {:update, MyApp.Server, {:advanced, []}}
      ]}
     ]
   }
   ```
   This file will typically be checked in to SCM.
2. Add the appup file to the Mix project definition in mix.exs and add the
   `:appup` compiler.
   ```elixir
   # Mix.exs
   def project do
     [
       appup: "appup.ex", # Relative to the project root.
       compilers: Mix.compilers() ++ [:appup]
     ]
   end
   ```
   
## Relup Generation

Castle contains a mix task, `castle.relup`, that simplifies the generation of
the relup file. Assuming you have two _unpacked_ releases e.g. `0.1.0` and `0.1.1` 
and you wish to generate a relup between them:

```shell
> mix castle.relup --target myapp/releases/0.1.1/myapp --fromto myapp/releases/0.1.0/myapp
```

If the generated file is in the project root, it will be copied during 
post-assembly to the release.