blob: a68159e372cd000fca1eb375ddeaa857ed2a47cc [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2011, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.nico.core.runtime;
import java.util.Map;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.IStreamListener;
import org.eclipse.debug.core.model.IFlushableStreamMonitor;
import org.eclipse.debug.core.model.IStreamMonitor;
import org.eclipse.debug.core.model.IStreamsProxy;
import org.eclipse.debug.core.model.RuntimeProcess;
/**
* Runtime process supporting logging of the process output without attaching a console
*/
public class LogRuntimeProcess extends RuntimeProcess {
private boolean fLogOnly;
private RuntimeProcessOutput fLog;
public LogRuntimeProcess(final ILaunch launch, final Process process, final String name,
final Map<String, String> attributes) {
super(launch, process, name, attributes);
}
@Override
protected IStreamsProxy createStreamsProxy() {
fLogOnly = ToolRunner.captureLogOnly(getLaunch().getLaunchConfiguration());
final IStreamsProxy proxy = super.createStreamsProxy();
if (fLogOnly) {
fLog = new RuntimeProcessOutput(proxy, fLogOnly);
}
return proxy;
}
@Override
public IStreamsProxy getStreamsProxy() {
if (!fLogOnly) {
return super.getStreamsProxy();
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(final Class<T> adapterType) {
if (adapterType == ILogOutput.class) {
return (T) fLog;
}
return super.getAdapter(adapterType);
}
}
class RuntimeProcessOutput implements ILogOutput {
private final class StreamListener implements IStreamListener {
private final IStreamMonitor fStreamMonitor;
private boolean fFlushed;
private StreamListener(final IStreamMonitor streamMonitor) {
fStreamMonitor = streamMonitor;
fStreamMonitor.addListener(this);
}
@Override
public void streamAppended(final String text, final IStreamMonitor monitor) {
if (!fFlushed) {
String contents = null;
synchronized (fStreamMonitor) {
fFlushed = true;
contents = fStreamMonitor.getContents();
if (fFlush && fStreamMonitor instanceof IFlushableStreamMonitor) {
final IFlushableStreamMonitor m = (IFlushableStreamMonitor) fStreamMonitor;
m.flushContents();
m.setBuffered(false);
}
}
append(contents);
}
else {
append(text);
}
}
public void init() {
streamAppended(null, fStreamMonitor);
}
public void dispose() {
fStreamMonitor.removeListener(this);
}
}
private final StringBuilder fStringBuilder = new StringBuilder(0x1000);
private StreamListener fOutputStreamListener;
private StreamListener fErrorStreamListener;
private final boolean fFlush;
private final int fHighWater;
private final int fLowWater;
public RuntimeProcessOutput(final IStreamsProxy proxy, final boolean flush) {
fFlush = flush;
fHighWater = 0x10000;
fLowWater = fHighWater - 0x1000;
fOutputStreamListener = new StreamListener(proxy.getOutputStreamMonitor());
fErrorStreamListener = new StreamListener(proxy.getErrorStreamMonitor());
fOutputStreamListener.init();
fErrorStreamListener.init();
}
private synchronized void append(final String text) {
if (text == null) {
return;
}
if (fStringBuilder.length() + text.length() > fHighWater) {
int idx = fStringBuilder.length() + text.length() - fLowWater;
boolean found = false;
while (idx < fStringBuilder.length()) {
final char c = fStringBuilder.charAt(idx++);
if (c == '\n' || c == '\r') {
found = true;
}
else if (found) {
idx--;
break;
}
}
fStringBuilder.delete(0, idx);
}
fStringBuilder.append(text);
}
public synchronized void dispose() {
if (fOutputStreamListener != null) {
fOutputStreamListener.dispose();
fOutputStreamListener = null;
}
if (fErrorStreamListener != null) {
fErrorStreamListener.dispose();
fErrorStreamListener = null;
}
}
@Override
public synchronized String getOutput() {
return fStringBuilder.toString();
}
}