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 : FileName; 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)(FileName 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 } 45 catch (CheckException ex) { 46 try { 47 msg = ex.toString; 48 } 49 catch (Exception ex) { 50 msg = ex.msg; 51 } 52 } 53 catch (Exception ex) { 54 msg = ex.msg; 55 } 56 57 try { 58 logger.errorf("Invalid xml file '%s'", cast(string) fname); 59 logger.error(msg); 60 } 61 catch (Exception ex) { 62 } 63 64 return rval; 65 } 66 67 /** Store the input in a configuration file to make it easy to regenerate the 68 * test double. 69 */ 70 ref AppT makeXmlLog(AppT)(ref AppT app, string[] raw_cli_flags,) { 71 import std.algorithm : joiner, copy, splitter; 72 import std.array : array; 73 import std.file : thisExePath; 74 import std.format : format; 75 import std.path : baseName; 76 import std.range : dropOne, drop, takeOne; 77 import std.utf : byChar; 78 import std.xml; 79 import dextool.utility : dextoolVersion; 80 import dextool.xml : makePrelude; 81 82 auto exe_r = thisExePath.baseName.splitter('-'); 83 84 auto exe_name = "dextool"; 85 foreach (a; exe_r.save.takeOne) { 86 exe_name = a; 87 } 88 89 auto plugin_name = "unknown_plugin"; 90 foreach (a; exe_r.save.dropOne) { 91 plugin_name = a; 92 } 93 94 auto cleaned_cli = raw_cli_flags.drop(2); 95 96 auto doc = new Document(new Tag("dextool")); 97 doc.tag.attr["version"] = dextoolVersion; 98 { 99 auto command = new Element("command"); 100 command ~= new CData(format("%s %s %s", exe_name, plugin_name, 101 cleaned_cli.joiner(" ").byChar.array().idup)); 102 doc ~= new Comment("command line when dextool was executed"); 103 doc ~= command; 104 } 105 106 makePrelude(app); 107 doc.pretty(4).joiner("\n").copy(app); 108 109 return app; 110 }