1 /** 2 A module for providing interop between reggae and dub 3 */ 4 5 module reggae.dub.interop; 6 7 import reggae.options; 8 import reggae.dub.info; 9 import reggae.dub.call; 10 import reggae.dub.json; 11 import std.stdio; 12 import std.exception; 13 import std.conv; 14 import std.process; 15 16 DubInfo[string] gDubInfos; 17 18 19 @safe: 20 21 void maybeCreateReggaefile(in Options options) { 22 if(options.isDubProject && !options.projectBuildFile.exists) { 23 createReggaefile(options); 24 } 25 } 26 27 void createReggaefile(in Options options) { 28 writeln("[Reggae] Creating reggaefile.d from dub information"); 29 auto file = File("reggaefile.d", "w"); 30 file.writeln("import reggae;"); 31 file.writeln("mixin build!(dubDefaultTarget!());"); 32 33 if(!options.noFetch) dubFetch(_getDubInfo(options)); 34 } 35 36 37 private DubInfo _getDubInfo(in Options options) { 38 39 if("default" !in gDubInfos) { 40 immutable dubBuildArgs = ["dub", "--annotate", "build", "--compiler=dmd", "--print-configs"]; 41 immutable dubBuildOutput = _callDub(options, dubBuildArgs); 42 immutable configs = getConfigurations(dubBuildOutput); 43 44 if(configs.configurations.empty) { 45 immutable descArgs = ["dub", "describe"]; 46 immutable descOutput = _callDub(options, descArgs); 47 gDubInfos["default"] = getDubInfo(descOutput); 48 } else { 49 foreach(config; configs.configurations) { 50 immutable descArgs = ["dub", "describe", "-c", config]; 51 immutable descOutput = _callDub(options, descArgs); 52 gDubInfos[config] = getDubInfo(descOutput); 53 54 //dub adds certain flags to certain configurations automatically but these flags 55 //don't know up in the output to `dub describe`. Special case them here. 56 57 //unittest should only apply to the main package, hence [0] 58 if(config == "unittest") gDubInfos[config].packages[0].flags ~= " -unittest"; 59 60 } 61 gDubInfos["default"] = gDubInfos[configs.default_]; 62 } 63 } 64 65 return gDubInfos["default"]; 66 } 67 68 69 private string _callDub(in Options options, in string[] args) { 70 import std.process; 71 const string[string] env = null; 72 Config config = Config.none; 73 size_t maxOutput = size_t.max; 74 immutable workDir = options.projectPath; 75 76 immutable ret = execute(args, env, config, maxOutput, workDir); 77 enforce(ret.status == 0, text("Error calling ", args.join(" "), ":\n", 78 ret.output)); 79 return ret.output; 80 } 81 82 private void dubFetch(in DubInfo dubInfo) { 83 foreach(cmd; dubInfo.fetchCommands) { 84 immutable cmdStr = "'" ~ cmd.join(" ") ~ "'"; 85 writeln("Fetching package with cmd ", cmdStr); 86 immutable ret = execute(cmd); 87 if(ret.status) { 88 () @trusted { 89 stderr.writeln("Could not execute dub fetch with:\n", cmd.join(" "), "\n", 90 ret.output); 91 }(); 92 } 93 } 94 } 95 96 97 void writeDubConfig(in Options options, File file) { 98 file.writeln("import reggae.dub.info;"); 99 if(options.isDubProject) { 100 file.writeln("enum isDubProject = true;"); 101 auto dubInfo = _getDubInfo(options); 102 immutable targetType = dubInfo.packages[0].targetType; 103 enforce(targetType == "executable" || targetType == "library" || targetType == "staticLibrary", 104 text("Unsupported dub targetType '", targetType, "'")); 105 106 file.writeln(`const configToDubInfo = assocList([`); 107 108 const keys = () @trusted { return gDubInfos.keys; }(); 109 foreach(config; keys) { 110 file.writeln(` assocEntry("`, config, `", `, gDubInfos[config], `),`); 111 } 112 file.writeln(`]);`); 113 file.writeln; 114 } else { 115 file.writeln("enum isDubProject = false;"); 116 } 117 }