-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rust plugin: rewrite the Rust plugin ...
... using the new plugin system Signed-off-by: Zixing Liu <zixing.liu@canonical.com>
- Loading branch information
Showing
9 changed files
with
237 additions
and
223 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*- | ||
# | ||
# Copyright (C) 2023 Canonical Ltd | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License version 3 as | ||
# published by the Free Software Foundation. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import json | ||
import logging | ||
import subprocess | ||
from typing import Any, Dict, List, Set, cast | ||
|
||
from craft_parts import infos, plugins | ||
from overrides import overrides | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class RustPluginProperties(plugins.PluginProperties, plugins.PluginModel): | ||
"""The part properties used by the Rust plugin.""" | ||
|
||
source: str | ||
rust_channel: str = "stable" | ||
rust_features: List[str] = [] | ||
rust_path: List[str] = ["."] | ||
rust_use_global_lto: bool = False | ||
rust_no_default_features: bool = False | ||
|
||
@classmethod | ||
@overrides | ||
def unmarshal(cls, data: Dict[str, Any]) -> "RustPluginProperties": | ||
"""Populate class attributes from the part specification. | ||
:param data: A dictionary containing part properties. | ||
:return: The populated plugin properties data object. | ||
:raise pydantic.ValidationError: If validation fails. | ||
""" | ||
plugin_data = plugins.extract_plugin_properties( | ||
data, | ||
plugin_name="rust", | ||
required=["source"], | ||
) | ||
return cls(**plugin_data) | ||
|
||
|
||
class RustPlugin(plugins.Plugin): | ||
"""This Rust plugin is useful for building Rust based parts. | ||
Rust uses cargo to drive the build. | ||
This plugin uses the common plugin keywords as well as those for "sources". | ||
For more information check the 'plugins' topic for the former and the | ||
'sources' topic for the latter. | ||
Additionally, this plugin uses the following plugin-specific keywords: | ||
- rust-channel | ||
(string, default "stable") | ||
Used to select which Rust channel or version to use. | ||
It can be one of "stable", "beta", "nightly" or a version number. | ||
If you don't want this plugin to install Rust toolchain for you, | ||
you can put "none" for this option. | ||
- rust-features | ||
(list of strings) | ||
Features used to build optional dependencies | ||
- rust-path | ||
(list of strings, default [.]) | ||
Build specific crates inside the workspace | ||
- rust-no-default-features | ||
(boolean, default False) | ||
Whether to disable the default features in this crate. | ||
Equivalent to setting `--no-default-features` on the commandline. | ||
- rust-use-global-lto | ||
(boolean, default False) | ||
Whether to use global LTO. | ||
This option may significantly impact the build performance but | ||
reducing the final binary size. | ||
This will forcibly enable LTO for all the crates you specified, | ||
regardless of whether you have LTO enabled in the Cargo.toml file""" | ||
|
||
properties_class = RustPluginProperties | ||
|
||
def __init__( | ||
self, *, properties: plugins.PluginProperties, part_info: infos.PartInfo | ||
) -> None: | ||
super().__init__(properties=properties, part_info=part_info) | ||
|
||
@overrides | ||
def get_build_snaps(self) -> Set[str]: | ||
return set() | ||
|
||
@overrides | ||
def get_build_packages(self) -> Set[str]: | ||
return {"curl", "gcc", "git", "pkg-config", "findutils"} | ||
|
||
def _check_rustup(self) -> bool: | ||
try: | ||
rustup_version = subprocess.check_output(["rustup", "--version"]) | ||
return "rustup" in rustup_version.decode("utf-8") | ||
except Exception: | ||
return False | ||
|
||
def _get_setup_rustup(self, channel: str) -> List[str]: | ||
return [ | ||
f"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile=minimal --default-toolchain {channel}" | ||
] | ||
|
||
@overrides | ||
def get_build_environment(self) -> Dict[str, str]: | ||
return { | ||
"PATH": "${HOME}/.cargo/bin:${PATH}", | ||
} | ||
|
||
@overrides | ||
def get_build_commands(self) -> List[str]: | ||
options = cast(RustPluginProperties, self._options) | ||
|
||
rust_install_cmd: List[str] = [] | ||
rust_build_cmd: List[str] = [] | ||
config_cmd: List[str] = [] | ||
rust_postbuild_cmd: List[str] = [] | ||
|
||
if options.rust_channel == "none": | ||
rust_install_cmd = [] | ||
elif not self._check_rustup(): | ||
logger.info("Rustup not found, installing it") | ||
rust_install_cmd = self._get_setup_rustup(options.rust_channel) | ||
else: | ||
logger.info("Switch rustup channel to %s", options.rust_channel) | ||
rust_install_cmd = [f"rustup default {options.rust_channel}"] | ||
|
||
if options.rust_features: | ||
config_cmd.extend( | ||
["--features", "'{}'".format(" ".join(self.options.rust_features))] | ||
) | ||
|
||
if options.rust_use_global_lto: | ||
logger.info("Adding overrides for LTO support") | ||
config_cmd.extend( | ||
[ | ||
"--config 'profile.release.lto = true'", | ||
"--config 'profile.release.codegen-units = 1'", | ||
] | ||
) | ||
|
||
if options.rust_no_default_features: | ||
config_cmd.append("--no-default-features") | ||
|
||
for crate in options.rust_path: | ||
logger.info("Generating build commands for %s", crate) | ||
config_cmd_string = " ".join(config_cmd) | ||
rust_build_cmd_single = f"""if cargo read-manifest --manifest-path "{crate}"/Cargo.toml > /dev/null; then | ||
cargo install -f --locked --path "{crate}" --root "${{SNAPCRAFT_PART_INSTALL}}" {config_cmd_string} | ||
# remove the installation metadata | ||
rm -f "${{SNAPCRAFT_PART_INSTALL}}"/.crates{{.toml,2.json}} | ||
else | ||
# virtual workspace is a bit tricky, | ||
# we need to build the whole workspace and then copy the binaries ourselves | ||
pushd "{crate}" | ||
cargo build --workspace --release {config_cmd_string} | ||
# install the final binaries | ||
# TODO(liushuyu): this will also install proc macros in the workspace, | ||
# which the user may not want to keep in the final installation | ||
find ./target/release -maxdepth 1 -executable -exec install -Dvm755 {{}} "${{SNAPCRAFT_PART_INSTALL}}" ';' | ||
popd | ||
fi""" | ||
rust_build_cmd.append(rust_build_cmd_single) | ||
return rust_install_cmd + rust_build_cmd |
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 was deleted.
Oops, something went wrong.
Oops, something went wrong.