Newer
Older
dub_jkp / source / dub / package_.d
  1. /**
  2. Stuff with dependencies.
  3.  
  4. Copyright: © 2012 Matthias Dondorff
  5. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
  6. Authors: Matthias Dondorff
  7. */
  8. module dub.package_;
  9.  
  10. import dub.compilers.compiler;
  11. import dub.dependency;
  12. import dub.utils;
  13.  
  14. import std.array;
  15. import std.conv;
  16. import std.exception;
  17. import std.file;
  18. import vibecompat.core.log;
  19. import vibecompat.core.file;
  20. import vibecompat.data.json;
  21. import vibecompat.inet.url;
  22.  
  23. enum PackageJsonFilename = "package.json";
  24.  
  25.  
  26. /// Indicates where a package has been or should be installed to.
  27. enum InstallLocation {
  28. local,
  29. projectLocal,
  30. userWide,
  31. systemWide
  32. }
  33.  
  34. /// Representing an installed package, usually constructed from a json object.
  35. ///
  36. /// Json file example:
  37. /// {
  38. /// "name": "MetalCollection",
  39. /// "author": "VariousArtists",
  40. /// "version": "1.0.0",
  41. /// "url": "https://github.org/...",
  42. /// "keywords": "a,b,c",
  43. /// "category": "music.best",
  44. /// "dependencies": {
  45. /// "black-sabbath": ">=1.0.0",
  46. /// "CowboysFromHell": "<1.0.0",
  47. /// "BeneathTheRemains": {"version": "0.4.1", "path": "./beneath-0.4.1"}
  48. /// }
  49. /// "licenses": {
  50. /// ...
  51. /// }
  52. /// "configurations": {
  53. // TODO: what and how?
  54. /// }
  55. // TODO: plain like this or packed together?
  56. /// "
  57. /// "dflags-X"
  58. /// "lflags-X"
  59. /// "libs-X"
  60. /// "files-X"
  61. /// "copyFiles-X"
  62. /// "versions-X"
  63. /// "importPaths-X"
  64. /// "stringImportPaths-X"
  65. ///
  66. /// }
  67. /// }
  68. ///
  69. /// TODO: explain configurations
  70. class Package {
  71. static struct LocalPackageDef { string name; Version version_; Path path; }
  72.  
  73. private {
  74. InstallLocation m_location;
  75. Path m_path;
  76. Json m_meta;
  77. Dependency[string] m_dependencies;
  78. LocalPackageDef[] m_localPackageDefs;
  79. }
  80.  
  81. this(InstallLocation location, Path root)
  82. {
  83. this(jsonFromFile(root ~ PackageJsonFilename), location, root);
  84. }
  85.  
  86. this(Json packageInfo, InstallLocation location = InstallLocation.local, Path root = Path())
  87. {
  88. m_location = location;
  89. m_path = root;
  90. m_meta = packageInfo;
  91.  
  92. // extract dependencies and local package definitions
  93. if( auto pd = "dependencies" in packageInfo ){
  94. foreach( string pkg, verspec; *pd ) {
  95. enforce(pkg !in m_dependencies, "The dependency '"~pkg~"' is specified more than once." );
  96. if( verspec.type == Json.Type.Object ){
  97. // full blown specifier
  98. auto ver = verspec["version"].get!string;
  99. m_dependencies[pkg] = new Dependency("==", ver);
  100. m_localPackageDefs ~= LocalPackageDef(pkg, Version(ver), Path(verspec.path.get!string()));
  101. } else {
  102. // canonical "package-id": "version"
  103. m_dependencies[pkg] = new Dependency(verspec.get!string());
  104. }
  105. }
  106. }
  107. }
  108. @property string name() const { return cast(string)m_meta["name"]; }
  109. @property string vers() const { return cast(string)m_meta["version"]; }
  110. @property Version ver() const { return Version(m_meta["version"].get!string); }
  111. @property installLocation() const { return m_location; }
  112. @property Path path() const { return m_path; }
  113. @property const(Url) url() const { return Url.parse(cast(string)m_meta["url"]); }
  114. @property const(Dependency[string]) dependencies() const { return m_dependencies; }
  115. @property const(LocalPackageDef)[] localPackageDefs() const { return m_localPackageDefs; }
  116. @property string binaryPath() const { return m_meta["binaryPath"].opt!string; }
  117. @property string[] configurations()
  118. const {
  119. auto pv = "configurations" in m_meta;
  120. if( !pv ) return null;
  121. auto ret = appender!(string[])();
  122. foreach( string k, _; *pv )
  123. ret.put(k);
  124. return ret.data;
  125. }
  126.  
  127. /// Returns all BuildSettings for the given platform and config.
  128. BuildSettings getBuildSettings(BuildPlatform platform, string config)
  129. const {
  130. BuildSettings ret;
  131. ret.parse(m_meta, platform);
  132. if( config.length ){
  133. auto pcs = "configurations" in m_meta;
  134. if( !pcs ) return ret;
  135. auto pc = config in *pcs;
  136. if( !pc ) return ret;
  137. ret.parse(*pc, platform);
  138. }
  139. return ret;
  140. }
  141. /// Returns all sources as relative paths, prepend each with
  142. /// path() to get the absolute one.
  143. @property const(Path[]) sources() const {
  144. Path[] allSources;
  145. auto sourcePath = Path("source");
  146. auto customSourcePath = "sourcePath" in m_meta;
  147. if(customSourcePath)
  148. sourcePath = Path(customSourcePath.get!string());
  149. logTrace("Parsing directory for sources: %s", m_path ~ sourcePath);
  150. foreach(d; dirEntries((m_path ~ sourcePath).toNativeString(), "*.d", SpanMode.depth)) {
  151. // direct assignment allSources ~= Path(d.name)[...] spawns internal compiler/linker error
  152. if(isDir(d.name)) continue;
  153. auto p = Path(d.name);
  154. allSources ~= p[m_path.length..$];
  155. }
  156. return allSources;
  157. }
  158. /// TODO: what is the defaul configuration?
  159. string getDefaultConfiguration(BuildPlatform platform)
  160. const {
  161. string ret;
  162. auto cfgs = m_meta["configurations"].opt!(Json[string]);
  163. foreach( suffix; getPlatformSuffixIterator(platform) )
  164. if( auto pv = ("default"~suffix) in cfgs )
  165. ret = pv.get!string();
  166. return ret;
  167. }
  168.  
  169. /// Humanly readible information of this package and its dependencies.
  170. string info() const {
  171. string s;
  172. s ~= cast(string)m_meta["name"] ~ ", version '" ~ cast(string)m_meta["version"] ~ "'";
  173. s ~= "\n Dependencies:";
  174. foreach(string p, ref const Dependency v; m_dependencies)
  175. s ~= "\n " ~ p ~ ", version '" ~ to!string(v) ~ "'";
  176. return s;
  177. }
  178. /// direct access to the json of this package
  179. @property ref Json json() { return m_meta; }
  180. /// Writes the json file back to the filesystem
  181. void writeJson(Path path) {
  182. auto dstFile = openFile((path~PackageJsonFilename).toString(), FileMode.CreateTrunc);
  183. scope(exit) dstFile.close();
  184. dstFile.writePrettyJsonString(m_meta);
  185. }
  186. }