Skip to content

Commit

Permalink
Merge branch 'develop' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
NiklasRosenstein authored Feb 27, 2024
2 parents 1c785e1 + bfdd906 commit 3ae1674
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 237 deletions.
6 changes: 6 additions & 0 deletions .changelog/_unreleased.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ type = "fix"
description = "Do not use `dmypy` on Windows"
author = "@NiklasRosenstein"
component = "kraken-build"

[[entries]]
id = "db65bd12-a9d1-472c-a38b-6f889cdda683"
type = "improvement"
description = "Move bump version into publish"
author = "[email protected]"
43 changes: 4 additions & 39 deletions kraken-build/src/kraken/std/cargo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from .config import CargoConfig, CargoProject, CargoRegistry
from .tasks.cargo_auth_proxy_task import CargoAuthProxyTask
from .tasks.cargo_build_task import CargoBuildTask
from .tasks.cargo_bump_version_task import CargoBumpVersionTask
from .tasks.cargo_check_toolchain_version import CargoCheckToolchainVersionTask
from .tasks.cargo_clippy_task import CargoClippyTask
from .tasks.cargo_deny_task import CargoDenyTask
Expand All @@ -32,7 +31,6 @@
__all__ = [
"cargo_auth_proxy",
"cargo_build",
"cargo_bump_version",
"cargo_clippy",
"cargo_deny",
"cargo_fmt",
Expand All @@ -45,7 +43,6 @@
"cargo_update",
"CargoAuthProxyTask",
"CargoBuildTask",
"CargoBumpVersionTask",
"CargoClippyTask",
"CargoDenyTask",
"CargoProject",
Expand Down Expand Up @@ -287,42 +284,6 @@ def cargo_update(*, project: Project | None = None) -> CargoUpdateTask:
return task


def cargo_bump_version(
*,
version: str,
revert: bool = True,
name: str = "cargoBumpVersion",
registry: str | None = None,
project: Project | None = None,
cargo_toml_file: Path = Path("Cargo.toml"),
) -> CargoBumpVersionTask:
"""Get or create a task that bumps the version in `Cargo.toml`.
:param version: The version number to bump to.
:param revert: Revert the version number after all direct dependants have run.
:param name: The task name. Note that if another task with the same configuration but different name exists,
it will not change the name of the task and that task will still be reused.
:param group: The group to assign the task to (even if the task is reused)."""

# This task will write the "current" version (usually taken from git) into Cargo.toml
# That is useful at two places
# * at build time (because apps may use env!("CARGO_PKG_VERSION"))
# * at publish time (because the artifact file name is derived from the version)

project = project or Project.current()

task = project.task(name, CargoBumpVersionTask, group=CARGO_BUILD_SUPPORT_GROUP_NAME)
task.version = version
task.revert = revert
task.registry = registry
task.cargo_toml_file = cargo_toml_file

# project.do() only supports one group, but this task is needed in two groups
project.group(CARGO_PUBLISH_SUPPORT_GROUP_NAME).add(task)

return task


def cargo_build(
mode: Literal["debug", "release"],
incremental: bool | None = None,
Expand Down Expand Up @@ -437,6 +398,8 @@ def cargo_publish(
name: str = "cargoPublish",
package_name: str | None = None,
project: Project | None = None,
version: str | None = None,
cargo_toml_file: Path = Path("Cargo.toml"),
) -> CargoPublishTask:
"""Creates a task that publishes the create to the specified *registry*.
Expand Down Expand Up @@ -466,6 +429,8 @@ def cargo_publish(
task.retry_attempts = retry_attempts
task.package_name = package_name
task.env = Supplier.of_callable(lambda: {**cargo.build_env, **(env or {})})
task.version = version
task.cargo_toml_file = cargo_toml_file
task.depends_on(f":{CARGO_PUBLISH_SUPPORT_GROUP_NAME}?")
return task

Expand Down
20 changes: 16 additions & 4 deletions kraken-build/src/kraken/std/cargo/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import logging
import os
import subprocess
from dataclasses import dataclass, fields
from enum import Enum
Expand Down Expand Up @@ -70,7 +71,7 @@ class CargoMetadata:
target_directory: Path

@classmethod
def read(cls, project_dir: Path, locked: bool | None = None) -> CargoMetadata:
def read(cls, project_dir: Path, from_project_dir: bool = False, locked: bool | None = None) -> CargoMetadata:
cmd = [
"cargo",
"metadata",
Expand All @@ -79,17 +80,28 @@ def read(cls, project_dir: Path, locked: bool | None = None) -> CargoMetadata:
"--manifest-path",
str(project_dir / "Cargo.toml"),
]

# the .cargo/config.toml in user/foo/bar is not picked up when running this command from
# user/foo for example. This flag executes the subprocess from the project dir
if from_project_dir:
cwd = project_dir
else:
cwd = Path(os.getcwd())

if locked is None:
# Append `--locked` if a Cargo.lock file is found in the project directory or any of its parents.
project_dir = project_dir.absolute()
for parent in [project_dir, *project_dir.parents]:
if (parent / "Cargo.lock").exists():
cmd.append("--locked")
break
elif locked:
# if locked is True, we should *always* pass --locked.
# the expectation is that the command will fail w/o Cargo.lock.
# If locked is True, we should *always* pass --locked. The expectation is that the command will
# fail w/o a Cargo.lock file.
cmd.append("--locked")
result = subprocess.run(cmd, stdout=subprocess.PIPE)

result = subprocess.run(cmd, stdout=subprocess.PIPE, cwd=cwd)

if result.returncode != 0:
logger.error("Stderr: %s", result.stderr)
logger.error(f"Could not execute `{' '.join(cmd)}`, and thus can't read the cargo metadata.")
Expand Down
5 changes: 4 additions & 1 deletion kraken-build/src/kraken/std/cargo/tasks/cargo_build_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class CargoBuildTask(Task):
#: An output property for the Cargo libraries that are being produced by this build.
out_libraries: Property[list[CargoLibraryArtifact]] = Property.output()

#: Flag indicating if we should execute this command from the project directory
from_project_dir: Property[bool] = Property.default(False)

def __init__(self, name: str, project: Project) -> None:
super().__init__(name, project)

Expand Down Expand Up @@ -107,7 +110,7 @@ def execute(self) -> TaskStatus:
if self.target.get_or(None) in ("debug", "release"):
# Expose the output binaries that are produced by this task.
# We only expect a binary to be built if the target is debug or release.
manifest = CargoMetadata.read(self.project.directory)
manifest = CargoMetadata.read(self.project.directory, self.from_project_dir.get())
target_dir = manifest.target_directory / self.target.get()
for artifact in manifest.artifacts:
# Rust binaries have an extensionless name whereas libraries are prefixed with "lib" and suffixed with
Expand Down
69 changes: 0 additions & 69 deletions kraken-build/src/kraken/std/cargo/tasks/cargo_bump_version_task.py

This file was deleted.

58 changes: 56 additions & 2 deletions kraken-build/src/kraken/std/cargo/tasks/cargo_publish_task.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import contextlib
import logging
from pathlib import Path
from typing import Any

from kraken.common import not_none
from kraken.core import Project, Property
from kraken.common import atomic_file_swap, not_none
from kraken.core import Project, Property, TaskStatus
from kraken.std.cargo import CargoProject

from ..config import CargoRegistry
from .cargo_build_task import CargoBuildTask
Expand All @@ -28,6 +31,12 @@ class CargoPublishTask(CargoBuildTask):
#: Allow dirty worktree.
allow_dirty: Property[bool] = Property.default(False)

#: Version to be bumped up to
version: Property[str | None] = Property.default(None)

#: Cargo.toml which to temporarily bump
cargo_toml_file: Property[Path] = Property.default("Config.toml")

def get_cargo_command(self, env: dict[str, str]) -> list[str]:
super().get_cargo_command(env)
registry = self.registry.get()
Expand All @@ -54,3 +63,48 @@ def make_safe(self, args: list[str], env: dict[str, str]) -> None:
def __init__(self, name: str, project: Project) -> None:
super().__init__(name, project)
self._base_command = ["cargo", "publish"]

def _get_updated_cargo_toml(self, version: str) -> str:
from kraken.std.cargo.manifest import CargoManifest

manifest = CargoManifest.read(self.cargo_toml_file.get())
if manifest.package is None:
return manifest.to_toml_string()

# Cargo does not play nicely with semver metadata (ie. 1.0.1-dev3+abc123)
# We replace that to 1.0.1-dev3abc123
fixed_version_string = version.replace("+", "")
manifest.package.version = fixed_version_string
if manifest.workspace and manifest.workspace.package:
manifest.workspace.package.version = version

if self.registry.is_filled():
CargoProject.get_or_create(self.project)
registry = self.registry.get()
if manifest.dependencies:
self._push_version_to_path_deps(fixed_version_string, manifest.dependencies.data, registry.alias)
if manifest.build_dependencies:
self._push_version_to_path_deps(fixed_version_string, manifest.build_dependencies.data, registry.alias)
return manifest.to_toml_string()

def _push_version_to_path_deps(
self, version_string: str, dependencies: dict[str, Any], registry_alias: str
) -> None:
"""For each dependency in the given dependencies, if the dependency is a `path` dependency, injects the current
version and registry (required for publishing - path dependencies cannot be published alone)."""
for dep_name in dependencies:
dependency = dependencies[dep_name]
if isinstance(dependency, dict):
if "path" in dependency:
dependency["version"] = f"={version_string}"
dependency["registry"] = registry_alias

def execute(self) -> TaskStatus:
with contextlib.ExitStack() as stack:
if (version := self.version.get()) is not None:
content = self._get_updated_cargo_toml(version)
fp = stack.enter_context(atomic_file_swap(self.cargo_toml_file.get(), "w", always_revert=True))
fp.write(content)
fp.close()
result = super().execute()
return result
Loading

0 comments on commit 3ae1674

Please sign in to comment.