| /******************************************************************************* |
| * Copyright (c) 2020 RBEI and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v. 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Adhith Gopal - Initial contribution and API |
| *******************************************************************************/ |
| package org.eclipse.blockchain.core; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.Future; |
| |
| import org.eclipse.blockchain.core.events.BlockchainBuildEvent; |
| import org.eclipse.blockchain.core.events.BlockchainBuildTrigger; |
| import org.eclipse.blockchain.core.events.IBlockchainBuildEvent; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IncrementalProjectBuilder; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| |
| /** |
| * Ethereum Project builder |
| */ |
| public class EthereumBuilder extends IncrementalProjectBuilder { |
| /** |
| * Ethereum Project builder |
| */ |
| public static final String ETHEREUM_BUILDER = "org.eclipse.blockchain.core.ethbuilder"; |
| private static final String SOLIDITY_OUTPUT_FOLDER = "sol-output"; |
| private static ExecutorService service = Executors.newFixedThreadPool(4); |
| private final List<String> compileErrors = new ArrayList<>(); |
| private boolean change = false; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected IProject[] build(final int kind, final Map<String, String> args, final IProgressMonitor monitor) |
| throws CoreException { |
| this.compileErrors.clear(); |
| this.change = false; |
| try { |
| if ((IncrementalProjectBuilder.INCREMENTAL_BUILD == kind) |
| || (IncrementalProjectBuilder.AUTO_BUILD == kind)) { |
| IResourceDelta changes = getDelta(getProject()); |
| if (changes != null) { |
| incrementalBuild(changes); |
| } else { |
| clean(monitor); |
| fullBuild(); |
| } |
| } else if (IncrementalProjectBuilder.FULL_BUILD == kind) { |
| clean(monitor); |
| fullBuild(); |
| } |
| if (this.change) { |
| triggerBuildFinished(); |
| } |
| } catch (ExecutionException | InterruptedException e) { |
| BlockchainCore.getInstance().logException("", e.getMessage(), e); |
| } |
| return new IProject[0]; |
| } |
| |
| private void triggerBuildFinished() { |
| IBlockchainBuildEvent event = new BlockchainBuildEvent(this.compileErrors, getProject()); |
| new Thread(() -> { |
| BlockchainBuildTrigger.getInstance().notifyListeners(event); |
| }, "Blockchain Build Finished").start(); |
| } |
| |
| private void fullBuild() throws CoreException, InterruptedException, ExecutionException { |
| Set<IResource> changedFiles = new HashSet<>(); |
| List<Future<String>> scheduledFutures = new ArrayList<>(); |
| |
| getProject().accept((resource) -> { |
| if (resource != null) { |
| String fileExtension = resource.getFileExtension(); |
| if ((fileExtension != null) && fileExtension.equals("sol")) { |
| changedFiles.add(resource); |
| } |
| } |
| return true; |
| }); |
| |
| for (IResource resource : changedFiles) { |
| this.change = true; |
| scheduledFutures.add(scheduleCompile(resource)); |
| } |
| |
| waitForFuturesToComplete(scheduledFutures); |
| } |
| |
| private void incrementalBuild(final IResourceDelta changes) |
| throws CoreException, InterruptedException, ExecutionException { |
| Set<IResource> changedFiles = new HashSet<>(); |
| List<Future<String>> scheduledFutures = new ArrayList<>(); |
| |
| changes.accept((final IResourceDelta delta) -> { |
| IResource resource = delta.getResource(); |
| if (resource != null) { |
| String fileExtension = resource.getFileExtension(); |
| if ((fileExtension != null) && fileExtension.equals("sol")) { |
| changedFiles.add(resource); |
| } |
| } |
| return true; |
| }); |
| |
| for (IResource resource : changedFiles) { |
| this.change = true; |
| scheduledFutures.add(scheduleCompile(resource)); |
| } |
| |
| waitForFuturesToComplete(scheduledFutures); |
| } |
| |
| private void waitForFuturesToComplete(final List<Future<String>> scheduledFutures) |
| throws InterruptedException, ExecutionException { |
| while (!scheduledFutures.isEmpty()) { |
| List<Future<String>> futuresToRemove = new ArrayList<>(); |
| for (Future<String> scheduledFuture : scheduledFutures) { |
| if (scheduledFuture.isDone() || scheduledFuture.isCancelled()) { |
| String result = scheduledFuture.get(); |
| if (!result.isEmpty()) { |
| this.compileErrors.add(result); |
| } |
| futuresToRemove.add(scheduledFuture); |
| } |
| } |
| if (!futuresToRemove.isEmpty()) { |
| scheduledFutures.removeAll(futuresToRemove); |
| } |
| Thread.sleep(100); |
| } |
| } |
| |
| private Future<String> scheduleCompile(final IResource resourceToCompile) { |
| List<IResource> resourceToCompileAsSet = new ArrayList<>(); |
| resourceToCompileAsSet.add(resourceToCompile); |
| return service.submit(() -> {// NOSONAR |
| return CoreCommandExecutor.getInstance().solidityCompile(getProject().getName(), resourceToCompileAsSet, |
| getProject().getFolder(SOLIDITY_OUTPUT_FOLDER)); |
| }); |
| |
| } |
| |
| /** |
| * This cleans the solidity output folder {@inheritDoc} |
| */ |
| @Override |
| protected void clean(final IProgressMonitor monitor) throws CoreException { |
| IProject project = getProject(); |
| IFolder solidityOutputFolder = project.getFolder(SOLIDITY_OUTPUT_FOLDER); |
| |
| if (solidityOutputFolder.exists()) { |
| solidityOutputFolder.delete(true, new NullProgressMonitor()); |
| } |
| } |
| } |