SSH API
SSH connection, remote execution, and file transfer helpers are available under ptool.ssh and p.ssh.
ptool.ssh.connect
v0.1.0- Introduced.
ptool.ssh.connect(target_or_options) opens an SSH connection and returns a
Connection UserData.
Arguments:
target_or_options(string|table, required):- When a string is provided, it is treated as an SSH target.
- When a table is provided, it currently supports:
target(string, optional): SSH target string such as"[email protected]"or"[email protected]:2222".host(string, optional): Hostname or IP address.user(string, optional): SSH username. Defaults to$USER, or"root"if$USERis unavailable.port(integer, optional): SSH port. Defaults to22.auth(table, optional): Authentication settings.host_key(table, optional): Host key verification settings.connect_timeout_ms(integer, optional): Timeout in milliseconds. Defaults to10000.keepalive_interval_ms(integer, optional): Keepalive interval in milliseconds.
Supported target string examples:
local a = ptool.ssh.connect("[email protected]")
local b = ptool.ssh.connect("[email protected]:2222")
local c = ptool.ssh.connect("[2001:db8::10]:2222")
auth fields:
private_key_file(string, optional): Path to a private key file.private_key_passphrase(string, optional): Passphrase for the private key.password(string, optional): Password-based authentication.
Authentication behavior:
- If
auth.passwordis provided, password authentication is used. - Otherwise, if
auth.private_key_fileis provided, public-key authentication is used with that key. - Otherwise,
ptooltries these default private key files in order:~/.ssh/id_ed25519,~/.ssh/id_rsa,~/.ssh/id_ecdsa. - Relative key paths are resolved from the current
ptoolruntime directory, so they followptool.cd(...). ~and~/...are expanded in key paths.
host_key fields:
verify(string, optional): Host key verification mode. Supported values:"known_hosts": Verify against a known_hosts file (default)."ignore": Skip host key verification.
known_hosts_file(string, optional): Path to a known_hosts file. Used only whenverify = "known_hosts".
Host key behavior:
- When
known_hosts_fileis omitted, the default known_hosts location is used. - Relative
known_hosts_filepaths are resolved from the currentptoolruntime directory. ~and~/...are expanded inknown_hosts_file.
Example:
local ssh = ptool.ssh.connect({
host = "example.com",
user = "deploy",
port = 22,
auth = {
private_key_file = "~/.ssh/id_ed25519",
},
host_key = {
verify = "known_hosts",
},
})
ptool.ssh.Connection
v0.1.0- Introduced.
ptool.ssh.connect(...) returns a Connection UserData with the following
fields and methods:
- Fields:
conn.host(string)conn.user(string)conn.port(integer)conn.target(string)
- Methods:
conn:run(...)->tableconn:path(path)->userdataconn:exists(path)->booleanconn:is_file(path)->booleanconn:is_dir(path)->booleanconn:upload(local_path, remote_path[, options])->tableconn:download(remote_path, local_path[, options])->tableconn:close()->nil
ptool.ssh.Connection:run
v0.1.0- Introduced.
conn:run(...) executes a remote command through the current SSH connection.
The following call forms are supported:
conn:run("hostname")
conn:run("echo", "hello world")
conn:run("echo", {"hello", "world"})
conn:run("hostname", { stdout = "capture" })
conn:run("echo", {"hello", "world"}, { stdout = "capture" })
conn:run({ cmd = "git", args = {"rev-parse", "HEAD"} })
Argument rules:
conn:run(cmdline):cmdlineis sent as the remote command string.conn:run(cmd, argsline):cmdis treated as the command, andargslineis split using shell-style (shlex) rules.conn:run(cmd, args):cmdis a string andargsis an array of strings. Arguments are shell-quoted before remote execution.conn:run(cmdline, options):optionsoverrides this invocation.conn:run(cmd, args, options):optionsoverrides this invocation.conn:run(options):optionsis a table.- When the second argument is a table: if it is an array (consecutive integer
keys
1..n), it is treated asargs; otherwise it is treated asoptions.
When conn:run(options) is used, options currently supports:
cmd(string, required): The command name or executable path.args(string[], optional): The argument list.cwd(string, optional): Remote working directory. This is applied by prependingcd ... &&to the generated remote shell command.env(table, optional): Remote environment variables, where keys and values are strings. This is applied by prependingexport ... &&to the generated remote shell command.stdin(string, optional): String sent to the remote process stdin.echo(boolean, optional): Whether to echo the remote command before execution. Defaults tofalse.check(boolean, optional): Whether to raise an error immediately when the exit status is not0. Defaults tofalse.stdout(string, optional): Stdout handling strategy. Supported values:"inherit": Inherit to the current terminal (default)."capture": Capture intores.stdout."null": Discard the output.
stderr(string, optional): Stderr handling strategy. Supported values:"inherit": Inherit to the current terminal (default)."capture": Capture intores.stderr."null": Discard the output.
When the shortcut forms are used, the options table supports only:
stdin(string, optional): String sent to the remote process stdin.echo(boolean, optional): Whether to echo the remote command before execution. Defaults tofalse.check(boolean, optional): Whether to raise an error immediately when the exit status is not0. Defaults tofalse.stdout(string, optional): Stdout handling strategy. Supported values:"inherit": Inherit to the current terminal (default)."capture": Capture intores.stdout."null": Discard the output.
stderr(string, optional): Stderr handling strategy. Supported values:"inherit": Inherit to the current terminal (default)."capture": Capture intores.stderr."null": Discard the output.
Return value rules:
- A table is always returned with the following fields:
ok(boolean): Whether the remote exit status is0.code(integer|nil): The remote exit status. If the remote process exits by signal, this isnil.target(string): The SSH target string in the formuser@host:port.stdout(string, optional): Present whenstdout = "capture".stderr(string, optional): Present whenstderr = "capture".assert_ok(self)(function): Raises an error whenok = false.
Example:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:run("uname -a", { stdout = "capture" })
print(res.target)
print(res.stdout)
local res2 = ssh:run({
cmd = "git",
args = {"rev-parse", "HEAD"},
cwd = "/srv/app",
env = {
FOO = "bar",
},
stdout = "capture",
check = true,
})
print(res2.stdout)
ptool.ssh.Connection:path
v0.1.0- Introduced.
conn:path(path) creates a reusable remote path value bound to the current SSH
connection.
path(string, required): The remote path.- Returns: A remote path userdata that can be passed to
conn:upload(...),conn:download(...), andptool.fs.copy(...). - The returned remote path also supports:
remote:exists()->booleanremote:is_file()->booleanremote:is_dir()->boolean
Example:
local ssh = ptool.ssh.connect("[email protected]")
local remote_release = ssh:path("/srv/app/releases/current.tar.gz")
ssh:download(remote_release, "./tmp/current.tar.gz")
ptool.ssh.Connection:exists
v0.2.0- Introduced.
conn:exists(path) checks whether a remote path exists.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path exists, otherwisefalse.
Example:
local ssh = ptool.ssh.connect("[email protected]")
print(ssh:exists("/srv/app"))
print(ssh:path("/srv/app/releases/current.tar.gz"):exists())
ptool.ssh.Connection:is_file
v0.2.0- Introduced.
conn:is_file(path) checks whether a remote path exists and is a regular file.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path is a file, otherwisefalse.
Example:
local ssh = ptool.ssh.connect("[email protected]")
local remote_tarball = ssh:path("/srv/app/releases/current.tar.gz")
if ssh:is_file(remote_tarball) then
print("release tarball exists")
end
ptool.ssh.Connection:is_dir
v0.2.0- Introduced.
conn:is_dir(path) checks whether a remote path exists and is a directory.
path(string|remote path, required): The remote path to check. It can be a string or a value created byconn:path(...).- Returns:
truewhen the remote path is a directory, otherwisefalse.
Example:
local ssh = ptool.ssh.connect("[email protected]")
local releases = ssh:path("/srv/app/releases")
if releases:is_dir() then
print("releases directory is ready")
end
ptool.ssh.Connection:upload
v0.1.0- Introduced.
conn:upload(local_path, remote_path[, options]) uploads a local file to the
remote host.
local_path(string, required): The local file to upload.remote_path(string|remote path, required): The destination path on the remote host. It can be a string or a value created byconn:path(...).options(table, optional): Transfer options.- Returns: A table with the following fields:
bytes(integer): The number of bytes uploaded.from(string): The local source path.to(string): The remote destination path.
Supported transfer options:
parents(boolean, optional): Create the parent directory ofremote_pathbefore uploading. Defaults tofalse.overwrite(boolean, optional): Whether an existing destination file may be replaced. Defaults totrue.echo(boolean, optional): Whether to print the transfer before executing it. Defaults tofalse.
Example:
local ssh = ptool.ssh.connect("[email protected]")
local remote_tarball = ssh:path("/srv/app/releases/current.tar.gz")
local res = ssh:upload("./dist/app.tar.gz", remote_tarball, {
parents = true,
overwrite = true,
echo = true,
})
print(res.bytes)
print(res.to)
ptool.ssh.Connection:download
v0.1.0- Introduced.
conn:download(remote_path, local_path[, options]) downloads a remote file to a
local path.
remote_path(string|remote path, required): The source path on the remote host. It can be a string or a value created byconn:path(...).local_path(string, required): The local destination path.options(table, optional): Transfer options.- Returns: A table with the following fields:
bytes(integer): The number of bytes downloaded.from(string): The remote source path.to(string): The local destination path.
Supported transfer options:
parents(boolean, optional): Create the parent directory oflocal_pathbefore downloading. Defaults tofalse.overwrite(boolean, optional): Whether an existing destination file may be replaced. Defaults totrue.echo(boolean, optional): Whether to print the transfer before executing it. Defaults tofalse.
Example:
local ssh = ptool.ssh.connect("[email protected]")
local res = ssh:download("/srv/app/logs/app.log", "./tmp/app.log", {
parents = true,
overwrite = false,
echo = true,
})
print(res.bytes)
print(res.from)
ptool.ssh.Connection:close
v0.1.0- Introduced.
conn:close() closes the SSH connection.
Behavior:
- After closing, the connection can no longer be used.
- Closing an already-closed connection is allowed and has no effect.
Example:
local ssh = ptool.ssh.connect("[email protected]")
ssh:close()