ultimatepp/uppsrc/umk/Console.cpp
cxl ab794d7c33 umk: fixed to compile
git-svn-id: svn://ultimatepp.org/upp/trunk@15472 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2020-11-20 14:08:13 +00:00

297 lines
6 KiB
C++

#include "umake.h"
void ProcessEvents() {}
Console::Console() {
verbosebuild = false;
processes.SetCount(1);
console_lock = -1;
wrap_text = true;
console = false;
serial = 0;
}
void Console::Append(const String& s) {
if(!SilentMode)
Cout() << s;
}
int Console::Flush()
{
bool done_output = false;
int num_running = 0;
for(int i = 0; i < processes.GetCount(); i++)
if(!!processes[i].process)
num_running++;
if(num_running) {
int time = msecs();
for(int i = 0; i < processes.GetCount(); i++) {
Slot& slot = processes[i];
if(!!slot.process) {
Group& group = groups.GetAdd(slot.group);
group.msecs += (time - slot.last_msecs) / num_running;
group.raw_msecs += time - slot.last_msecs;
slot.last_msecs = time;
}
}
}
bool running = false;
for(int i = 0; i < processes.GetCount(); i++) {
Slot& slot = processes[i];
if(!slot.process)
continue;
String s;
slot.process->Read(s);
if(!IsNull(s)) {
done_output = true;
if(slot.outfile)
slot.outfile->Put(s);
if(!slot.quiet) {
if(console_lock < 0 || console_lock == i) {
console_lock = i;
Append(s);
}
else
slot.output.Cat(s);
}
}
if(!slot.process->IsRunning()) {
Kill(i);
if(slot.exitcode != 0 && verbosebuild)
spooled_output.Cat("Error executing " + slot.cmdline + "\n");
if(console_lock == i)
console_lock = -1;
FlushConsole();
CheckEndGroup();
continue;
}
running = true;
}
return !running ? -1 : done_output ? 1 : 0;
}
int Console::Execute(One<AProcess> p, const char *command, Stream *out, bool q)
{
Wait();
if(!Run(pick(p), command, out, q, 0))
return -1;
Wait();
return processes[0].exitcode;
}
int Console::Execute(const char *command, Stream *out, const char *envptr, bool q, bool)
{
try {
Wait();
One<AProcess> p;
if(p.Create<LocalProcess>().Start(command, envptr))
return Execute(pick(p), command, out, q);
}
catch(Exc e) {
}
ProcessEvents();
return Null;
}
int Console::AllocSlot()
{
int sleep = 0;
for(;;) {
for(int i = 0; i < processes.GetCount(); i++)
if(!IsRunning(i))
return i;
switch(Flush()) {
case -1: break;
case 0: sleep = min(sleep + 5, 20); break;
case +1: sleep = 0; break;
}
Sleep(sleep);
ProcessEvents();
}
}
bool Console::Run(const char *cmdline, Stream *out, const char *envptr, bool quiet, int slot, String key, int blitz_count)
{
try {
Wait(slot);
One<AProcess> sproc;
return sproc.Create<LocalProcess>().Start(cmdline, envptr) &&
Run(pick(sproc), cmdline, out, quiet, slot, key, blitz_count);
}
catch(Exc e) {
Append(e);
}
ProcessEvents();
return false;
}
bool Console::Run(One<AProcess> process, const char *cmdline, Stream *out, bool quiet, int slot, String key, int blitz_count)
{
if(!process) {
if(verbosebuild)
spooled_output << "Error running " << cmdline << "\n";
FlushConsole();
return false;
}
else if(verbosebuild)
spooled_output << cmdline << "\n";
Wait(slot);
Slot& pslot = processes[slot];
pslot.process = pick(process);
pslot.cmdline = cmdline;
pslot.outfile = out;
pslot.output = Null;
pslot.quiet = quiet;
pslot.key = key;
pslot.group = current_group;
pslot.last_msecs = msecs();
pslot.serial = ++serial;
groups.GetAdd(pslot.group).count += blitz_count;
if(processes.GetCount() == 1)
Wait(slot);
return true;
}
void Console::FlushConsole()
{
if(console_lock < 0) {
Append(spooled_output);
spooled_output = Null;
}
}
void Console::BeginGroup(String group)
{
Flush();
groups.GetAdd(current_group).finished = true;
groups.GetAdd(current_group = group);
CheckEndGroup();
}
void Console::EndGroup()
{
groups.GetAdd(current_group).finished = true;
CheckEndGroup();
current_group = Null;
}
bool Console::IsRunning()
{
for(int i = 0; i < processes.GetCount(); i++)
if(IsRunning(i))
return true;
return false;
}
bool Console::IsRunning(int slot)
{
if(slot < 0 || slot >= processes.GetCount() || !processes[slot].process)
return false;
return processes[slot].process->IsRunning();
}
void Console::Wait(int slot)
{
int sleep = 0;
while(processes[slot].process) {
ProcessEvents();
switch(Flush()) {
case -1: return;
case 0: sleep = min(sleep + 5, 20); break;
case +1: sleep = 0; break;
}
Sleep(sleep);
// Ctrl::GuiSleep(sleep);
}
}
bool Console::Wait()
{
int sleep = 0;
for(;;) {
ProcessEvents();
switch(Flush()) {
case -1: return error_keys.IsEmpty();
case 0: sleep = min(sleep + 5, 20); break;
case +1: sleep = 0; break;
}
Sleep(sleep);
// Ctrl::GuiSleep(sleep);
}
}
void Console::OnFinish(Event<> cb)
{
Finisher& f = finisher.Add();
f.serial = serial;
f.cb = cb;
}
void Console::Kill()
{
for(int i = 0; i < processes.GetCount(); i++)
Kill(i);
}
void Console::Kill(int islot)
{
Slot& slot = processes[islot];
if(slot.process) {
slot.process->Kill();
slot.exitcode = slot.process->GetExitCode();
if(slot.exitcode != 0 && !IsNull(slot.key))
error_keys.Add(slot.key);
slot.process.Clear();
spooled_output.Cat(slot.output);
if(console_lock == islot)
console_lock = -1;
FlushConsole();
}
CheckEndGroup();
int minserial = INT_MAX;
for(int i = 0; i < processes.GetCount(); i++)
minserial = min(processes[i].serial, minserial);
int i = 0;
while(i < finisher.GetCount()) {
const Finisher& f = finisher[i];
if(f.serial > minserial)
i++;
else {
f.cb();
finisher.Remove(i);
}
}
}
void Console::SetSlots(int s)
{
Kill();
processes.SetCount(s);
}
void Console::CheckEndGroup()
{
for(int g = groups.GetCount(); --g >= 0;) {
String gname = groups.GetKey(g);
Group& group = groups[g];
if(!IsNull(gname) && group.finished) {
int p = processes.GetCount();
while(--p >= 0 && !(!!processes[p].process && processes[p].group == gname))
;
if(p < 0) {
if(group.count > 0) {
String msg = NFormat("%s: %d file(s) built in %s, %d msecs / file",
gname, group.count, PrintTime(group.msecs), group.msecs / group.count);
msg << '\n';
spooled_output.Cat(msg);
if(console_lock < 0) {
Append(spooled_output);
spooled_output = Null;
}
}
groups.Remove(g);
}
}
}
}