relpipe-data/examples-ini.xml
branchv_0
changeset 329 5bc2bb8b7946
equal deleted inserted replaced
328:cc60c8dd7924 329:5bc2bb8b7946
       
     1 <stránka
       
     2 	xmlns="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
       
     3 	xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro">
       
     4 
       
     5 	<nadpis>Reading and writing INI and unix configs</nadpis>
       
     6 	<perex>work with INI, classic key=value configurations, Java .properties or Manifests</perex>
       
     7 	<m:pořadí-příkladu>05300</m:pořadí-příkladu>
       
     8 
       
     9 	<text xmlns="http://www.w3.org/1999/xhtml">
       
    10 
       
    11 		<p>
       
    12 			INI is very common simple text format used for configuration files.
       
    13 			It extends classic <i>key=value</i> config files and adds one more level – sections – for structuring.
       
    14 		</p>
       
    15 
       
    16 		<p>
       
    17 			Unfortunatelly, there is no single INI standard and we have to deal with various INI dialects.
       
    18 			Some organizations specify their own INI dialect, but often INI files lacking any formal specification are used.
       
    19 			Our tools support various specifics and dialects through the <code>--parser-option</code> options.
       
    20 			Like any other CLI options, they are supported in our Bash completion scripts.
       
    21 		</p>
       
    22 		
       
    23 		<!--
       
    24 		<p>(please note that OS/2 uses binary INI files that are currently not supported in <m:name/> and it is unsure whether they will ever be)</p>
       
    25 		-->
       
    26 
       
    27 		<p>
       
    28 			Classic (<i>unix</i>) <i>key=value</i> config files can be considered a dialect or a subset of the INI format
       
    29 			and thus be processed by INI input and output filters.
       
    30 			It is like INI without any sections or INI having only global properties (<i>key=value</i> at the beginning of the file).
       
    31 			Java <i>.properties</i> and <i>MANIFEST.MF</i> files are similar case. They also can be processed by our tools.
       
    32 		</p>
       
    33 
       
    34 		<h3>Simple INI example</h3>
       
    35 
       
    36 		<p>This is a simple INI file:</p>
       
    37 
       
    38 		<m:pre jazyk="ini" src="examples/ini-simple.ini"/>
       
    39 
       
    40 		<p>We read such INI file using this command:</p>
       
    41 
       
    42 		<m:pre jazyk="text"><![CDATA[cat ini-simple.ini | relpipe-in-ini | relpipe-out-tabular]]></m:pre>
       
    43 
       
    44 		<p>and get:</p>
       
    45 
       
    46 		<m:pre jazyk="text" src="examples/ini-simple.tabular"/>
       
    47 
       
    48 		<p>
       
    49 			Of course, we can do more that listing the entries as a table.
       
    50 			We can convert them to other formats or e.g. run some command on each entry.
       
    51 			Or modify certain values or add/remove entries and save as new INI file.
       
    52 		</p>
       
    53 
       
    54 		<h3>More complex INI example</h3>
       
    55 
       
    56 		<p>
       
    57 			The INI format is just seemingly simple. There is much more than <i>section/key/value</i>.
       
    58 			Our parser is by default configured to eat as much INI as possible.
       
    59 			It can be tuned by <code>--parser-option</code> CLI options.
       
    60 			Sometimes, such tuning is necessary, because some INI features are conflicting – some INI dialects are mutually exclusive.
       
    61 		</p>
       
    62 
       
    63 
       
    64 		<p>(please note that syntax highlighting does not support advanced INI features and is sometimes broken)</p>
       
    65 
       
    66 		<m:pre jazyk="ini" src="examples/ini-complex.ini"/>
       
    67 
       
    68 		<p>We read such INI file using this command:</p>
       
    69 
       
    70 		<m:pre jazyk="text"><![CDATA[cat ini-simple.ini | relpipe-in-ini --enable-sub-keys true | relpipe-out-tabular]]></m:pre>
       
    71 
       
    72 		<p>and get:</p>
       
    73 
       
    74 		<m:pre jazyk="text" src="examples/ini-complex.tabular"/>
       
    75 
       
    76 		<p>
       
    77 			If we omit the <code>--enable-sub-keys true</code> option, the <code>sub_key</code> attribute disappears
       
    78 			and we get <code>a[x]</code> and <code>a[y]</code> in the <code>key</code> attribute
       
    79 			i.e. brackets are not interpreted in any special way – they are considered just part of the key.
       
    80 		</p>
       
    81 
       
    82 		<p>See Bash completion for complete list of options and dialects.</p>
       
    83 
       
    84 
       
    85 		<h3>Keeping comments and whitespace while modifying the INI files</h3>
       
    86 
       
    87 		<p>
       
    88 			Comments and empty lines are ignored by default and does not generate any output.
       
    89 			This is desired behavior in most cases.
       
    90 			But sometimes we want to pass them through.
       
    91 			We may e.g. generate some XHTML report or other user-friendly output containing the comments,
       
    92 			or we may want to modify existing INI without losing original comments and formatting.
       
    93 			The tool offers the <code>--enable-comments</code> and <code>--enable-whitespace</code> options.
       
    94 			They allows lossless or almost lossless round-trip conversion from INI to relations and back.
       
    95 		</p>
       
    96 
       
    97 		<p>
       
    98 			Besides that, we have also the <code>--enable-event-numbers</code> and <code>--enable-line-numbers</code> options.
       
    99 			But they are useful mostly for debugging purposes.
       
   100 		</p>
       
   101 
       
   102 		<p>If we enable all that options, we get this output:</p>
       
   103 
       
   104 		<m:pre jazyk="text" src="examples/ini-complex.full.tabular"/>
       
   105 
       
   106 		<p>
       
   107 			So we can take the simple INI file (see above) and pass it through a filter
       
   108 			that changes (on-the-fly) the <code>x</code> value in the <code>first-section</code>:
       
   109 		</p>
       
   110 
       
   111 		<m:pre jazyk="bash"><![CDATA[cat ini-simple.ini \
       
   112 	| relpipe-in-ini --enable-comments true \
       
   113 	| relpipe-tr-scheme \
       
   114 		--relation 'ini' \
       
   115 			--for-each '
       
   116 				(if (and (string= $section "first-section") (string= $key "x"))
       
   117 					(set! $value "256"))' \
       
   118 	| relpipe-out-ini]]></m:pre>
       
   119 
       
   120 		<p>and get an INI file that contains original comments and modified values:</p>
       
   121 
       
   122 		<m:pre jazyk="ini" src="examples/ini-simple.modified.ini"/>
       
   123 
       
   124 		<p>
       
   125 			Both the comment at the beginning of the file
       
   126 			and the <code>x</code> value in <code>second-section</code>
       
   127 			were kept intact.
       
   128 		</p>
       
   129 
       
   130 		<m:pre jazyk="bash"><![CDATA[cat ini-simple.ini \
       
   131 	| relpipe-in-ini --enable-comments true \
       
   132 	| relpipe-tr-awk \
       
   133 		--relation '.*' \
       
   134 			--for-each '(section == "first-section" && key == "x") { value = "256"; }; record();' \
       
   135 	| relpipe-out-ini]]></m:pre>
       
   136 
       
   137 		<p>
       
   138 			This AWK filter will generate the same output.
       
   139 			And we can simply add comments just by adding e.g. <code>comment = "the script changed this value";</code> after the <code>value = "256";</code>
       
   140 			which results in:
       
   141 		</p>
       
   142 
       
   143 		<m:pre jazyk="ini"><![CDATA[x = 256 ; the script changed this value]]></m:pre>
       
   144 
       
   145 		<p>This way we can automatically modify our configuration files.</p>
       
   146 
       
   147 
       
   148 		<h3>Generating INI files</h3>
       
   149 
       
   150 		<p>
       
   151 			The <code>relpipe-out-ini</code> tool serves not only for recreating already existing INI files but also for creating new ones.
       
   152 			Data may come from various sources – CSV editor, script, SQL query etc. – and may come in diferent shapes.
       
   153 			While on the INI side we use the term „dialect“, on the relational side we use the term „style“.
       
   154 		</p>
       
   155 
       
   156 
       
   157 		<p>So in <code>relpipe-out-ini</code> we can chose from several <i>styles</i>:</p>
       
   158 
       
   159 		<ul>
       
   160 			<li><code>standard</code>: expects same structure as generated by <code>relpipe-in-ini</code>; can generate also comments and whitespace</li>
       
   161 			<li><code>literal</code>: relation name → section name; attribute name → key; attribute value → value; multiple records → duplicate section names</li>
       
   162 			<li><code>section-first</code>: like <code>literal</code>, just section names are taken from the first attribute</li>
       
   163 			<li><code>dropped</code>: this relation is ignored/skipped</li>
       
   164 			<li><code>auto</code>: use <code>standard</code> style if the relation has <code>key</code> and <code>value</code> attributes; otherwise use <code>literal</code> style</li>
       
   165 		</ul>
       
   166 
       
   167 		<p>Each relation might be processed in different way – use the <code>--relation</code> and regular expression describing the relation(s) name.</p>
       
   168 
       
   169 		<p>
       
   170 			We may for example run:
       
   171 		</p>
       
   172 
       
   173 		<m:pre jazyk="shell"><![CDATA[relpipe-in-x11 --list-input-devices true \
       
   174 	| relpipe-tr-awk \
       
   175 		--relation '.*' \
       
   176 			--output-attribute 'type'  string \
       
   177 			--output-attribute 'id'    integer \
       
   178 			--output-attribute 'name'  string \
       
   179 			--where 'type == "mouse" || type == "keyboard"' \
       
   180 	| relpipe-out-ini --style section-first]]></m:pre>
       
   181 
       
   182 		<p>and get INI like this:</p>
       
   183 
       
   184 
       
   185 		<m:pre jazyk="ini"><![CDATA[[keyboard]
       
   186 id = 6
       
   187 name = Power Button
       
   188 
       
   189 [keyboard]
       
   190 id = 7
       
   191 name = Video Bus
       
   192 
       
   193 [keyboard]
       
   194 id = 8
       
   195 name = Power Button
       
   196 
       
   197 [mouse]
       
   198 id = 10
       
   199 name = Logitech USB Trackball
       
   200 
       
   201 [keyboard]
       
   202 id = 16
       
   203 name = AT Translated Set 2 keyboard
       
   204 
       
   205 [keyboard]
       
   206 id = 12
       
   207 name = ZSA Technology Labs Inc ErgoDox EZ Shine Keyboard
       
   208 
       
   209 [mouse]
       
   210 id = 9
       
   211 name = 3Dconnexion 3Dconnexion Universal Receiver Mouse]]></m:pre>
       
   212 
       
   213 		<p>
       
   214 			This way, we can generate INI files to be loaded as configuration files by other programs.
       
   215 			We can also use <code>relpipe-out-ini</code> for displaying data rather vertically than horizontally (like in common <code>relpipe-out-tabular</code>).
       
   216 			This is useful for data with long values or many attributes.
       
   217 			The <code>relpipe-out-recfile</code> tool can also server this purpose.
       
   218 		</p>
       
   219 
       
   220 		<h3>Generating XHTML report from several INI files</h3>
       
   221 
       
   222 		<p>
       
   223 			INI format is used by many programs like Mercurial, Git, KDE, Gnome… and also by <m:a href="examples-tr-sql-odbc">ODBC</m:a>.
       
   224 			Its configuration is spread across several INI files (system-wide driver configuration and connections and user-specific connections).
       
   225 			We can collect all these INI files, use their names as relation names and generate a nice XHTML report:
       
   226 		</p>
       
   227 
       
   228 		<m:pre jazyk="bash"><![CDATA[for file in /etc/odbcinst.ini /etc/odbc.ini ~/.odbc.ini ; do
       
   229 	cat "$file" | relpipe-in-ini --relation "$(basename $file)";
       
   230 done | relpipe-out-xhtml > odbc-report.xhtml]]></m:pre>
       
   231 
       
   232 		<p>
       
   233 			n.b. It might contain also sensitive information like passwords.
       
   234 			We may use some <code>relpipe-tr-*</code> filter to remove such records or replace such values by <code>********</code>.
       
   235 		</p>
       
   236 
       
   237 
       
   238 		<h3>Java .properties and MANIFEST.MF</h3>
       
   239 
       
   240 		<p>
       
   241 			Java has built-in support for simple key=value format – so called <i>.properties files</i>.
       
   242 			They are often used for storing flat data where more advanced format (like XML) is not necessary.
       
   243 			This format supports comments and some escaping sequences.
       
   244 			Escaping of non-ASCII characters was mandatory but since Java 9 the UTF-8 encoding is used by default (no need to call <code>native2ascii</code>).
       
   245 			In <m:name/> we consider .properties files to be a dialect of the INI format so it is supported in <code>relpipe-in-ini</code> and <code>relpipe-out-ini</code>.
       
   246 			The same applies to the MANIFEST.MF which is another key=value format used in the Java world.
       
   247 			Thus we can read and write e.g. Java resource bundles (localization), Java EE or Spring application configs or MANIFEST.MF containing OSGi metadata and other information.
       
   248 		</p>
       
   249 
       
   250 		<m:pre jazyk="bash"><![CDATA[# read .properties or MANIFEST.MF:
       
   251 cat example.properties | relpipe-in-ini --parser-option dialect java-properties  | …
       
   252 cat MANIFEST.MF        | relpipe-in-ini --parser-option dialect java-manifest-mf | …
       
   253 
       
   254 # write .properties or MANIFEST.MF:
       
   255 … | relpipe-out-ini --writer-option dialect java-properties  > example.properties
       
   256 … | relpipe-out-ini --writer-option dialect java-manifest-mf > MANIFEST.MF]]></m:pre>
       
   257 
       
   258 		<p>
       
   259 			We can pass such data through various transformation (SQL, AWK, Scheme, XPath etc.)
       
   260 			and do conversions to/from various formats (CSV, INI, XML, XHTML, YAML, Recfile, ASN.1 etc.)
       
   261 			or convert .properties to MANIFEST.MF and vice versa.
       
   262 		</p>
       
   263 
       
   264 
       
   265 		<h3>Classic <i>unix</i> key=value config files</h3>
       
   266 
       
   267 		<p>
       
   268 			Many <i>unix</i> or GNU/Linux programs use simple key=value configuration files with <code>#</code> comments
       
   269 			and some basic escaping (like <code>\\</code> → <code>\</code>, <code>\n</code> → <i>new line</i> etc.)
       
   270 			It is very similar to Java .properties mentioned above.
       
   271 		</p>
       
   272 
       
   273 		<p>
       
   274 			The configuration is often spread across many small files heavily stuffed with comments.
       
   275 			If we want to collect just the valid configuration entries from all the files,
       
   276 			we may somehow misuse the INI input filter and the fact that given files contain no sections – turn the filenames into section names
       
   277 			and feed the result to the <code>relpipe-in-ini</code>:
       
   278 		</p>
       
   279 
       
   280 
       
   281 		<m:pre jazyk="bash"><![CDATA[head -n -0 /etc/sysctl.d/*.conf \
       
   282 	| sed -E 's/==> (.*) <==/[\1]/g' \
       
   283 	| relpipe-in-ini --relation 'sysctl' \
       
   284 	| relpipe-out-tabular]]></m:pre>
       
   285 
       
   286 		<p>This gives us nice overview of our system configuration:</p>
       
   287 		<m:pre jazyk="text"><![CDATA[sysctl:
       
   288  ╭─────────────────────────────────────────┬────────────────────────────────────┬────────────────╮
       
   289  │ section                        (string) │ key                       (string) │ value (string) │
       
   290  ├─────────────────────────────────────────┼────────────────────────────────────┼────────────────┤
       
   291  │ /etc/sysctl.d/uhd-usrp2.conf            │ net.core.rmem_max                  │ 50000000       │
       
   292  │ /etc/sysctl.d/uhd-usrp2.conf            │ net.core.wmem_max                  │ 1048576        │
       
   293  │ /etc/sysctl.d/10-console-messages.conf  │ kernel.printk                      │ 4 4 1 7        │
       
   294  │ /etc/sysctl.d/10-ipv6-privacy.conf      │ net.ipv6.conf.all.use_tempaddr     │ 2              │
       
   295  │ /etc/sysctl.d/10-ipv6-privacy.conf      │ net.ipv6.conf.default.use_tempaddr │ 2              │
       
   296  │ /etc/sysctl.d/10-kernel-hardening.conf  │ kernel.kptr_restrict               │ 1              │
       
   297  │ /etc/sysctl.d/10-link-restrictions.conf │ fs.protected_hardlinks             │ 1              │
       
   298  │ /etc/sysctl.d/10-link-restrictions.conf │ fs.protected_symlinks              │ 1              │
       
   299  │ /etc/sysctl.d/10-magic-sysrq.conf       │ kernel.sysrq                       │ 176            │
       
   300  │ /etc/sysctl.d/10-network-security.conf  │ net.ipv4.conf.default.rp_filter    │ 1              │
       
   301  │ /etc/sysctl.d/10-network-security.conf  │ net.ipv4.conf.all.rp_filter        │ 1              │
       
   302  │ /etc/sysctl.d/10-network-security.conf  │ net.ipv4.tcp_syncookies            │ 1              │
       
   303  │ /etc/sysctl.d/10-ptrace.conf            │ kernel.yama.ptrace_scope           │ 1              │
       
   304  │ /etc/sysctl.d/10-zeropage.conf          │ vm.mmap_min_addr                   │ 65536          │
       
   305  │ /etc/sysctl.d/99-sysctl.conf            │ kernel.sysrq                       │ 1              │
       
   306  ╰─────────────────────────────────────────┴────────────────────────────────────┴────────────────╯
       
   307 Record count: 15]]></m:pre>
       
   308 
       
   309 		
       
   310 		<p>We can also do this:</p>
       
   311 		<m:pre jazyk="bash"><![CDATA[find /etc/sysctl.d/ -name '*.conf' \
       
   312 	| while read f; do echo "[$f]"; cat "$f"; done \
       
   313 	| relpipe-in-ini \
       
   314 	| relpipe-out-tabular]]></m:pre>
       
   315 	
       
   316 		<p>Or create a reusable function:</p>
       
   317 		<m:pre jazyk="bash"><![CDATA[list-config() {
       
   318 	head -n -0 "$@" \
       
   319 		| sed -E 's/==> (.*) <==/[\1]/g' \
       
   320 		| relpipe-in-ini --relation "configs" \
       
   321 		| relpipe-out-tabular --write-types false;
       
   322 }]]></m:pre>
       
   323 
       
   324 		<p>and call it this way:</p>
       
   325 		<m:pre jazyk="bash"><![CDATA[list-config /etc/sysctl.d/*.conf]]></m:pre>
       
   326 
       
   327 		<p>It is a bit dirty hack (what if the file name, key or value contains <code>&lt;==</code> or <code>[…]</code>?) but it will work quite well.</p>
       
   328 		
       
   329 		<p>And like with Java .properties and MANIFEST-MF, we can use the <code>relpipe-out-ini</code> to generate the configuration files.</p>
       
   330 		
       
   331 	</text>
       
   332 
       
   333 </stránka>