def contract_file(contract_dir_hint, contract_file_hint): ''' Given contract dir and contract file hints, determine the file. Contract files are those extended with ``wast``, ``wasm`` and ``abi``. First, the ``contract_file_hint`` may be an absolute path. Next, it may be relative to the contract directory. The contract directory is the container for the project of a contract. This directory is determined with the ``contract_dir`` function, basing on the ``contract_dir_hint``. Any contract directory contains directories and files structured according to few schemes: flat structure with all the files in this directory as in the ``eos/contracts/*`` contract directories in the EOS repository; structure with a directory named ``build`` as resulting from the EOSFactory templates; ''' contract_dir_hint = utils.wslMapWindowsLinux(contract_dir_hint) contract_file_hint = utils.wslMapWindowsLinux(contract_file_hint) # ? ``contract_file_hint`` may be an absolute path to a file trace = contract_file_hint + "\n" if os.path.isabs(contract_file_hint) \ and os.path.isfile(contract_file_hint): return contract_file_hint # ? it may be relative to the contract directory. contract_dir_ = contract_dir(contract_dir_hint) # ? flat structure with all the files in this directory contract_file = os.path.join(contract_dir_, contract_file_hint) trace = trace + contract_file + "\n" if os.path.isfile(contract_file): return contract_file # ? structure with a directory named ``build`` # and ``contract_file_hint`` is relative file contract_file = os.path.join(contract_dir_, "build", contract_file_hint) trace = trace + contract_file + "\n" if os.path.isfile(contract_file): return contract_file # ? structure with a directory named ``build`` # and ``contract_file_hint`` is a file extension merely build_dir = os.path.join(contract_dir_, "build") trace = trace + build_dir + "\n" files = os.listdir(build_dir) for file in files: if os.path.splitext(file)[1] == contract_file_hint: return os.path.join(build_dir, file) raise errors.Error(''' Cannot determine the contract file basing on hints: contract dir hint: {} contract file hint: {} Tried path list: {} '''.format(contract_dir_hint, contract_file_hint, trace))
def contract_source_files(contract_dir_hint): '''List files CPP/C and ABI files from directory given with a hint. Args: contract_dir_hint (str): An argument to the function :func:`.contract_dir` Raises: .core.errors.Error: If the list is empty. ''' contract_dir_ = contract_dir(utils.wslMapWindowsLinux(contract_dir_hint)) trace = contract_dir_ + "\n" source_dir = contract_dir_ srcs = source_files(source_dir) if srcs: return (source_dir, srcs) source_dir = os.path.join(contract_dir_, "src") trace = trace + source_dir + "\n" srcs = source_files(source_dir) if srcs: return (source_dir, srcs) raise errors.Error(''' Cannot find any contract source directory. Tried path list: {} '''.format(trace))
def update_vscode(c_cpp_properties_path): c_cpp_properties_path = utils.wslMapWindowsLinux(c_cpp_properties_path) with open(c_cpp_properties_path) as f: c_cpp_properties = f.read() pattern = re.compile(EOSIO_CDT_PATTERN) if re.findall(pattern, c_cpp_properties): new = c_cpp_properties.replace( re.findall(pattern, c_cpp_properties)[0], eosio_cdt_version()[0]) if not new == c_cpp_properties: with open(c_cpp_properties_path, 'w') as f: f.write(new) pattern = re.compile(UBUNTU_PATTERN) root = wsl_root() if root: if re.findall(pattern, c_cpp_properties): new = c_cpp_properties.replace( re.findall(pattern, c_cpp_properties)[0], root) if not new == c_cpp_properties: with open(c_cpp_properties_path, 'w') as f: f.write(new)
def contract_workspace_dir(dont_set_workspace=False): '''The absolute path to the contract workspace. The contract workspace is a directory where automatically created projects are placed by default. It is set while EOSFactory is installed. If not set, the projects are stored in the `.config.CONTRACTS_DIR` subdirectory (typically *contracts/*) of the EOSFActory installation, if EOSFactory is installed from its GitHub repository, otherwise, they go to a directory specified as `join(.config.TMP, .config.CONTRACTS_DIR)`. The setting may be changed with *EOSIO_CONTRACT_WORKSPACE* entry in the *config.json* file, see :func:`.current_config`. Args: dont_set_workspace (bool): If set, do not query for empty workspace directory. ''' if dont_set_workspace: return config_map()[contract_workspace_dir_[0]] if not contract_workspace_dir_[0] in config_map(): set_contract_workspace_dir() workspace_dir = config_value(contract_workspace_dir_) path = utils.wslMapWindowsLinux(workspace_dir) if os.path.isabs(path): if os.path.exists(path): return path else: raise errors.Error(''' The path '{}', set as the contract workspace directory, does not exist. '''.format(path), translate=False) else: if not is_site_package(): path = os.path.join(eosf_dir(), path) else: path = os.path.join(TMP, path) if not os.path.exists(path): os.makedirs(path) if os.path.exists(path): return path else: raise errors.Error(''' The path '{}' resolved as the contract workspace directory directory does not exist. '''.format(workspace_dir, translate=False)) return path
def set(contract_workspace_dir): if contract_workspace_dir: path = utils.wslMapWindowsLinux(contract_workspace_dir) if os.path.exists(path) and os.path.isdir(path): map = config_map() map[contract_workspace_dir_[0]] = path write_config_map(map) return True return False
def update_eosio_cpp_includes(c_cpp_properties_path, root=""): c_cpp_properties_path = utils.wslMapWindowsLinux(c_cpp_properties_path) with open(c_cpp_properties_path) as f: c_cpp_properties = f.read() dir_pattern = re.compile( '^.*{}(/.+/eosio\.cdt/\d\.\d\.\d/).+'.format(root), re.M) dir = eosio_cpp_dir() if re.findall(dir_pattern, c_cpp_properties): new = c_cpp_properties.replace( re.findall(dir_pattern, c_cpp_properties)[0], dir) if not new == c_cpp_properties: with open(c_cpp_properties_path, 'w') as f: f.write(new)
def contract_dir(contract_dir_hint): '''Given a hint, determine the contract root directory. The ``contract_dir_hint`` is tested to be either - an absolute path, or - a path relative to either - the directory given with :func:`contract_workspace`, or - the directory given with :func:`eosf_dir` ``/contracts``. Args: contract_dir_hint (path): A directory path, may be not absolute. Raises: .core.errors.Error: If the result is not defined. ''' contract_dir_hint = utils.wslMapWindowsLinux(contract_dir_hint) # ? the absolute path to a contract directory trace = contract_dir_hint + "\n" if os.path.isfile(contract_dir_hint): contract_dir_hint = os.path.dirname(contract_dir_hint) if os.path.isabs(contract_dir_hint): if os.path.exists(contract_dir_hint): return os.path.realpath(contract_dir_hint) # ? the relative path to a contract directory, relative to the directory # set with the 'contract_workspace_dir()' function contract_dir_ = os.path.join(contract_workspace_dir(), contract_dir_hint) trace = trace + contract_dir_ + "\n" if os.path.isdir(contract_dir_): if os.path.exists(contract_dir_): return os.path.realpath(contract_dir_) # ? the relative path to a contract directory, relative to # 'eosfactory_data()/contracts' contract_dir_ = os.path.join(eosfactory_data(), CONTRACTS_DIR, contract_dir_hint) trace = trace + contract_dir_ + "\n" if os.path.isdir(contract_dir_): if os.path.exists(contract_dir_): return os.path.realpath(contract_dir_) raise errors.Error(''' Cannot determine the contract directory. Tried: {} '''.format(trace), translate=False)
def contract_dir(contract_dir_hint): '''Given a hint, determine the contract directory. The contract directory is the container for the project of a contract. The hint is probed to be one of the following pieces of information: the absolute path to a contract directory; the relative path to a contract directory, relative to the directory set with the ``contract_workspace_`` variable; the relative path to a contract directory, relative to the ``contracts`` directory in the repository of EOSFactory; the relative path to a contract directory, relative to the ``contracts`` directory in the repository of EOSIO. ''' contract_dir_hint = utils.wslMapWindowsLinux(contract_dir_hint) # ? the absolute path to a contract directory trace = contract_dir_hint + "\n" if os.path.isfile(contract_dir_hint): contract_dir_hint = os.path.dirname(contract_dir_hint) if os.path.isabs(contract_dir_hint): return contract_dir_hint # ? the relative path to a contract directory, relative to the directory # set with the 'contract_workspace_' variable contract_dir_ = os.path.join(config_value(contract_workspace_), contract_dir_hint) trace = trace + contract_dir_ + "\n" if os.path.isdir(contract_dir_): return contract_dir_ # ? the relative path to a contract directory, relative to the # ``contracts`` directory in the repository of EOSFactory contract_dir_ = os.path.join(eosf_dir(), CONTRACTS_DIR, contract_dir_hint) trace = trace + contract_dir_ + "\n" if os.path.isdir(contract_dir_): return contract_dir_ # ? the relative path to a contract directory, relative to the # ``contracts`` directory in the repository of EOSIO contract_dir_ = os.path.join(config_value(eosio_repository_dir_), EOSIO_CONTRACT_DIR, contract_dir_hint) trace = trace + contract_dir_ + "\n" if os.path.isdir(contract_dir_): return contract_dir_ raise errors.Error(''' Cannot determine the contract directory. Tried path list: {} '''.format(trace))
def get_c_cpp_properties(contract_dir, c_cpp_properties_path): if not c_cpp_properties_path: c_cpp_properties_path = os.path.join(contract_dir, ".vscode/c_cpp_properties.json") else: c_cpp_properties_path = utils.wslMapWindowsLinux(c_cpp_properties_path) if not os.path.exists(c_cpp_properties_path): raise errors.Error(''' The given path does not exist: ${} '''.format(c_cpp_properties_path)) if os.path.exists(c_cpp_properties_path): try: with open(c_cpp_properties_path, "r") as input: return json.loads(input.read()) except Exception as e: raise errors.Error(str(e)) else: return json.loads(replace_templates(vscode.c_cpp_properties))
def contract_source_files(contract_dir_hint): contract_dir_ = contract_dir(utils.wslMapWindowsLinux(contract_dir_hint)) trace = contract_dir_ + "\n" source_path = contract_dir_ srcs = source_files(source_path) if srcs: return (source_path, srcs) source_path = os.path.join(contract_dir_, "src") trace = trace + source_path + "\n" srcs = source_files(source_path) if srcs: return (source_path, srcs) raise errors.Error(''' Cannot find any contract source directory. Tried path list: {} '''.format(trace))
def project_from_template( project_name, template=None, workspace_dir=None, c_cpp_prop_path=None, include=None, libs=None, remove_existing=False, open_vscode=False, throw_exists=False, verbosity=None): '''Given the project name and template name, create a smart contract project. - **parameters**:: project_name: The name of the project, or an existing path to a directory. template: The name of the template used. workspace_dir: If set, the folder for the work-space. Defaults to the value returned by the config.contract_workspace() function. include: If set, comma-separated list of include folders. libs: If set, comma-separated list of libraries. remove_existing: If set, overwrite any existing project. visual_studio_code: If set, open the ``VSCode``, if available. verbosity: The logging configuration. ''' project_name = utils.wslMapWindowsLinux(project_name.strip()) template = template.strip() template_dir = utils.wslMapWindowsLinux(template) if not os.path.isdir(template_dir): template_dir = os.path.join( config.eosf_dir(), TEMPLATE_CONTRACTS_DIR, template) if not os.path.isdir(template_dir): raise errors.Error(''' TemplateCreate '{}' does not exist. '''.format(template_dir)) if c_cpp_prop_path: c_cpp_prop_path = utils.wslMapWindowsLinux(c_cpp_prop_path) if os.path.exists(c_cpp_prop_path): try: with open(c_cpp_prop_path, "r") as input: c_cpp_properties = input.read() except Exception: c_cpp_properties = vscode.c_cpp_properties() else: c_cpp_properties = vscode.c_cpp_properties() c_cpp_properties = replace_templates(c_cpp_properties) if include: c_cpp_properties_json = json.loads(c_cpp_properties) c_cpp_properties_json[CONFIGURATIONS][0][INCLUDE_PATH].extend( include.split(", ")) c_cpp_properties_json[CONFIGURATIONS][0][BROWSE]["path"].extend( include.split(", ")) c_cpp_properties = json.dumps(c_cpp_properties_json, indent=4) if libs: c_cpp_properties_json = json.loads(c_cpp_properties) c_cpp_properties_json[CONFIGURATIONS][0]["libs"].extend( libs.split(", ")) c_cpp_properties = json.dumps(c_cpp_properties_json, indent=4) split = os.path.split(project_name) if os.path.isdir(split[0]): project_dir = project_name project_name = split[1] else: if not workspace_dir \ or not os.path.isabs(workspace_dir) \ or not os.path.exists(workspace_dir): workspace_dir = config.contract_workspace() workspace_dir = workspace_dir.strip() project_dir = os.path.join(workspace_dir, project_name) if os.path.isdir(project_dir): if os.listdir(project_dir): if remove_existing: try: shutil.rmtree(project_dir) except Exception as e: raise errors.Error(''' Cannot remove the directory {}. error message: ============== {} '''.format(project_dir, str(e))) else: msg = ''' NOTE: Contract workspace '{}' already exists. Cannot overwrite it. '''.format(project_dir) if throw_exists: raise errors.Error(msg) else: raise errors.Error(msg) return try: # make contract directory and its build directory: os.makedirs(os.path.join(project_dir, "build")) except Exception as e: raise errors.Error(str(e)) def copy_dir_contents( project_dir, template_dir, directory, project_name): contents = os.listdir(os.path.join(template_dir, directory)) for item in contents: path = os.path.join(directory, item) template_path = os.path.join(template_dir, path) contract_path = os.path.join( project_dir, path.replace( TEMPLATE_NAME, project_name)) if os.path.isdir(template_path): os.mkdir(contract_path) copy_dir_contents( project_dir, template_dir, path, project_name) elif os.path.isfile(template_path): copy(template_path, contract_path, project_name) def copy(template_path, contract_path, project_name): with open(template_path, "r") as input: template = input.read() if TEMPLATE_HOME in template or TEMPLATE_ROOT in template: home = os.environ["HOME"] root = "" if is_windows_ubuntu(): replace_templates(template) template = template.replace("${" + TEMPLATE_NAME + "}", project_name) template = template.replace(C_CPP_PROP, c_cpp_properties) template = template.replace(TASK_JSON, vscode.TASKS) with open(contract_path, "w") as output: output.write(template) copy_dir_contents(project_dir, template_dir, "", project_name) logger.TRACE(''' * Contract project '{}' created from template '{}' '''.format(project_name, template_dir), verbosity) if open_vscode: if is_windows_ubuntu(): command_line = "cmd.exe /C code {}".format( utils.wslMapLinuxWindows(project_dir)) elif uname() == "Darwin": command_line = "open -n -b com.microsoft.VSCode --args {}".format( project_dir) else: command_line = "code {}".format(project_dir) os.system(command_line) logger.INFO(''' ######### Created contract project ``{}``, originated from template ``{}``. '''.format(project_name, template_dir), verbosity) return project_dir
def contract_file(contract_dir_hint, contract_file_hint): ''' Given contract directory and contract file hints, determine a contract file. The contract directory is determined with the function :func:`.contract_dir`, basing on the *contract_dir_hint* argument. Contract files are ABI or WASM ones. Contract file hint is an absolute path to a contract file, or it is relative to the contract dir, ir it is a file extension. Any contract directory considered to be structured according to one of the following patterns: - all the files in the contract directory, - contract files in the *build* subdirectory. Args: contract_dir_hint (path): A directory path, may be not absolute. contract_file_hint (str or path): A file extension, or file path, may be not absolute. Raises: .core.errors.Error: If the result is not defined. ''' contract_dir_hint = utils.wslMapWindowsLinux(contract_dir_hint) contract_file_hint = utils.wslMapWindowsLinux(contract_file_hint) # Contract file hint is an absolute path to a contract file: trace = contract_file_hint + "\n" if os.path.isabs(contract_file_hint) \ and os.path.isfile(contract_file_hint): return contract_file_hint contract_dir_ = contract_dir(contract_dir_hint) # All the files in the contract directory: contract_file = os.path.join(contract_dir_, contract_file_hint) trace = trace + contract_file + "\n" if os.path.isfile(contract_file): return contract_file # Contract files in the *build* subdirectory, # and *contract_file_hint* is a relative file contract_file = os.path.join(contract_dir_, "build", contract_file_hint) trace = trace + contract_file + "\n" if os.path.isfile(contract_file): return contract_file # Contract files in the *build* subdirectory, # and *contract_file_hint* is a file extension merely build_dir = os.path.join(contract_dir_, "build") trace = trace + build_dir + "\n" files = os.listdir(build_dir) for file in files: if os.path.splitext(file)[1] == contract_file_hint: return os.path.join(build_dir, file) raise errors.Error(''' Cannot determine the contract file basing on hints: contract dir hint: {} contract file hint: {} Tried path list: {} '''.format(contract_dir_hint, contract_file_hint, trace))
def linuxize_path(path): return utils.wslMapWindowsLinux(path.replace(ROOT, ""))
def build( contract_dir_hint, c_cpp_properties_path=None, compile_only=False, is_test_mode=False, is_execute=False, verbosity=None): '''Produce ABI and WASM files. Compiler options come with the argument 'c_cpp_properties_path', as components of 'compilerOptions' list. Option can be any of the 'eosio-cpp' options, plus the following ones: * --src - list of the source files, absolute or relative to 'src' or project directories, for example: --src hello.cpp tests/hello_test.cpp * -o - the same as the corresponding eosio-cpp option, but may be relative to 'build' directory Without any option set, the only source file is determined as a result of the function :func:`.core.config.contract_source_files`, if the result is a single file. If it is not, an error is thrown, stating that the source file has to be specified with the '--src' option. The ABI and WASM targets are named after the contract source file. Args: contract_dir_hint (str): Path, may be partial, to the project directory. c_cpp_properties_path (str): If set, the path to a c_cpp_properties json file in '.vscode' folder in the project directory. compile_only (bool): If set, do not link. verbosity (([.core.logger.Verbosity])): Verbosity parameter, used in loggers. ''' contract_dir = config.contract_dir(contract_dir_hint) # contract_source_files[0] is directory, contract_source_files[1] is contents: contract_source_files = config.contract_source_files(contract_dir) c_cpp_properties = get_c_cpp_properties( contract_dir, c_cpp_properties_path) build_dir = get_target_dir(contract_dir) target_path = None compile_options = [] source_files = [] ############################################################################ # begin compiler option logics ############################################################################ recardian_dir = "-R=" + get_recardian_dir(contract_source_files[0]) if is_test_mode \ and vscode.TEST_OPTIONS in c_cpp_properties[CONFIGURATIONS][0]: compile_options_ = c_cpp_properties[CONFIGURATIONS][0]\ [vscode.TEST_OPTIONS] elif not is_test_mode \ and vscode.CODE_OPTIONS in c_cpp_properties[CONFIGURATIONS][0]: compile_options_ = c_cpp_properties[CONFIGURATIONS][0]\ [vscode.CODE_OPTIONS] else: compile_options_ = [] contract_src_name = None is_verbose = False if not "-abigen" in compile_options_: compile_options.append("-abigen") if is_test_mode and not "-fnative" in compile_options_: compile_options.append("-fnative") for i in range(0, len(compile_options_)): entry = compile_options_[i] if "-R=" in entry: recardian_dir = entry elif "-contract=" in entry: contract_src_name = entry.replace("-contract=", "").strip() compile_options.append(entry) elif "--verbose" in entry: is_verbose = True elif "-o" in entry: target_path = utils.wslMapWindowsLinux( entry.replace("-o", "").strip()) if not target_path: if i + 1 < len(compile_options_): target_path = compile_options_[i + 1] else: raise errors.Error(''' The option '-o' does not has its value set: {} '''.format(compile_options_)) if not os.path.isabs(target_path): target_path = os.path.join(build_dir, target_path) target_dir = os.path.dirname(target_path) if not os.path.exists(target_dir): try: os.makedirs(target_dir) except Exception as e: raise errors.Error(''' Cannot make directory set with the option '-o'. {} '''.format(str(e))) elif "-abigen_output" in entry: abigen_path = utils.wslMapWindowsLinux( entry.replace("-abigen_output=", "").strip()) if not os.path.isabs(abigen_path): abigen_path = os.path.join(build_dir, abigen_path) abigen_dir = os.path.dirname(abigen_path) if not os.path.exists(abigen_dir): try: os.makedirs(abigen_dir) except Exception as e: raise errors.Error(''' Cannot make directory set with the option '-abigen_output'. {} '''.format(str(e))) compile_options.append("-abigen_output={}".format(abigen_path)) elif "--src" in entry: input_files_ = utils.wslMapWindowsLinux( entry.replace("--src", "").strip()) if not input_files_: next_index = i + 1 while True: if next_index >= len(compile_options_): break next_item = compile_options_[next_index] if "-" in next_item: break input_files_ = input_files_ + " " + next_item if not input_files_: raise errors.Error(''' The option '--src' does not has its value set: {} '''.format(compile_options_)) for input_file in input_files_.split(" "): temp = input_file if not os.path.isabs(temp): temp = os.path.join(contract_source_files[0], input_file) if not contract_src_name: contract_src_name = os.path.splitext( os.path.basename(temp))[0] if not os.path.exists(temp): temp = os.path.join(contract_dir, input_file) if not os.path.exists(temp): raise errors.Error(''' The source file {} cannot be found. It is neither absolute nor relative to the contract directory or relative to the 'src' directory. '''.format(input_file)) temp = os.path.normpath(temp) if not temp in source_files: source_files.append(temp) else: compile_options.append(entry) compile_options.append(recardian_dir) if not source_files: source_files = contract_source_files[1] if not source_files: raise errors.Error(''' Cannot find any source file (".c", ".cpp",".cxx", ".c++") in the contract folder. ''') if not is_test_mode and len(source_files) > 1: raise errors.Error(''' Cannot determine the source file of the contract. There is many files in the 'src' directory, namely: {} Specify the file with the compiler option '--src', for example: --src src_dir/hello.cpp The file path is to be absolute or relative to the project directory. '''.format("\n".join(source_files))) if not contract_src_name: contract_src_name = os.path.splitext( os.path.basename(source_files[0]))[0] if not contract_src_name and len(source_files) == 1: contract_src_name = os.path.splitext( os.path.basename(source_files[0]))[0] ############################################################################ # end compiler option logics ############################################################################ if not target_path: target_path = os.path.normpath( os.path.join(build_dir, contract_src_name + ".wasm")) abigen_path = os.path.normpath( os.path.join(build_dir, contract_src_name + ".abi")) if is_execute: logger.TRACE(''' Executing target {} '''.format(target_path)) command_line = [target_path] if setup.is_print_command_lines and setup.is_save_command_lines: setup.add_to__command_line_file(" ".join(command_line)) if setup.is_print_command_lines or is_verbose: logger.DEBUG(''' ######## command line: {} '''.format(" ".join(command_line)), [logger.Verbosity.DEBUG]) utils.long_process(command_line, build_dir, is_verbose=True, prompt=target_path) return command_line = [config.eosio_cpp()] if compile_only: command_line.append("-c") else: command_line.extend(["-o", target_path]) for entry in c_cpp_properties[CONFIGURATIONS][0][vscode.INCLUDE_PATH]: if WORKSPACE_FOLDER in entry: entry = entry.replace(WORKSPACE_FOLDER, contract_dir) command_line.append("-I=" + linuxize_path(entry)) else: path = linuxize_path(entry) if not path in config.eosio_cpp_includes(): command_line.append( "-I=" + path) for entry in c_cpp_properties[CONFIGURATIONS][0][vscode.LIBS]: command_line.append( "-l=" + linuxize_path(entry)) for entry in compile_options: command_line.append(entry) for input_file in source_files: command_line.append(input_file) if setup.is_print_command_lines and setup.is_save_command_lines: setup.add_to__command_line_file(" ".join(command_line)) if setup.is_print_command_lines or is_verbose: logger.DEBUG(''' ######## command line: {} '''.format(" ".join(command_line)), [logger.Verbosity.DEBUG]) utils.long_process(command_line, build_dir, is_verbose=True, prompt="eosio-cpp") if not compile_only: if "wasm" in target_path: logger.TRACE(''' ABI file writen to file: {} '''.format(os.path.normpath(abigen_path)), verbosity) logger.TRACE(''' WASM file writen to file: {} '''.format(os.path.normpath(target_path)), verbosity) else: logger.TRACE(''' terget writen to file: {} '''.format(os.path.normpath(target_path)), verbosity) print("eosio-cpp: OK")
def unpack(contract_dir=None, zip_file=None): '''Unack a contract project folder. Make a new contract project folder from a zip file produced with the function :func:`pack`. If the given zip file is an arbitrary one, expands it with omiting files matching the `config.IGNORE_LIST`, and localizes the '.vscode.c_cpp_properties.json' file, if found. Args: contract_dir (str): The contract project directory to be created. zip_file (str): The zip file to be extracted. ''' if not contract_dir: raise errors.Error(''' The directory of the new contract has to be specified. ''') contract_dir = utils.wslMapWindowsLinux(contract_dir) if os.path.exists(contract_dir) and os.listdir(contract_dir): raise errors.Error(''' The directory {} is not empty. Cannot overwrite it. '''.format(os.path.realpath(contract_dir))) if not zip_file: raise errors.Error(''' The zip file, defining the new directory, has to be specified. ''') zip_file = utils.wslMapWindowsLinux(zip_file) if not os.path.exists(zip_file): raise errors.Error(''' The zip file {} does not exists '''.format(os.path.realpath(zip_file))) def convert_c_cpp_properties(member, zipfile_object): if "c_cpp_properties.json" in member.filename: c_cpp_properties = zipfile_object.read(member).decode("utf-8") eosio_cdt_include = re.compile(EOSIO_CDT_INCLUDE) if re.findall(eosio_cdt_include, c_cpp_properties): c_cpp_properties = c_cpp_properties.replace( re.findall(eosio_cdt_include, c_cpp_properties)[0], EOSIO_CDT_HOME) eosio_cdt_root = config.wsl_root() + config.eosio_cdt_root() c_cpp_properties = c_cpp_properties.replace( EOSIO_CDT_HOME, eosio_cdt_root) if not os.path.exists(os.path.join(contract_dir, ".vscode")): os.makedirs(os.path.join(contract_dir, ".vscode")) with open(os.path.join(contract_dir, member.filename), "w+") as f: f.write(c_cpp_properties) return True return False try: with zipfile.ZipFile(zip_file) as zf: info_list = zf.infolist() for member in info_list: if is_valid(member.filename, config.IGNORE_LIST): if not convert_c_cpp_properties(member, zf): zf.extract(member, contract_dir) except Exception as e: raise errors.Error(''' Cannot extract the zip file {} to the directory {} The error message is {} '''.format(os.path.realpath(zip_file), os.path.realpath(contract_dir), str(e))) create_ignore_list_file(contract_dir) create_utils(contract_dir) create_task_json(contract_dir)
def pack(contract_dir=None, zip_file=None): '''Pack a contract project folder. If an EOSIO contract project which is a VSCode folder is to be passed by e-mail, it has to be compressed. However, this should not be done in a straightforward way, because of the following issues: There are volume binaries there. There are local configuring files in the .vscode folder. There are your private notes and scratchpads there. The paths in the .vscode/c_cpp_properties.json are localized according to the local operating system. Make compression automatically, solving the issues. With default arguments, produce a zip file, in the project folder. The file is named after the folder name. Args: contract_dir (str): If set, the contract project directory, otherwise cwd. zip_file (str): If set, the name of the zip file, otherwise <project directory>/<project directory name>.zip ''' if not contract_dir: contract_dir = os.getcwd() else: contract_dir = utils.wslMapWindowsLinux(contract_dir) if not os.path.exists(contract_dir): raise errors.Error(''' The given contract directory {} does not exist. ''') if not os.path.isdir(contract_dir): raise errors.Error(''' The given contract path {} is not a directory. ''') if not zip_file: zip_file = os.path.realpath( os.path.join(os.getcwd(), os.path.basename(contract_dir) + ".zip")) else: zip_file = utils.wslMapWindowsLinux(zip_file) if os.path.exists(zip_file): try: os.remove(zip_file) except Exception as e: raise errors.Error(''' Cannot remove the project zip file {} The error message is {} '''.format(zip_file, str(e))) ignore_file = create_ignore_list_file(contract_dir, True) ignore_list = [] with open(ignore_file, "r") as f: for l in f: line = l.strip() if not line[0] == "#": ignore_list.append(line) if not zip_file in ignore_list: ignore_list.append(zip_file) if not config.IGNORE_FILE in ignore_list: ignore_list.append(config.IGNORE_FILE) def convert_c_cpp_properties(path, path_rel, zipfile_object): if "c_cpp_properties.json" in path: with open(path, "r") as f: c_cpp_properties = f.read() eosio_cdt_include = re.compile(EOSIO_CDT_INCLUDE) if re.findall(eosio_cdt_include, c_cpp_properties): c_cpp_properties = c_cpp_properties.replace( re.findall(eosio_cdt_include, c_cpp_properties)[0], EOSIO_CDT_HOME) print("adding {}".format(path_rel)) zipfile_object.writestr(path_rel, c_cpp_properties) return True return False def project_files(search_dir, zipfile_object): files = [] paths = os.listdir(search_dir) for file in paths: path = os.path.join(search_dir, file) if os.path.isfile(path): if not path == zip_file: path_rel = os.path.relpath(path, contract_dir) if is_valid(path_rel, ignore_list): if not convert_c_cpp_properties( path, path_rel, zipfile_object): print("adding {}".format(path_rel)) zipfile_object.write(path, path_rel) else: project_files(path, zipfile_object) try: with zipfile.ZipFile(zip_file, mode='w') as zf: project_files(contract_dir, zf) except: raise errors.Error(''' Cannot zip the directory {} to the zip file {} The error message is {} '''.format(os.path.realpath(contract_dir), os.path.realpath(zip_file), str(e)))
def ABI( contract_dir_hint=None, c_cpp_properties_path=None, verbosity=None): '''Given a hint to a contract directory, produce ABI file. ''' contract_dir = config.contract_dir(contract_dir_hint) # source_files[0] is directory, source_files[1] is contents: contract_source_files = config.contract_source_files(contract_dir) source_files = [] source_ext = [".c", ".cpp",".cxx", ".c++"] for file in contract_source_files[1]: if os.path.splitext(file)[1].lower() in source_ext: source_files.append(file) if not source_files: raise errors.Error(''' "The source is empty. The assumed contract dir is {} '''.format(contract_dir)) return code_name = os.path.splitext(os.path.basename(source_files[0]))[0] target_dir = get_target_dir(contract_source_files[0]) target_path = os.path.normpath( os.path.join(target_dir, code_name + ".abi")) for file in contract_source_files[1]: if os.path.splitext(file)[1].lower() == ".abi": logger.INFO(''' NOTE: An ABI exists in the source directory. Cannot overwrite it: {} Just copying it to the target directory. '''.format(file), verbosity) shutil.move(file, target_path) return command_line = [ config.eosio_cpp(), "-contract=" + code_name, "-R=" + get_resources_dir(contract_source_files[0]), "-abigen", "-abigen_output=" + target_path] c_cpp_properties = get_c_cpp_properties( contract_dir, c_cpp_properties_path) for entry in c_cpp_properties[CONFIGURATIONS][0][INCLUDE_PATH]: if WORKSPACE_FOLDER in entry: entry = entry.replace(WORKSPACE_FOLDER, contract_dir) command_line.append( "-I" + utils.wslMapWindowsLinux(entry)) else: if not EOSIO_CPP_INCLUDE in entry: command_line.append( "-I" + utils.wslMapWindowsLinux( strip_wsl_root(entry))) for file in source_files: command_line.append(file) try: eosio_cpp(command_line, target_dir) except Exception as e: raise errors.Error(str(e)) logger.TRACE(''' ABI file writen to file: {} '''.format(target_path), verbosity)
def template_create(project_name, template_dir=None, workspace_dir=None, remove_existing=False, open_vscode=False, throw_exists=False): '''Given the project name and template name, create a smart contract project. ''' project_name = project_name.strip() template_dir = template_dir.strip() template_dir = utils.wslMapWindowsLinux(template_dir) if not template_dir: template_dir = config.DEFAULT_TEMPLATE if not os.path.isdir(template_dir): template_dir = os.path.join(config.eosf_dir(), TEMPLATE_CONTRACTS_DIR, template_dir) if not os.path.isdir(template_dir): raise errors.Error(''' TemplateCreate '{}' does not exist. '''.format(template_dir)) if not workspace_dir \ or not os.path.isabs(workspace_dir) \ or not os.path.exists(workspace_dir): workspace_dir = config.contract_workspace() workspace_dir = workspace_dir.strip() project_name = utils.wslMapWindowsLinux(project_name.strip()) split = os.path.split(project_name) if os.path.isdir(split[0]): project_dir = project_name project_name = split[1] else: project_dir = os.path.join(workspace_dir, project_name) if os.path.isdir(project_dir): if os.listdir(project_dir): if remove_existing: try: shutil.rmtree(project_dir) except Exception as e: raise errors.Error(str(e)) else: msg = ''' NOTE: Contract workspace '{}' already exists. Cannot overwrite it. '''.format(project_dir) if throw_exists: raise errors.Error(msg) else: logger.ERROR(msg) return try: # make contract directory and its build directory: os.makedirs(os.path.join(project_dir, "build")) except Exception as e: raise errors.Error(str(e)) def copy_dir_contents(project_dir, template_dir, directory, project_name): contents = os.listdir(os.path.join(template_dir, directory)) for item in contents: path = os.path.join(directory, item) template_path = os.path.join(template_dir, path) contract_path = os.path.join( project_dir, path.replace(TEMPLATE_NAME, project_name)) if os.path.isdir(template_path): os.mkdir(contract_path) copy_dir_contents(project_dir, template_dir, path, project_name) elif os.path.isfile(template_path): copy(template_path, contract_path, project_name) def copy(template_path, contract_path, project_name): with open(template_path, "r") as input: template = input.read() if TEMPLATE_HOME in template or TEMPLATE_ROOT in template: home = os.environ["HOME"] root = "" eosio_dir = config.eosio_repository_dir() if is_windows_ubuntu(): home = config.wsl_root() + home root = config.wsl_root() eosio_dir = config.wsl_root() + eosio_dir template = template.replace(TEMPLATE_HOME, home) template = template.replace(TEMPLATE_ROOT, root) template = template.replace(TEMPLATE_EOSIO_DIR, eosio_dir) template = template.replace("@" + TEMPLATE_NAME + "@", project_name) with open(contract_path, "w") as output: output.write(template) copy_dir_contents(project_dir, template_dir, "", project_name) logger.TRACE(''' * Contract project '{}' created from template '{}' '''.format(project_name, project_dir)) if open_vscode: if is_windows_ubuntu(): command_line = "cmd.exe /C code {}".format( utils.wslMapLinuxWindows(project_dir)) elif uname() == "Darwin": command_line = "open -n -b com.microsoft.VSCode --args {}".format( project_dir) else: command_line = "code {}".format(project_dir) os.system(command_line) return project_dir
def WASM( contract_dir_hint, c_cpp_properties_path=None, compile_only=False, verbosity=None): '''Produce WASM code. ''' contract_dir = config.contract_dir(contract_dir_hint) # source_files[0] is directory, source_files[1] is contents: contract_source_files = config.contract_source_files(contract_dir) source_files = [] source_ext = [".c", ".cpp",".cxx", ".c++"] for file in contract_source_files[1]: if os.path.splitext(file)[1].lower() in source_ext: source_files.append(file) if not source_files: raise errors.Error(''' "The source is empty. The assumed contract dir is {} '''.format(contract_dir)) return code_name = os.path.splitext(os.path.basename(source_files[0]))[0] target_dir = get_target_dir(contract_source_files[0]) target_path = os.path.normpath( os.path.join(target_dir, code_name + ".wasm")) c_cpp_properties = get_c_cpp_properties( contract_dir, c_cpp_properties_path) command_line = [config.eosio_cpp()] for entry in c_cpp_properties[CONFIGURATIONS][0][INCLUDE_PATH]: if WORKSPACE_FOLDER in entry: entry = entry.replace(WORKSPACE_FOLDER, contract_dir) command_line.append("-I=" + utils.wslMapWindowsLinux(entry)) else: if not EOSIO_CPP_INCLUDE in entry: command_line.append( "-I=" + utils.wslMapWindowsLinux(strip_wsl_root(entry))) for entry in c_cpp_properties[CONFIGURATIONS][0]["libs"]: command_line.append( "-l=" + utils.wslMapWindowsLinux(strip_wsl_root(entry))) for entry in c_cpp_properties[CONFIGURATIONS][0]["compilerOptions"]: command_line.append(entry) for file in source_files: command_line.append(file) if setup.is_print_command_line: print("######## \n{}:".format(" ".join(command_line))) if compile_only: command_line.append("-c=") command_line.append("-o=" + target_path) try: eosio_cpp(command_line, target_dir) except Exception as e: raise errors.Error(str(e)) if not compile_only: logger.TRACE(''' WASM file writen to file: {} '''.format(os.path.normpath(target_path)), verbosity)