# Forecastle
Build-time support for hot-code upgrades.
`Forecastle` provides build-time support for the generation of releases that correctly support hot-code 
upgrades. This includes:
  - Copying appup and relup files into place.
  - Organising the generated release structure so that it's ready for hot-code upgrades.
  - Replacing the shell script with one that supports release unpacking and installtion
Additionally, `Forecastle` ships with a appup compiler and a mix task for relup generation.
## Installation
`Forecastle` is not intended to be taken as a direct dependency.  Most applications should prefer to
take a dependency on [Castle](https://hexdocs.pm/castle/readme.html) directly which will, in turn 
take a build-time dependency on `Forecastle`.
For projects that don't define a release, but use the `appup` compiler, it's sufficient to 
bring `Castle` in as a build-time dependency:
```elixir
def deps do
  [
    {:castle, "~> 0.3.0", runtime: false}
  ]
end
```
For projects that _do_ define one or more releases, `Castle` should be brought in
as a runtime dependency:
```elixir
def deps do
  [
    {:castle, "~> 0.3.0"}
  ]
end
```
## Integration
`Forecastle` integrates into the steps of the release assembly process. It requires
that the `Forecastle.pre_assemble/1` and `Forecastle.post_assemble/1` functions are
placed around the `:assemble` step, e.g.:
```elixir
defp releases do
  [
    myapp: [
      include_executables_for: [:unix],
      steps: [&Forecastle.pre_assemble/1, :assemble, &Forecastle.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. `Forecastle` 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 `Forecastle` 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 replaced with one that provides
    additional commands to manage releases.
  - 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.
## The Appup Compiler
You are responsible for writing the [appup](https://www.erlang.org/doc/man/appup.html)
scripts for your application, but `Forecastle` 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.exs,
   {
    '0.1.1', # Code is eval'd so can also: to_charlist(Mix.Project.config[:version]),
     [
      {'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.exs", # Relative to the project root.
       compilers: Mix.compilers() ++ [:appup]
     ]
   end
   ```
   
## Relup Generation
Forecastle contains a mix task, `forecastle.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 forecastle.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.