1 module dlangide.builders.builder; 2 3 import dlangui.core.logger; 4 import dlangide.workspace.project; 5 import dlangide.workspace.workspace; 6 import dlangide.ui.outputpanel; 7 import dlangide.builders.extprocess; 8 import dlangui.widgets.appframe; 9 import std.algorithm; 10 import std.array; 11 import core.thread; 12 import std.string; 13 import std.conv; 14 15 alias BuildResultListener = void delegate(int); 16 17 class Builder : BackgroundOperationWatcher { 18 protected Project _project; 19 protected ExternalProcess _extprocess; 20 protected OutputPanel _log; 21 protected ProtectedTextStorage _box; 22 protected ProjectConfiguration _projectConfig; 23 protected BuildConfiguration _buildConfig; 24 protected BuildOperation _buildOp; 25 protected bool _verbose; 26 protected BuildResultListener _listener; 27 protected int _exitCode = int.min; 28 protected string _toolchain; 29 protected string _arch; 30 31 @property Project project() { return _project; } 32 @property void project(Project p) { _project = p; } 33 34 this(AppFrame frame, Project project, OutputPanel log, ProjectConfiguration projectConfig, BuildConfiguration buildConfig, 35 BuildOperation buildOp, bool verbose, 36 string toolchain = null, 37 string arch = null, 38 BuildResultListener listener = null) { 39 super(frame); 40 _listener = listener; 41 _projectConfig = projectConfig; 42 _buildConfig = buildConfig; 43 _buildOp = buildOp; 44 _verbose = verbose; 45 _project = project; 46 _log = log; 47 _toolchain = toolchain; 48 _arch = arch; 49 _extprocess = new ExternalProcess(); 50 _box = new ProtectedTextStorage(); 51 } 52 53 /// log lines 54 void pollText() { 55 dstring text = _box.readText(); 56 if (text.length) { 57 _log.appendText(null, text); 58 } 59 } 60 61 /// returns icon of background operation to show in status line 62 override @property string icon() { return "folder"; } 63 /// update background operation status 64 override void update() { 65 scope(exit)pollText(); 66 ExternalProcessState state = _extprocess.state; 67 if (state == ExternalProcessState.None) { 68 _log.clear(); 69 _box.writeText("Running dub\n"d); 70 char[] program = "dub".dup; 71 char[][] params; 72 char[] dir = _project.dir.dup; 73 74 if (_buildOp == BuildOperation.Build || _buildOp == BuildOperation.Rebuild) { 75 params ~= "build".dup; 76 if (_buildOp == BuildOperation.Rebuild) { 77 params ~= "--force".dup; 78 } 79 if (!_arch.empty) 80 params ~= ("--arch=" ~ _arch).dup; 81 if (!_toolchain.empty) 82 params ~= ("--compiler=" ~ _toolchain).dup; 83 params ~= "--build-mode=allAtOnce".dup; 84 } else if (_buildOp == BuildOperation.Clean) { 85 params ~= "clean".dup; 86 } else if (_buildOp == BuildOperation.Run) { 87 if (_projectConfig.type == ProjectConfiguration.Type.Library) { 88 params ~= "test".dup; 89 } else { 90 params ~= "run".dup; 91 } 92 } else if (_buildOp == BuildOperation.Upgrade) { 93 params ~= "upgrade".dup; 94 params ~= "--force-remove".dup; 95 } 96 97 if (_buildOp != BuildOperation.Clean && _buildOp != BuildOperation.Upgrade) { 98 switch (_buildConfig) { 99 default: 100 case BuildConfiguration.Debug: 101 params ~= "--build=debug".dup; 102 break; 103 case BuildConfiguration.Release: 104 params ~= "--build=release".dup; 105 break; 106 case BuildConfiguration.Unittest: 107 params ~= "--build=unittest".dup; 108 break; 109 } 110 } 111 112 if(_projectConfig.name != ProjectConfiguration.DEFAULT_NAME) { 113 params ~= "--config=".dup ~ _projectConfig.name; 114 } 115 116 if (_verbose) 117 params ~= "-v".dup; 118 119 state = _extprocess.run(program, params, dir, _box, null); 120 if (state != ExternalProcessState.Running) { 121 _box.writeText("Failed to run builder tool\n"d); 122 _finished = true; 123 destroy(_extprocess); 124 _extprocess = null; 125 return; 126 } 127 } 128 state = _extprocess.poll(); 129 if (state == ExternalProcessState.Stopped) { 130 _exitCode = _extprocess.result; 131 _box.writeText("Builder finished with result "d ~ to!dstring(_extprocess.result) ~ "\n"d); 132 _finished = true; 133 return; 134 } 135 if (_cancelRequested) { 136 _extprocess.kill(); 137 _extprocess.wait(); 138 _finished = true; 139 return; 140 } 141 super.update(); 142 } 143 override void removing() { 144 super.removing(); 145 if (_exitCode != int.min && _listener) 146 _listener(_exitCode); 147 } 148 }