Tempo.Holidays.Build (Tempo.Holidays v0.1.0)

Copy Markdown View Source

Build-time generation of the compiled holiday data.

Downloads a pinned date-holidays bundle and compiles every territory to one nested priv/holidays/<CC>.etf — the country's holidays plus each state's and region's own holidays and the rule keys they override, which Tempo.Holidays.Data merges at load time (so the country's holidays are not duplicated into every state). The version is pinned exactly (not a range), so a build is reproducible: the same input yields the same output, and the data need not be vendored in git.

ensure_built/0 runs from the :holidays Mix compiler and is a no-op once the current pinned data is in place, in the current data format — so warm builds, and every consumer build (where the etf ships in the package), do no network I/O, while a change to the serialised structs regenerates it. build/1 forces a fresh download and is what mix tempo.holidays.update runs.

Each rule is read with Tempo.DateRule as it is built, to leave out one it does not read, and reading a rule can work out a date: an equinox needs Astro's ephemeris, and a date of another calendar needs Calendrical. So build/1 starts Tempo's applications (:ex_tempo, which starts Astro before Calendrical) before it reads, as the :holidays compiler runs before anything is started.

This module is Mix-only: it runs at the maintainer's build time, never at a consumer's runtime.

Summary

Types

Why the data could not be built: a version that is not three numbers, a directory that could not be made, a bundle that could not be downloaded, or an application that could not be started.

Functions

Downloads a date-holidays release's bundle of holiday data and writes every territory's data from it, whatever is already on disk.

The directory the package's own data is written to: its priv/holidays.

Builds the package's own data unless it is already built from the pinned release, as the :holidays compiler asks at each compilation.

Compile one territory's holidays from an already-decoded bundle.

An error build/1 returns, in words.

The date-holidays release the package's own data is built from.

The URL of the bundle of holiday data of the pinned date-holidays release.

The URL of the bundle of holiday data of a date-holidays release.

Types

error()

@type error() ::
  {:invalid_version, term()}
  | {:directory, Path.t(), File.posix()}
  | {:download_failed, String.t(), term()}
  | {atom(), term()}

Why the data could not be built: a version that is not three numbers, a directory that could not be made, a bundle that could not be downloaded, or an application that could not be started.

Functions

build(options \\ [])

@spec build(keyword()) :: {:ok, non_neg_integer(), [String.t()]} | {:error, error()}

Downloads a date-holidays release's bundle of holiday data and writes every territory's data from it, whatever is already on disk.

Arguments

  • options is a keyword list of options.

Options

  • :version is the date-holidays release, three numbers such as "3.38.0". The default is pinned_version/0.

  • :directory is where the data is written. The default is default_directory/0.

  • :language is the ISO 639-1 code of the holidays' names. The default is "en".

Returns

  • {:ok, territory_count, unsupported}, where unsupported lists the rules of the release Tempo.DateRule does not read, whose holidays are left out of the data, or

  • {:error, reason}: {:invalid_version, version}, {:directory, directory, posix}, {:download_failed, url, reason}, or an application that cannot be started. message/1 says each in words.

default_directory()

@spec default_directory() :: String.t()

The directory the package's own data is written to: its priv/holidays.

Returns

  • The directory, a path.

Examples

iex> Path.basename(Tempo.Holidays.Build.default_directory())
"holidays"

ensure_built()

@spec ensure_built() :: :noop | :ok | {:error, error()}

Builds the package's own data unless it is already built from the pinned release, as the :holidays compiler asks at each compilation.

Returns

  • :noop where the data is in place: on a warm build, and on every build of an application where the data ships in the package, so neither touches the network, or

  • :ok where it was built, or

  • {:error, reason} as build/1 returns it.

holidays_from_bundle(bundle, code, language)

@spec holidays_from_bundle(map(), String.t(), String.t()) :: [
  Tempo.Holidays.Holiday.t()
]

Compile one territory's holidays from an already-decoded bundle.

Pure — no network or filesystem — so the compile step is testable on its own. Returns [] for a territory the bundle does not carry.

Arguments

  • bundle is the decoded holidays.json map.

  • code is the territory's CLDR/IANA code as a string, such as "US".

  • language is the ISO 639-1 code for name selection.

Returns

message(reason)

@spec message(error()) :: String.t()

An error build/1 returns, in words.

Arguments

Returns

  • The message, a string.

Examples

iex> Tempo.Holidays.Build.message({:directory, "/x", :enotdir})
"could not make /x: not a directory"

pinned_version()

@spec pinned_version() :: String.t()

The date-holidays release the package's own data is built from.

Returns

  • The release, a version string.

Examples

iex> Tempo.Holidays.Build.pinned_version()
"3.38.0"

source_url()

@spec source_url() :: String.t()

The URL of the bundle of holiday data of the pinned date-holidays release.

Returns

  • The URL, a string.

Examples

iex> Tempo.Holidays.Build.source_url()
"https://cdn.jsdelivr.net/npm/date-holidays@3.38.0/data/holidays.json"

source_url(version)

@spec source_url(String.t()) :: String.t()

The URL of the bundle of holiday data of a date-holidays release.

Arguments

  • version is a date-holidays release, such as "3.37.0".

Returns

  • The URL, a string.

Examples

iex> Tempo.Holidays.Build.source_url("3.37.0")
"https://cdn.jsdelivr.net/npm/date-holidays@3.37.0/data/holidays.json"