Class: Space::Src::CLI::Sync::Run
- Inherits:
-
Dry::CLI::Command
- Object
- Dry::CLI::Command
- Space::Src::CLI::Sync::Run
- Includes:
- GlobalOptions
- Defined in:
- lib/space_src/cli/sync.rb
Instance Method Summary collapse
Methods included from GlobalOptions
Instance Method Details
#call(repo: nil, plain: nil, json: nil, no_color: nil, quiet: nil) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/space_src/cli/sync.rb', line 29 def call(repo: nil, plain: nil, json: nil, no_color: nil, quiet: nil, **) paths = CLI.make_paths paths.ensure! config = Config::Store.load(paths.config_file).success # Log rotation pre-step (slice-4 gate G5). launchd owns # the stdout/stderr redirect via StandardOutPath / # StandardErrorPath; the sync process rotates those # files at the start of each run so the previous run's # log doesn't grow unbounded. The rotator renames the # file to a timestamped archive (preserving bytes); the # current process's inherited fd still points to the # renamed file, so writes during this run succeed. # launchd opens a fresh file at the original path on # the next spawn. No-op when the log is missing or # under-threshold (sync tests in G4 stay green). rotate_plist_logs(paths) # Resolved BEFORE the scoping block: the "scoping sync to:" # notice below is prose, and must be suppressed in JSON mode # for the same reason the summary line is. Resolution depends # only on flags/env/out, so it is safe this early. mode = UI::Mode.resolve( flags: {plain: plain, json: json, no_color: no_color, quiet: quiet}, env: CLI.env, out: out ) # Every line of --json output must parse as one JSON object. human = mode.format != :json if repo target = scope_target(repo) return fail_with(self, "invalid repo reference: #{repo.inspect} (expected host/owner/name)") if target.failure? match = target.success found = config.repos.find { |r| Repo::Helpers.same_repo?(r, match) } if found.nil? return fail_with(self, "no such tracked repo: #{Repo::Helpers.format_ref(match)}") end # Filtered config: only the one matched repo, no orgs # (org expansion would discover other repos — that's # exactly the G4 "other repo gets no state row" test # path, so we explicitly empty orgs here). config = Config::Store.with(config, repos: [found], orgs: []) out.puts "scoping sync to: #{Repo::Helpers.format_ref(found)}" if human end reporter = if mode.format == :json UI::JsonReporter.new(out) elsif mode.animate UI::InteractiveReporter.new(out, mode: mode) else UI::PlainReporter.new(out, mode: mode) end # prune only on a full sweep. With --repo the config above was # narrowed to one repo, so pruning would delete the state rows # for every OTHER tracked repo. result = Space::Src::Sync::Engine.new(reporter: reporter) .call(config: config, paths: paths, prune: repo.nil?) if result.failure? return fail_with(self, "sync failed: #{format_failure(result.failure)}") end report = result.success # JsonReporter already emits a run_finished event carrying the # summary, so suppressing the prose line loses nothing. out.puts "synced #{report.processed} repo(s)" if human CLI.record_outcome(Outcome.new(exit_code: 0)) end |