gowsl

package module
v0.0.0-...-f4267f8 Latest Latest
Warning

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

Go to latest
Published: Feb 20, 2025 License: MIT Imports: 19 Imported by: 1

README

GoWSL

This module offers an idiomatic interface between your Go code and the Windows Subsystem for Linux (WSL) API (wslApi.dll and occasionally wsl.exe). It offers wrappers around common actions to manage WSL distros.

Code quality Go Reference Go Report Card License

Aim

We aim not to extend the aforementioned API, but rather to provide a safe, idiomatic, and easy-to-use wrapper around it. The goal is to enable the development of applications that build on top of it.

Requirements

  • Windows Subsystem for Linux must be installed (documentation) and enabled.
  • Go version must be equal to or above 1.20.

Development

Your help would be very much appreciated! Check out the CONTRIBUTING document to see how you could collaborate.

Contact

You are welcome to create a new issue on this repository if you find bugs or wish to make any feature request.

Documentation

Overview

Package gowsl implements an idiomatic interface to manage the Windows Subsystem for Linux from Go. It uses WslApi calls when possible, and otherwise reads the registry or, as a last resort, may subprocess wsl.exe.

This package also contains a mock WSL backend which can be useful for testing, as setting up WSL distros for every test-case can be quite time-consuming. This mock back-end is disabled by default, and can be enabled by using the context returned by the WithMock function.

Index

Constants

View Source
const (
	Stopped       = state.Stopped
	Running       = state.Running
	Installing    = state.Installing
	Uninstalling  = state.Uninstalling
	NonRegistered = state.NotRegistered
)

The states here reported are the ones obtained via `wsl.exe -l -v`, with the addition of NonRegistered.

Variables

View Source
var ErrNotExist = windows.ErrNotExist

ErrNotExist is the error returned when a distro does not exist.

Functions

func Install

func Install(ctx context.Context, appxName string) error

Install installs a new distro from the Windows store.

func MockAvailable

func MockAvailable() bool

MockAvailable indicates if the mock can be accessed at runtime. It is always accessible at compile-time to make writing tests easier, but you should use:

   ctx := context.Background()
   if wsl.MockAvailable() {
	    m := mock.New()
        // set up the mock ...
        ctx = wsl.WithMock(ctx, m)
   }

func Shutdown

func Shutdown(ctx context.Context) error

Shutdown powers off all of WSL, including all other distros. Equivalent to:

wsl --shutdown

func WithMock

func WithMock(ctx context.Context, m *mock.Backend) context.Context

WithMock adds the mock back-end to the context when GoWSL has been compiled with the gowslmock tag. Otherwise, it panics.

Types

type Cmd

type Cmd struct {
	// Public parameters
	Stdin  io.Reader // Reader to read stdin from
	Stdout io.Writer // Writer to write stdout into
	Stderr io.Writer // Writer to write stdout into
	UseCWD bool      // Whether WSL is launched in the current working directory (true) or the home directory (false)

	// Book-keeping
	Process *os.Process // The windows handle to the WSL process

	ProcessState *os.ProcessState // Status of the process. Cached because it cannot be read after the process is closed.
	// contains filtered or unexported fields
}

Cmd is a wrapper around the Windows process spawned by WslLaunch. Its interface is the same as the standard library's exec (except for func Command) and its implementation is very similar.

A Cmd cannot be reused after calling its Run method.

func (*Cmd) CombinedOutput

func (c *Cmd) CombinedOutput() (out []byte, err error)

CombinedOutput runs the command and returns its combined standard output and standard error.

func (*Cmd) Output

func (c *Cmd) Output() (out []byte, err error)

Output runs the command and returns its standard output. Any returned error will usually be of type *ExitError. If c.Stderr was nil, Output populates ExitError.Stderr.

func (*Cmd) Run

func (c *Cmd) Run() error

Run starts the specified WslProcess and waits for it to complete.

The returned error is nil if the command runs and exits with a zero exit status.

If the command fails to run or doesn't complete successfully, the error is of type *ExitError.

func (*Cmd) Start

func (c *Cmd) Start() (err error)

Start starts the specified command but does not wait for it to complete.

The Wait method will return the exit code and release associated resources once the command exits.

func (*Cmd) StderrPipe

func (c *Cmd) StderrPipe() (r io.ReadCloser, err error)

