config#

import userdir_publish.config

Layered configuration: defaults, user config, project config, and CLI flags.

Each layer overrides the one before it. For the login name, a matching host entry in the user config overrides the project config, while the CLI takes precedence over both. The USER environment variable supplies the fallback. Exact host entries take precedence over patterns; otherwise the first matching pattern in file order applies.

Transport#

How to reach the web directory, see Settings.transport.

alias of Literal[‘auto’, ‘local’, ‘ssh’]

PermissionPreset#

Named permission settings, see Settings.permissions.

alias of Literal[‘private’, ‘group-writable’, ‘none’]

PERMISSION_PRESETS: dict[Literal['private', 'group-writable', 'none'], str | None] = {'group-writable': 'Dg=rwxs,Do=x,Fg=rw,Fo=r', 'none': None, 'private': 'Dg-rwx,Do=x,Fg-rwx,Fo=r'}#

Named arguments for rsync --chmod, see Settings.permissions.

CHMOD_PATTERN = '^[DF]?(?:[0-7]{3,4}|[ugoa]*(?:[-+=][rwxXst]*)+)(?:,[DF]?(?:[0-7]{3,4}|[ugoa]*(?:[-+=][rwxXst]*)+))*$'#

Comma-separated clauses accepted by rsync --chmod, such as D2775,Fg-w.

Settings.permissions must be a key of PERMISSION_PRESETS or match this pattern.

exception ConfigError[source]#

Bases: ValueError

Raised when a configuration value is invalid.

class Settings(source: str | None = None, host: str | None = None, web_root: str = '~/public_html', subdirectory: str = '', keep: tuple[str, ...] = (), permissions: Literal['private', 'group-writable', 'none'] | str = 'private', transport: Literal['auto', 'local', 'ssh'] = 'auto', htaccess_source: str | None = None, url: str | None = None, user: str | None = None, _project_root: Path = PosixPath('.'))[source]#

Bases: object

Merged and validated configuration for one publication.

Create it with load_settings rather than directly, so that all configuration layers are applied and the values are validated.

source: str | None = None[source]#

Directory of the built website, relative to the directory with pyproject.toml.

The first command-line argument overrides it.

host: str | None = None[source]#

SSH host that serves the pages. Without it, only local publishing is possible.

web_root: str = '~/public_html'[source]#

Web directory on the server. {user} is replaced by the login name.

A leading ~ means the home directory of the login on the server.

subdirectory: str = ''[source]#

Subdirectory of the web root that this project owns. Empty means the web root.

Files in it that are not in the build are deleted.

keep: tuple[str, ...] = ()[source]#

rsync filter patterns, relative to the target, for files that are never deleted.

For example, /*/ keeps all top-level directories.

permissions: Literal['private', 'group-writable', 'none'] | str = 'private'[source]#

Permissions of the published files, as a preset or a raw rsync --chmod spec.

private hides the files from group members, group-writable lets the group maintain a shared page, and none keeps the local modes.

transport: Literal['auto', 'local', 'ssh'] = 'auto'[source]#

How to reach the web directory.

auto uses SSH if host is set and the target does not exist on this machine.

htaccess_source: str | None = None[source]#

Directory, relative to the project root, whose .htaccess files the build must contain.

Publishing is refused if a build lacks one of them or contains an outdated copy.

url: str | None = None[source]#

Address printed after publishing. {user} and {subdirectory} are replaced.

Defaults to https://{host}/~{user}/{subdirectory}/ if host is set.

user: str | None = None[source]#

Login name on the host. Defaults to the USER environment variable.

property login: str[source]#

user, or the USER environment variable if it is not set.

Raises:

ConfigError – If neither is set.

property chmod: str | None[source]#

permissions as rsync --chmod spec, or None to leave them as is.

property source_dir: Path[source]#

source resolved against the project root.

Raises:

ConfigError – If source is not set.

property htaccess_dir: Path | None[source]#

htaccess_source resolved against the project root.

property target: str[source]#

web_root with {user} replaced, followed by subdirectory.

A leading ~ is kept, so the path is valid on the host and on this machine.

Raises:

ConfigError – If the web root is empty.

property remote_target: str[source]#

Target path for SSH, where a leading ~/ means the login’s home.

resolved_url() → str | None[source]#

url with {user} and {subdirectory} replaced.

Without url, the address is derived from host, or None if that is unset.

load_settings(cli: dict[str, Any] | None = None, *, project_root: Path | None = None, user_config: Path | None = None) → Settings[source]#

Merge all configuration layers into one Settings object.

Entries of cli that are None count as not given. project_root is the directory with the pyproject.toml that holds the project configuration and defaults to the nearest such directory at or above the working directory. user_config defaults to user_config_path.

Raises:

ConfigError – If an option is unknown or a value is invalid.

user_config_path() → Path[source]#

Locate the user configuration file.

This is $XDG_CONFIG_HOME/userdir-publish.toml if it exists, otherwise $XDG_CONFIG_HOME/userdir-publish/config.toml. XDG_CONFIG_HOME defaults to ~/.config.

Raises:

ConfigError – If both files exist.