14
14
from pathlib import Path
15
15
from typing import TYPE_CHECKING , Dict , List , Optional , Set , Tuple , Type , Union
16
16
17
+ from solc_select .solc_select import (
18
+ install_artifacts ,
19
+ installed_versions ,
20
+ current_version ,
21
+ artifact_path ,
22
+ )
17
23
from crytic_compile .compilation_unit import CompilationUnit
18
- from crytic_compile .platform import all_platforms , solc_standard_json
24
+ from crytic_compile .platform import all_platforms
25
+ from crytic_compile .platform .solc_standard_json import SolcStandardJson
26
+ from crytic_compile .platform .vyper import VyperStandardJson
19
27
from crytic_compile .platform .abstract_platform import AbstractPlatform
20
28
from crytic_compile .platform .all_export import PLATFORMS_EXPORT
21
29
from crytic_compile .platform .solc import Solc
@@ -84,6 +92,7 @@ class CryticCompile:
84
92
Main class.
85
93
"""
86
94
95
+ # pylint: disable=too-many-branches
87
96
def __init__ (self , target : Union [str , AbstractPlatform ], ** kwargs : str ) -> None :
88
97
"""See https://github.com/crytic/crytic-compile/wiki/Configuration
89
98
Target is usually a file or a project directory. It can be an AbstractPlatform
@@ -114,8 +123,55 @@ def __init__(self, target: Union[str, AbstractPlatform], **kwargs: str) -> None:
114
123
115
124
self ._working_dir = Path .cwd ()
116
125
126
+ # pylint: disable=too-many-nested-blocks
117
127
if isinstance (target , str ):
118
128
platform = self ._init_platform (target , ** kwargs )
129
+ # If the platform is Solc it means we are trying to compile a single
130
+ # we try to see if we are in a known compilation framework to retrieve
131
+ # information like remappings and solc version
132
+ if isinstance (platform , Solc ):
133
+ # Try to get the platform of the current working directory
134
+ platform_wd = next (
135
+ (
136
+ p (target )
137
+ for p in get_platforms ()
138
+ if p .is_supported (str (self ._working_dir ), ** kwargs )
139
+ ),
140
+ None ,
141
+ )
142
+ # If no platform has been found or if it's a Solc we can't do anything
143
+ if platform_wd and not isinstance (platform_wd , Solc ):
144
+ platform_config = platform_wd .config (str (self ._working_dir ))
145
+ if platform_config :
146
+ kwargs ["solc_args" ] = ""
147
+ kwargs ["solc_remaps" ] = ""
148
+
149
+ if platform_config .remappings :
150
+ kwargs ["solc_remaps" ] = platform_config .remappings
151
+ if (
152
+ platform_config .solc_version
153
+ and platform_config .solc_version != current_version ()[0 ]
154
+ ):
155
+ solc_version = platform_config .solc_version
156
+ if solc_version in installed_versions ():
157
+ kwargs ["solc" ] = str (artifact_path (solc_version ).absolute ())
158
+ else :
159
+ # Respect foundry offline option and don't install a missing solc version
160
+ if not platform_config .offline :
161
+ install_artifacts ([solc_version ])
162
+ kwargs ["solc" ] = str (artifact_path (solc_version ).absolute ())
163
+ if platform_config .optimizer :
164
+ kwargs ["solc_args" ] += "--optimize"
165
+ if platform_config .optimizer_runs :
166
+ kwargs [
167
+ "solc_args"
168
+ ] += f"--optimize-runs { platform_config .optimizer_runs } "
169
+ if platform_config .via_ir :
170
+ kwargs ["solc_args" ] += "--via-ir"
171
+ if platform_config .allow_paths :
172
+ kwargs ["solc_args" ] += f"--allow-paths { platform_config .allow_paths } "
173
+ if platform_config .evm_version :
174
+ kwargs ["solc_args" ] += f"--evm-version { platform_config .evm_version } "
119
175
else :
120
176
platform = target
121
177
@@ -622,18 +678,14 @@ def compile_all(target: str, **kwargs: str) -> List[CryticCompile]:
622
678
**kwargs: optional arguments. Used: "solc_standard_json"
623
679
624
680
Raises:
625
- ValueError : If the target could not be compiled
681
+ NotImplementedError : If the target could not be compiled
626
682
627
683
Returns:
628
684
List[CryticCompile]: Returns a list of CryticCompile instances for all compilations which occurred.
629
685
"""
630
686
use_solc_standard_json = kwargs .get ("solc_standard_json" , False )
631
687
632
- # Attempt to perform glob expansion of target/filename
633
- globbed_targets = glob .glob (target , recursive = True )
634
-
635
688
# Check if the target refers to a valid target already.
636
- # If it does not, we assume it's a glob pattern.
637
689
compilations : List [CryticCompile ] = []
638
690
if os .path .isfile (target ) or is_supported (target ):
639
691
if target .endswith (".zip" ):
@@ -645,28 +697,33 @@ def compile_all(target: str, **kwargs: str) -> List[CryticCompile]:
645
697
compilations = load_from_zip (tmp .name )
646
698
else :
647
699
compilations .append (CryticCompile (target , ** kwargs ))
648
- elif os .path .isdir (target ) or len (globbed_targets ) > 0 :
649
- # We create a new glob to find solidity files at this path (in case this is a directory)
650
- filenames = glob .glob (os .path .join (target , "*.sol" ))
651
- if not filenames :
652
- filenames = glob .glob (os .path .join (target , "*.vy" ))
653
- if not filenames :
654
- filenames = globbed_targets
655
-
700
+ elif os .path .isdir (target ):
701
+ solidity_filenames = glob .glob (os .path .join (target , "*.sol" ))
702
+ vyper_filenames = glob .glob (os .path .join (target , "*.vy" ))
656
703
# Determine if we're using --standard-solc option to
657
704
# aggregate many files into a single compilation.
658
705
if use_solc_standard_json :
659
706
# If we're using standard solc, then we generated our
660
707
# input to create a single compilation with all files
661
- standard_json = solc_standard_json .SolcStandardJson ()
662
- for filename in filenames :
663
- standard_json .add_source_file (filename )
664
- compilations .append (CryticCompile (standard_json , ** kwargs ))
708
+ solc_standard_json = SolcStandardJson ()
709
+ solc_standard_json .add_source_files (solidity_filenames )
710
+ compilations .append (CryticCompile (solc_standard_json , ** kwargs ))
665
711
else :
666
712
# We compile each file and add it to our compilations.
667
- for filename in filenames :
713
+ for filename in solidity_filenames :
668
714
compilations .append (CryticCompile (filename , ** kwargs ))
715
+
716
+ if vyper_filenames :
717
+ vyper_standard_json = VyperStandardJson ()
718
+ vyper_standard_json .add_source_files (vyper_filenames )
719
+ compilations .append (CryticCompile (vyper_standard_json , ** kwargs ))
669
720
else :
670
- raise ValueError (f"{ str (target )} is not a file or directory." )
721
+ raise NotImplementedError ()
722
+ # TODO split glob into language
723
+ # # Attempt to perform glob expansion of target/filename
724
+ # globbed_targets = glob.glob(target, recursive=True)
725
+ # print(globbed_targets)
726
+
727
+ # raise ValueError(f"{str(target)} is not a file or directory.")
671
728
672
729
return compilations
0 commit comments