augeas 0.6.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.
@@ -0,0 +1,48 @@
1
+ /*
2
+ * augeas.h: internal headers for Augeas Ruby bindings
3
+ *
4
+ * Copyright (C) 2008-2011 Red Hat Inc.
5
+ *
6
+ * This library is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * This library is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with this library; if not, write to the Free Software
18
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ */
20
+
21
+ #include <ruby.h>
22
+
23
+ #ifndef _AUGEAS_H_
24
+ #define _AUGEAS_H_
25
+
26
+ #define StringValueCStrOrNull(v) \
27
+ NIL_P(v) ? NULL : StringValueCStr(v)
28
+
29
+ /* memstream support from Augeas internal.h */
30
+ struct memstream {
31
+ FILE *stream;
32
+ char *buf;
33
+ size_t size;
34
+ };
35
+
36
+ int __aug_init_memstream(struct memstream *ms);
37
+ int __aug_close_memstream(struct memstream *ms);
38
+
39
+ #endif
40
+
41
+ /*
42
+ * Local variables:
43
+ * indent-tabs-mode: nil
44
+ * c-indent-level: 4
45
+ * c-basic-offset: 4
46
+ * tab-width: 4
47
+ * End:
48
+ */
@@ -0,0 +1,46 @@
1
+ ##
2
+ # extconf.rb: Ruby extension configuration
3
+ #
4
+ # Copyright (C) 200 Red Hat Inc.
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # Author: Bryan Kearney <bkearney@redhat.com>
21
+ ##
22
+ require 'mkmf'
23
+
24
+ extension_name = '_augeas'
25
+
26
+ # On Darwin compile for x86_64 only and link with augeas library to avoid dyld errors.
27
+ if RbConfig::CONFIG['target_os'] =~ /darwin/
28
+ $CFLAGS = $CFLAGS.gsub(/\-arch\ i386/, '')
29
+ $LDFLAGS = $LDFLAGS.gsub(/\-arch\ i386/, '')
30
+ $LDSHARED = RbConfig::MAKEFILE_CONFIG['LDSHARED']
31
+ RbConfig::MAKEFILE_CONFIG['LDSHARED'] = $LDSHARED.gsub(/\-arch\ i386/, '')
32
+ $LIBS += "-laugeas"
33
+ end
34
+
35
+ # Use have_library rather than pkg_config
36
+ unless have_library("augeas")
37
+ raise "libaugeas is not installed"
38
+ end
39
+
40
+ pkg_config('augeas')
41
+
42
+ unless have_library("xml2")
43
+ raise "libxml2 is not installed"
44
+ end
45
+
46
+ create_makefile(extension_name)
@@ -0,0 +1,383 @@
1
+ ##
2
+ # augeas.rb: Ruby wrapper for augeas
3
+ #
4
+ # Copyright (C) 2008 Red Hat Inc.
5
+ # Copyright (C) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 2.1 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ #
21
+ # Authors: Ionuț Arțăriși <iartarisi@suse.cz>
22
+ # Bryan Kearney <bkearney@redhat.com>
23
+ # Artem Sheremet <dot.doom@gmail.com>
24
+ ##
25
+
26
+ require "_augeas"
27
+
28
+ # Wrapper class for the augeas[http://augeas.net] library.
29
+ class Augeas
30
+ private_class_method :new
31
+
32
+ class Error < RuntimeError; end
33
+ class NoMemoryError < Error; end
34
+ class InternalError < Error; end
35
+ class InvalidPathError < Error; end
36
+ class NoMatchError < Error; end
37
+ class MultipleMatchesError < Error; end
38
+ class LensSyntaxError < Error; end
39
+ class LensNotFoundError < Error; end
40
+ class MultipleTransformsError < Error; end
41
+ class NoSpanInfoError < Error; end
42
+ class DescendantError < Error; end
43
+ class CommandExecutionError < Error; end
44
+ class InvalidArgumentError < Error; end
45
+ class InvalidLabelError < Error; end
46
+ @@error_hash = {
47
+ # the cryptic error names come from the C library, we just make
48
+ # them more ruby and more human
49
+ ENOMEM => NoMemoryError,
50
+ EINTERNAL => InternalError,
51
+ EPATHX => InvalidPathError,
52
+ ENOMATCH => NoMatchError,
53
+ EMMATCH => MultipleMatchesError,
54
+ ESYNTAX => LensSyntaxError,
55
+ ENOLENS => LensNotFoundError,
56
+ EMXFM => MultipleTransformsError,
57
+ ENOSPAN => NoSpanInfoError,
58
+ EMVDESC => DescendantError,
59
+ ECMDRUN => CommandExecutionError,
60
+ EBADARG => InvalidArgumentError,
61
+ ELABEL => InvalidLabelError,
62
+ }
63
+
64
+ # Create a new Augeas instance and return it.
65
+ #
66
+ # Use +:root+ as the filesystem root. If +:root+ is +nil+, use the value
67
+ # of the environment variable +AUGEAS_ROOT+. If that doesn't exist
68
+ # either, use "/".
69
+ #
70
+ # +:loadpath+ is a colon-spearated list of directories that modules
71
+ # should be searched in. This is in addition to the standard load path
72
+ # and the directories in +AUGEAS_LENS_LIB+
73
+ #
74
+ # The following flags can be specified in a hash. They all default to
75
+ # false and can be enabled by setting them to true
76
+ #
77
+ # :type_check - typecheck lenses (since it can be very expensive it is
78
+ # not done by default)
79
+ #
80
+ # :no_stdinc - do not use the builtin load path for modules
81
+ #
82
+ # :no_load - do not load the tree during the initialization phase
83
+ #
84
+ # :no_modl_autoload - do not load the tree during the initialization phase
85
+ #
86
+ # :enable_span - track the span in the input nodes
87
+ #
88
+ # :save_mode can be one of :backup, :newfile, :noop as explained below.
89
+ #
90
+ # :noop - make save a no-op process, just record what would have changed
91
+ #
92
+ # :backup - keep the original file with an .augsave extension
93
+ #
94
+ # :newfile - save changes into a file with an .augnew extension and
95
+ # do not overwrite the original file.
96
+ #
97
+ # When a block is given, the Augeas instance is passed as the only
98
+ # argument into the block and closed when the block exits.
99
+ # With no block, the Augeas instance is returned.
100
+ def self.create(opts={}, &block)
101
+ # aug_flags is a bitmask in the underlying library, we add all the
102
+ # values of the flags which were set to true to the default value
103
+ # Augeas::NONE (which is 0)
104
+ aug_flags = Augeas::NONE
105
+
106
+ flags = {
107
+ :type_check => Augeas::TYPE_CHECK,
108
+ :no_stdinc => Augeas::NO_STDINC,
109
+ :no_load => Augeas::NO_LOAD,
110
+ :no_modl_autoload => Augeas::NO_MODL_AUTOLOAD,
111
+ :enable_span => Augeas::ENABLE_SPAN
112
+ }
113
+ save_modes = {
114
+ :backup => Augeas::SAVE_BACKUP,
115
+ :newfile => Augeas::SAVE_NEWFILE,
116
+ :noop => Augeas::SAVE_NOOP
117
+ }
118
+ opts.each_key do |key|
119
+ if flags.key? key
120
+ aug_flags += flags[key]
121
+ elsif key == :save_mode
122
+ if save_modes[opts[:save_mode]]
123
+ aug_flags += save_modes[opts[:save_mode]]
124
+ else
125
+ raise ArgumentError, "Invalid save mode #{opts[:save_mode]}."
126
+ end
127
+ elsif key != :root && key != :loadpath
128
+ raise ArgumentError, "Unknown argument #{key}."
129
+ end
130
+ end
131
+
132
+ aug = Augeas::open3(opts[:root], opts[:loadpath], aug_flags)
133
+
134
+ if block_given?
135
+ begin
136
+ yield aug
137
+ ensure
138
+ aug.close
139
+ end
140
+ else
141
+ return aug
142
+ end
143
+ end
144
+
145
+ # Get the value associated with +path+.
146
+ def get(path)
147
+ run_command :augeas_get, path
148
+ end
149
+
150
+ # Return true if there is an entry for this path, false otherwise
151
+ def exists(path)
152
+ run_command :augeas_exists, path
153
+ end
154
+
155
+ # Set one or multiple elements to path.
156
+ # Multiple elements are mainly sensible with a path like
157
+ # .../array[last()+1], since this will append all elements.
158
+ def set(path, *values)
159
+ values.flatten.each { |v| run_command :augeas_set, path, v }
160
+ end
161
+
162
+ # Set multiple nodes in one operation. Find or create a node matching SUB
163
+ # by interpreting SUB as a path expression relative to each node matching
164
+ # BASE. If SUB is '.', the nodes matching BASE will be modified.
165
+
166
+ # +base+ the base node
167
+ # +sub+ the subtree relative to the base
168
+ # +value+ the value for the nodes
169
+ def setm(base, sub, value)
170
+ run_command :augeas_setm, base, sub, value
171
+ end
172
+
173
+ # Remove all nodes matching path expression +path+ and all their
174
+ # children.
175
+ # Raises an <tt>Augeas::InvalidPathError</tt> when the +path+ is invalid.
176
+ def rm(path)
177
+ run_command :augeas_rm, path
178
+ end
179
+
180
+ # Return an Array of all the paths that match the path expression +path+
181
+ #
182
+ # Returns an empty Array if no paths were found.
183
+ # Raises an <tt>Augeas::InvalidPathError</tt> when the +path+ is invalid.
184
+ def match(path)
185
+ run_command :augeas_match, path
186
+ end
187
+
188
+ # Create the +path+ with empty value if it doesn't exist
189
+ def touch(path)
190
+ set(path, nil) if match(path).empty?
191
+ end
192
+
193
+ # Evaluate +expr+ and set the variable +name+ to the resulting
194
+ # nodeset. The variable can be used in path expressions as $name.
195
+ # Note that +expr+ is evaluated when the variable is defined, not when
196
+ # it is used.
197
+ def defvar(name, expr)
198
+ run_command :augeas_defvar, name, expr
199
+ end
200
+
201
+ # Define the variable +name+ to the result of evaluating +expr+, which
202
+ # must be a nodeset. If no node matching +expr+ exists yet, one is
203
+ # created and +name+ will refer to it. When a node is created and
204
+ # +value+ is given, the new node's value is set to +value+.
205
+ def defnode(name, expr, value=nil)
206
+ run_command :augeas_defnode, name, expr, value
207
+ end
208
+
209
+ # Clear the +path+, i.e. make its value +nil+
210
+ def clear(path)
211
+ augeas_set(path, nil)
212
+ end
213
+
214
+ # Add a transform under <tt>/augeas/load</tt>
215
+ #
216
+ # The HASH can contain the following entries
217
+ # * <tt>:lens</tt> - the name of the lens to use
218
+ # * <tt>:name</tt> - a unique name; use the module name of the LENS
219
+ # when omitted
220
+ # * <tt>:incl</tt> - a list of glob patterns for the files to transform
221
+ # * <tt>:excl</tt> - a list of the glob patterns to remove from the
222
+ # list that matches <tt>:incl</tt>
223
+ def transform(hash)
224
+ lens = hash[:lens]
225
+ name = hash[:name]
226
+ incl = hash[:incl]
227
+ excl = hash[:excl]
228
+ raise ArgumentError, "No lens specified" unless lens
229
+ raise ArgumentError, "No files to include" unless incl
230
+ name = lens.split(".")[0].sub("@", "") unless name
231
+
232
+ xfm = "/augeas/load/#{name}/"
233
+ set(xfm + "lens", lens)
234
+ set(xfm + "incl[last()+1]", incl)
235
+ set(xfm + "excl[last()+1]", excl) if excl
236
+ end
237
+
238
+ # Clear all transforms under <tt>/augeas/load</tt>. If +load+
239
+ # is called right after this, there will be no files
240
+ # under +/files+
241
+ def clear_transforms
242
+ rm("/augeas/load/*")
243
+ end
244
+
245
+ # Write all pending changes to disk.
246
+ # Raises <tt>Augeas::CommandExecutionError</tt> if saving fails.
247
+ def save
248
+ begin
249
+ run_command :augeas_save
250
+ rescue Augeas::CommandExecutionError => e
251
+ raise e, "Saving failed. Search the augeas tree in /augeas//error"+
252
+ "for the actual errors."
253
+ end
254
+
255
+ nil
256
+ end
257
+
258
+ def clearm(path, sub)
259
+ setm(path, sub, nil)
260
+ end
261
+
262
+ # Load files according to the transforms in /augeas/load or those
263
+ # defined via <tt>transform</tt>. A transform Foo is represented
264
+ # with a subtree /augeas/load/Foo. Underneath /augeas/load/Foo, one
265
+ # node labeled 'lens' must exist, whose value is the fully
266
+ # qualified name of a lens, for example 'Foo.lns', and multiple
267
+ # nodes 'incl' and 'excl' whose values are globs that determine
268
+ # which files are transformed by that lens. It is an error if one
269
+ # file can be processed by multiple transforms.
270
+ def load
271
+ begin
272
+ run_command :augeas_load
273
+ rescue Augeas::CommandExecutionError => e
274
+ raise e, "Loading failed. Search the augeas tree in /augeas//error"+
275
+ "for the actual errors."
276
+ end
277
+
278
+ nil
279
+ end
280
+
281
+ # Move node +src+ to +dst+. +src+ must match exactly one node in
282
+ # the tree. +dst+ must either match exactly one node in the tree,
283
+ # or may not exist yet. If +dst+ exists already, it and all its
284
+ # descendants are deleted. If +dst+ does not exist yet, it and all
285
+ # its missing ancestors are created.
286
+ #
287
+ # Raises <tt>Augeas::NoMatchError</tt> if the +src+ node does not exist
288
+ # Raises <tt>Augeas::MultipleMatchesError</tt> if there were
289
+ # multiple matches in +src+
290
+ # Raises <tt>Augeas::DescendantError</tt> if the +dst+ node is a
291
+ # descendant of the +src+ node.
292
+ def mv(src, dst)
293
+ run_command :augeas_mv, src, dst
294
+ end
295
+
296
+ # Get the filename, label and value position in the text of this node
297
+ #
298
+ # Raises <tt>Augeas::NoMatchError</tt> if the node could not be found
299
+ # Raises <tt>Augeas::NoSpanInfo</tt> if the node associated with
300
+ # +path+ doesn't belong to a file or doesn't exist
301
+ def span(path)
302
+ run_command :augeas_span, path
303
+ end
304
+
305
+ # Run one or more newline-separated commands specified by +text+,
306
+ # returns an array of [successful_commands_number, output] or
307
+ # [-2, output] in case 'quit' command has been encountered.
308
+ # Raises <tt>Augeas::CommandExecutionError</tt> if gets an invalid command
309
+ def srun(text)
310
+ run_command(:augeas_srun, text)
311
+ end
312
+
313
+ # Lookup the label associated with +path+
314
+ # Raises <tt>Augeas::NoMatchError</tt> if the +path+ node does not exist
315
+ def label(path)
316
+ run_command :augeas_label, path
317
+ end
318
+
319
+ # Rename the label of all nodes matching +path+ to +label+
320
+ # Raises <tt>Augeas::NoMatchError</tt> if the +path+ node does not exist
321
+ # Raises <tt>Augeas::InvalidLabelError</tt> if +label+ is invalid
322
+ def rename(path, label)
323
+ run_command :augeas_rename, path, label
324
+ end
325
+
326
+ # Use the value of node +node+ as a string and transform it into a tree
327
+ # using the lens +lens+ and store it in the tree at +path+,
328
+ # which will be overwritten. +path+ and +node+ are path expressions.
329
+ def text_store(lens, node, path)
330
+ run_command :augeas_text_store, lens, node, path
331
+ end
332
+
333
+ # Transform the tree at +path+ into a string lens +lens+ and store it
334
+ # in the node +node_out+, assuming the tree was initially generated using
335
+ # the value of node +node_in+. +path+, +node_in+ and +node_out+ are path expressions.
336
+ def text_retrieve(lens, node_in, path, node_out)
337
+ run_command :augeas_text_retrieve, lens, node_in, path, node_out
338
+ end
339
+
340
+ # Make +label+ a sibling of +path+ by inserting it directly before
341
+ # or after +path+.
342
+ # The boolean +before+ determines if +label+ is inserted before or
343
+ # after +path+.
344
+ def insert(path, label, before)
345
+ run_command :augeas_insert, path, label, before
346
+ end
347
+
348
+ # Set path expression context to +path+ (in /augeas/context)
349
+ def context=(path)
350
+ set('/augeas/context', path)
351
+ end
352
+
353
+ # Get path expression context (from /augeas/context)
354
+ def context
355
+ get('/augeas/context')
356
+ end
357
+
358
+ private
359
+
360
+ # Run a command and raise any errors that happen due to execution.
361
+ #
362
+ # +cmd+ name of the Augeas command to run
363
+ # +params+ parameters with which +cmd+ will be called
364
+ #
365
+ # Returns whatever the original +cmd+ returns
366
+ def run_command(cmd, *params)
367
+ result = self.send cmd, *params
368
+
369
+ errcode = error[:code]
370
+ unless errcode.zero?
371
+ raise @@error_hash[errcode],
372
+ "#{error[:message]} #{error[:details]}"
373
+ end
374
+
375
+ if result.kind_of? Fixnum and result < 0
376
+ # we raise CommandExecutionError here, because this is the error that
377
+ # augtool raises in this case as well
378
+ raise CommandExecutionError, "Command failed. Return code was #{result}."
379
+ end
380
+
381
+ return result
382
+ end
383
+ end