Avoid use of link_whole in the gsettings backend
[dconf.git] / bin / dconf.vala
blob349e1ea19f93a8afb597571ddcf576299f2a3452
1 /*
2 * Copyright © 2010, 2011 Codethink Limited
3 * Copyright © 2011 Canonical Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the licence, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
21 void show_help (bool requested, string? command) {
22 var str = new StringBuilder ();
23 string? description = null;
24 string? synopsis = null;
26 switch (command) {
27 case null:
28 break;
30 case "help":
31 description = "Print help";
32 synopsis = " COMMAND ";
33 break;
35 case "read":
36 description = "Read the value of a key. -d to read default values.";
37 synopsis = " [-d] KEY ";
38 break;
40 case "list":
41 description = "List the sub-keys and sub-dirs of a dir";
42 synopsis = " DIR ";
43 break;
45 case "list-locks":
46 description = "List the locks under a dir";
47 synopsis = " DIR ";
48 break;
50 case "write":
51 description = "Write a new value to a key";
52 synopsis = " KEY VALUE ";
53 break;
55 case "reset":
56 description = "Reset a key or dir. -f is required for dirs.";
57 synopsis = " [-f] PATH ";
58 break;
60 case "compile":
61 description = "Compile a binary database from keyfiles";
62 synopsis = " OUTPUT KEYFILEDIR ";
63 break;
65 case "update":
66 description = "Update the system dconf databases";
67 synopsis = "";
68 break;
70 case "watch":
71 description = "Watch a path for key changes";
72 synopsis = " PATH ";
73 break;
75 case "dump":
76 description = "Dump an entire subpath to stdout";
77 synopsis = " DIR ";
78 break;
80 case "load":
81 description = "Populate a subpath from stdin";
82 synopsis = " DIR ";
83 break;
85 default:
86 str.append_printf ("Unknown command '%s'\n\n", command);
87 command = null;
88 break;
91 if (command == null) {
92 str.append (
93 """Usage:
94 dconf COMMAND [ARGS...]
96 Commands:
97 help Show this information
98 read Read the value of a key
99 list List the contents of a dir
100 write Change the value of a key
101 reset Reset the value of a key or dir
102 compile Compile a binary database from keyfiles
103 update Update the system databases
104 watch Watch a path for changes
105 dump Dump an entire subpath to stdout
106 load Populate a subpath from stdin
108 Use 'dconf help COMMAND' to get detailed help.
110 """);
111 } else {
112 str.append ("Usage:\n");
113 str.append_printf (" dconf %s%s\n\n", command, synopsis);
114 str.append_printf ("%s\n\n", description);
116 if (synopsis != "") {
117 str.append ("Arguments:\n");
119 if (" COMMAND " in synopsis) {
120 str.append (" COMMAND The (optional) command to explain\n");
123 if (" PATH " in synopsis) {
124 str.append (" PATH Either a KEY or DIR\n");
127 if (" PATH " in synopsis || " KEY " in synopsis) {
128 str.append (" KEY A key path (starting, but not ending with '/')\n");
131 if (" PATH " in synopsis || " DIR " in synopsis) {
132 str.append (" DIR A directory path (starting and ending with '/')\n");
135 if (" VALUE " in synopsis) {
136 str.append (" VALUE The value to write (in GVariant format)\n");
139 if (" OUTPUT " in synopsis) {
140 str.append (" OUTPUT The filename of the (binary) output\n");
143 if (" KEYFILEDIR " in synopsis) {
144 str.append (" KEYFILEDIR The path to the .d directory containing keyfiles\n");
148 str.append ("\n");
151 if (requested) {
152 print ("%s", str.str);
153 } else {
154 printerr ("%s", str.str);
158 void dconf_help (string[] args) throws Error {
159 show_help (true, args[2]);
162 void dconf_read (string?[] args) throws Error {
163 var client = new DConf.Client ();
164 var flags = DConf.ReadFlags.NONE;
165 var index = 2;
167 if (args[index] == "-d") {
168 flags = DConf.ReadFlags.DEFAULT_VALUE;
169 index++;
172 var key = args[index];
174 DConf.verify_key (key);
176 var result = client.read_full (key, flags, null);
178 if (result != null) {
179 print ("%s\n", result.print (true));
183 void dconf_list (string?[] args) throws Error {
184 var client = new DConf.Client ();
185 var dir = args[2];
187 DConf.verify_dir (dir);
189 foreach (var item in client.list (dir)) {
190 print ("%s\n", item);
194 void dconf_list_locks (string?[] args) throws Error {
195 var client = new DConf.Client ();
196 var dir = args[2];
198 DConf.verify_dir (dir);
200 foreach (var item in client.list_locks (dir)) {
201 print ("%s\n", item);
205 void dconf_write (string?[] args) throws Error {
206 var client = new DConf.Client ();
207 var key = args[2];
208 var val = args[3];
210 DConf.verify_key (key);
212 client.write_sync (key, Variant.parse (null, val));
215 void dconf_reset (string?[] args) throws Error {
216 var client = new DConf.Client ();
217 bool force = false;
218 var index = 2;
220 if (args[index] == "-f") {
221 force = true;
222 index++;
225 var path = args[index];
227 DConf.verify_path (path);
229 if (DConf.is_dir (path) && !force) {
230 throw new OptionError.FAILED ("-f must be given to (recursively) reset entire dirs");
233 client.write_sync (path, null);
236 void show_path (DConf.Client client, string path) {
237 if (DConf.is_key (path)) {
238 var value = client.read (path);
240 print (" %s\n", value != null ? value.print (true) : "unset");
244 void watch_function (DConf.Client client, string path, string[] items, string? tag) {
245 foreach (var item in items) {
246 var full = path + item;
247 print ("%s\n", full);
248 show_path (client, full);
250 print ("\n");
253 void dconf_watch (string?[] args) throws Error {
254 var client = new DConf.Client ();
255 var path = args[2];
257 DConf.verify_path (path);
259 client.changed.connect (watch_function);
260 client.watch_sync (path);
262 new MainLoop (null, false).run ();
265 void dconf_blame (string?[] args) throws Error {
266 var connection = Bus.get_sync (BusType.SESSION, null);
267 var reply = connection.call_sync ("ca.desrt.dconf", "/ca/desrt/dconf", "ca.desrt.dconf.ServiceInfo", "Blame",
268 null, new VariantType ("(s)"), DBusCallFlags.NONE, -1, null);
269 print ("%s", reply.get_child_value (0).get_string (null));
272 void dconf_complete (string[] args) throws Error {
273 var suffix = args[2];
274 var path = args[3];
276 if (path == "") {
277 print ("/\n");
278 return;
281 if (path[0] == '/') {
282 var client = new DConf.Client ();
283 var last = 0;
285 for (var i = 1; path[i] != '\0'; i++) {
286 if (path[i] == '/') {
287 last = i;
291 var dir = path.substring (0, last + 1);
292 foreach (var item in client.list (dir)) {
293 var full_item = dir + item;
295 if (full_item.has_prefix (path) && item.has_suffix (suffix)) {
296 print ("%s%s\n", full_item, full_item.has_suffix ("/") ? "" : " ");
302 delegate void Command (string[] args) throws Error;
304 struct CommandMapping {
305 unowned Command func;
306 string name;
308 public CommandMapping (string name, Command func) {
309 this.name = name;
310 this.func = func;
314 int main (string[] args) {
315 assert (args.length != 0);
316 Environment.set_prgname (args[0]);
318 Intl.setlocale (LocaleCategory.ALL, "");
320 var map = new CommandMapping[] {
321 CommandMapping ("help", dconf_help),
322 CommandMapping ("read", dconf_read),
323 CommandMapping ("list", dconf_list),
324 CommandMapping ("list-locks", dconf_list_locks),
325 CommandMapping ("write", dconf_write),
326 CommandMapping ("reset", dconf_reset),
327 CommandMapping ("compile", dconf_compile),
328 CommandMapping ("update", dconf_update),
329 CommandMapping ("watch", dconf_watch),
330 CommandMapping ("dump", dconf_dump),
331 CommandMapping ("load", dconf_load),
332 CommandMapping ("blame", dconf_blame),
333 CommandMapping ("_complete", dconf_complete)
336 try {
337 if (args[1] == null) {
338 throw new OptionError.FAILED ("no command specified");
341 foreach (var mapping in map) {
342 if (mapping.name == args[1]) {
343 mapping.func (args);
344 return 0;
348 throw new OptionError.FAILED ("unknown command %s", args[1]);
349 } catch (Error e) {
350 stderr.printf ("error: %s\n\n", e.message);
351 show_help (false, args[1]);
352 return 1;