StderrPipe returns a pipe that will be connected to the command's standard error when the command starts.

Wait will close the pipe after seeing the command exit, so most callers need not close the pipe themselves. It is thus incorrect to call Wait before all reads from the pipe have completed. For the same reason, it is incorrect to use Run when using StderrPipe.

func (*Cmd) StdinPipe

func (c *Cmd) StdinPipe() (w io.WriteCloser, err error)

StdinPipe returns a pipe that will be connected to the command's standard input when the command starts. The pipe will be closed automatically after Wait sees the command exit. A caller need only call Close to force the pipe to close sooner. For example, if the command being run will not exit until standard input is closed, the caller must close the pipe.

func (*Cmd) StdoutPipe

func (c *Cmd) StdoutPipe() (r io.ReadCloser, err error)

StdoutPipe returns a pipe that will be connected to the command's standard output when the command starts.

Wait will close the pipe after seeing the command exit, so most callers need not close the pipe themselves. It is thus incorrect to call Wait before all reads from the pipe have completed. For the same reason, it is incorrect to call Run when using StdoutPipe.

func (*Cmd) Wait

func (c *Cmd) Wait() (err error)

Wait waits for the command to exit and waits for any copying to stdin or copying from stdout or stderr to complete.

The command must have been started by Start.

The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.

If the command fails to run or doesn't complete successfully, the error is of type ExitError. Other error types may be returned for I/O problems.

If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits for the respective I/O loop copying to or from the process to complete.

Wait releases any resources associated with the Cmd.

type Configuration

type Configuration struct {
	Version    uint8  // Type of filesystem used (lxfs vs. wslfs, relevant only to WSL1)
	DefaultUID uint32 // User ID of default user
	flags.Unpacked
	DefaultEnvironmentVariables map[string]string // Environment variables passed to the distro by default
}

Configuration is the configuration of the distro.

type Distro

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

Distro is an abstraction around a WSL distro.

func DefaultDistro

func DefaultDistro(ctx context.Context) (d Distro, ok bool, err error)

DefaultDistro gets the current default distribution.

func Import

func Import(ctx context.Context, distributionName, sourcePath, destinationPath string) (Distro, error)

Import creates a new distro from a source root filesystem.

func NewDistro

func NewDistro(ctx context.Context, name string) Distro

NewDistro declares a new distribution, but does not register it nor check if it exists.

func RegisteredDistros

func RegisteredDistros(ctx context.Context) (distros []Distro, err error)

RegisteredDistros returns a slice of the registered distros.

func (*Distro) Command

func (d *Distro) Command(ctx context.Context, cmd string) *Cmd

Command returns the Cmd struct to execute the named program with the given arguments in the same string.

It sets only the command and stdin/stdout/stderr in the returned structure.

The provided context is used to kill the process (by calling CloseHandle) if the context becomes done before the command completes on its own.

func (*Distro) DefaultUID

func (d *Distro) DefaultUID(uid uint32) (err error)

DefaultUID sets the user to the one specified.

func (*Distro) DriveMountingEnabled

func (d *Distro) DriveMountingEnabled(value bool) (err error)

DriveMountingEnabled sets the ENABLE_DRIVE_MOUNTING flag to the provided value. Enabling it mounts the windows filesystem into WSL's.

func (Distro) Equal

func (d Distro) Equal(other Distro) bool

Equal compares two distros for equality independent of their name casing.

func (*Distro) GUID

func (d *Distro) GUID() (id uuid.UUID, err error)

GUID returns the Global Unique IDentifier for the distro.

func (Distro) GetConfiguration

func (d Distro) GetConfiguration() (c Configuration, err error)

GetConfiguration is a wrapper around Win32's WslGetDistributionConfiguration. It returns a configuration object with information about the distro.

func (*Distro) InteropEnabled

func (d *Distro) InteropEnabled(value bool) (err error)

InteropEnabled sets the ENABLE_INTEROP flag to the provided value. Enabling allows you to launch Windows executables from WSL.

func (Distro) IsRegistered

func (d Distro) IsRegistered() (registered bool, err error)

IsRegistered returns a boolean indicating whether a distro is registered or not.

func (Distro) Name

func (d Distro) Name() string

Name is a getter for the DistroName as shown in "wsl.exe --list".

func (*Distro) PathAppended

func (d *Distro) PathAppended(value bool) (err error)

