Skip to content

Commit c408acd

Browse files
committed
feat: Parametrize iana database download_url
1 parent 830f445 commit c408acd

11 files changed

Lines changed: 184 additions & 75 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ erl_crash.dump
44
*.ez
55
/doc
66
/priv/latest_remote_poll.txt
7+
/priv/tmp_downloads

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.2.0

config/config.exs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# This file is responsible for configuring your application
22
# and its dependencies with the aid of the Mix.Config module.
3-
use Mix.Config
3+
import Config
44

55
config :logger, utc_log: true
66
config :tzdata, :autoupdate, :enabled
7+
8+
config :tzdata, download_url: "https://data.iana.org/time-zones/tzdata-latest.tar.gz"
79
# config :tzdata, :data_dir, "/etc/elixir_tzdata_storage"

lib/tzdata/data_loader.ex

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@ defmodule Tzdata.DataLoader do
55
# Can poll for newest version of tz data and can download
66
# and extract it.
77
@download_url "https://data.iana.org/time-zones/tzdata-latest.tar.gz"
8-
def download_new(url \\ @download_url) do
8+
9+
def download_url do
10+
Application.fetch_env!(:tzdata, :download_url)
11+
end
12+
13+
def download_new do
14+
download_new(download_url())
15+
end
16+
17+
def download_new(url) do
918
Logger.debug("Tzdata downloading new data from #{url}")
1019
set_latest_remote_poll_date()
1120
{:ok, {200, headers, body}} = http_client().get(url, [], follow_redirect: true)
@@ -39,7 +48,11 @@ defmodule Tzdata.DataLoader do
3948
only_line_in_file |> String.replace(~r/\s/, "")
4049
end
4150

42-
def last_modified_of_latest_available(url \\ @download_url) do
51+
def last_modified_of_latest_available do
52+
last_modified_of_latest_available(download_url())
53+
end
54+
55+
def last_modified_of_latest_available(url) do
4356
set_latest_remote_poll_date()
4457

4558
case http_client().head(url, [], []) do
@@ -51,7 +64,11 @@ defmodule Tzdata.DataLoader do
5164
end
5265
end
5366

54-
def latest_file_size(url \\ @download_url) do
67+
def latest_file_size do
68+
latest_file_size(download_url())
69+
end
70+
71+
def latest_file_size(url) do
5572
set_latest_remote_poll_date()
5673

5774
case latest_file_size_by_head(url) do

lib/tzdata/period_builder.ex

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,17 @@ defmodule Tzdata.PeriodBuilder do
9797
def h_calc_next_zone_line(_btz_data, period, _, zone_line_tl, _) when zone_line_tl == [] do
9898
case period do
9999
nil -> []
100-
_ -> [ period ]
100+
_ -> [period]
101101
end
102102
end
103103

104104
# If there is a zone line tail, we recursively add to the list of periods with that zone line tail
105105
def h_calc_next_zone_line(btz_data, period, until_utc, zone_line_tl, letter) do
106106
tail = calc_periods(btz_data, zone_line_tl, until_utc, hd(zone_line_tl).rules, letter)
107+
107108
case period do
108109
nil -> tail
109-
_ -> [ period | tail ]
110+
_ -> [period | tail]
110111
end
111112
end
112113

@@ -194,8 +195,12 @@ defmodule Tzdata.PeriodBuilder do
194195
letter
195196
) do
196197
until_utc = datetime_to_utc(Map.get(zone_line, :until), utc_off, std_off)
197-
tail = calc_periods(btz_data, zone_line_tl, until_utc, Map.get(hd(zone_line_tl), :rules), letter)
198-
if from == until_utc do # empty period may happen when 'until' of zone line coincides with end of rule
198+
199+
tail =
200+
calc_periods(btz_data, zone_line_tl, until_utc, Map.get(hd(zone_line_tl), :rules), letter)
201+
202+
# empty period may happen when 'until' of zone line coincides with end of rule
203+
if from == until_utc do
199204
tail
200205
else
201206
from_standard_time = standard_time_from_utc(from, utc_off)
@@ -211,7 +216,7 @@ defmodule Tzdata.PeriodBuilder do
211216
zone_abbr: TzUtil.period_abbrevation(zone_line.format, std_off, letter)
212217
}
213218

