1883b52f3850638db24c6c690bdc1a31c2f7dccd
[nit.git] / lib / popcorn / pop_config.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Configuration file and options for Popcorn apps
18 #
19 # `pop_config` provide a configuration framework for Popcorn apps based on ini
20 # files.
21 #
22 # By default `AppConfig` provides `app.host` and `app.port` keys, it's all we
23 # need to start an app:
24 #
25 # ~~~
26 # import popcorn
27 # import popcorn::pop_config
28 #
29 # # Parse app options
30 # var opts = new AppOptions.from_args(args)
31 #
32 # # Build config from options
33 # var config = new AppConfig.from_options(opts)
34 #
35 # # Use options
36 # var app = new App
37 # app.listen(config.app_host, config.app_port)
38 # ~~~
39 #
40 # For more advanced uses, `AppConfig` and `AppOptions` can be specialized to
41 # offer additional config options:
42 #
43 # ~~~
44 # import popcorn
45 # import popcorn::pop_config
46 #
47 # class MyConfig
48 # super AppConfig
49 #
50 # # My secret code I don't want to share in my source repository
51 # var secret: String = value_or_default("secret", "my-secret")
52 #
53 # redef init from_options(options) do
54 # super
55 # if options isa MyOptions then
56 # var secret = options.opt_secret.value
57 # if secret != null then self["secret"] = secret
58 # end
59 # end
60 # end
61 #
62 # class MyOptions
63 # super AppOptions
64 #
65 # var opt_secret = new OptionString("My secret string", "--secret")
66 #
67 # redef init do
68 # super
69 # add_option opt_secret
70 # end
71 # end
72 #
73 # class SecretHandler
74 # super Handler
75 #
76 # # Config to use to access `secret`
77 # var config: MyConfig
78 #
79 # redef fun get(req, res) do
80 # res.send config.secret
81 # end
82 # end
83 #
84 # var opts = new MyOptions.from_args(args)
85 # var config = new MyConfig.from_options(opts)
86 #
87 # var app = new App
88 # app.use("/secret", new SecretHandler(config))
89 # app.listen(config.app_host, config.app_port)
90 # ~~~
91 module pop_config
92
93 import ini
94 import opts
95
96 # Configuration file for Popcorn apps
97 #
98 # ~~~
99 # import popcorn
100 # import popcorn::pop_config
101 #
102 # # Build config from default values
103 # var config = new AppConfig("app.ini")
104 #
105 # # Change config values
106 # config["app.port"] = 3001.to_s
107 #
108 # # Use options
109 # var app = new App
110 # app.listen(config.app_host, config.app_port)
111 # ~~~
112 class AppConfig
113 super ConfigTree
114
115 # Kind of options used by this config
116 type OPTIONS: AppOptions
117
118 # Default configuration file path
119 var default_config_file: String = "app.ini"
120
121 # Web app host name
122 #
123 # * key: `app.host`
124 # * default: `localhost`
125 var app_host: String is lazy do return value_or_default("app.host", "localhost")
126
127 # Web app port
128 #
129 # * key: `app.port`
130 # * default: `3000`
131 var app_port: Int is lazy do return value_or_default("app.port", "3000").to_i
132
133 # Init `self` from a `AppOptions` option values
134 init from_options(opts: OPTIONS) do
135 init(opts.opt_config.value or else default_config_file)
136 var opt_host = opts.opt_host.value
137 if opt_host != null then self["app.host"] = opt_host
138 var opt_port = opts.opt_port.value
139 if opt_port > 0 then self["app.port"] = opt_port.to_s
140 end
141
142 # Return the registered value for `key` or `default`
143 protected fun value_or_default(key: String, default: String): String do
144 return self[key] or else default
145 end
146 end
147
148 # Options configuration for Popcorn apps
149 #
150 # Use the `AppOptions` class in your app to parse command line args:
151 # ~~~
152 # import popcorn
153 # import popcorn::pop_config
154 #
155 # # Parse app options
156 # var opts = new AppOptions.from_args(args)
157 #
158 # # Build config from options
159 # var config = new AppConfig.from_options(opts)
160 #
161 # # Use options
162 # var app = new App
163 # app.listen(config.app_host, config.app_port)
164 # ~~~
165 class AppOptions
166 super OptionContext
167
168 # Help option.
169 var opt_help = new OptionBool("Show this help message", "-h", "--help")
170
171 # Path to app config file.
172 var opt_config = new OptionString("Path to app config file", "--config")
173
174 # Host name to bind on (will overwrite the config one).
175 var opt_host = new OptionString("Host to bind the server on", "--host")
176
177 # Port number to bind on (will overwrite the config one).
178 var opt_port = new OptionInt("Port number to use", -1, "--port")
179
180 # You should redefined this method to add your options
181 init do
182 super
183 add_option(opt_help, opt_config, opt_host, opt_port)
184 end
185
186 # Initialize `self` and parse `args`
187 init from_args(args: Collection[String]) do
188 init
189 parse(args)
190 end
191 end