Skip to content

Commit

Permalink
BaseTools/Plugin/RustEnvironmentCheck: Add rust-src component check (#…
Browse files Browse the repository at this point in the history
…611)

## Description

Checks if the rust-src component is installed for the workspace
toolchain.

This is a basic requirement to build firmware code and not having
rust-src can result in an obscure error during firmware build.

- [ ] Impacts functionality?
- **Functionality** - Does the change ultimately impact how firmware
functions?
- Examples: Add a new library, publish a new PPI, update an algorithm,
...
- [ ] Impacts security?
- **Security** - Does the change have a direct security impact on an
application,
    flow, or firmware?
  - Examples: Crypto algorithm change, buffer overflow fix, parameter
    validation improvement, ...
- [ ] Breaking change?
- **Breaking change** - Will anyone consuming this change experience a
break
    in build or boot behavior?
- Examples: Add a new library class, move a module to a different repo,
call
    a function in a new library class in a pre-existing module, ...
- [ ] Includes tests?
  - **Tests** - Does the change include any explicit test code?
  - Examples: Unit tests, integration tests, robot tests, ...
- [ ] Includes documentation?
- **Documentation** - Does the change contain explicit documentation
additions
    outside direct code modifications (and comments)?
- Examples: Update readme file, add feature readme file, link to
documentation
    on an a separate Web page, ...

## How This Was Tested

- Verify with the `rust-src` component installed/uninstalled
- Check on Linux and Windows

## Integration Instructions

N/A - Instructions included in log output

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
  • Loading branch information
makubacki authored and kenlautner committed Jan 19, 2024
1 parent 170d1d7 commit 1cc3b35
Showing 1 changed file with 79 additions and 12 deletions.
91 changes: 79 additions & 12 deletions BaseTools/Plugin/RustEnvironmentCheck/RustEnvironmentCheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
from edk2toollib.utility_functions import RunCmd
from io import StringIO

WORKSPACE_TOOLCHAIN_FILE = "rust-toolchain.toml"

RustToolInfo = namedtuple("RustToolInfo", ["presence_cmd", "install_help"])
RustToolChainInfo = namedtuple("RustToolChainInfo", ["error", "toolchain"])

Expand Down Expand Up @@ -59,35 +61,45 @@ def verify_cmd(name: str, params: str = "--version") -> bool:
logging_level=logging.DEBUG)
return ret == 0

def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo:
"""Verifies the rust toolchain used in the workspace is available.
Note: This function does not use the toml library to parse the toml
file since the file is very simple and its not desirable to add the
toml module as a dependency.
def get_workspace_toolchain_version() -> RustToolChainInfo:
"""Returns the rust toolchain version specified in the workspace
toolchain file.
Returns:
RustToolChainInfo: A tuple that indicates if the toolchain is
available and any the toolchain version if found.
RustToolChainInfo: The rust toolchain information. If an error
occurs, the error field will be True with no toolchain info.
"""
WORKSPACE_TOOLCHAIN_FILE = "rust-toolchain.toml"

toolchain_version = None
try:
with open(WORKSPACE_TOOLCHAIN_FILE, 'r') as toml_file:
content = toml_file.read()
match = re.search(r'channel\s*=\s*"([^"]+)"', content)
if match:
toolchain_version = match.group(1)
return RustToolChainInfo(error=False, toolchain=toolchain_version)
except FileNotFoundError:
# If a file is not found. Do not check any further.
return RustToolChainInfo(error=False, toolchain=None)
return RustToolChainInfo(error=True, toolchain=None)

def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo:
"""Verifies the rust toolchain used in the workspace is available.
Note: This function does not use the toml library to parse the toml
file since the file is very simple and its not desirable to add the
toml module as a dependency.
if not toolchain_version:
Returns:
RustToolChainInfo: A tuple that indicates if the toolchain is
available and any the toolchain version if found.
"""
toolchain_version = get_workspace_toolchain_version()
if toolchain_version.error or not toolchain_version:
# If the file is not in an expected format, let that be handled
# elsewhere and do not look further.
return RustToolChainInfo(error=False, toolchain=None)

toolchain_version = toolchain_version.toolchain

installed_toolchains = StringIO()
ret = RunCmd("rustup", "toolchain list",
outstream=installed_toolchains,
Expand All @@ -104,6 +116,58 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo:
for toolchain in installed_toolchains),
toolchain=toolchain_version)

def verify_rust_src_component_is_installed() -> bool:
"""Verifies the rust-src component is installed.
Returns:
bool: True if the rust-src component is installed for the default
toolchain or the status could not be determined, otherwise, False.
"""
toolchain_version = get_workspace_toolchain_version()
if toolchain_version.error or not toolchain_version:
# If the file is not in an expected format, let that be handled
# elsewhere and do not look further.
return True

toolchain_version = toolchain_version.toolchain

rustup_output = StringIO()
ret = RunCmd("rustc", "--version --verbose",
outstream=rustup_output,
logging_level=logging.DEBUG)
if ret != 0:
# rustc installation is checked elsewhere. Exit here on failure.
return True

for line in rustup_output.getvalue().splitlines():
start_index = line.lower().strip().find("host: ")
if start_index != -1:
target_triple = line[start_index + len("host: "):]
break
else:
logging.error("Failed to get host target triple information.")
return False

rustup_output = StringIO()
ret = RunCmd("rustup", f"component list --toolchain {toolchain_version}",
outstream=rustup_output,
logging_level=logging.DEBUG)
if ret != 0:
# rustup installation and the toolchain are checked elsewhere.
# Exit here on failure.
return True

for component in rustup_output.getvalue().splitlines():
if "rust-src (installed)" in component:
return True

logging.error("The Rust toolchain is installed but the rust-src component "
"needs to be installed:\n\n"
f" rustup component add --toolchain {toolchain_version}-"
f"{target_triple} rust-src")

return False

generic_rust_install_instructions = \
"Visit https://rustup.rs/ to install Rust and cargo."

Expand Down Expand Up @@ -184,4 +248,7 @@ def verify_workspace_rust_toolchain_is_installed() -> RustToolChainInfo:
f"{rust_toolchain_info.toolchain}-<host>\"")
errors += 1

if not verify_rust_src_component_is_installed():
errors += 1

return errors

0 comments on commit 1cc3b35

Please sign in to comment.