augeas 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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