rsyncclient

package
v0.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2025 License: BSD-3-Clause Imports: 8 Imported by: 1

Documentation

Overview

Package rsyncclient implements an rsync client (only), but note that gokrazy/rsync contains a native Go rsync implementation that supports sending and receiving files as client or server, compatible with the original tridge rsync (from the samba project) or openrsync (used on OpenBSD and macOS 15+).

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

func New

func New(args []string, opts ...Option) (*Client, error)

New creates a new Client. You can call Client.Run one or more times with the same Client.

func (*Client) Run

func (c *Client) Run(ctx context.Context, conn io.ReadWriter, paths []string) (*Result, error)

Run starts one run of the rsync protocol (not the rsync daemon protocol), see also https://michael.stapelberg.ch/posts/2022-07-02-rsync-how-does-it-work/.

If you just want to transfer some data from an already running rsync server or remote system, use the github.com/gokrazy/rsync/rsynccmd package instead, which will take care of starting rsync as a subprocess (locally or remotely), or of connecting to an rsync daemon via TCP.

The Run method operates on any kind of connection (using the io.ReadWriter interface) and is meant to be used when you need more control over the setup. For example, maybe you want to set up some custom tunneling to an rsync process running deep in some remote cloud infrastructure.

Or maybe you want to connect an rsync client and server to each other via a custom RPC protocol. In that case, you will need to transport the Client.ServerCommandOptions to the server and then arrange for two io.ReadWriter connections between client and server.

Example (ReceiveFromSubprocess)
package main

import (
	"context"
	"io"
	"log"
	"os/exec"

	"github.com/gokrazy/rsync/rsyncclient"
)

func main() {
	args, src, dest := []string{"-av"}, "/usr/share/man", "/tmp/man"
	client, err := rsyncclient.New(args)
	if err != nil {
		log.Fatal(err)
	}

	// Start an rsync server and run an rsync client on its stdin/stdout.
	rsync := exec.Command("rsync", client.ServerCommandOptions(src)...)
	stdin, err := rsync.StdinPipe()
	if err != nil {
		log.Fatal(err)
	}
	stdout, err := rsync.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := rsync.Start(); err != nil {
		log.Fatal(err)
	}
	// Create an io.ReadWriter from a Reader and a Writer.
	rw := &struct {
		io.Reader
		io.Writer
	}{
		Reader: stdout, // The client reads from the server's stdout.
		Writer: stdin,  // The client writes to the server's stdin.
	}

	if _, err := client.Run(context.Background(), rw, []string{dest}); err != nil {
		log.Fatal(err)
	}
}
Output:

Example (SendToGoroutine)
package main

import (
	"context"
	"io"
	"log"

	"github.com/gokrazy/rsync/internal/rsyncopts"
	"github.com/gokrazy/rsync/rsyncclient"
	"github.com/gokrazy/rsync/rsyncd"
)

func main() {
	ctx := context.Background()

	args, src, dest := []string{"-av"}, "/usr/share/man", "/tmp/man"
	client, err := rsyncclient.New(args, rsyncclient.WithSender())
	if err != nil {
		log.Fatal(err)
	}

	// Start an rsync server and run an rsync client on
	// an io.Pipe()-backend stdin/stdout.
	rsync, err := rsyncd.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}
	// stdin from the view of the rsync server
	stdinrd, stdinwr := io.Pipe()
	stdoutrd, stdoutwr := io.Pipe()
	go func() {
		conn := rsyncd.NewConnection(stdinrd, stdoutwr, "<io.Pipe>")
		pc, err := rsyncopts.ParseArguments(client.ServerCommandOptions(dest))
		if err != nil {
			log.Fatalf("parsing server args: %v", err)
		}
		if err := rsync.InternalHandleConn(ctx, conn, nil, pc); err != nil {
			log.Fatal(err)
		}
	}()

	// Create an io.ReadWriter from a Reader and a Writer.
	rw := &struct {
		io.Reader
		io.Writer
	}{
		Reader: stdoutrd, // The client reads from the server's stdout.
		Writer: stdinwr,  // The client writes to the server's stdin.
	}

	if _, err := client.Run(ctx, rw, []string{src}); err != nil {
		log.Fatal(err)
	}
}
Output:

func (*Client) ServerCommandOptions

func (c *Client) ServerCommandOptions(path string, paths ...string) []string

ServerCommandOptions returns the options that rsync would use to spawn the server process.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option specifies the client options.

func WithSender

func WithSender() Option

WithSender enables sender mode (receiver by default).

func WithStderr

func WithStderr(stderr io.Writer) Option

WithStderr makes the Client write to the specified stderr instead of os.Stderr.

func WithoutNegotiate

func WithoutNegotiate() Option

WithoutNegotiate disables protocol version negotiation (enabled by default).

type Result

type Result struct {
	Stats *rsyncstats.TransferStats
}

Result contains information about a transfer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL