/******************************************************************************* * Copyright (c) 2016 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package com.github.rustdt.tooling.ops; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import java.nio.file.Path; import melnorme.lang.tooling.common.ops.IOperationMonitor; import melnorme.lang.tooling.toolchain.ops.AbstractToolOperation; import melnorme.lang.tooling.toolchain.ops.IToolOperationService; import melnorme.lang.tooling.toolchain.ops.OperationSoftFailure; import melnorme.lang.tooling.toolchain.ops.SourceOpContext; import melnorme.utilbox.collections.ArrayList2; import melnorme.utilbox.concurrency.OperationCancellation; import melnorme.utilbox.core.CommonException; import melnorme.utilbox.process.ExternalProcessHelper.ExternalProcessResult; public class RustFmtOperation implements AbstractToolOperation<String> { protected final SourceOpContext sourceOpContext; protected final IToolOperationService toolOpService; protected final Path rustFmt; public RustFmtOperation(SourceOpContext sourceOpContext, IToolOperationService toolOpService, Path rustFmt) { this.sourceOpContext = assertNotNull(sourceOpContext); this.toolOpService = assertNotNull(toolOpService); this.rustFmt = assertNotNull(rustFmt); } @Override public String executeToolOperation(IOperationMonitor om) throws CommonException, OperationCancellation, OperationSoftFailure { ArrayList2<String> cmdLine = ArrayList2.create(rustFmt.toString()); // cmdLine.add("--write-mode=diff"); cmdLine.add("--skip-children"); ProcessBuilder pb = new ProcessBuilder(cmdLine); // set directory, workaround for bug: https://github.com/rust-lang-nursery/rustfmt/issues/562 // Also, it make rustfmt look for the rustfmt.toml config file in folders parent chain pb.directory(sourceOpContext.getFileLocation().getParent().toFile()); String input = sourceOpContext.getSource(); return handleResult(toolOpService.runProcess(pb, input, om)); } protected String handleResult(ExternalProcessResult result) throws CommonException, OperationSoftFailure { int exitValue = result.exitValue; if(exitValue == 3) { // Some warnings were generated, but `rustfmt` did complete, so use the result // TODO: we could display the warnings in a non-modal notification UI // or even as warning markers? } else if(exitValue != 0) { String msg = "`rustfmt` did not complete successfully, exit code: " + exitValue + "\n" + result.getStdErrBytes().toUtf8String(); throw new OperationSoftFailure(msg); } // formatted file is in stdout return result.getStdOutBytes().toUtf8String(); } }