1234module cli56import json27import os8import src.build9import src.exchange10import src.fmt11import src.history12import src.machine13import src.release14import src.remote15import src.storage1617pub fn cmd_offer(raw []string) int {18 args := parse('offer', raw, Options{19 values: ['notes']20 flags: ['json', 'builds']21 }) or { return usage_error(err.msg()) }22 23 24 if args.positional.len > 0 {25 return usage_error('offer takes no arguments, not "${args.positional_at(0)}"')26 }27 if args.value_or_none('notes') != none && !args.flag('builds') {28 return usage_error('--notes belongs to --builds')29 }30 store := open_store() or { return refuse(args.json(), err.msg()) }31 defer {32 store.close()33 }34 mut backend := this_machine_backend() or { return refuse(args.json(), err.msg()) }35 if args.flag('builds') {36 return offer_builds(args, store, mut backend)37 }38 report := exchange.offer(store, mut backend) or { return refuse(args.json(), err.msg()) }39 if args.json() {40 emit_json(json2.encode(OfferedJson{41 repo: report.repo42 saves: report.saves43 objects: report.objects44 events: report.events45 head: report.head46 }))47 return 048 }49 if report.saves + report.objects + report.events == 0 {50 ok('the remote already has everything from [${report.head}]')51 return 052 }53 ok('offered ${report.saves} saves · ${report.objects} objects · ${report.events} events to "${report.repo}"')54 note('remote head is now [${report.head}]')55 return 056}5758596061fn offer_builds(args Args, store &storage.Store, mut backend remote.Backend) int {62 head := history.head(store) or { return refuse(args.json(), exchange.no_saves) }63 if exchange.dirty(store, head) or { true } {64 return refuse(args.json(), 'save or checkpoint first — a release is built from a save')65 }66 report := exchange.offer(store, mut backend) or { return refuse(args.json(), err.msg()) }67 config := build.read_config(store.root) or { return refuse(args.json(), err.msg()) }68 69 release_version := build.project_version(store.root) or {70 return refuse(args.json(), err.msg())71 }72 notes := args.value('notes')73 release.check_notes(notes) or { return refuse(args.json(), err.msg()) }74 published := release.publish(store, mut backend, report.repo, config, release_version, notes) or {75 return refuse(args.json(), err.msg())76 }77 if args.json() {78 emit_json(json2.encode(PublishedJson{79 repo: report.repo80 version: published.version81 files: published.files.map(PublishedFileJson{82 platform: it.platform83 name: it.name84 size: it.size85 blake3: it.blake386 })87 }))88 return 089 }90 for file in published.files {91 ok('${file.platform} ${file.name} (${fmt.human_bytes(file.size)})')92 }93 ok('published ${published.version} of "${report.repo}" from [${report.head}]')94 return 095}969798pub fn this_machine_backend() !remote.Backend {99 settings := machine.load_remote()!100 if settings.kind == machine.kind_folder {101 102 103 104 if !os.is_dir(settings.path) {105 return error('the remote folder ${settings.path} is not there — is its disk mounted? ("koh remote" changes it)')106 }107 return remote.new_folder(settings.path)!108 }109 credentials := machine.load_credentials()!110 return remote.new_s3(settings.endpoint, settings.bucket, settings.region,111 credentials.access_key, credentials.secret_key)!112}113114115116117pub fn auto_offer(store &storage.Store, quiet bool) {118 if !machine.has_remote() {119 return120 }121 mut backend := this_machine_backend() or {122 if !quiet {123 note('not offered: ${err.msg()}')124 }125 return126 }127 report := exchange.offer(store, mut backend) or {128 if !quiet {129 note('not offered: ${err.msg()}')130 }131 return132 }133 if !quiet && report.saves + report.objects + report.events > 0 {134 note('offered to "${report.repo}" — ${report.saves} saves · ${report.objects} objects')135 }136}137138struct OfferedJson {139 repo string140 saves int141 objects int142 events int143 head string144}145146struct PublishedFileJson {147 platform string148 name string149 size i64150 blake3 string151}152153struct PublishedJson {154 repo string155 version string156 files []PublishedFileJson157}