gitbay/Repos/RepoCreateViewModel.swift

v1.1.1
gitbay-ios/gitbay/Repos/RepoCreateViewModel.swift history · blame · raw

55 lines · 1985 bytes

 1import Foundation
 2import Observation
 3
 4/// `repo create <owner/name> [--private]` and
 5/// `repo import <owner/name> --from <url> [--private] [--token-stdin]`.
 6@Observable
 7@MainActor
 8final class RepoCreateViewModel {
 9
10    private(set) var working = false
11    private(set) var errorMessage: String?
12
13    private let client: GitbayClient
14
15    init(client: GitbayClient) {
16        self.client = client
17    }
18
19    nonisolated private struct Created: Decodable, Sendable {
20        let path: String
21    }
22
23    /// Returns the created repo's path, or nil with `errorMessage` set.
24    func create(path: String, isPrivate: Bool) async -> String? {
25        var argv = ["repo", "create", path.trimmingCharacters(in: .whitespaces)]
26        if isPrivate { argv.append("--private") }
27        return await run(argv, stdin: nil)
28    }
29
30    /// The token, when there is one, travels on stdin and never in the
31    /// URL: the server refuses credentials embedded in `--from`.
32    func importRepo(path: String, from: String, isPrivate: Bool, token: String) async -> String? {
33        var argv = ["repo", "import", path.trimmingCharacters(in: .whitespaces),
34                    "--from", from.trimmingCharacters(in: .whitespaces)]
35        if isPrivate { argv.append("--private") }
36        let token = token.trimmingCharacters(in: .whitespacesAndNewlines)
37        if !token.isEmpty { argv.append("--token-stdin") }
38        return await run(argv, stdin: token.isEmpty ? nil : token + "\n")
39    }
40
41    private func run(_ argv: [String], stdin: String?) async -> String? {
42        working = true
43        errorMessage = nil
44        defer { working = false }
45        do {
46            let created = try await client.run(argv, stdin: stdin, as: Created.self)
47            return created?.path
48        } catch let error as GitbayError {
49            errorMessage = error.userFacingMessage
50        } catch {
51            errorMessage = GitbayError.transport(error).userFacingMessage
52        }
53        return nil
54    }
55}