This repository has been archived by the owner on Dec 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add support for option --allow-paths #1010
Merged
Merged
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
0510240
Replacing the enum type 'Options' with more flexible interface 'Option'
tglaeser 79f4159
Upgrading module org.ethereum:solcJ-all to version 0.4.10
tglaeser 52fa9ff
Preparing for upgrade of module org.ethereum:solcJ-all to version 0.4…
tglaeser 34caf03
Adding support for option --allow-paths
tglaeser 8e6721b
Upgrading module org.ethereum:solcJ-all to version 0.4.19
tglaeser 5e1d607
Making Option and inner interface
76c6ac4
Make objects of type Option serializable
tglaeser c924799
Merge remote-tracking branch 'upstream/develop' into develop
tglaeser c8b8097
Adding new option types CombinedJson and AllowPaths ... registering a…
tglaeser 5b063b1
Reverting the fully qualified contract name back to contract name ...…
tglaeser 6f29521
Adding new methods to access the contract metadata
tglaeser 351b0c2
Returning the contracts and keys as type List
tglaeser c1294de
Removing this part of the test ... not platform independent ... expec…
tglaeser ccbadb4
Adding JavaDoc ... more assertions with test
tglaeser File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,20 +17,26 @@ | |
*/ | ||
package org.ethereum.solidity.compiler; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnore; | ||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class CompilationResult { | ||
|
||
public Map<String, ContractMetadata> contracts; | ||
public String version; | ||
@JsonProperty("contracts") private Map<String, ContractMetadata> contracts; | ||
@JsonProperty("version") public String version; | ||
|
||
public static CompilationResult parse(String rawJson) throws IOException { | ||
@JsonIgnore public static CompilationResult parse(String rawJson) throws IOException { | ||
if(rawJson == null || rawJson.isEmpty()){ | ||
CompilationResult empty = new CompilationResult(); | ||
empty.contracts = Collections.emptyMap(); | ||
|
@@ -42,6 +48,52 @@ public static CompilationResult parse(String rawJson) throws IOException { | |
} | ||
} | ||
|
||
@JsonIgnore public Path getContractPath() { | ||
if (contracts.size() > 1) { | ||
throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); | ||
} else { | ||
String key = contracts.keySet().iterator().next(); | ||
return Paths.get(key.substring(0, key.lastIndexOf(':'))); | ||
} | ||
} | ||
|
||
@JsonIgnore public String getContractName() { | ||
if (contracts.size() > 1) { | ||
throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); | ||
} else { | ||
String key = contracts.keySet().iterator().next(); | ||
return key.substring(key.lastIndexOf(':') + 1); | ||
} | ||
} | ||
|
||
@JsonIgnore public ContractMetadata getContract(String contractName) { | ||
if (contractName == null && contracts.size() == 1) { | ||
return contracts.values().iterator().next(); | ||
} else if (contractName == null || contractName.isEmpty()) { | ||
throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify the contract name. Available keys (" + getContractKeys() + ")."); | ||
} | ||
for (Map.Entry<String, ContractMetadata> entry : contracts.entrySet()) { | ||
String key = entry.getKey(); | ||
String name = key.substring(key.lastIndexOf(':') + 1); | ||
if (contractName.equals(name)) { | ||
return entry.getValue(); | ||
} | ||
} | ||
throw new UnsupportedOperationException("Source contains more than 1 contact. Please specify a valid contract name. Available keys (" + getContractKeys() + ")."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be something with "not found" |
||
} | ||
|
||
@JsonIgnore public ContractMetadata getContract(Path contractPath, String contractName) { | ||
return contracts.get(contractPath.toAbsolutePath().toString() + ':' + contractName); | ||
} | ||
|
||
@JsonIgnore public List<ContractMetadata> getContracts() { | ||
return new ArrayList<>(contracts.values()); | ||
} | ||
|
||
@JsonIgnore public List<String> getContractKeys() { | ||
return new ArrayList<>(contracts.keySet()); | ||
} | ||
|
||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public static class ContractMetadata { | ||
public String abi; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,15 +17,24 @@ | |
*/ | ||
package org.ethereum.solidity.compiler; | ||
|
||
import com.google.common.base.Joiner; | ||
import org.ethereum.config.SystemProperties; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.*; | ||
import java.io.BufferedOutputStream; | ||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.Serializable; | ||
import java.nio.file.Path; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
|
||
@Component | ||
public class SolidityCompiler { | ||
|
||
|
@@ -38,38 +47,114 @@ public SolidityCompiler(SystemProperties config) { | |
solc = new Solc(config); | ||
} | ||
|
||
public static Result compile(File sourceDirectory, boolean combinedJson, Options... options) throws IOException { | ||
public static Result compile(File sourceDirectory, boolean combinedJson, Option... options) throws IOException { | ||
return getInstance().compileSrc(sourceDirectory, false, combinedJson, options); | ||
} | ||
|
||
public enum Options { | ||
/** | ||
* This class is mainly here for backwards compatibility; however we are now reusing it making it the solely public | ||
* interface listing all the supported options. | ||
*/ | ||
public static final class Options { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you, please, add comment here, that it's here for backward compatibility There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
public static final OutputOption AST = OutputOption.AST; | ||
public static final OutputOption BIN = OutputOption.BIN; | ||
public static final OutputOption INTERFACE = OutputOption.INTERFACE; | ||
public static final OutputOption ABI = OutputOption.ABI; | ||
public static final OutputOption METADATA = OutputOption.METADATA; | ||
public static final OutputOption ASTJSON = OutputOption.ASTJSON; | ||
|
||
private static final NameOnlyOption OPTIMIZE = NameOnlyOption.OPTIMIZE; | ||
private static final NameOnlyOption VERSION = NameOnlyOption.VERSION; | ||
|
||
private static class CombinedJson extends ListOption { | ||
private CombinedJson(List values) { | ||
super("combined-json", values); | ||
} | ||
} | ||
public static class AllowPaths extends ListOption { | ||
public AllowPaths(List values) { | ||
super("allow-paths", values); | ||
} | ||
} | ||
} | ||
|
||
public interface Option extends Serializable { | ||
String getValue(); | ||
String getName(); | ||
} | ||
|
||
private static class ListOption implements Option { | ||
private String name; | ||
private List values; | ||
|
||
private ListOption(String name, List values) { | ||
this.name = name; | ||
this.values = values; | ||
} | ||
|
||
@Override public String getValue() { | ||
StringBuilder result = new StringBuilder(); | ||
for (Object value : values) { | ||
if (OutputOption.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((OutputOption) value).getName() : ',' + ((OutputOption) value).getName()); | ||
} else if (Path.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((Path) value).toAbsolutePath().toString() : ',' + ((Path) value).toAbsolutePath().toString()); | ||
} else if (File.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? ((File) value).getAbsolutePath() : ',' + ((File) value).getAbsolutePath()); | ||
} else if (String.class.isAssignableFrom(value.getClass())) { | ||
result.append((result.length() == 0) ? value : "," + value); | ||
} else { | ||
throw new UnsupportedOperationException("Unexpected type, value '" + value + "' cannot be retrieved."); | ||
} | ||
} | ||
return result.toString(); | ||
} | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { return name; } | ||
} | ||
|
||
private enum NameOnlyOption implements Option { | ||
OPTIMIZE("optimize"), | ||
VERSION("version"); | ||
|
||
private String name; | ||
|
||
NameOnlyOption(String name) { | ||
this.name = name; | ||
} | ||
|
||
@Override public String getValue() { return ""; } | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { | ||
return name; | ||
} | ||
} | ||
|
||
private enum OutputOption implements Option { | ||
AST("ast"), | ||
BIN("bin"), | ||
INTERFACE("interface"), | ||
ABI("abi"), | ||
METADATA("metadata"), | ||
METADATA("metadata"), | ||
ASTJSON("ast-json"); | ||
|
||
private String name; | ||
|
||
Options(String name) { | ||
OutputOption(String name) { | ||
this.name = name; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
@Override public String getValue() { return ""; } | ||
@Override public String getName() { return name; } | ||
@Override public String toString() { | ||
return name; | ||
} | ||
} | ||
|
||
public static class Result { | ||
public String errors; | ||
public String output; | ||
private boolean success = false; | ||
private boolean success; | ||
|
||
public Result(String errors, String output, boolean success) { | ||
this.errors = errors; | ||
|
@@ -125,11 +210,11 @@ public void run() { | |
} | ||
} | ||
|
||
public static Result compile(byte[] source, boolean combinedJson, Options... options) throws IOException { | ||
public static Result compile(byte[] source, boolean combinedJson, Option... options) throws IOException { | ||
return getInstance().compileSrc(source, false, combinedJson, options); | ||
} | ||
|
||
public Result compileSrc(File source, boolean optimize, boolean combinedJson, Options... options) throws IOException { | ||
public Result compileSrc(File source, boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = prepareCommandOptions(optimize, combinedJson, options); | ||
|
||
commandParts.add(source.getAbsolutePath()); | ||
|
@@ -156,24 +241,33 @@ public Result compileSrc(File source, boolean optimize, boolean combinedJson, Op | |
return new Result(error.getContent(), output.getContent(), success); | ||
} | ||
|
||
private List<String> prepareCommandOptions(boolean optimize, boolean combinedJson, Options[] options) throws IOException { | ||
private List<String> prepareCommandOptions(boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = new ArrayList<>(); | ||
commandParts.add(solc.getExecutable().getCanonicalPath()); | ||
if (optimize) { | ||
commandParts.add("--optimize"); | ||
commandParts.add("--" + Options.OPTIMIZE.getName()); | ||
} | ||
if (combinedJson) { | ||
commandParts.add("--combined-json"); | ||
commandParts.add(Joiner.on(',').join(options)); | ||
Option combinedJsonOption = new Options.CombinedJson(getElementsOf(OutputOption.class, options)); | ||
commandParts.add("--" + combinedJsonOption.getName()); | ||
commandParts.add(combinedJsonOption.getValue()); | ||
} else { | ||
for (Options option : options) { | ||
for (Option option : getElementsOf(OutputOption.class, options)) { | ||
commandParts.add("--" + option.getName()); | ||
} | ||
} | ||
for (Option option : getElementsOf(ListOption.class, options)) { | ||
commandParts.add("--" + option.getName()); | ||
commandParts.add(option.getValue()); | ||
} | ||
return commandParts; | ||
} | ||
|
||
public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, Options... options) throws IOException { | ||
private static <T> List<T> getElementsOf(Class<T> clazz, Option... options) { | ||
return Arrays.stream(options).filter(clazz::isInstance).map(clazz::cast).collect(toList()); | ||
} | ||
|
||
public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, Option... options) throws IOException { | ||
List<String> commandParts = prepareCommandOptions(optimize, combinedJson, options); | ||
|
||
ProcessBuilder processBuilder = new ProcessBuilder(commandParts) | ||
|
@@ -205,7 +299,7 @@ public Result compileSrc(byte[] source, boolean optimize, boolean combinedJson, | |
public static String runGetVersionOutput() throws IOException { | ||
List<String> commandParts = new ArrayList<>(); | ||
commandParts.add(getInstance().solc.getExecutable().getCanonicalPath()); | ||
commandParts.add("--version"); | ||
commandParts.add("--" + Options.VERSION.getName()); | ||
|
||
ProcessBuilder processBuilder = new ProcessBuilder(commandParts) | ||
.directory(getInstance().solc.getExecutable().getParentFile()); | ||
|
@@ -231,12 +325,10 @@ public static String runGetVersionOutput() throws IOException { | |
throw new RuntimeException("Problem getting solc version: " + error.getContent()); | ||
} | ||
|
||
|
||
|
||
public static SolidityCompiler getInstance() { | ||
if (INSTANCE == null) { | ||
INSTANCE = new SolidityCompiler(SystemProperties.getDefault()); | ||
} | ||
return INSTANCE; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add javadoc to getters, especially to this one. There should be mentioned, that if there are more than 1 contract with the same name, only first will be returned, so you should use
{@link getContract(Path contractPath, String contractName)}
for this cases.