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 }