1 /** 2 Package recipe reading/writing facilities. 3 4 Copyright: © 2015-2016, Sönke Ludwig 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dub.recipe.io; 9 10 import dub.recipe.packagerecipe; 11 import dub.internal.vibecompat.inet.path; 12 13 14 /** Reads a package recipe from a file. 15 16 The file format (JSON/SDLang) will be determined from the file extension. 17 18 Params: 19 filename = Path of the package recipe file 20 parent_name = Optional name of the parent package (if this is a sub package) 21 22 Returns: Returns the package recipe contents 23 Throws: Throws an exception if an I/O or syntax error occurs 24 */ 25 PackageRecipe readPackageRecipe(string filename, string parent_name = null) 26 { 27 return readPackageRecipe(Path(filename), parent_name); 28 } 29 /// ditto 30 PackageRecipe readPackageRecipe(Path filename, string parent_name = null) 31 { 32 import dub.internal.utils : stripUTF8Bom; 33 import dub.internal.vibecompat.core.file : openFile, FileMode; 34 35 string text; 36 37 { 38 auto f = openFile(filename.toNativeString(), FileMode.read); 39 scope(exit) f.close(); 40 text = stripUTF8Bom(cast(string)f.readAll()); 41 } 42 43 return parsePackageRecipe(text, filename.toNativeString(), parent_name); 44 } 45 46 /** Parses an in-memory package recipe. 47 48 The file format (JSON/SDLang) will be determined from the file extension. 49 50 Params: 51 contents = The contents of the recipe file 52 filename = Name associated with the package recipe - this is only used 53 to determine the file format from the file extension 54 parent_name = Optional name of the parent package (if this is a sub 55 package) 56 57 Returns: Returns the package recipe contents 58 Throws: Throws an exception if an I/O or syntax error occurs 59 */ 60 PackageRecipe parsePackageRecipe(string contents, string filename, string parent_name = null) 61 { 62 import std.algorithm : endsWith; 63 import dub.internal.vibecompat.data.json; 64 import dub.recipe.json : parseJson; 65 import dub.recipe.sdl : parseSDL; 66 67 PackageRecipe ret; 68 69 if (filename.endsWith(".json")) parseJson(ret, parseJsonString(contents, filename), parent_name); 70 else if (filename.endsWith(".sdl")) parseSDL(ret, contents, parent_name, filename); 71 else assert(false, "readPackageRecipe called with filename with unknown extension: "~filename); 72 return ret; 73 } 74 75 76 unittest { // issue #711 - configuration default target type not correct for SDL 77 import dub.compilers.buildsettings : TargetType; 78 auto inputs = [ 79 "dub.sdl": "name \"test\"\nconfiguration \"a\" {\n}", 80 "dub.json": "{\"name\": \"test\", \"configurations\": [{\"name\": \"a\"}]}" 81 ]; 82 foreach (file, content; inputs) { 83 auto pr = parsePackageRecipe(content, file); 84 assert(pr.name == "test"); 85 assert(pr.configurations.length == 1); 86 assert(pr.configurations[0].name == "a"); 87 assert(pr.configurations[0].buildSettings.targetType == TargetType.library); 88 } 89 } 90 91 unittest { // issue #711 - configuration default target type not correct for SDL 92 import dub.compilers.buildsettings : TargetType; 93 auto inputs = [ 94 "dub.sdl": "name \"test\"\ntargetType \"autodetect\"\nconfiguration \"a\" {\n}", 95 "dub.json": "{\"name\": \"test\", \"targetType\": \"autodetect\", \"configurations\": [{\"name\": \"a\"}]}" 96 ]; 97 foreach (file, content; inputs) { 98 auto pr = parsePackageRecipe(content, file); 99 assert(pr.name == "test"); 100 assert(pr.configurations.length == 1); 101 assert(pr.configurations[0].name == "a"); 102 assert(pr.configurations[0].buildSettings.targetType == TargetType.library); 103 } 104 } 105 106 unittest { // issue #711 - configuration default target type not correct for SDL 107 import dub.compilers.buildsettings : TargetType; 108 auto inputs = [ 109 "dub.sdl": "name \"test\"\ntargetType \"executable\"\nconfiguration \"a\" {\n}", 110 "dub.json": "{\"name\": \"test\", \"targetType\": \"executable\", \"configurations\": [{\"name\": \"a\"}]}" 111 ]; 112 foreach (file, content; inputs) { 113 auto pr = parsePackageRecipe(content, file); 114 assert(pr.name == "test"); 115 assert(pr.configurations.length == 1); 116 assert(pr.configurations[0].name == "a"); 117 assert(pr.configurations[0].buildSettings.targetType == TargetType.executable); 118 } 119 } 120 121 122 /** Writes the textual representation of a package recipe to a file. 123 124 Note that the file extension must be either "json" or "sdl". 125 */ 126 void writePackageRecipe(string filename, in ref PackageRecipe recipe) 127 { 128 import dub.internal.vibecompat.core.file : openFile, FileMode; 129 auto f = openFile(filename, FileMode.createTrunc); 130 scope(exit) f.close(); 131 serializePackageRecipe(f, recipe, filename); 132 } 133 134 /// ditto 135 void writePackageRecipe(Path filename, in ref PackageRecipe recipe) 136 { 137 writePackageRecipe(filename.toNativeString, recipe); 138 } 139 140 /** Converts a package recipe to its textual representation. 141 142 The extension of the supplied `filename` must be either "json" or "sdl". 143 The output format is chosen accordingly. 144 */ 145 void serializePackageRecipe(R)(ref R dst, in ref PackageRecipe recipe, string filename) 146 { 147 import std.algorithm : endsWith; 148 import dub.internal.vibecompat.data.json : writeJsonString; 149 import dub.recipe.json : toJson; 150 import dub.recipe.sdl : toSDL; 151 152 if (filename.endsWith(".json")) 153 dst.writeJsonString!(R, true)(toJson(recipe)); 154 else if (filename.endsWith(".sdl")) 155 toSDL(recipe).toSDLDocument(dst); 156 else assert(false, "writePackageRecipe called with filename with unknown extension: "~filename); 157 } 158