1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 
10 Helper functions for xml reading and writing.
11 */
12 module dextool.xml;
13 
14 import std.typecons : Nullable;
15 
16 import logger = std.experimental.logger;
17 
18 import dextool.type : Path;
19 
20 /// Generate the xml prelude.
21 void makePrelude(AppT)(ref AppT app) {
22     import std.format : formattedWrite;
23 
24     formattedWrite(app, `<?xml version="1.0" encoding="UTF-8"?>` ~ "\n");
25 }
26 
27 /// Parse an xml file.
28 Nullable!T readRawConfig(T, alias parseFunc)(Path fname) @trusted nothrow {
29     static import std.file;
30     import std.utf : validate;
31     import std.xml;
32 
33     string msg;
34     Nullable!T rval;
35 
36     try {
37         string fin = cast(string) std.file.read(fname);
38         validate(fin);
39         check(fin);
40         auto xml = new DocumentParser(fin);
41 
42         rval = parseFunc(xml);
43         return rval;
44     } catch (CheckException ex) {
45         try {
46             msg = ex.toString;
47         } catch (Exception ex) {
48             msg = ex.msg;
49         }
50     } catch (Exception ex) {
51         msg = ex.msg;
52     }
53 
54     try {
55         logger.errorf("Invalid xml file '%s'", cast(string) fname);
56         logger.error(msg);
57     } catch (Exception ex) {
58     }
59 
60     return rval;
61 }
62 
63 /** Store the input in a configuration file to make it easy to regenerate the
64  * test double.
65  */
66 ref AppT makeXmlLog(AppT)(ref AppT app, string[] raw_cli_flags,) {
67     import std.algorithm : joiner, copy, splitter;
68     import std.array : array;
69     import std.file : thisExePath;
70     import std.format : format;
71     import std.path : baseName;
72     import std.range : dropOne, drop, takeOne;
73     import std.utf : byChar;
74     import std.xml;
75     import dextool.utility : dextoolVersion;
76     import dextool.xml : makePrelude;
77 
78     auto exe_r = thisExePath.baseName.splitter('-');
79 
80     auto exe_name = "dextool";
81     foreach (a; exe_r.save.takeOne) {
82         exe_name = a;
83     }
84 
85     auto plugin_name = "unknown_plugin";
86     foreach (a; exe_r.save.dropOne) {
87         plugin_name = a;
88     }
89 
90     // dropping first argument in commandline (i.e. '/path/to/dextool/dextool-mainfname')
91     auto cleaned_cli = raw_cli_flags.drop(1);
92 
93     auto doc = new Document(new Tag("dextool"));
94     doc.tag.attr["version"] = dextoolVersion.get;
95     {
96         auto command = new Element("command");
97         command ~= new CData(format("%s %s %s", exe_name, plugin_name,
98                 cleaned_cli.joiner(" ").byChar.array().idup));
99         doc ~= new Comment("command line when dextool was executed");
100         doc ~= command;
101     }
102 
103     makePrelude(app);
104     doc.pretty(4).joiner("\n").copy(app);
105 
106     return app;
107 }