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

fs.Digest is declared in Rust #10905

Merged
merged 2 commits into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 10 additions & 3 deletions src/python/pants/backend/python/goals/coverage_py_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
import pytest

from pants.backend.python.goals.coverage_py import CoverageSubsystem, create_coverage_config
from pants.engine.fs import CreateDigest, Digest, DigestContents, FileContent, PathGlobs
from pants.engine.fs import (
EMPTY_DIGEST,
CreateDigest,
Digest,
DigestContents,
FileContent,
PathGlobs,
)
from pants.testutil.option_util import create_subsystem
from pants.testutil.rule_runner import MockGet, run_rule_with_mocks

Expand All @@ -22,7 +29,7 @@ def mock_handle_config(request: CreateDigest) -> Digest:
assert isinstance(request[0], FileContent)
assert request[0].is_executable is False
resolved_config.append(request[0].content.decode())
return Digest("jerry", 30)
return EMPTY_DIGEST

def mock_read_config(_: PathGlobs) -> DigestContents:
# This shouldn't be called if no config file provided.
Expand All @@ -37,7 +44,7 @@ def mock_read_config(_: PathGlobs) -> DigestContents:
]

result = run_rule_with_mocks(create_coverage_config, rule_args=[coverage], mock_gets=mock_gets)
assert result.digest.fingerprint == "jerry"
assert result.digest.fingerprint == EMPTY_DIGEST.fingerprint
assert len(resolved_config) == 1
return resolved_config[0]

Expand Down
3 changes: 2 additions & 1 deletion src/python/pants/core/goals/fmt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,10 @@ def test_streaming_output_skip() -> None:


