1 module reggae.backend.tup; 2 3 4 import reggae.build; 5 import reggae.range; 6 import reggae.options; 7 import std.array; 8 import std.typecons; 9 10 @safe: 11 12 struct Tup { 13 enum fileName = "Tupfile"; 14 15 Build build; 16 const(Options) options; 17 18 this(Build build, in string projectPath) { 19 import reggae.config: options; 20 auto modOptions = options.dup; 21 modOptions.projectPath = projectPath; 22 this(build, modOptions); 23 } 24 25 this(Build build, in Options options) { 26 this.build = build; 27 this.options = options; 28 } 29 30 string output() pure { 31 auto ret = banner ~ lines.join("\n") ~ "\n"; 32 if(options.export_) ret = options.eraseProjectPath(ret); 33 return ret; 34 } 35 36 string[] lines() pure { 37 38 string[] lines; 39 foreach(target; build.range) { 40 if(target.getCommandType == CommandType.code) 41 throw new Exception("Command type 'code' not supported for tup backend"); 42 43 //tup does its own dependency detection, trying to output 44 //dependency files actually causes an error, so we request 45 //none to be generated 46 immutable line = ": " ~ 47 target.dependenciesInProjectPath(options.projectPath).join(" ") ~ " |> " ~ 48 target.shellCommand(options, No.dependencies) ~ " |> " ~ 49 target.expandOutputs(options.projectPath).join(" "); 50 lines ~= line; 51 } 52 return lines; 53 } 54 55 void writeBuild() @system { 56 import std.file; 57 import std.string; 58 import std.stdio; 59 import std.path; 60 import std.process; 61 62 if(!".tup".exists) { 63 immutable args = ["tup", "init"]; 64 const string[string] env = null; 65 Config config = Config.none; 66 size_t maxOutput = size_t.max; 67 68 try 69 execute(args, env, config, maxOutput, options.workingDir); 70 catch(ProcessException _) 71 stderr.writeln("Could not execute '", args.join(" "), 72 "'. tup builds need to do that first."); 73 } 74 auto file = File(buildPath(options.workingDir, fileName), "w"); 75 file.write(output); 76 } 77 }