Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix "deps check all" command #388

Merged
merged 7 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 56 additions & 7 deletions multiversx_sdk_cli/cli_deps.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import logging
from typing import Any
from typing import Any, List, Tuple

from multiversx_sdk_cli import cli_shared, config, dependencies, errors
from multiversx_sdk_cli.dependencies.install import get_deps_dict
from multiversx_sdk_cli.dependencies.modules import DependencyModule
from multiversx_sdk_cli.myprocess import run_process

logger = logging.getLogger("cli.deps")

Expand Down Expand Up @@ -34,16 +36,63 @@ def install(args: Any):

def check(args: Any):
name: str = args.name
module = dependencies.get_module_by_key(name)
tag_to_check: str = config.get_dependency_tag(module.key)

if name == "all":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After re-thinking about this, maybe we can drop check all and install all? On the long run, maybe it's better (less issues, less corner cases) if we do.

Let's double check with @ovidiuolteanu and @ccorcoveanu. I feel deps install all is quite exotic.

Comment on lines +38 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo does not seem to be loaded correctly when trying to install all deps

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested and it seems to work now 👍

all_dependencies = dependencies.get_all_deps()
missing_dependencies: List[Tuple[str, str]] = []

for dependency in all_dependencies:
tag_to_check: str = config.get_dependency_tag(dependency.key)
is_installed = check_module_is_installed(dependency, tag_to_check)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not handle rust the complete way, as done below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


if not is_installed:
missing_dependencies.append((dependency.key, tag_to_check))

if len(missing_dependencies):
raise errors.DependenciesMissing(missing_dependencies)
return
if name == "rust":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice for having the check done in this new, better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now refactored.

module = dependencies.get_module_by_key(name)
tag_to_check: str = config.get_dependency_tag(module.key)

is_installed = check_module_is_installed(module, tag_to_check)
if is_installed:
actual_rust = _get_actual_installed_rust_version()

if tag_to_check in actual_rust:
logger.info(f"[{module.key} {tag_to_check}] is installed.")
return
if "command not found" in actual_rust:
logger.warning("You have installed Rust without using `rustup`.")
return
else:
logger.warning(f"The Rust version you have installed does not match the recommended version.\nInstalled [{actual_rust}], expected [{tag_to_check}].")
return

raise errors.DependencyMissing(module.key, tag_to_check)
else:
module = dependencies.get_module_by_key(name)
tag_to_check: str = config.get_dependency_tag(module.key)

is_installed = check_module_is_installed(module, tag_to_check)
if is_installed:
logger.info(f"[{module.key} {tag_to_check}] is installed.")
return

raise errors.DependencyMissing(module.key, tag_to_check)


def check_module_is_installed(module: DependencyModule, tag_to_check: str) -> bool:
resolution: str = config.get_dependency_resolution(module.key)
resolution = resolution if resolution else "HOST"

logger.info(f"Checking dependency: module = {module.key}, tag = {tag_to_check}, resolution = {resolution}")

installed = module.is_installed(tag_to_check)
if installed:
logger.info(f"[{name} {tag_to_check}] is installed.")
return
return installed


raise errors.DependencyMissing(name, tag_to_check)
def _get_actual_installed_rust_version() -> str:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have it directly in Rust dependency module - modules.py, by overriding is_installed()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it in the Rust module.

