Newer
Older
dub_jkp / source / dub / recipe / io.d
  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 = NativePath 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(NativePath(filename), parent_name);
  28. }
  29. /// ditto
  30. PackageRecipe readPackageRecipe(NativePath 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. default_package_name = Optional default package name (if no package name
  57. is found in the recipe this value will be used)
  58.  
  59. Returns: Returns the package recipe contents
  60. Throws: Throws an exception if an I/O or syntax error occurs
  61. */
  62. PackageRecipe parsePackageRecipe(string contents, string filename, string parent_name = null,
  63. string default_package_name = null)
  64. {
  65. import std.algorithm : endsWith;
  66. import dub.compilers.buildsettings : TargetType;
  67. import dub.internal.vibecompat.data.json;
  68. import dub.recipe.json : parseJson;
  69. import dub.recipe.sdl : parseSDL;
  70.  
  71. PackageRecipe ret;
  72.  
  73. ret.name = default_package_name;
  74.  
  75. if (filename.endsWith(".json")) parseJson(ret, parseJsonString(contents, filename), parent_name);
  76. else if (filename.endsWith(".sdl")) parseSDL(ret, contents, parent_name, filename);
  77. else assert(false, "readPackageRecipe called with filename with unknown extension: "~filename);
  78.  
  79. // Fix for issue #711: `targetType` should be inherited, or default to library
  80. TargetType defaultTT = (ret.buildSettings.targetType == TargetType.autodetect) ?
  81. TargetType.library : ret.buildSettings.targetType;
  82. foreach (ref conf; ret.configurations)
  83. if (conf.buildSettings.targetType == TargetType.autodetect)
  84. conf.buildSettings.targetType = defaultTT;
  85.  
  86. return ret;
  87. }
  88.  
  89.  
  90. unittest { // issue #711 - configuration default target type not correct for SDL
  91. import dub.compilers.buildsettings : TargetType;
  92. auto inputs = [
  93. "dub.sdl": "name \"test\"\nconfiguration \"a\" {\n}",
  94. "dub.json": "{\"name\": \"test\", \"configurations\": [{\"name\": \"a\"}]}"
  95. ];
  96. foreach (file, content; inputs) {
  97. auto pr = parsePackageRecipe(content, file);
  98. assert(pr.name == "test");
  99. assert(pr.configurations.length == 1);
  100. assert(pr.configurations[0].name == "a");
  101. assert(pr.configurations[0].buildSettings.targetType == TargetType.library);
  102. }
  103. }
  104.  
  105. unittest { // issue #711 - configuration default target type not correct for SDL
  106. import dub.compilers.buildsettings : TargetType;
  107. auto inputs = [
  108. "dub.sdl": "name \"test\"\ntargetType \"autodetect\"\nconfiguration \"a\" {\n}",
  109. "dub.json": "{\"name\": \"test\", \"targetType\": \"autodetect\", \"configurations\": [{\"name\": \"a\"}]}"
  110. ];
  111. foreach (file, content; inputs) {
  112. auto pr = parsePackageRecipe(content, file);
  113. assert(pr.name == "test");
  114. assert(pr.configurations.length == 1);
  115. assert(pr.configurations[0].name == "a");
  116. assert(pr.configurations[0].buildSettings.targetType == TargetType.library);
  117. }
  118. }
  119.  
  120. unittest { // issue #711 - configuration default target type not correct for SDL
  121. import dub.compilers.buildsettings : TargetType;
  122. auto inputs = [
  123. "dub.sdl": "name \"test\"\ntargetType \"executable\"\nconfiguration \"a\" {\n}",
  124. "dub.json": "{\"name\": \"test\", \"targetType\": \"executable\", \"configurations\": [{\"name\": \"a\"}]}"
  125. ];
  126. foreach (file, content; inputs) {
  127. auto pr = parsePackageRecipe(content, file);
  128. assert(pr.name == "test");
  129. assert(pr.configurations.length == 1);
  130. assert(pr.configurations[0].name == "a");
  131. assert(pr.configurations[0].buildSettings.targetType == TargetType.executable);
  132. }
  133. }
  134.  
  135.  
  136. /** Writes the textual representation of a package recipe to a file.
  137.  
  138. Note that the file extension must be either "json" or "sdl".
  139. */
  140. void writePackageRecipe(string filename, const scope ref PackageRecipe recipe)
  141. {
  142. import dub.internal.vibecompat.core.file : openFile, FileMode;
  143. auto f = openFile(filename, FileMode.createTrunc);
  144. scope(exit) f.close();
  145. serializePackageRecipe(f, recipe, filename);
  146. }
  147.  
  148. /// ditto
  149. void writePackageRecipe(NativePath filename, const scope ref PackageRecipe recipe)
  150. {
  151. writePackageRecipe(filename.toNativeString, recipe);
  152. }
  153.  
  154. /** Converts a package recipe to its textual representation.
  155.  
  156. The extension of the supplied `filename` must be either "json" or "sdl".
  157. The output format is chosen accordingly.
  158. */
  159. void serializePackageRecipe(R)(ref R dst, const scope ref PackageRecipe recipe, string filename)
  160. {
  161. import std.algorithm : endsWith;
  162. import dub.internal.vibecompat.data.json : writeJsonString;
  163. import dub.recipe.json : toJson;
  164. import dub.recipe.sdl : toSDL;
  165.  
  166. if (filename.endsWith(".json"))
  167. dst.writeJsonString!(R, true)(toJson(recipe));
  168. else if (filename.endsWith(".sdl"))
  169. toSDL(recipe).toSDLDocument(dst);
  170. else assert(false, "writePackageRecipe called with filename with unknown extension: "~filename);
  171. }