-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
compile.mib.ex
150 lines (119 loc) · 3.22 KB
/
compile.mib.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
defmodule Mix.Tasks.Compile.Mib do
@moduledoc """
MIBs compiler
`:snmpc` expects instrumentation functions to be defined when parsing MIBs.
This libraries provides macros for generating instrumentation modules out of
MIB file (see `Snmp.Mib`). When compiling instrumentation module, we need MIB
to be parsed, as well as its dependencies.
This module compiles MIB into `*.bin` with fake instrumentation. `Snmp.Mib`
will recompile `.mib` file into `.bin` with proper instrumentation
declaration.
## Configuration
* `:snmpc_opts` - compilation options for the compiler. See below for
options.
Options:
* `:srcdir` - directory where to find '*.mib' files. Defaults to `"mibs"`
* `:destdir` - directory to put generated files. Default to `"priv/mibs"`
* `:includes` - directories to look for imported definitions, in addition to
`:srcdir`. Default to `[]`
* `:includes_lib` - application directories to look for other mibs. Default
to `[]`
* `:extra_opts` - any extra option to pass to snmpc compiler
"""
@shortdoc "Compile MIB files"
@task_name "compile.mib"
use Mix.Task.Compiler
alias Snmp.Compiler.Options
@doc false
def run(_args) do
Mix.Project.apps_paths()
|> case do
nil ->
do_compile(Mix.Project.get())
apps_paths ->
Enum.each(apps_paths, fn {app, path} ->
:ok = Mix.Project.in_project(app, path, &do_compile/1)
end)
end
end
@doc false
def clean do
opts = Options.from_project()
opts
|> targets()
|> case do
[] ->
:ok
paths ->
info("cleanup " <> Enum.join(paths, " "))
Enum.each(paths, &File.rm/1)
end
end
###
### Priv
###
defp do_compile(_project) do
opts = Options.from_project()
opts = %{opts | instrumentation: false}
opts
|> sources()
|> sort_dependencies(opts)
|> Snmp.Compiler.run(opts)
|> case do
{:ok, _} ->
:ok
{:error, error} ->
error
|> List.wrap()
|> Enum.each(&error/1)
{:error, error}
end
end
defp info(msg) do
Mix.shell().info([:bright, @task_name, :normal, " ", msg])
end
defp error(msg) when is_binary(msg) do
Mix.shell().info([:bright, @task_name, :normal, " ", :red, msg])
end
defp error(err),
do: err |> inspect() |> error()
defp sources(%{srcdir: srcdir}) do
srcdir
|> Path.join("*.mib")
|> Path.wildcard()
|> Enum.map(&Path.expand/1)
end
defp targets(%{destdir: destdir}) do
destdir
|> Path.join("*.bin")
|> Path.wildcard()
|> Enum.map(&Path.expand/1)
end
defp sort_dependencies(sources, opts) do
graph = :digraph.new()
_ =
for src <- sources do
:digraph.add_vertex(graph, src)
end
_ =
for src <- sources do
case Snmp.Compiler.dependencies(src, opts) do
{:ok, deps} ->
for dep <- deps do
:digraph.add_edge(graph, dep, src)
end
{:error, error} ->
raise error
end
end
result =
case :digraph_utils.topsort(graph) do
false ->
sources
ordered ->
ordered
end
:digraph.delete(graph)
result
end
end