Skip to content

linux.copy() raises NotImplementedError between two independent SubprocessConnector machines on the same host #129

Description

@kvmajo

`linux.copy()` decides two paths are "on the same host" purely by
class inheritance:

https://github.com/Rahix/tbot/blob/master/tbot/machine/linux/copy.py#L118

if isinstance(p1.host, p2.host.__class__) or isinstance(p2.host, p1.host.__class__):
    # Both paths are on the same host
    ...

This only matches when one machine's class is literally a subclass of
the other's. If a project defines two separate machine classes that
both connect via `connector.SubprocessConnector` (i.e. both actually
run on localhost) but don't inherit from each other, `copy()` doesn't
recognize them as the same host. It then falls through every
SSH/Paramiko-specific branch and hits:

raise NotImplementedError(f"Can't copy from {p1.host} to {p2.host}!")

even though both machines run commands on the same filesystem and a
plain `cp` would work.

Repro

class LabHost(connector.SubprocessConnector, linux.Bash):
    ...

class LocalHost(connector.SubprocessConnector, linux.Bash):
    ...

with tbot.ctx.request(tbot.role.LocalHost) as local, \
     tbot.ctx.request(tbot.role.LabHost) as lab:
    linux.copy(local.workdir / "foo", lab.workdir / "foo")
    # NotImplementedError: Can't copy from <LabHost ...> to <LocalHost ...>!

Suggested fix

Detect "same host" by checking that both machines are
`SubprocessConnector` instances (i.e. both run locally), rather than
requiring one machine's class to be a subclass of the other's:

if isinstance(p1.host, connector.SubprocessConnector) and isinstance(p2.host, connector.SubprocessConnector):
    ...

Currently working around this downstream by special-casing this
combination and calling `local.exec0("cp", ...)` directly instead of
`linux.copy()`/`utils.copy_to_dir()`.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions