config.ck 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. config.ck
  9. Abstract:
  10. This module implements the config command for Santa.
  11. Author:
  12. Evan Green 24-May-2017
  13. Environment:
  14. Chalk
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. import io;
  20. from getopt import gnuGetopt;
  21. from json import dumps, loads;
  22. from santa.config import config;
  23. from santa.lib.santaconfig import SantaConfig;
  24. //
  25. // --------------------------------------------------------------------- Macros
  26. //
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. //
  31. // ------------------------------------------------------ Data Type Definitions
  32. //
  33. //
  34. // ----------------------------------------------- Internal Function Prototypes
  35. //
  36. function
  37. _listConfig (
  38. actor,
  39. json
  40. );
  41. function
  42. _printConfigValue (
  43. prefix,
  44. value
  45. );
  46. //
  47. // -------------------------------------------------------------------- Globals
  48. //
  49. var description = "Get or set application parameters";
  50. var shortOptions = "af:hjlrsu";
  51. var longOptions = [
  52. "add",
  53. "file=",
  54. "help",
  55. "json",
  56. "list",
  57. "remove",
  58. "system",
  59. "user"
  60. ];
  61. var usage =
  62. "usage: santa config [options] key\n"
  63. " santa config [options] key value [value...]\n"
  64. "santa config gets or sets an application configuration value.\n"
  65. "Valid options are:\n"
  66. " -f, --file=file -- Work on the specified config file.\n"
  67. " -j, --json -- Print the result in JSON or read the value as JSON.\n"
  68. " -s, --system -- Work on the system store rather than the user's store.\n"
  69. " -u, --user -- Work on the user store instead of the combination of "
  70. "all stores\n"
  71. " -r, --remove -- Remove the given key\n"
  72. " -a, --add -- Add to the given key instead of replacing it.\n"
  73. " -l, --list -- List all values found in the store.\n";
  74. //
  75. // ------------------------------------------------------------------ Functions
  76. //
  77. function
  78. command (
  79. args
  80. )
  81. /*++
  82. Routine Description:
  83. This routine implements the config command.
  84. Arguments:
  85. args - Supplies the arguments to the function.
  86. Return Value:
  87. Returns an exit code.
  88. --*/
  89. {
  90. var action = null;
  91. var actioncount = 0;
  92. var actor = config;
  93. var argc;
  94. var json = false;
  95. var list = false;
  96. var name;
  97. var options = gnuGetopt(args[1...-1], shortOptions, longOptions);
  98. var previous;
  99. var value;
  100. args = options[1];
  101. argc = args.length();
  102. options = options[0];
  103. for (option in options) {
  104. name = option[0];
  105. value = option[1];
  106. if ((name == "-a") || (name == "--add")) {
  107. action = "add";
  108. actioncount += 1;
  109. } else if ((name == "-f") || (name == "--file")) {
  110. config.__init(value, {});
  111. } else if ((name == "-s") || (name == "--system")) {
  112. actor = actor._global;
  113. } else if ((name == "-h") || (name == "--help")) {
  114. Core.print(usage);
  115. return 1;
  116. } else if ((name == "-j") || (name == "--json")) {
  117. json = true;
  118. } else if ((name == "-l") || (name == "--list")) {
  119. list = true;
  120. } else if ((name == "-r") || (name == "--remove")) {
  121. action = "remove";
  122. actioncount += 1;
  123. } else if ((name == "-u") || (name == "--user")) {
  124. actor = actor._user;
  125. } else {
  126. Core.raise(ValueError("Invalid option '%s'" % name));
  127. }
  128. }
  129. if (list) {
  130. if ((argc != 0) || (actioncount != 0)) {
  131. Core.raise(ValueError("Expected no arguments with --list"));
  132. }
  133. _listConfig(actor, json);
  134. return 0;
  135. }
  136. if (actioncount > 1) {
  137. Core.raise(ValueError("Specify only one action"));
  138. }
  139. if (argc == 0) {
  140. Core.raise(ValueError("Expected an argument"));
  141. }
  142. //
  143. // If no actor was specified and this is not a get operation, default to
  144. // the user store. Otherwise the action is performed on the override store,
  145. // causing no changes to stick, which is probably not what the user wanted.
  146. //
  147. if ((action != null) || (argc != 1)) {
  148. if (actor is SantaConfig) {
  149. actor = actor._user;
  150. }
  151. }
  152. if (argc == 1) {
  153. if (action == "remove") {
  154. actor.setKey(args[0], null);
  155. actor.save();
  156. } else if (action == null) {
  157. value = actor.getKey(args[0]);
  158. if ((value is Dict) || (value is List) || (json != false)) {
  159. Core.print(dumps(value, 4));
  160. } else {
  161. Core.print(value.__str());
  162. }
  163. } else {
  164. Core.raise(ValueError("Cannot perform %s with only one argument" %
  165. action));
  166. }
  167. } else if (argc == 2) {
  168. value = args[1];
  169. if (json != false) {
  170. value = loads(value);
  171. } else {
  172. //
  173. // Convert true, false, and anything that looks like a number. To
  174. // override this behavior, use the --json flag.
  175. //
  176. if (value == "true") {
  177. value = true;
  178. } else if (value == "false") {
  179. value = false;
  180. } else {
  181. try {
  182. value = Int.fromString(value);
  183. } except ValueError {}
  184. }
  185. }
  186. if (action == "add") {
  187. previous = actor.getKey(args[0]);
  188. if (previous != null) {
  189. if (previous is List) {
  190. previous.append(value);
  191. value = previous;
  192. } else {
  193. value = [previous, value];
  194. }
  195. }
  196. actor.setKey(args[0], value);
  197. actor.save();
  198. } else if (action == null) {
  199. actor.setKey(args[0], value);
  200. actor.save();
  201. } else {
  202. Core.raise(ValueError("Cannot perform %s with two arguments" %
  203. action));
  204. }
  205. //
  206. // Many arguments.
  207. //
  208. } else {
  209. value = [];
  210. if (action == "add") {
  211. previous = actor.getKey(args[0]);
  212. if (previous != null) {
  213. if (previous is List) {
  214. value = previous;
  215. } else {
  216. value = [previous];
  217. }
  218. }
  219. }
  220. for (arg in args[1...-1]) {
  221. if (json) {
  222. arg = loads(arg);
  223. }
  224. value.append(arg);
  225. }
  226. if ((action == null) || (action == "add")) {
  227. actor.setKey(args[0], value);
  228. actor.save();
  229. } else {
  230. Core.raise(ValueError("Cannot perform %s with many arguments" %
  231. action));
  232. }
  233. }
  234. return 0;
  235. }
  236. //
  237. // --------------------------------------------------------- Internal Functions
  238. //
  239. function
  240. _listConfig (
  241. actor,
  242. json
  243. )
  244. /*++
  245. Routine Description:
  246. This routine lists the configuration for the given dictionary.
  247. Arguments:
  248. actor - Supplies the configuration to work on.
  249. json - Supplies whether or not to print in JSON format.
  250. Return Value:
  251. Returns an exit code.
  252. --*/
  253. {
  254. actor = actor.dict();
  255. if (json) {
  256. Core.print(dumps(actor, 4));
  257. } else {
  258. _printConfigValue("", actor);
  259. }
  260. return 0;
  261. }
  262. function
  263. _printConfigValue (
  264. prefix,
  265. value
  266. )
  267. /*++
  268. Routine Description:
  269. This routine prints a configuration value, recursively.
  270. Arguments:
  271. prefix - Supplies the prefix to print on all values.
  272. value - Supplies the value to print.
  273. Return Value:
  274. None.
  275. --*/
  276. {
  277. var index;
  278. if (value is Dict) {
  279. if (prefix != "") {
  280. prefix += ".";
  281. }
  282. for (key in value) {
  283. _printConfigValue("%s%s" % [prefix, key.__str()], value[key]);
  284. }
  285. } else if (value is List) {
  286. for (index in 0..value.length()) {
  287. _printConfigValue("%s[%d]" % [prefix, index], value[index]);
  288. }
  289. } else {
  290. Core.print("%s = %s" % [prefix, value.__str()]);
  291. }
  292. return;
  293. }