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 }