Skip to content

Commit f2b3a9a

Browse files
committed
Add marker protocols describing supported actions for API resources
1 parent 2268ae0 commit f2b3a9a

File tree

10 files changed

+380
-287
lines changed

10 files changed

+380
-287
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// Copyright 2020 Iskandar Abudiab (iabudiab.dev)
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
import Foundation
18+
import PathKit
19+
import ShellOut
20+
21+
class JSONSchemaProcessor {
22+
23+
let apiVersion: String
24+
25+
init(apiVersion: String) {
26+
self.apiVersion = apiVersion
27+
}
28+
29+
func process(outputPath: Path) throws -> Definitions {
30+
let definitionsPath = try generateJSONSchema(outputPath: outputPath)
31+
var schema = try loadAndDecodeJson(url: definitionsPath.url, type: Definitions.self)
32+
schema.definitions = Dictionary(uniqueKeysWithValues: schema.definitions.map { key, value in
33+
return (key.sanitizedRef() , value)
34+
})
35+
36+
return schema
37+
}
38+
39+
private func generateJSONSchema(outputPath: PathKit.Path) throws -> PathKit.Path {
40+
let jsonSchemaPath = outputPath + Path("schema-\(apiVersion)")
41+
let openAPIURL = "https://raw.githubusercontent.com/kubernetes/kubernetes/\(apiVersion)/api/openapi-spec/swagger.json"
42+
43+
let _ = try shellOut(to: "/usr/local/bin/openapi2jsonschema", arguments: [
44+
"--expanded", "--kubernetes",
45+
"--prefix", "https://swiftkube.dev/schema/\(apiVersion)/_definitions.json",
46+
"-o", jsonSchemaPath.absolute().string,
47+
openAPIURL
48+
])
49+
50+
return jsonSchemaPath + Path("_definitions.json")
51+
}
52+
53+
private func loadAndDecodeJson<T: Decodable>(url: URL, type: T.Type) throws -> T {
54+
guard let data = try String(contentsOf: url, encoding: .utf8).data(using: .utf8) else {
55+
throw ModelGenError.RuntimeError(message: "Error decoding JSON")
56+
}
57+
return try JSONDecoder().decode(type, from: data)
58+
}
59+
}

Sources/SwiftkubeModelGen/Model/GroupVersionKind.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct GroupVersionKind: Decodable, Hashable {
7272
}
7373

7474
var renderedNamespaceScope: Bool {
75-
return NamespaceScope[kind]!
75+
return ResourceScope[self] ?? false
7676
}
7777

7878
func hash(into hasher: inout Hasher) {

Sources/SwiftkubeModelGen/Model/Resource.swift

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,25 @@ struct Definitions: Decodable {
3535
var definitions: [String: Resource]
3636
}
3737

38-
struct Resource: Decodable, Comparable {
38+
class Resource: Decodable, Comparable {
3939

40-
let gvk: GroupVersionKind?
41-
let type: Type
42-
let description: String
43-
let required: [String]
40+
var gvk: GroupVersionKind?
41+
var type: Type
42+
var description: String
43+
var required: [String]
4444
var properties: [Property]
4545
var deprecated: Bool = false
4646
var requiresCodableExtension: Bool = false
4747
var hasMetadata: Bool = false
4848
var isListResource: Bool = false
4949
var isAPIResource: Bool = false
50-
var isListableResource: Bool = false
5150
var isNamespaced: Bool = false
52-
var isClusterScoped: Bool = false
51+
var isReadableResource: Bool = false
52+
var isListableResource: Bool = false
53+
var isCreatableResource: Bool = false
54+
var isReplaceableResource: Bool = false
55+
var isDeletableResource: Bool = false
56+
var isCollectionDeletableResource: Bool = false
5357

5458
enum CodingKeys: String, CodingKey {
5559
case type
@@ -59,7 +63,7 @@ struct Resource: Decodable, Comparable {
5963
case gvk = "x-kubernetes-group-version-kind"
6064
}
6165

62-
init(from decoder: Decoder) throws {
66+
required init(from decoder: Decoder) throws {
6367
let resourceKey = decoder.codingPath.last?.stringValue
6468

6569
if let _ = IgnoredSchemaTypes.first(where: { resourceKey?.hasPrefix($0) ?? false }) {
@@ -109,13 +113,6 @@ struct Resource: Decodable, Comparable {
109113
self.requiresCodableExtension = properties.contains { $0.type.requiresCodableExtension }
110114
self.hasMetadata = properties.contains { $0.type.isMetadata }
111115
self.isListResource = properties.contains(where: { $0.name == "items" }) && gvk?.kind.hasSuffix("List") ?? false
112-
self.isAPIResource = APITypes.contains(gvk?.kind ?? "")
113-
self.isNamespaced = NamespaceScope.contains { (key: String, value: Bool) -> Bool in
114-
key == gvk?.kind && value == true
115-
}
116-
self.isClusterScoped = NamespaceScope.contains { (key: String, value: Bool) -> Bool in
117-
key == gvk?.kind && value == false
118-
}
119116
}
120117

121118
static func < (lhs: Resource, rhs: Resource) -> Bool {

Sources/SwiftkubeModelGen/Model/TypeReference.swift

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,18 @@
1616

1717
import Foundation
1818

19-
private let TypePrefixes = Set([
20-
"io.k8s.api.",
21-
"io.k8s.apiextensions-apiserver.pkg.apis.",
22-
"io.k8s.apimachinery.pkg.apis.",
23-
"io.k8s.kube-aggregator.pkg.apis.",
24-
])
25-
2619
struct TypeReference: Hashable, Comparable {
2720
let ref: String
21+
let gvk: GroupVersionKind
2822
let group: String
2923
let version: String
30-
let gvk: GroupVersionKind
3124
let kind: String
3225
let listItemKind: String
3326
let apiVersion: String
3427

3528
init(ref: String) {
36-
let sanitized = ref.deletingPrefix("#/definitions/")
37-
38-
self.ref = sanitized
39-
let key = TypePrefixes.reduce(self.ref) { result, prefix in
40-
result.deletingPrefix(prefix)
41-
}
42-
43-
let gvk = key.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: true)
29+
self.ref = ref.sanitizedRef()
30+
let gvk = self.ref.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: true)
4431
self.group = String(gvk[0])
4532
self.version = String(gvk[1])
4633
self.kind = String(gvk[2])
@@ -59,4 +46,8 @@ struct TypeReference: Hashable, Comparable {
5946
let rgvk = GroupVersionKind(group: rhs.group, version: rhs.version, kind: rhs.kind)
6047
return lgvk < rgvk
6148
}
49+
50+
func hash(into hasher: inout Hasher) {
51+
hasher.combine(ref)
52+
}
6253
}

0 commit comments

Comments
 (0)