ucl 0.1.3.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/LICENSE-DEPENDENCIES.md +161 -0
- data/README.md +270 -0
- data/ext/extconf.rb +67 -3
- data/ext/libucl/COPYING +23 -0
- data/ext/libucl/include/ucl.h +1689 -0
- data/ext/libucl/klib/khash.h +627 -0
- data/ext/libucl/klib/kvec.h +161 -0
- data/ext/libucl/src/mum.h +440 -0
- data/ext/libucl/src/tree.h +209 -0
- data/ext/libucl/src/ucl_chartable.h +267 -0
- data/ext/libucl/src/ucl_emitter.c +721 -0
- data/ext/libucl/src/ucl_emitter_streamline.c +178 -0
- data/ext/libucl/src/ucl_emitter_utils.c +521 -0
- data/ext/libucl/src/ucl_hash.c +642 -0
- data/ext/libucl/src/ucl_hash.h +115 -0
- data/ext/libucl/src/ucl_internal.h +668 -0
- data/ext/libucl/src/ucl_msgpack.c +1574 -0
- data/ext/libucl/src/ucl_parser.c +3247 -0
- data/ext/libucl/src/ucl_schema.c +1102 -0
- data/ext/libucl/src/ucl_sexp.c +229 -0
- data/ext/libucl/src/ucl_util.c +4004 -0
- data/ext/libucl/uthash/uthash.h +720 -0
- data/ext/libucl/uthash/utlist.h +1076 -0
- data/ext/libucl/uthash/utstring.h +412 -0
- data/ext/ucl.c +398 -90
- data/test/test_ucl.rb +452 -0
- data/ucl.gemspec +30 -7
- metadata +77 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c42a6b4100d7e40d367f9328f9d3a34aef3269daf8c8c41a10b88488cc4c5317
|
|
4
|
+
data.tar.gz: 960751a96ec18a4edb15ad341c0c6d9cdc3736d43d2fc67fb33aecfa6855afac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a47ad9b9b5ab638c6b957bfcad4044f91bd252343ae8630bd035efc4ac82fb668dbeef27efa29995a4e467372017f8233c9e1c99e8f79a380193bca5a252b144
|
|
7
|
+
data.tar.gz: 11e52d228e3c71d9ef3a9e1415ac724996ea0f2531fb431f5ea8e4b4361cf981630a2d50c3eee04d40f85464b2a50c00a7592579a495d523e0bbe4569f90ebc4
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Stéphane D'Alu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Bundled Dependency Licences
|
|
2
|
+
|
|
3
|
+
The `ucl` gem itself is MIT-licensed (see `LICENSE`). Built against a
|
|
4
|
+
system-wide libucl, that is the whole story: nothing here is distributed.
|
|
5
|
+
|
|
6
|
+
When no system libucl is found, the gem compiles the bundled copy in
|
|
7
|
+
`ext/libucl` (a git submodule pinned to an upstream release tag) into the
|
|
8
|
+
extension, and so redistributes the sources below. All are permissive and
|
|
9
|
+
non-copyleft; each asks only that its notice be retained. Every file keeps
|
|
10
|
+
its original header, and the texts are reproduced here so they travel with a
|
|
11
|
+
compiled (binary) distribution too -- what the BSD-2-Clause binary clause
|
|
12
|
+
requires.
|
|
13
|
+
|
|
14
|
+
| Component | Licence | Copyright | Files |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| libucl | BSD-2-Clause | Vsevolod Stakhov | `ext/libucl/src/ucl_*.{c,h}`, `ext/libucl/include/ucl.h`, `ext/libucl/COPYING` |
|
|
17
|
+
| uthash (uthash.h, utlist.h, utstring.h) | BSD-1-Clause | Troy D. Hanson | `ext/libucl/uthash/*.h` |
|
|
18
|
+
| klib (khash.h, kvec.h) | MIT | Attractive Chaos | `ext/libucl/klib/*.h` |
|
|
19
|
+
| mum hash (mum.h) | MIT | Vladimir Makarov | `ext/libucl/src/mum.h` |
|
|
20
|
+
| tree.h (AVL trees) | MIT-style, no sublicence clause | Ian Piumarta | `ext/libucl/src/tree.h` |
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Licence texts
|
|
24
|
+
|
|
25
|
+
### libucl
|
|
26
|
+
|
|
27
|
+
BSD-2-Clause
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Copyright (c) 2013-2014, Vsevolod Stakhov <vsevolod@highsecure.ru>
|
|
31
|
+
All rights reserved.
|
|
32
|
+
|
|
33
|
+
Redistribution and use in source and binary forms, with or without
|
|
34
|
+
modification, are permitted provided that the following conditions are met:
|
|
35
|
+
|
|
36
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
37
|
+
list of conditions and the following disclaimer.
|
|
38
|
+
|
|
39
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
40
|
+
this list of conditions and the following disclaimer in the documentation
|
|
41
|
+
and/or other materials provided with the distribution.
|
|
42
|
+
|
|
43
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
44
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
45
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
46
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
47
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
48
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
49
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
50
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
51
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
52
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### uthash (uthash.h, utlist.h, utstring.h)
|
|
56
|
+
|
|
57
|
+
BSD-1-Clause
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/
|
|
61
|
+
All rights reserved.
|
|
62
|
+
|
|
63
|
+
Redistribution and use in source and binary forms, with or without
|
|
64
|
+
modification, are permitted provided that the following conditions are met:
|
|
65
|
+
|
|
66
|
+
Redistributions of source code must retain the above copyright
|
|
67
|
+
notice, this list of conditions and the following disclaimer.
|
|
68
|
+
|
|
69
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
70
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
71
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
72
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
73
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
74
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
75
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
76
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
77
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
78
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
79
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### klib (khash.h, kvec.h)
|
|
83
|
+
|
|
84
|
+
MIT
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
The MIT License
|
|
88
|
+
|
|
89
|
+
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
|
|
90
|
+
|
|
91
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
92
|
+
a copy of this software and associated documentation files (the
|
|
93
|
+
"Software"), to deal in the Software without restriction, including
|
|
94
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
95
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
96
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
97
|
+
the following conditions:
|
|
98
|
+
|
|
99
|
+
The above copyright notice and this permission notice shall be
|
|
100
|
+
included in all copies or substantial portions of the Software.
|
|
101
|
+
|
|
102
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
103
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
104
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
105
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
106
|
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
107
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
108
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
109
|
+
SOFTWARE.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### mum hash (mum.h)
|
|
113
|
+
|
|
114
|
+
MIT
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
Copyright (c) 2016 Vladimir Makarov <vmakarov@gcc.gnu.org>
|
|
118
|
+
|
|
119
|
+
Permission is hereby granted, free of charge, to any person
|
|
120
|
+
obtaining a copy of this software and associated documentation
|
|
121
|
+
files (the "Software"), to deal in the Software without
|
|
122
|
+
restriction, including without limitation the rights to use, copy,
|
|
123
|
+
modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
124
|
+
of the Software, and to permit persons to whom the Software is
|
|
125
|
+
furnished to do so, subject to the following conditions:
|
|
126
|
+
|
|
127
|
+
The above copyright notice and this permission notice shall be
|
|
128
|
+
included in all copies or substantial portions of the Software.
|
|
129
|
+
|
|
130
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
131
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
132
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
133
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
134
|
+
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
135
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
136
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
137
|
+
SOFTWARE.
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### tree.h (AVL trees)
|
|
141
|
+
|
|
142
|
+
MIT-style. Note it grants no sublicence right and asks that the notice
|
|
143
|
+
appear in supporting documentation -- which this file provides.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Copyright (c) 2005 Ian Piumarta
|
|
147
|
+
|
|
148
|
+
All rights reserved.
|
|
149
|
+
|
|
150
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
151
|
+
of this software and associated documentation files (the 'Software'), to deal
|
|
152
|
+
in the Software without restriction, including without limitation the rights
|
|
153
|
+
to use, copy, modify, merge, publish, distribute, and/or sell copies of the
|
|
154
|
+
Software, and to permit persons to whom the Software is furnished to do so,
|
|
155
|
+
provided that the above copyright notice(s) and this permission notice appear
|
|
156
|
+
in all copies of the Software and that both the above copyright notice(s) and
|
|
157
|
+
this permission notice appear in supporting documentation.
|
|
158
|
+
|
|
159
|
+
THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
|
160
|
+
```
|
|
161
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
ruby-ucl
|
|
2
|
+
========
|
|
3
|
+
|
|
4
|
+
Ruby bindings to the [libucl][1] library for parsing configuration files
|
|
5
|
+
written in the **U**niversal **C**onfiguration **L**anguage (UCL).
|
|
6
|
+
|
|
7
|
+
UCL is a configuration format inspired by [nginx][2] and JSON. It is a
|
|
8
|
+
superset of JSON, so any valid JSON document is also valid UCL, while
|
|
9
|
+
adding a more relaxed, human-friendly syntax (unquoted keys, comments,
|
|
10
|
+
optional commas, multipliers, macros, …).
|
|
11
|
+
|
|
12
|
+
Parsed configurations are returned as plain Ruby objects (`Hash`,
|
|
13
|
+
`Array`, `String`, `Integer`, `Float`, `true`/`false`, `nil`), so no
|
|
14
|
+
special object model has to be learned.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Installation
|
|
18
|
+
------------
|
|
19
|
+
|
|
20
|
+
~~~sh
|
|
21
|
+
gem install ucl
|
|
22
|
+
~~~
|
|
23
|
+
|
|
24
|
+
Or add it to your `Gemfile`:
|
|
25
|
+
|
|
26
|
+
~~~ruby
|
|
27
|
+
gem 'ucl'
|
|
28
|
+
~~~
|
|
29
|
+
|
|
30
|
+
To track this repository instead of a released gem, **`submodules: true` is
|
|
31
|
+
required**:
|
|
32
|
+
|
|
33
|
+
~~~ruby
|
|
34
|
+
gem 'ucl', github: 'sdalu/ruby-ucl', submodules: true
|
|
35
|
+
~~~
|
|
36
|
+
|
|
37
|
+
libucl is vendored as a git submodule (see below), and Bundler does not fetch
|
|
38
|
+
submodules unless asked. Without that option `ext/libucl` stays empty and the
|
|
39
|
+
build fails — except on a machine that happens to have a system-wide libucl,
|
|
40
|
+
where it quietly links against that instead, and only fails once it is
|
|
41
|
+
deployed somewhere that has none.
|
|
42
|
+
|
|
43
|
+
The extension binds to the native [libucl][1] library. At build time it is
|
|
44
|
+
resolved as follows:
|
|
45
|
+
|
|
46
|
+
1. If a system-wide libucl is found (via `pkg-config`, or under `/opt` or
|
|
47
|
+
`/usr/local`), the extension links against it.
|
|
48
|
+
2. Otherwise the copy bundled with the gem is compiled directly into the
|
|
49
|
+
extension. This needs nothing but a C compiler — no network access, no
|
|
50
|
+
`cmake`, no extra gems.
|
|
51
|
+
|
|
52
|
+
You can force the bundled copy regardless of any system installation:
|
|
53
|
+
|
|
54
|
+
~~~sh
|
|
55
|
+
gem install ucl -- --enable-vendor-libucl
|
|
56
|
+
# or, with Bundler:
|
|
57
|
+
bundle config set build.ucl --enable-vendor-libucl
|
|
58
|
+
~~~
|
|
59
|
+
|
|
60
|
+
Building the bundled copy also compiles out `.include` over http/ftp, which
|
|
61
|
+
is gated on libucl's optional fetch support. A system-wide libucl may have it
|
|
62
|
+
enabled — see [Untrusted input](#untrusted-input).
|
|
63
|
+
|
|
64
|
+
> **Debian/Ubuntu note:** do **not** `apt install libucl-dev`. That package
|
|
65
|
+
> is an unrelated [UCL *data-compression* library][3] that merely shares the
|
|
66
|
+
> name — it does not provide `ucl_parser_new`. The configuration parser is
|
|
67
|
+
> not packaged for Debian, so just let the gem build its bundled copy — a C
|
|
68
|
+
> compiler is all you need. (The parser *is* packaged on Fedora, Homebrew and
|
|
69
|
+
> FreeBSD ports as `libucl`.)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
Usage
|
|
73
|
+
-----
|
|
74
|
+
|
|
75
|
+
~~~ruby
|
|
76
|
+
require 'ucl'
|
|
77
|
+
|
|
78
|
+
# Parse a string of UCL data
|
|
79
|
+
UCL.parse(File.read('foo.conf'))
|
|
80
|
+
|
|
81
|
+
# Same, with macros disabled -- use this for input you do not control
|
|
82
|
+
UCL.safe_parse(untrusted_string)
|
|
83
|
+
|
|
84
|
+
# Parse a file directly (enables file-relative variables such as $FILENAME)
|
|
85
|
+
UCL.load_file('foo.conf')
|
|
86
|
+
|
|
87
|
+
# Pass flags explicitly (combine them with a bitwise OR)
|
|
88
|
+
UCL.load_file('foo.conf', UCL::KEY_SYMBOL | UCL::KEY_LOWERCASE)
|
|
89
|
+
|
|
90
|
+
# Or set the default flags applied to every subsequent call
|
|
91
|
+
UCL.flags = UCL::KEY_SYMBOL
|
|
92
|
+
UCL.parse('name = value') #=> { :name => "value" }
|
|
93
|
+
~~~
|
|
94
|
+
|
|
95
|
+
Both `parse` and `load_file` accept an optional `flags` argument. When it
|
|
96
|
+
is omitted, the value of `UCL.flags` (default: no flag) is used.
|
|
97
|
+
`UCL.safe_parse` takes the same arguments as `parse` and always adds
|
|
98
|
+
`UCL::DISABLE_MACRO` (see *Untrusted input* below).
|
|
99
|
+
|
|
100
|
+
On a malformed configuration, or if conversion of the parsed tree fails,
|
|
101
|
+
a `UCL::Error` is raised.
|
|
102
|
+
|
|
103
|
+
Given a configuration like:
|
|
104
|
+
|
|
105
|
+
~~~nginx
|
|
106
|
+
# a sample configuration
|
|
107
|
+
name = example
|
|
108
|
+
# timeout is parsed as a number of seconds, max_size understands multipliers
|
|
109
|
+
timeout = 30s
|
|
110
|
+
max_size = 10mb
|
|
111
|
+
|
|
112
|
+
servers = [
|
|
113
|
+
{ host = a.example, port = 8080 },
|
|
114
|
+
{ host = b.example, port = 8081 },
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
logging {
|
|
118
|
+
level = info
|
|
119
|
+
enabled = yes
|
|
120
|
+
}
|
|
121
|
+
~~~
|
|
122
|
+
|
|
123
|
+
`UCL.load_file` returns:
|
|
124
|
+
|
|
125
|
+
~~~ruby
|
|
126
|
+
{
|
|
127
|
+
"name" => "example",
|
|
128
|
+
"timeout" => 30.0,
|
|
129
|
+
"max_size" => 10485760,
|
|
130
|
+
"servers" => [ { "host" => "a.example", "port" => 8080 },
|
|
131
|
+
{ "host" => "b.example", "port" => 8081 } ],
|
|
132
|
+
"logging" => { "level" => "info", "enabled" => true },
|
|
133
|
+
}
|
|
134
|
+
~~~
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
Flags
|
|
138
|
+
-----
|
|
139
|
+
|
|
140
|
+
| Flag | Effect |
|
|
141
|
+
|------------------|---------------------------------------------------------------|
|
|
142
|
+
| `KEY_SYMBOL` | Return object keys as `Symbol` instead of `String`. |
|
|
143
|
+
| `KEY_LOWERCASE` | Convert all keys to lower case. |
|
|
144
|
+
| `NO_TIME` | Do not parse time values; keep them as strings. |
|
|
145
|
+
| `DISABLE_MACRO` | Disable processing of macros (e.g. `.include`); see *Untrusted input*. |
|
|
146
|
+
| `NO_FILEVARS` | Do not predefine `$FILENAME` / `$CURDIR` (affects `parse`; `load_file` still sets them from the file). |
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
Untrusted input
|
|
150
|
+
---------------
|
|
151
|
+
|
|
152
|
+
`UCL.parse` and `UCL.load_file` process macros, so a configuration can pull
|
|
153
|
+
in other files through `.include`:
|
|
154
|
+
|
|
155
|
+
~~~ruby
|
|
156
|
+
UCL.parse('.include "/etc/secrets.conf"')
|
|
157
|
+
#=> the contents of that file, as Ruby objects
|
|
158
|
+
~~~
|
|
159
|
+
|
|
160
|
+
That is a feature of the format — it is how a configuration is split across
|
|
161
|
+
several files — but it means **a configuration string from an untrusted
|
|
162
|
+
source can read any file the process can read**. Parse such input with
|
|
163
|
+
`UCL.safe_parse`, which is `UCL.parse` with `UCL::DISABLE_MACRO` always
|
|
164
|
+
added:
|
|
165
|
+
|
|
166
|
+
~~~ruby
|
|
167
|
+
UCL.safe_parse(params[:config]) # `.include` is not executed
|
|
168
|
+
~~~
|
|
169
|
+
|
|
170
|
+
`load_file` has no `safe_` counterpart: the path comes from the caller, so
|
|
171
|
+
the decision to trust the file has already been made. Pass
|
|
172
|
+
`UCL::DISABLE_MACRO` explicitly if a trusted path holds untrusted content.
|
|
173
|
+
|
|
174
|
+
If libucl was built with URL includes enabled (the bundled build disables
|
|
175
|
+
them; a system-wide libucl may not), `.include` can also fetch over the
|
|
176
|
+
network. One more reason to reach for `safe_parse`.
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
Limits
|
|
180
|
+
------
|
|
181
|
+
|
|
182
|
+
Objects nested more than **1000 levels** deep are rejected with a
|
|
183
|
+
`UCL::Error`. Converting the parsed tree recurses once per level, as does
|
|
184
|
+
libucl's own handling of it, so an unbounded depth would exhaust the C
|
|
185
|
+
stack — a 1 MiB thread stack (what a Puma or Sidekiq worker gets) is gone
|
|
186
|
+
at roughly 15000 levels. Real configurations nest a handful of levels;
|
|
187
|
+
Ruby's own JSON parser stops at 100.
|
|
188
|
+
|
|
189
|
+
> **Known limitation.** The check happens when the parsed tree is converted,
|
|
190
|
+
> which is too late for input that is *both* deeply nested *and* malformed:
|
|
191
|
+
> libucl then releases its half-built tree recursively from inside
|
|
192
|
+
> `ucl_parser_free()`, out of reach of this binding, and a document such as
|
|
193
|
+
> `'a = ' + '[' * 20_000` raises `SystemStackError` instead of `UCL::Error`
|
|
194
|
+
> and leaks the parser. Deeply nested *well-formed* input is handled
|
|
195
|
+
> correctly. If you parse untrusted configurations, cap their size.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
Type mapping
|
|
199
|
+
------------
|
|
200
|
+
|
|
201
|
+
| UCL type | Ruby type |
|
|
202
|
+
|------------|--------------------------|
|
|
203
|
+
| object | `Hash` |
|
|
204
|
+
| array | `Array` |
|
|
205
|
+
| string | `String` |
|
|
206
|
+
| integer | `Integer` |
|
|
207
|
+
| float | `Float` |
|
|
208
|
+
| time | `Float` (seconds) |
|
|
209
|
+
| boolean | `true` / `false` |
|
|
210
|
+
| null | `nil` |
|
|
211
|
+
|
|
212
|
+
Notes:
|
|
213
|
+
|
|
214
|
+
* The parser uses explicit (not implicit) arrays, so a key repeated several
|
|
215
|
+
times is collected into an `Array` of its values:
|
|
216
|
+
|
|
217
|
+
~~~ruby
|
|
218
|
+
UCL.parse("a = 1\na = 2") #=> { "a" => [1, 2] }
|
|
219
|
+
UCL.parse("a = 1") #=> { "a" => 1 }
|
|
220
|
+
~~~
|
|
221
|
+
|
|
222
|
+
* Integers understand size multipliers (`1k` → 1000, `1kb` → 1024,
|
|
223
|
+
`1mb` → 1048576), hexadecimal (`0x1f` → 31) and JSON is accepted as-is.
|
|
224
|
+
|
|
225
|
+
* **A trailing `#` comment suppresses suffix parsing.** `t = 30s` is the
|
|
226
|
+
float `30.0` and `n = 10mb` the integer `10485760`, but `t = 30s # note`
|
|
227
|
+
and `n = 10mb # note` come back as the *strings* `"30s"` and `"10mb"`.
|
|
228
|
+
Plain integers and floats are unaffected (`n = 1 # note` is `1`). This is
|
|
229
|
+
libucl's behaviour, not the binding's; put the comment on its own line
|
|
230
|
+
when the value carries a unit or a multiplier.
|
|
231
|
+
|
|
232
|
+
* Returned strings carry their verbatim bytes but are tagged with the
|
|
233
|
+
`ASCII-8BIT` (binary) encoding; call `String#force_encoding('UTF-8')` if
|
|
234
|
+
you need them as UTF-8.
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
Development
|
|
238
|
+
-----------
|
|
239
|
+
|
|
240
|
+
~~~sh
|
|
241
|
+
git submodule update --init # populate ext/libucl (bundled libucl sources)
|
|
242
|
+
bundle install # install development dependencies
|
|
243
|
+
rake compile # build the C extension into ext/
|
|
244
|
+
rake test # compile and run the test suite
|
|
245
|
+
rake clobber # remove all generated files
|
|
246
|
+
~~~
|
|
247
|
+
|
|
248
|
+
`rake test` works with the development gems installed system-wide too; with
|
|
249
|
+
a `Gemfile.lock` present, prefix commands with `bundle exec`.
|
|
250
|
+
|
|
251
|
+
`ext/libucl` is a git submodule pinned to an upstream release tag; `rake
|
|
252
|
+
compile` and `rake build` both refuse to run until it is populated. To move
|
|
253
|
+
to a newer libucl, check out the new tag inside it and commit the pointer.
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
License
|
|
257
|
+
-------
|
|
258
|
+
|
|
259
|
+
Released under the MIT License. See [LICENSE](LICENSE).
|
|
260
|
+
|
|
261
|
+
When built against a system-wide libucl, nothing else is distributed. When
|
|
262
|
+
the bundled copy is compiled in, the gem also redistributes libucl and the
|
|
263
|
+
libraries vendored inside it (uthash, klib, mum, tree.h) — all permissive,
|
|
264
|
+
all notice-retention only. Their texts are in
|
|
265
|
+
[LICENSE-DEPENDENCIES.md](LICENSE-DEPENDENCIES.md).
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
[1]: https://github.com/vstakhov/libucl
|
|
269
|
+
[2]: https://nginx.org/
|
|
270
|
+
[3]: https://www.oberhumer.com/opensource/ucl/
|
data/ext/extconf.rb
CHANGED
|
@@ -1,7 +1,71 @@
|
|
|
1
1
|
require 'mkmf'
|
|
2
2
|
|
|
3
|
+
# Vendored libucl (vstakhov's Universal Configuration Language parser), used
|
|
4
|
+
# when no system-wide installation is found. It lives in ext/libucl, a git
|
|
5
|
+
# submodule pinned to a release tag. NOTE: this is *not* the Debian
|
|
6
|
+
# `libucl-dev` package, which is an unrelated compression library.
|
|
7
|
+
#
|
|
8
|
+
# Its sources are compiled straight into this extension rather than built as a
|
|
9
|
+
# separate library: src/ucl_internal.h defines the HAVE_* macros itself when
|
|
10
|
+
# HAVE_CONFIG_H is absent -- upstream calls this the "embedded build" and ships
|
|
11
|
+
# a Makefile.unix for it -- so no configure step is needed, and with it go the
|
|
12
|
+
# download, cmake, and any question of which libucl the linker picks up.
|
|
13
|
+
#
|
|
14
|
+
# One useful side effect: `.include` over http/ftp is gated on HAVE_FETCH_H and
|
|
15
|
+
# CURL_H, which the embedded build never defines, so remote includes are
|
|
16
|
+
# compiled out. A system-wide libucl may well have them enabled.
|
|
17
|
+
LIBUCL_DIR = File.join(__dir__, 'libucl').freeze
|
|
3
18
|
|
|
4
|
-
|
|
5
|
-
|
|
19
|
+
# Force using the bundled copy, ignoring any system installation:
|
|
20
|
+
# gem install ucl -- --enable-vendor-libucl
|
|
21
|
+
# bundle config set build.ucl --enable-vendor-libucl
|
|
22
|
+
# UCL_VENDOR_LIBUCL=1 rake compile
|
|
23
|
+
force_vendor = enable_config('vendor-libucl', false) ||
|
|
24
|
+
ENV.key?('UCL_VENDOR_LIBUCL')
|
|
6
25
|
|
|
7
|
-
|
|
26
|
+
# Locate a system-wide libucl: pkg-config first, then the usual prefixes.
|
|
27
|
+
def system_libucl
|
|
28
|
+
return true if pkg_config('libucl')
|
|
29
|
+
|
|
30
|
+
find_header( 'ucl.h', '/opt/include', '/usr/local/include') &&
|
|
31
|
+
find_library('ucl', 'ucl_parser_new', '/opt/lib', '/usr/local/lib')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The submodule is not populated in a fresh clone, and a gem packaged without
|
|
35
|
+
# it would fail here rather than at `git submodule update` time.
|
|
36
|
+
def bundled_libucl
|
|
37
|
+
File.exist?(File.join(LIBUCL_DIR, 'src', 'ucl_parser.c'))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if !force_vendor && system_libucl
|
|
41
|
+
message "Using system libucl.\n"
|
|
42
|
+
else
|
|
43
|
+
unless bundled_libucl
|
|
44
|
+
abort "\nThe bundled libucl sources are missing from #{LIBUCL_DIR}.\n" \
|
|
45
|
+
"In a git checkout, populate the submodule with:\n" \
|
|
46
|
+
" git submodule update --init\n" \
|
|
47
|
+
"In an installed gem this means the gem was packaged without them; " \
|
|
48
|
+
"please report it.\n" \
|
|
49
|
+
"Failing that, install libucl system-wide and build again.\n"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Prepended so that a system-wide ucl.h cannot shadow the bundled one.
|
|
53
|
+
$INCFLAGS = "-I#{LIBUCL_DIR}/include -I#{LIBUCL_DIR}/uthash " \
|
|
54
|
+
"-I#{LIBUCL_DIR}/src -I#{LIBUCL_DIR}/klib #{$INCFLAGS}"
|
|
55
|
+
|
|
56
|
+
# Every .c under src/ -- the same set CMakeLists.txt lists as UCLSRC.
|
|
57
|
+
$srcs = [File.join(__dir__, 'ucl.c')] +
|
|
58
|
+
Dir[File.join(LIBUCL_DIR, 'src', '*.c')].sort
|
|
59
|
+
$objs = $srcs.map { |src| "#{File.basename(src, '.c')}.o" }
|
|
60
|
+
$VPATH << "$(srcdir)/libucl/src"
|
|
61
|
+
|
|
62
|
+
# libucl's own build passes both; without them its sources emit a few hundred
|
|
63
|
+
# warning lines through an unrelated gem's install log.
|
|
64
|
+
$CFLAGS << ' -Wno-pointer-sign -Wno-unused-parameter'
|
|
65
|
+
|
|
66
|
+
have_library('m') # libucl relies on the math library
|
|
67
|
+
|
|
68
|
+
message "Compiling the bundled libucl into the extension.\n"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
create_makefile('ucl')
|
data/ext/libucl/COPYING
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2013-2014, Vsevolod Stakhov <vsevolod@highsecure.ru>
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|