//! Machine-wide remote settings. //! //! Everything machine-specific lives in `~/.config/koh/`, never inside a repo: //! one remote per machine, and the S3 keys in a file only the user can read. //! The format is plain `key=value` lines so it can be read and edited by hand. module machine import os pub const remote_file = 'remote' pub const credentials_file = 'credentials' pub const kind_folder = 'folder' pub const kind_s3 = 's3' pub struct RemoteSettings { pub: kind string path string // folder backend endpoint string // s3 backend bucket string region string } pub struct Credentials { pub: access_key string secret_key string } pub fn save_remote(settings RemoteSettings) ! { os.mkdir_all(config_dir(), os.MkdirParams{})! mut text := '# written by koh remote — the remote for every repo on this machine\n' text += 'kind=${settings.kind}\n' if settings.kind == kind_folder { text += 'path=${settings.path}\n' } else { text += 'endpoint=${settings.endpoint}\n' text += 'bucket=${settings.bucket}\n' text += 'region=${settings.region}\n' } os.write_file(config_path(remote_file), text)! } pub fn load_remote() !RemoteSettings { text := os.read_file(config_path(remote_file)) or { return error('this machine has no remote yet — run "koh remote"') } values := parse_config(text) settings := RemoteSettings{ kind: values['kind'] or { '' } path: values['path'] or { '' } endpoint: values['endpoint'] or { '' } bucket: values['bucket'] or { '' } region: values['region'] or { '' } } if settings.kind !in [kind_folder, kind_s3] { return error('the remote setting in ${config_path(remote_file)} is not readable — run "koh remote" again') } return settings } pub fn has_remote() bool { return os.is_file(config_path(remote_file)) } pub fn forget_remote() ! { if os.exists(config_path(remote_file)) { os.rm(config_path(remote_file))! } } // save_credentials writes the keys so that only the user can read them. pub fn save_credentials(credentials Credentials) ! { os.mkdir_all(config_dir(), os.MkdirParams{})! mut text := '# written by koh remote — keep this file private\n' text += 'access_key=${credentials.access_key}\n' text += 'secret_key=${credentials.secret_key}\n' path := config_path(credentials_file) os.write_file(path, text)! os.chmod(path, 0o600)! } pub fn load_credentials() !Credentials { text := os.read_file(config_path(credentials_file)) or { return error('this machine has no S3 keys yet — run "koh remote"') } values := parse_config(text) credentials := Credentials{ access_key: values['access_key'] or { '' } secret_key: values['secret_key'] or { '' } } if credentials.access_key == '' || credentials.secret_key == '' { return error('the S3 keys in ${config_path(credentials_file)} are incomplete — run "koh remote" again') } return credentials } fn parse_config(text string) map[string]string { mut values := map[string]string{} for line in text.split_into_lines() { trimmed := line.trim_space() if trimmed == '' || trimmed.starts_with('#') { continue } at := trimmed.index('=') or { continue } values[trimmed[..at].trim_space()] = trimmed[at + 1..].trim_space() } return values }