Merge remote-tracking branch 'canonical/next'
[sinan.git] / src / sin_file_info.erl
blob55bc032e74194b676b7a57f84b84c957968d5115
1 %% -*- mode: Erlang; fill-column: 80; comment-column: 75; -*-
2 %%%---------------------------------------------------------------------------
3 %%% @copyright Erlware, LLC
4 %%% @author Eric Merritt <ericbmerritt@gmail.com>
5 %%% @author Anders Nygren <anders.nygren@gmail.com>
6 %%% @doc Parse an erlang file (yrl, hrl, erl) and information about the file
7 %%% that is relevant to the build system
8 %%% @end
9 %%%-------------------------------------------------------------------
10 -module(sin_file_info).
12 %% API
13 -export([file_regex/0, process_file/3, initialize/2]).
14 -export_type([date/0, time/0, date_time/0, mod/0]).
16 -include_lib("sinan/include/sinan.hrl").
17 -include_lib("kernel/include/file.hrl").
20 %%====================================================================
21 %% Types
22 %%====================================================================
23 -type date() :: {Year :: non_neg_integer(),
24 Month :: non_neg_integer(),
25 Day :: non_neg_integer()}.
27 -type time() :: {Hour :: non_neg_integer(),
28 Minute :: non_neg_integer(),
29 Second :: non_neg_integer()}.
31 -type date_time() :: {date() , time()}.
32 -type mod() :: record(module).
34 -type type() :: hrl | erl | yrl | jxa | {other, string()}.
36 %%====================================================================
37 %% API
38 %%====================================================================
39 file_regex() ->
40 "^((.+\.erl)|(.+\.hrl)|(.+\.yrl)|(.+\.jxa))$".
42 -spec process_file(sin_state:state(), string(), [string()]) ->
43 sinan:mod().
44 process_file(State0, Path0, Includes) ->
45 sin_sig:do_if_changed(?MODULE,
46 Path0,
47 fun deps_changed/2,
48 fun(Path1, State1) ->
49 do_extract(State1, Path1, Includes)
50 end, State0).
52 -spec initialize(string(), type()) ->
53 sin_file_info:mod().
54 initialize(Path, Type) ->
55 #module{type=Type,
56 path=Path,
57 module_deps=sets:new(),
58 includes=sets:new(),
59 tags=sets:new(),
60 include_timestamps=[],
61 called_modules=sets:new()}.
64 %%====================================================================
65 %% Internal Functions
66 %%====================================================================
67 -spec deps_changed(mod(), sin_state:state()) -> boolean().
68 deps_changed(#module{include_timestamps=Includes}, State) ->
69 lists:any(fun({Path, Stamp}) ->
70 not Stamp == get_timestamp_info(State, Path)
71 end, Includes).
73 -spec do_extract(sin_state:state(), string(), [string()]) ->
74 {sin_state:state(), mod()}.
75 do_extract(State0, Path, Includes) ->
76 case filename:extension(Path) of
77 Ext when Ext == ".erl";
78 Ext == ".hrl";
79 Ext == ".yrl" ->
80 {State1, Mod0, ChangeSig} = sin_erl_info:process_file(State0,
81 Path,
82 Includes),
83 Mod1 = add_stamp_info(State1, Path, Mod0, ChangeSig),
84 {State1, Mod1};
85 Ext when Ext == ".jxa" ->
86 {State1, Mod0, ChangeSig} = sin_jxa_info:process_file(State0,
87 Path,
88 Includes),
89 Mod1 = add_stamp_info(State1, Path, Mod0, ChangeSig),
90 {State1, Mod1};
91 Error ->
92 ?SIN_RAISE(State0, {unable_to_parse_file, Path, Error})
93 end.
95 -spec add_stamp_info(sin_state:state(), string(), mod(), term()) -> mod().
96 add_stamp_info(State, Path, Mod, ChangeSig) ->
97 Mod#module{changed=get_timestamp_info(State, Path),
98 change_sig=ChangeSig}.
100 -spec get_timestamp_info(sin_state:state(), string()) -> non_neg_integer().
101 get_timestamp_info(State, Path) ->
102 case file:read_file_info(Path) of
103 {ok, FileInfo} ->
104 FileInfo#file_info.mtime;
105 {error, enoent} ->
107 {error, Reason} ->
108 ?SIN_RAISE(State, {unable_to_get_file_info, Path, Reason})
109 end.