PathAppended sets the APPEND_NT_PATH flag to the provided value. Enabling it allows WSL to append /mnt/c/... (or wherever your mount point is) in front of Windows executables.

func (*Distro) Register

func (d *Distro) Register(rootFsPath string) (err error)

Register is a wrapper around Win32's WslRegisterDistribution. It creates a new distro with a copy of the given tarball as its filesystem.

func (*Distro) SetAsDefault

func (d *Distro) SetAsDefault() error

SetAsDefault sets a particular distribution as the default one. Equivalent to:

wsl --set-default <distro>

func (*Distro) Shell

func (d *Distro) Shell(args ...ShellOption) (err error)

Shell is a wrapper around Win32's WslLaunchInteractive, which starts a shell on WSL with the specified command. If no command is specified, the default shell for that distro is launched.

If the command is interactive (e.g. python, sh, bash, fish, etc.) an interactive session is started. This is a synchronous, blocking call.

Stdout and Stderr are sent to the console, even if os.Stdout and os.Stderr are redirected:

PS> go run .\examples\demo.go > demo.log # This will not redirect the Shell

Stdin will read from os.Stdin but if you try to pass it via powershell strange things happen, same as if you did:

PS> "exit 5" | wsl.exe

Can be used with optional helper parameters UseCWD and WithCommand.

func (*Distro) State

func (d *Distro) State() (s State, err error)

State returns the current state of the distro.

func (Distro) String

func (d Distro) String() string

String deserializes a distro its GUID and its configuration as a yaml string. If there is an error, it is printed as part of the yaml.

func (*Distro) Terminate

func (d *Distro) Terminate() error

Terminate powers off the distro. Equivalent to:

wsl --terminate <distro>

func (*Distro) Uninstall

func (d *Distro) Uninstall(ctx context.Context) (err error)

Uninstall removes the distro's associated AppxPackage (if there is one) and unregisters the distro.

func (*Distro) Unregister

func (d *Distro) Unregister() (err error)

Unregister is a wrapper around Win32's WslUnregisterDistribution. It irreparably destroys a distro and its filesystem.

type ShellError

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

ShellError returns error information when shell commands do not succeed.

func (*ShellError) Error

func (err *ShellError) Error() string

Error makes it so ShellError implements the error interface. In displays the exit code and some auxiliary info.

We know that exit codes above 255 come from Windows, but error codes under 256 can come from both sides.

func (*ShellError) ExitCode

func (err *ShellError) ExitCode() uint32

ExitCode is a getter for the exit code of the shell when it produces. Experimentally we've seen that linux produces exit codes under 255, and Windows produces them above or equal to 256.

type ShellOption

type ShellOption func(*shellOptions)

ShellOption is an optional parameter for (*Distro).Shell. Use any of the provided functions such as UseCWD().

func UseCWD

func UseCWD() ShellOption

UseCWD is an optional parameter for (*Distro).Shell that makes it so the shell is started on the current working directory. Otherwise, it starts at the distro's $HOME.

func WithCommand

func WithCommand(cmd string) ShellOption

WithCommand is an optional parameter for (*Distro).Shell that allows you to shell into WSL with the specified command. Particularly useful to choose what shell to use. Otherwise, it uses the distro's default shell.

type State

type State = state.State

State is the state of a particular distro as seen in `wsl.exe -l -v`.

Directories

Path Synopsis
internal
backend
Package backend defines all the actions that a back-end to GoWSL must be able to perform in order to run, or otherwise mock WSL.
Package backend defines all the actions that a back-end to GoWSL must be able to perform in order to run, or otherwise mock WSL.
backend/windows
Package windows contains the production backend.
Package windows contains the production backend.
flags
Package flags contains the enum used by WSL to display some configuration of a WSL distro.
Package flags contains the enum used by WSL to display some configuration of a WSL distro.
state
Package state defines the state enum so that both backends can use it
Package state defines the state enum so that both backends can use it
Package mock mocks the WSL api, useful for tests as it allows parallelism, decoupling, and execution speed.
Package mock mocks the WSL api, useful for tests as it allows parallelism, decoupling, and execution speed.
internal/distrostate
Package distrostate implements the mocking of the state of the distro (i.e.
Package distrostate implements the mocking of the state of the distro (i.e.

Jump to

Keyboard shortcuts

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