view src/org/tmatesoft/hg/internal/ProcessExecHelper.java @ 568:8ed4f4f4f0a6

Blame facility refactored, get ready for follow/no-follow support
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 10 Apr 2013 15:45:53 +0200
parents 9c9c442b5f2e
children
line wrap: on
line source
/*
 * Copyright (c) 2012 TMate Software Ltd
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@hg4j.com
 */
package org.tmatesoft.hg.internal;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * Utility to run shell commands. Not thread-safe.
 * Beware of memory overcommitment issue on Linux - suprocess get allocated virtual memory of parent process size
 * @see http://developers.sun.com/solaris/articles/subprocess/subprocess.html
 * 
 * @author Artem Tikhomirov
 * @author TMate Software Ltd.
 */
public class ProcessExecHelper {
	private File dir;
	private int exitValue;
	private ProcessBuilder pb;
	
	public ProcessExecHelper() {
	}
	
	protected List<String> prepareCommand(List<String> cmd) {
		return cmd;
	}
	
	public CharSequence exec(String... command) throws IOException, InterruptedException {
		return exec(Arrays.asList(command));
	}

	public CharSequence exec(List<String> command) throws IOException, InterruptedException {
		List<String> cmd = prepareCommand(command);
		if (pb == null) {
			pb = new ProcessBuilder(cmd).directory(dir).redirectErrorStream(true);
		} else {
			pb.command(cmd); // dir and redirect are set
		}
		Process p = pb.start();
		InputStreamReader stdOut = new InputStreamReader(p.getInputStream());
		LinkedList<CharBuffer> l = new LinkedList<CharBuffer>();
		int r = -1;
		CharBuffer b = null;
		do {
			if (b == null || b.remaining() < b.capacity() / 3) {
				b = CharBuffer.allocate(512);
				l.add(b);
			}
			r = stdOut.read(b);
		} while (r != -1);
		int total = 0;
		for (CharBuffer cb : l) {
			total += cb.position();
			cb.flip();
		}
		CharBuffer res = CharBuffer.allocate(total);
		for (CharBuffer cb : l) {
			res.put(cb);
		}
		res.flip();
		p.waitFor();
		exitValue = p.exitValue();
		return res;
	}
	
	public int exitValue() {
		return exitValue;
	}

	public ProcessExecHelper cwd(File wd) {
		dir = wd;
		if (pb != null) {
			pb.directory(dir);
		}
		return this;
	}
}