1234567module machine89import os1011pub const remote_file = 'remote'12pub const credentials_file = 'credentials'1314pub const kind_folder = 'folder'15pub const kind_s3 = 's3'1617pub struct RemoteSettings {18pub:19 kind string20 path string 21 endpoint string 22 bucket string23 region string24}2526pub struct Credentials {27pub:28 access_key string29 secret_key string30}3132pub fn save_remote(settings RemoteSettings) ! {33 os.mkdir_all(config_dir(), os.MkdirParams{})!34 mut text := '# written by koh remote — the remote for every repo on this machine\n'35 text += 'kind=${settings.kind}\n'36 if settings.kind == kind_folder {37 text += 'path=${settings.path}\n'38 } else {39 text += 'endpoint=${settings.endpoint}\n'40 text += 'bucket=${settings.bucket}\n'41 text += 'region=${settings.region}\n'42 }43 os.write_file(config_path(remote_file), text)!44}4546pub fn load_remote() !RemoteSettings {47 text := os.read_file(config_path(remote_file)) or {48 return error('this machine has no remote yet — run "koh remote"')49 }50 values := parse_config(text)51 settings := RemoteSettings{52 kind: values['kind'] or { '' }53 path: values['path'] or { '' }54 endpoint: values['endpoint'] or { '' }55 bucket: values['bucket'] or { '' }56 region: values['region'] or { '' }57 }58 if settings.kind !in [kind_folder, kind_s3] {59 return error('the remote setting in ${config_path(remote_file)} is not readable — run "koh remote" again')60 }61 return settings62}6364pub fn has_remote() bool {65 return os.is_file(config_path(remote_file))66}6768pub fn forget_remote() ! {69 if os.exists(config_path(remote_file)) {70 os.rm(config_path(remote_file))!71 }72}737475pub fn save_credentials(credentials Credentials) ! {76 os.mkdir_all(config_dir(), mode: 0o700)!77 78 os.chmod(config_dir(), 0o700)!79 mut text := '# written by koh remote — keep this file private\n'80 text += 'access_key=${credentials.access_key}\n'81 text += 'secret_key=${credentials.secret_key}\n'82 path := config_path(credentials_file)83 84 85 86 temporary := '${path}.tmp-${os.getpid()}'87 88 89 if os.exists(temporary) || os.is_link(temporary) {90 os.rm(temporary)!91 }92 mut file := os.open_file(temporary, 'w', 0o600) or {93 os.rm(temporary) or {}94 return err95 }96 os.chmod(temporary, 0o600) or {97 file.close()98 os.rm(temporary) or {}99 return err100 }101 file.write_string(text) or {102 file.close()103 os.rm(temporary) or {}104 return err105 }106 file.close()107 108 if (os.read_file(temporary) or { '' }) != text {109 os.rm(temporary) or {}110 return error('could not write ${path}')111 }112 113 if os.is_dir(path) {114 os.rm(temporary) or {}115 return error('${path} is a directory')116 }117 os.rename(temporary, path) or {118 os.rm(temporary) or {}119 return err120 }121}122123pub fn load_credentials() !Credentials {124 path := config_path(credentials_file)125 text := os.read_file(path) or {126 return error('this machine has no S3 keys yet — run "koh remote"')127 }128 129 130 if os.stat(path)!.mode & 0o077 != 0 {131 return error('${path} can be read by others — run "chmod 600 ${path}"')132 }133 values := parse_config(text)134 credentials := Credentials{135 access_key: values['access_key'] or { '' }136 secret_key: values['secret_key'] or { '' }137 }138 if credentials.access_key == '' || credentials.secret_key == '' {139 return error('the S3 keys in ${config_path(credentials_file)} are incomplete — run "koh remote" again')140 }141 return credentials142}143144fn parse_config(text string) map[string]string {145 mut values := map[string]string{}146 for line in text.split_into_lines() {147 trimmed := line.trim_space()148 if trimmed == '' || trimmed.starts_with('#') {149 continue150 }151 at := trimmed.index('=') or { continue }152 values[trimmed[..at].trim_space()] = trimmed[at + 1..].trim_space()153 }154 return values155}