Skip to content

Commit

Permalink
Feature/update version (#51)
Browse files Browse the repository at this point in the history
* update solcJ-all and web3j-core version
* update travis build infrastrucutre
* new exception for solc and pragma version mismatch
  • Loading branch information
h2mch committed Jan 9, 2020
1 parent 48c5be9 commit c696442
Show file tree
Hide file tree
Showing 32 changed files with 360 additions and 147 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
@@ -1,7 +1,7 @@
language: java

jdk:
- oraclejdk8
- openjdk11

sudo: false # as per http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/

Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Expand Up @@ -3,7 +3,7 @@
<groupId>org.web3j</groupId>
<artifactId>web3j-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>4.2.1-SNAPSHOT</version>
<version>4.5.11-SNAPSHOT</version>

<name>web3j Maven Mojo</name>
<description>Mojo's web3j Maven plugin is used to create java classes based on the solidity
Expand All @@ -16,8 +16,8 @@
<maven.compiler.target>1.8</maven.compiler.target>
<maven.version>3.6.0</maven.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<web3j.version>4.2.0</web3j.version>
<solcJ.version>0.4.25</solcJ.version>
<web3j.version>4.5.11</web3j.version>
<solcJ.version>0.5.7</solcJ.version>
</properties>

<licenses>
Expand Down
104 changes: 72 additions & 32 deletions src/main/java/org/web3j/mavenplugin/JavaClassGeneratorMojo.java
@@ -1,6 +1,8 @@
package org.web3j.mavenplugin;


import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
Expand All @@ -9,18 +11,24 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.shared.model.fileset.FileSet;
import org.apache.maven.shared.model.fileset.util.FileSetManager;
import org.web3j.abi.datatypes.Address;
import org.web3j.codegen.SolidityFunctionWrapper;
import org.web3j.mavenplugin.solidity.CompilerResult;
import org.web3j.mavenplugin.solidity.SolidityCompiler;
import org.web3j.mavenplugin.solidity.VersionMismatchException;
import org.web3j.protocol.ObjectMapperFactory;
import org.web3j.protocol.core.methods.response.AbiDefinition;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -65,7 +73,7 @@ public class JavaClassGeneratorMojo extends AbstractMojo {
private Path createPath(String destinationPath) throws IOException {
Path path = Paths.get(destinationPath, packageName);

if (Files.notExists(path)) {
if (!path.toFile().exists()) {
Files.createDirectories(path);
}
return path;
Expand Down Expand Up @@ -109,29 +117,37 @@ private Map<String, Map<String, String>> extractContracts(String result) throws
return contracts;
}

private String parseSoliditySources(Collection<String> includedFiles) throws MojoExecutionException {
if (includedFiles == null || includedFiles.isEmpty())
return "{}";
CompilerResult result = SolidityCompiler.getInstance(getLog()).compileSrc(
soliditySourceFiles.getDirectory(),
includedFiles,
pathPrefixes,
SolidityCompiler.Options.ABI,
SolidityCompiler.Options.BIN,
SolidityCompiler.Options.INTERFACE,
SolidityCompiler.Options.METADATA
);
if (result.isFailed()) {
throw new MojoExecutionException("Could not compile solidity files\n" + result.errors);
private void generatedJavaClass(Map<String, String> results, String contractName) throws IOException, ClassNotFoundException {
if (!StringUtils.containsIgnoreCase(outputFormat, "java")) {
return;
}

getLog().debug("\t\tResult:\t" + result.output);
if (result.errors.contains("Warning:")) {
getLog().info("\tCompile Warning:\n" + result.errors);
} else {
getLog().debug("\t\tError: \t" + result.errors);
int addressLength = Address.DEFAULT_LENGTH / Byte.SIZE;
boolean primitiveTypes = false;

List<AbiDefinition> functionDefinitions = loadContractDefinition(results.get(SolidityCompiler.Options.ABI.getName()));


if (functionDefinitions.isEmpty()) {
getLog().warn("Unable to parse input ABI file");
return;
}
return result.output;

new SolidityFunctionWrapper(
nativeJavaType,
primitiveTypes,
false, //generateSendTxForCalls
addressLength)
.generateJavaFiles(
org.web3j.tx.Contract.class,
contractName,
results.get(SolidityCompiler.Options.BIN.getName()),
functionDefinitions,
StringUtils.defaultString(outputDirectory.getJava(), sourceDestination),
packageName,
null

);
}

private void processContractFile(Collection<String> files) throws MojoExecutionException {
Expand Down Expand Up @@ -192,16 +208,39 @@ private void generatedBin(Map<String, String> contractResult, String contractNam
}
}

private void generatedJavaClass(Map<String, String> results, String contractName) throws IOException, ClassNotFoundException {
if (!StringUtils.containsIgnoreCase(outputFormat, "java")) {
return;
protected List<AbiDefinition> loadContractDefinition(String absFile) throws IOException {
ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class);
return Arrays.asList(abiDefinition);
}

private String parseSoliditySources(Collection<String> includedFiles) throws MojoExecutionException {
if (includedFiles.isEmpty()) {
return "{}";
}
CompilerResult result = SolidityCompiler.getInstance(getLog()).compileSrc(
soliditySourceFiles.getDirectory(),
includedFiles,
pathPrefixes,
SolidityCompiler.Options.ABI,
SolidityCompiler.Options.BIN,
SolidityCompiler.Options.INTERFACE,
SolidityCompiler.Options.METADATA
);
if (result.isFailed()) {
if (result.errors.contains("Source file requires different compiler version")) {
throw new VersionMismatchException(SolidityCompiler.getInstance(getLog()).getUsedSolCVersion(), result.errors);
}
throw new MojoExecutionException("Could not compile solidity files\n" + result.errors);
}

getLog().debug("\t\tResult:\t" + result.output);
if (result.errors.contains("Warning:")) {
getLog().info("\tCompile Warning:\n" + result.errors);
} else {
getLog().debug("\t\tError: \t" + result.errors);
}
new SolidityFunctionWrapper(nativeJavaType).generateJavaFiles(
contractName,
results.get(SolidityCompiler.Options.BIN.getName()),
results.get(SolidityCompiler.Options.ABI.getName()),
StringUtils.defaultString(outputDirectory.getJava(), sourceDestination),
packageName);
return result.output;
}

private void processResult(String result, String warnMsg) throws MojoExecutionException {
Expand All @@ -210,13 +249,14 @@ private void processResult(String result, String warnMsg) throws MojoExecutionEx
getLog().warn(warnMsg);
return;
}
for (String contractName : contracts.keySet()) {
for (Map.Entry<String, Map<String, String>> entry : contracts.entrySet()) {
String contractName = entry.getKey();
if (isFiltered(contractName)) {
getLog().debug("\tContract '" + contractName + "' is filtered");
continue;
}
try {
Map<String, String> contractResult = contracts.get(contractName);
Map<String, String> contractResult = entry.getValue();
generatedJavaClass(contractResult, contractName);
generatedAbi(contractResult, contractName);
generatedBin(contractResult, contractName);
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/web3j/mavenplugin/solidity/Constant.java
@@ -0,0 +1,10 @@
package org.web3j.mavenplugin.solidity;

import java.util.regex.Pattern;

public interface Constant {

Pattern SOLC_VERSION_PATTERN = Pattern.compile("Version: (.*)", Pattern.MULTILINE);
Pattern SOLIDITY_VERSION_EXTRACT = Pattern.compile("(pragma solidity.*;)", Pattern.MULTILINE);

}
94 changes: 65 additions & 29 deletions src/main/java/org/web3j/mavenplugin/solidity/SolC.java
@@ -1,28 +1,32 @@
package org.web3j.mavenplugin.solidity;

import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Scanner;
import java.util.regex.Matcher;

/**
* Wrapper class to the native solc execution on different platforms.
*
* <p>
* Inspired by https://github.com/ethereum/ethereumj/tree/develop/ethereumj-core/src/main/java/org/ethereum/solidity
*/
public class SolC {

private File solc = null;
private File solc;

private String canonicalPath;
private String canonicalWorkingDirectory;
private File workingDirectory;
private String version;

SolC() {
try {
initBundled();
solc = initBundled();

canonicalPath = solc.getCanonicalPath();
canonicalWorkingDirectory = solc.getParentFile().getCanonicalPath();
Expand All @@ -33,31 +37,33 @@ public class SolC {
}
}

private void initBundled() throws IOException {
File tmpDir = new File(System.getProperty("java.io.tmpdir"), "solc");
tmpDir.setReadable(true);
tmpDir.setWritable(true);
tmpDir.setExecutable(true);
tmpDir.mkdirs();
private String evaluateSolCVersion() {
try {
Process p = Runtime.getRuntime().exec(getCanonicalPath() + " --version");

String solcPath = "/native/" + getOS() + "/solc/";
InputStream is = getClass().getResourceAsStream(solcPath + "file.list");
Scanner scanner = new Scanner(is);
while (scanner.hasNext()) {
String s = scanner.next();
File targetFile = new File(tmpDir, s);
InputStream fis = getClass().getResourceAsStream(solcPath + s);
Files.copy(fis, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
if (solc == null) {
// first file in the list denotes executable
solc = targetFile;
solc.setExecutable(true);
try (java.util.Scanner s = new java.util.Scanner(p.getInputStream())) {
String output = s.useDelimiter("\\A").hasNext() ? s.next() : "";

if (p.waitFor() == 0) {
Matcher matcher = Constant.SOLC_VERSION_PATTERN.matcher(output);
if (matcher.find()) {
return matcher.group(1);
}
}
}
targetFile.deleteOnExit();
} catch (InterruptedException | IOException e) {
throw new RuntimeException("Could not evaluate SolC Version from '" + getCanonicalPath() + "'", e);
}
tmpDir.deleteOnExit();
throw new RuntimeException("Could not evaluate SolC Version from '" + getCanonicalPath() + "'");
}

public String getCanonicalPath() {
return canonicalPath;
}

public String getCanonicalWorkingDirectory() {
return canonicalWorkingDirectory;
}

private String getOS() {
String osName = System.getProperty("os.name").toLowerCase();
Expand All @@ -72,17 +78,47 @@ private String getOS() {
}
}

public String getCanonicalPath() {
return canonicalPath;
}

public String getCanonicalWorkingDirectory() {
return canonicalWorkingDirectory;
/**
* Evaluate (lazy) the version of the solC Library.
* <p>
* The first time this getter is called, a version call to solC is executed. (<code>solc
* --version</code>)
*
* @return
*/
public String getVersion() {
if (StringUtils.isEmpty(version)) {
version = evaluateSolCVersion();
}
return version;
}

public File getWorkingDirectory() {
return workingDirectory;
}

private File initBundled() throws IOException {
File solC = null;
File tmpDir = new File(System.getProperty("java.io.tmpdir"), "solc");
tmpDir.setReadable(true);
tmpDir.setWritable(true);
tmpDir.setExecutable(true);
tmpDir.mkdirs();

String solcPath = "/native/" + getOS() + "/solc/";
InputStream is = getClass().getResourceAsStream(solcPath + "file.list");
Scanner scanner = new Scanner(is);
if (scanner.hasNext()) {
// first file in the list denotes executable
String s = scanner.next();
File targetFile = new File(tmpDir, s);
InputStream fis = getClass().getResourceAsStream(solcPath + s);
Files.copy(fis, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
solC = targetFile;
solC.setExecutable(true);
targetFile.deleteOnExit();
}
tmpDir.deleteOnExit();
return solC;
}
}

0 comments on commit c696442

Please sign in to comment.