214-
[ period | tail ]
219+
[period | tail]
215220
end
216221
end
217222

@@ -286,9 +291,14 @@ defmodule Tzdata.PeriodBuilder do
286291

287292
until_utc = datetime_to_utc(TzUtil.time_for_rule(rule, year), utc_off, std_off)
288293
# truncate end of period to within time range of zone line
289-
until_before_lower_limit = is_integer(lower_limit) && is_integer(until_utc) && lower_limit > until_utc
294+
until_before_lower_limit =
295+
is_integer(lower_limit) && is_integer(until_utc) && lower_limit > until_utc
296+
290297
until_utc = if until_before_lower_limit, do: lower_limit, else: until_utc
291-
last_included_rule = is_integer(upper_limit) && is_integer(until_utc) && upper_limit <= until_utc
298+
299+
last_included_rule =
300+
is_integer(upper_limit) && is_integer(until_utc) && upper_limit <= until_utc
301+
292302
until_utc = if last_included_rule, do: upper_limit, else: until_utc
293303
# derive standard and wall time for 'until'
294304
until_standard_time = standard_time_from_utc(until_utc, utc_off)
@@ -313,38 +323,41 @@ defmodule Tzdata.PeriodBuilder do
313323

314324
# If we've hit the upper time boundary of this zone line, we do not need to examine any more
315325
# rules for this rule set OR there are no more years to consider for this rule set
316-
if last_included_rule || no_more_years && no_more_rules do
326+
if last_included_rule || (no_more_years && no_more_rules) do
317327
h_calc_next_zone_line(btz_data, period, until_utc, zone_line_tl, letter)
318328
else
319-
tail = cond do
320-
# If there are no more rules for the year, continue with the next year
321-
no_more_rules ->
322-
calc_rule_periods(
323-
btz_data,
324-
[zone_line | zone_line_tl],
325-
until_utc,
326-
utc_off,
327-
rule.save,
328-
years |> tl,
329-
zone_rules,
330-
rule.letter
331-
)
332-
# Else continue with those rules
333-
true ->
334-
calc_periods_for_year(
335-
btz_data,
336-
[zone_line | zone_line_tl],
337-
until_utc,
338-
utc_off,
339-
rule.save,
340-
years,
341-
zone_rules,
342-
rules_tail,
343-
rule.letter,
344-
lower_limit
345-
)
346-
end
347-
if period == nil, do: tail, else: [ period | tail ]
329+
tail =
330+
cond do
331+
# If there are no more rules for the year, continue with the next year
332+
no_more_rules ->
333+
calc_rule_periods(
334+
btz_data,
335+
[zone_line | zone_line_tl],
336+
until_utc,
337+
utc_off,
338+
rule.save,
339+
years |> tl,
340+
zone_rules,
341+
rule.letter
342+
)
343+
344+
# Else continue with those rules
345+
true ->
346+
calc_periods_for_year(
347+
btz_data,
348+
[zone_line | zone_line_tl],
349+
until_utc,
350+
utc_off,
351+
rule.save,
352+
years,
353+
zone_rules,
354+
rules_tail,
355+
rule.letter,
356+
lower_limit
357+
)
358+
end
359+
360+
if period == nil, do: tail, else: [period | tail]
348361
end
349362
end
350363

@@ -353,9 +366,9 @@ defmodule Tzdata.PeriodBuilder do
353366
def sort_rules_by_time(rules, year) do
354367
# n.b., we can have many rules per month - such as time changes for religious festivals
355368
rules
356-
|> Enum.map(&({&1, TzUtil.tz_day_to_date(year, &1.in, &1.on)}))
369+
|> Enum.map(&{&1, TzUtil.tz_day_to_date(year, &1.in, &1.on)})
357370
|> Enum.sort(&(elem(&1, 1) < elem(&2, 1)))
358-
|> Enum.map(&(elem(&1, 0)))
371+
|> Enum.map(&elem(&1, 0))
359372
end
360373