def test_streaming_output_changed() -> None:
changed_digest = Digest(EMPTY_DIGEST.fingerprint, 2)
result = FmtResult(
input=EMPTY_DIGEST,
output=Digest("abc", 10),
output=changed_digest,
stdout="stdout",
stderr="stderr",
formatter_name="formatter",
Expand Down
15 changes: 6 additions & 9 deletions src/python/pants/engine/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import TYPE_CHECKING, Iterable, Optional, Tuple, Union

from pants.engine.collection import Collection
from pants.engine.internals.native_engine import PyDigest
from pants.engine.rules import QueryRule, side_effecting
from pants.option.global_options import GlobMatchErrorBehavior as GlobMatchErrorBehavior
from pants.util.meta import frozen_after_init
Expand All @@ -14,16 +15,12 @@
from pants.engine.internals.scheduler import SchedulerSession


@dataclass(frozen=True)
class Digest:
"""A Digest is a lightweight reference to a set of files known about by the engine.

You can use `await Get(Snapshot, Digest)` to set the file names referred to, or use `await
Get(DigestContents, Digest)` to see the actual file content.
"""
"""A Digest is a lightweight reference to a set of files known about by the engine.

fingerprint: str
serialized_bytes_length: int
You can use `await Get(Snapshot, Digest)` to set the file names referred to, or use `await
Copy link
Contributor

Choose a reason for hiding this comment

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

s/set/get/ ?

Get(DigestContents, Digest)` to see the actual file content.
"""
Digest = PyDigest


@dataclass(frozen=True)
Expand Down
5 changes: 4 additions & 1 deletion src/python/pants/engine/internals/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ python_integration_tests(

python_library(
name='native',
sources=['native.py'],
sources=[
'native.py',
'native_engine.pyi',
Copy link
Contributor

Choose a reason for hiding this comment

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

Woot! This is exciting to see used.

],
dependencies=[
':native_engine',
],
Expand Down
59 changes: 31 additions & 28 deletions src/python/pants/engine/internals/native.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pants.base.exiter import ExitCode
from pants.engine.fs import PathGlobs
from pants.engine.internals import native_engine
from pants.engine.internals.native_engine import ( # type: ignore[import]
from pants.engine.internals.native_engine import (
PyExecutionRequest,
PyExecutionStrategyOptions,
PyExecutor,
Expand Down Expand Up @@ -71,18 +71,18 @@ def generator_send(
if isinstance(res, Get):
# Get.
return PyGeneratorResponseGet(
res.output_type,
res.input_type,
res.input,
product=res.output_type,
declared_subject=res.input_type,
subject=res.input,
)
elif type(res) in (tuple, list):
# GetMulti.
return PyGeneratorResponseGetMulti(
tuple(
gets=tuple(
PyGeneratorResponseGet(
get.output_type,
get.input_type,
get.input,
product=get.output_type,
declared_subject=get.input_type,
subject=get.input,
Comment on lines +83 to +85
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, fine to not fix, but I thought I had fixed most of the Rust code to call this input and output.

)
for get in res
)
Expand All @@ -94,7 +94,7 @@ def generator_send(
raise
# This was a `return` from a coroutine, as opposed to a `StopIteration` raised
# by calling `next()` on an empty iterator.
return PyGeneratorResponseBreak(e.value)
return PyGeneratorResponseBreak(val=e.value)


class RawFdRunner(Protocol):
Expand Down Expand Up @@ -211,11 +211,11 @@ def new_session(
session_values: SessionValues,
) -> PySession:
return PySession(
scheduler,
dynamic_ui,
build_id,
should_report_workunits,
session_values,
scheduler=scheduler,
should_render_ui=dynamic_ui,
build_id=build_id,
should_report_workunits=should_report_workunits,
session_values=session_values,
)

def new_scheduler(
Expand Down Expand Up @@ -266,20 +266,23 @@ def new_scheduler(
local_enable_nailgun=execution_options.process_execution_local_enable_nailgun,
)

return self.lib.scheduler_create(
self._executor,
tasks,
types,
# Project tree.
build_root,
local_store_dir,
local_execution_root_dir,
named_caches_dir,
ca_certs_path,
ignore_patterns,
use_gitignore,
remoting_options,
exec_stategy_opts,
return cast(
PyScheduler,
self.lib.scheduler_create(
self._executor,
tasks,
types,
# Project tree.
build_root,
local_store_dir,
local_execution_root_dir,
named_caches_dir,
ca_certs_path,
ignore_patterns,
use_gitignore,
remoting_options,
exec_stategy_opts,
),
)

def set_panic_handler(self):
Expand Down
48 changes: 48 additions & 0 deletions src/python/pants/engine/internals/native_engine.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import Any

# TODO: black and flake8 disagree about the content of this file:
# see https://github.com/psf/black/issues/1548
# flake8: noqa: E302

class PyDigest:
def __init__(self, fingerprint: str, serialized_bytes_length: int) -> None: ...
@property
def fingerprint(self) -> str: ...
@property
def serialized_bytes_length(self) -> int: ...

class PyExecutionRequest:
def __init__(self, **kwargs: Any) -> None: ...

class PyExecutionStrategyOptions:
def __init__(self, **kwargs: Any) -> None: ...

class PyExecutor:
def __init__(self, **kwargs: Any) -> None: ...

class PyGeneratorResponseBreak:
def __init__(self, **kwargs: Any) -> None: ...

class PyGeneratorResponseGet:
def __init__(self, **kwargs: Any) -> None: ...

class PyGeneratorResponseGetMulti:
def __init__(self, **kwargs: Any) -> None: ...

class PyNailgunServer:
def __init__(self, **kwargs: Any) -> None: ...

class PyRemotingOptions:
def __init__(self, **kwargs: Any) -> None: ...

class PyScheduler:
def __init__(self, **kwargs: Any) -> None: ...

class PySession:
def __init__(self, **kwargs: Any) -> None: ...

class PyTasks:
def __init__(self, **kwargs: Any) -> None: ...

class PyTypes:
def __init__(self, **kwargs: Any) -> None: ...
3 changes: 1 addition & 2 deletions src/python/pants/engine/internals/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
RemovePrefix,
Snapshot,
)
from pants.engine.internals.native_engine import PyTypes # type: ignore[import]
from pants.engine.internals.native_engine import PyTypes
from pants.engine.internals.nodes import Return, Throw
from pants.engine.internals.selectors import Params
from pants.engine.internals.session import SessionValues
Expand Down Expand Up @@ -130,7 +130,6 @@ def __init__(
tasks = self._register_rules(rule_index, union_membership)

types = PyTypes(
directory_digest=Digest,
file_digest=FileDigest,
snapshot=Snapshot,
paths=Paths,
Expand Down
12 changes: 10 additions & 2 deletions src/python/pants/engine/process_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@

import pytest

from pants.engine.fs import CreateDigest, Digest, DigestContents, FileContent, PathGlobs, Snapshot
from pants.engine.fs import (
EMPTY_DIGEST,
CreateDigest,
Digest,
DigestContents,
FileContent,
PathGlobs,
Snapshot,
)
from pants.engine.internals.scheduler import ExecutionError
from pants.engine.process import (
BinaryPathRequest,
Expand Down Expand Up @@ -451,7 +459,7 @@ def test_non_fallible_failing_command_raises(self):


def test_running_interactive_process_in_workspace_cannot_have_input_files() -> None:
mock_digest = Digest("fake", 1)
mock_digest = Digest(EMPTY_DIGEST.fingerprint, 1)
with pytest.raises(ValueError):
InteractiveProcess(argv=["/bin/echo"], input_digest=mock_digest, run_in_workspace=True)

Expand Down
1 change: 1 addition & 0 deletions src/rust/engine/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/rust/engine/hashing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ authors = [ "Pants Build <[email protected]>" ]
publish = false

[dependencies]
byteorder = "1.3"
digest = "0.9"
generic-array = "0.14"
hex = "0.3.1"
Expand Down
9 changes: 9 additions & 0 deletions src/rust/engine/hashing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

use byteorder::ByteOrder;
use digest::consts::U32;
use generic_array::GenericArray;
use serde::de::{MapAccess, Visitor};
Expand Down Expand Up @@ -85,6 +86,14 @@ impl Fingerprint {
}
s
}

///
/// Using the fact that a Fingerprint is computed using a strong hash function, computes a strong
/// but short hash value from a prefix.
///
pub fn prefix_hash(&self) -> u64 {
byteorder::BigEndian::read_u64(&self.0)
}
}

impl fmt::Display for Fingerprint {
Expand Down
Loading