args = ["rustup", "default"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will throw if rust is not installed beforehand, and the error is not caught (sorry if I'm mistaken).

Perhaps do a try / catch here and return empty string if missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It didn't trow any error as it was called only if is_installed was True.

output = run_process(args, dump_to_stdout=False)
return output.rstrip("\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps use strip() directly, in case other whitespace might occur in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now using strip().

43 changes: 3 additions & 40 deletions multiversx_sdk_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
from pathlib import Path
from typing import Any, Dict, List

import semver

from multiversx_sdk_cli import errors, utils
from multiversx_sdk_cli.ux import show_warning

Expand Down Expand Up @@ -146,7 +144,6 @@ def _guard_valid_config_deletion(name: str):
def get_defaults() -> Dict[str, Any]:
return {
"dependencies.vmtools.tag": "v1.4.60",
"dependencies.mx_sdk_rs.tag": "latest",
"dependencies.vmtools.urlTemplate.linux": "https://github.com/multiversx/mx-chain-vm-go/archive/{TAG}.tar.gz",
"dependencies.vmtools.urlTemplate.osx": "https://github.com/multiversx/mx-chain-vm-go/archive/{TAG}.tar.gz",
"dependencies.vmtools.urlTemplate.windows": "https://github.com/multiversx/mx-chain-vm-go/archive/{TAG}.tar.gz",
Expand All @@ -156,9 +153,9 @@ def get_defaults() -> Dict[str, Any]:
"dependencies.golang.urlTemplate.linux": "https://golang.org/dl/{TAG}.linux-amd64.tar.gz",
"dependencies.golang.urlTemplate.osx": "https://golang.org/dl/{TAG}.darwin-amd64.tar.gz",
"dependencies.golang.urlTemplate.windows": "https://golang.org/dl/{TAG}.windows-amd64.zip",
"dependencies.twiggy.tag": "latest",
"dependencies.sc-meta.tag": "latest",
"dependencies.testwallets.tag": "latest",
"dependencies.twiggy.tag": "",
"dependencies.sc-meta.tag": "",
"dependencies.testwallets.tag": "v1.0.0",
"dependencies.testwallets.urlTemplate.linux": "https://github.com/multiversx/mx-sdk-testwallets/archive/{TAG}.tar.gz",
"dependencies.testwallets.urlTemplate.osx": "https://github.com/multiversx/mx-sdk-testwallets/archive/{TAG}.tar.gz",
"dependencies.testwallets.urlTemplate.windows": "https://github.com/multiversx/mx-sdk-testwallets/archive/{TAG}.tar.gz",
Expand Down Expand Up @@ -254,42 +251,8 @@ def determine_final_args(argv: List[str], config_args: Dict[str, Any]) -> List[s

def get_dependency_directory(key: str, tag: str) -> Path:
parent_directory = get_dependency_parent_directory(key)
if tag == 'latest':
if not parent_directory.is_dir():
return parent_directory / tag
tag = get_latest_semver_from_directory(parent_directory)

return parent_directory / tag


def get_dependency_parent_directory(key: str) -> Path:
return SDK_PATH / key


def get_latest_semver_from_directory(directory: Path) -> str:
subdirs = [subdir.name for subdir in directory.iterdir()]
try:
return get_latest_semver(subdirs)
except IndexError:
raise Exception(f'no versions found in {directory}')


def get_latest_semver(versions: List[str]) -> str:
semantic_versions = parse_strings_to_semver(versions)
latest_version = sorted(semantic_versions).pop()
return 'v' + str(latest_version)


def parse_strings_to_semver(version_strings: List[str]) -> List[semver.VersionInfo]:
versions = []
for version_string in version_strings:
try:
# Omit the 'v' prefix of the version string
version_string = version_string[1:]
version = semver.VersionInfo.parse(version_string)
except ValueError:
continue

versions.append(version)

return versions
7 changes: 5 additions & 2 deletions multiversx_sdk_cli/dependencies/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from multiversx_sdk_cli.dependencies.install import install_module, get_module_directory, get_module_by_key, get_golang
from multiversx_sdk_cli.dependencies.install import (get_all_deps, get_golang,
get_module_by_key,
get_module_directory,
install_module)

__all__ = ["install_module", "get_module_directory", "get_module_by_key", "get_golang"]
__all__ = ["install_module", "get_module_directory", "get_module_by_key", "get_golang", "get_all_deps"]
8 changes: 4 additions & 4 deletions multiversx_sdk_cli/dependencies/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

def install_module(key: str, overwrite: bool = False):
if key == 'all':
modules = _get_all_deps()
modules = get_all_deps()
else:
modules = [get_module_by_key(key)]

Expand All @@ -29,7 +29,7 @@ def get_module_directory(key: str) -> Path:


def get_module_by_key(key: str) -> DependencyModule:
matches = [module for module in _get_all_deps() if module.key == key or key in module.aliases]
matches = [module for module in get_all_deps() if module.key == key or key in module.aliases]
if len(matches) != 1:
raise errors.UnknownDependency(key)

Expand All @@ -39,15 +39,15 @@ def get_module_by_key(key: str) -> DependencyModule:
def get_deps_dict() -> Dict[str, DependencyModule]:
deps: Dict[str, DependencyModule] = dict()

for module in _get_all_deps():
for module in get_all_deps():
deps[module.key] = module
for alias in module.aliases:
deps[alias] = module

return deps


def _get_all_deps() -> List[DependencyModule]:
def get_all_deps() -> List[DependencyModule]:
return [
Rust(key="rust"),
GolangModule(key="golang"),
Expand Down
24 changes: 2 additions & 22 deletions multiversx_sdk_cli/dependencies/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ def install(self, overwrite: bool) -> None:
# We install the default tag
tag = config.get_dependency_tag(self.key)

if tag == 'latest':
tag = self.get_latest_release()

logger.info(f"install: key={self.key}, tag={tag}, overwrite={overwrite}")

if self._should_skip(tag, overwrite):
Expand Down Expand Up @@ -60,9 +57,6 @@ def is_installed(self, tag: str) -> bool:
def get_env(self) -> Dict[str, str]:
raise NotImplementedError()

def get_latest_release(self) -> str:
raise NotImplementedError()

def get_resolution(self) -> DependencyResolution:
return get_dependency_resolution(self.key)

Expand Down Expand Up @@ -135,14 +129,6 @@ def _get_download_url(self, tag: str) -> str:
url = url.replace("{TAG}", tag)
return url

def get_latest_release(self) -> str:
if self.repo_name is None or self.organisation is None:
raise ValueError(f'{self.key}: repo_name or organisation not specified')

org_repo = f'{self.organisation}/{self.repo_name}'
tag = utils.query_latest_release_tag(org_repo)
return tag

def _get_archive_path(self, tag: str) -> Path:
tools_folder = Path(workstation.get_tools_folder())
archive = tools_folder / f"{self.key}.{tag}.{self.archive_type}"
Expand Down Expand Up @@ -252,9 +238,6 @@ def get_env(self) -> Dict[str, str]:
def get_gopath(self) -> Path:
return self.get_parent_directory() / "GOPATH"

def get_latest_release(self) -> str:
raise errors.UnsupportedConfigurationValue("Golang tag must always be explicit, not latest")


class Rust(DependencyModule):
def is_installed(self, tag: str) -> bool:
Expand Down Expand Up @@ -338,7 +321,7 @@ def _install_sc_meta(self):
tag = config.get_dependency_tag("sc-meta")
args = ["cargo", "install", "multiversx-sc-meta", "--locked"]

if tag != "latest":
if tag != "":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be if not tag (also below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with if tag:

args.extend(["--version", tag])

myprocess.run_process(args)
Expand All @@ -354,7 +337,7 @@ def _install_twiggy(self):
tag = config.get_dependency_tag("twiggy")
args = ["cargo", "install", "twiggy"]

if tag != "latest":
if tag != "":
args.extend(["--version", tag])

myprocess.run_process(args)
Expand Down Expand Up @@ -383,9 +366,6 @@ def get_directory(self, tag: str) -> Path:
def get_env(self) -> Dict[str, str]:
return dict(os.environ)

def get_latest_release(self) -> str:
raise errors.UnsupportedConfigurationValue("Rust tag must either be explicit, empty or 'nightly'")


class TestWalletsModule(StandaloneModule):
def __init__(self, key: str):
Expand Down
16 changes: 13 additions & 3 deletions multiversx_sdk_cli/errors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

from pathlib import Path
from typing import Any, Union
from typing import Any, List, Tuple, Union


class KnownError(Exception):
Expand Down Expand Up @@ -49,6 +49,16 @@ def __init__(self, name: str, tag: str):
super().__init__(f"Dependency missing: {name} {tag}")


class DependenciesMissing(KnownError):
def __init__(self, dependencies: List[Tuple[str, str]]):
message = "Dependencies missing: \n"

for dependency in dependencies:
message += f"{dependency[0]} {dependency[1]}\n"

super().__init__(message.rstrip("\n"))


class UnknownDependency(KnownError):
def __init__(self, name: str):
super().__init__(f"Unknown dependency: {name}")
Expand Down Expand Up @@ -80,8 +90,8 @@ def __init__(self, action_or_item: str, platform: str):


class BuildError(KnownError):
def __init__(self, message, inner=None):
super().__init__(f"Build error: {message}.", inner)
def __init__(self, message: str):
super().__init__(f"Build error: {message}.")


class UnknownArgumentFormat(KnownError):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from pathlib import Path

from multiversx_sdk_cli import config, dependencies, myprocess, utils
from multiversx_sdk_cli import dependencies, myprocess, utils
from multiversx_sdk_cli.errors import BadFile
from multiversx_sdk_cli.projects.report.features.report_option import \
ReportFeature
Expand Down
12 changes: 12 additions & 0 deletions multiversx_sdk_cli/tests/test_cli_deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,15 @@ def test_deps_install_testwallets():
def test_deps_check_testwallets():
return_code = main(["deps", "check", "testwallets"])
assert return_code == 0


@pytest.mark.skip_on_windows
def test_deps_install_all():
return_code = main(["deps", "install", "all"])
assert return_code == 0


@pytest.mark.skip_on_windows
def test_deps_check_all():
return_code = main(["deps", "check", "all"])
assert return_code == 0
25 changes: 0 additions & 25 deletions multiversx_sdk_cli/tests/test_modules.py

This file was deleted.

21 changes: 0 additions & 21 deletions multiversx_sdk_cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,27 +218,6 @@ def parse_keys(bls_public_keys):
return parsed_keys, len(keys)


def query_latest_release_tag(repo: str) -> str:
"""
Queries the Github API to retrieve the latest released tag of the specified
repository. The repository must be of the form 'organisation/project'.
"""
url = f'https://api.github.com/repos/{repo}/releases/latest'

github_api_token = multiversx_sdk_cli.config.get_value('github_api_token')
headers = dict()
if github_api_token != '':
headers['Authorization'] = f'token {github_api_token}'

session = requests_cache.CachedSession('mxpy_requests_cache', use_cache_dir=True, cache_control=True)
response = session.get(url, headers=headers)
response.raise_for_status()

release = response.json()
latest_release_tag: str = release['tag_name']
return latest_release_tag


def log_explorer(chain: str, name: str, path: str, details: str):
networks = {
"1": ("MultiversX Mainnet Explorer", "https://explorer.multiversx.com"),
Expand Down
Loading