361374
@doc """

mix.exs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
defmodule Tzdata.Mixfile do
22
use Mix.Project
33

4-
@version "1.1.1"
5-
64
def project do
75
[
86
app: :tzdata,
97
name: "tzdata",
10-
version: @version,
8+
version: version(),
119
elixir: "~> 1.8",
1210
package: package(),
1311
description: description(),
@@ -28,15 +26,16 @@ defmodule Tzdata.Mixfile do
2826
defp deps do
2927
[
3028
{:hackney, "~> 1.17"},
31-
{:ex_doc, "~> 0.21", only: :dev, runtime: false}
29+
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
30+
{:mox, "~> 1.2", only: :test}
3231
]
3332
end
3433

3534
defp docs do
3635
[
3736
main: "readme",
38-
extras: ["README.md"],
39-
source_ref: "v#{@version}"
37+
extras: ["README.md", "VERSION"],
38+
source_ref: "v#{version()}"
4039
]
4140
end
4241

@@ -63,4 +62,10 @@ defmodule Tzdata.Mixfile do
6362
CHANGELOG*)
6463
}
6564
end
65+
66+
defp version do
67+
"./VERSION"
68+
|> File.read!()
69+
|> String.trim()
70+
end
6671
end

mix.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
"makeup_elixir": {:hex, :makeup_elixir, "0.15.0", "98312c9f0d3730fde4049985a1105da5155bfe5c11e47bdc7406d88e01e4219b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "75ffa34ab1056b7e24844c90bfc62aaf6f3a37a15faa76b07bc5eba27e4a8b4a"},
99
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
1010
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
11+
"mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
12+
"nimble_ownership": {:hex, :nimble_ownership, "1.0.0", "3f87744d42c21b2042a0aa1d48c83c77e6dd9dd357e425a038dd4b49ba8b79a1", [:mix], [], "hexpm", "7c16cc74f4e952464220a73055b557a273e8b1b7ace8489ec9d86e9ad56cb2cc"},
1113
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
1214
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
1315
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},

test/data_loader_test.exs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
defmodule Tzdata.DataLoaderTest do
2+
use ExUnit.Case, async: false
3+
alias Tzdata.HTTPClient.Mock
4+
doctest Tzdata.DataLoader
5+
import Mox
6+
7+
setup :verify_on_exit!
8+
9+
setup do
10+
client = Application.get_env(:tzdata, :http_client)
11+
Application.put_env(:tzdata, :http_client, Tzdata.HTTPClient.Mock)
12+
13+
Application.put_env(
14+
:tzdata,
15+
:download_url,
16+
"https://data.iana.org/time-zones/tzdata-latest.tar.gz"
17+
)
18+
19+
on_exit(fn ->
20+
Application.put_env(:tzdata, :http_client, client)
21+
:ok
22+
end)
23+
end
24+
25+
describe "download_new/1" do
26+
test "when url not given, should download content from default url" do
27+
expect(Mock, :get, fn "https://data.iana.org/time-zones/tzdata-latest.tar.gz",
28+
_,
29+
[follow_redirect: true] ->
30+
{:ok,
31+
{200, [{"Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT"}],
32+
File.read!("test/tzdata_fixtures/tzdata2024a.tar.gz")}}
33+
end)
34+
35+
assert {:ok, 451_270, "2024a", _new_dir_name, "Wed, 21 Oct 2015 07:28:00 GMT"} =
36+
Tzdata.DataLoader.download_new()
37+
end
38+
39+
test "when url given, should download content from given url" do
40+
expect(Mock, :get, fn "https://data.iana.org/time-zones/tzdata2024a.tar.gz", _, _ ->
41+
{:ok,
42+
{200, [{"Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT"}],
43+
File.read!("test/tzdata_fixtures/tzdata2024a.tar.gz")}}
44+
end)
45+
46+
assert {:ok, 451_270, "2024a", _new_dir_name, "Wed, 21 Oct 2015 07:28:00 GMT"} =
47+
Tzdata.DataLoader.download_new(
48+
"https://data.iana.org/time-zones/tzdata2024a.tar.gz"
49+
)
50+
end
51+
end
52+
end

test/test_helper.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
ExUnit.start()
2+
3+
Mox.defmock(Tzdata.HTTPClient.Mock, for: Tzdata.HTTPClient)

0 commit comments

Comments
 (0)