From 23258e63b6e3a127abb3646d14e3c45b90745db7 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Wed, 22 Nov 2023 17:06:47 -0500 Subject: [PATCH] [Release Tooling] Initial xcprivacy file generation tooling --- ReleaseTooling/Package.swift | 8 ++++ .../Sources/PrivacyKit/PrivacyManifest.swift | 21 +++++++++ .../PrivacyManifestWizard.swift | 40 +++++++++++++++++ .../PrivacyManifestGenerator/main.swift | 44 +++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 ReleaseTooling/Sources/PrivacyKit/PrivacyManifest.swift create mode 100644 ReleaseTooling/Sources/PrivacyManifestGenerator/PrivacyManifestWizard.swift create mode 100644 ReleaseTooling/Sources/PrivacyManifestGenerator/main.swift diff --git a/ReleaseTooling/Package.swift b/ReleaseTooling/Package.swift index 9dd95938fa3..839cf2539c5 100644 --- a/ReleaseTooling/Package.swift +++ b/ReleaseTooling/Package.swift @@ -26,6 +26,7 @@ let package = Package( .executable(name: "zip-builder", targets: ["ZipBuilder"]), .executable(name: "podspecs-tester", targets: ["PodspecsTester"]), .executable(name: "manifest", targets: ["ManifestParser"]), + .executable(name: "privacy-manifest-generator", targets: ["PrivacyManifestGenerator"]), ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", .exact("0.1.0")), @@ -53,5 +54,12 @@ let package = Package( .target( name: "Utils" ), + .target( + name: "PrivacyManifestGenerator", + dependencies: ["ArgumentParser", "PrivacyKit"] + ), + .target( + name: "PrivacyKit" + ), ] ) diff --git a/ReleaseTooling/Sources/PrivacyKit/PrivacyManifest.swift b/ReleaseTooling/Sources/PrivacyKit/PrivacyManifest.swift new file mode 100644 index 00000000000..ddf43c9c1fe --- /dev/null +++ b/ReleaseTooling/Sources/PrivacyKit/PrivacyManifest.swift @@ -0,0 +1,21 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Represents a Privacy Manifest as described in +/// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files +public struct PrivacyManifest { + public init() {} +} diff --git a/ReleaseTooling/Sources/PrivacyManifestGenerator/PrivacyManifestWizard.swift b/ReleaseTooling/Sources/PrivacyManifestGenerator/PrivacyManifestWizard.swift new file mode 100644 index 00000000000..b36ba5fe498 --- /dev/null +++ b/ReleaseTooling/Sources/PrivacyManifestGenerator/PrivacyManifestWizard.swift @@ -0,0 +1,40 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation +import PrivacyKit + +/// Provides an API to walk the client through the creation of a Privacy +/// Manifest via a series of questions. +final class PrivacyManifestWizard { + private let xcframework: URL + + init(xcframework: URL) { + self.xcframework = xcframework + } + + func nextQuestion() -> String? { + // TODO(ncooke3): Implement. + nil + } + + func processAnswer(_ answer: String) throws { + // TODO(ncooke3): Implement. + } + + func createManifest() throws -> PrivacyManifest { + // TODO(ncooke3): Implement. + return PrivacyManifest() + } +} diff --git a/ReleaseTooling/Sources/PrivacyManifestGenerator/main.swift b/ReleaseTooling/Sources/PrivacyManifestGenerator/main.swift new file mode 100644 index 00000000000..e3cb4a9c67f --- /dev/null +++ b/ReleaseTooling/Sources/PrivacyManifestGenerator/main.swift @@ -0,0 +1,44 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import ArgumentParser +import Foundation + +struct PrivacyManifestGenerator: ParsableCommand { + @Argument( + help: ArgumentHelp("The xcframework to create the Privacy Manifest for."), + transform: URL.init(fileURLWithPath:) + ) + var xcframework: URL + + func validate() throws { + guard xcframework.pathExtension == "xcframework" else { + throw ValidationError("Given path does not end in `.xcframework`: \(xcframework.path)") + } + } + + func run() throws { + let wizard = PrivacyManifestWizard(xcframework: xcframework) + + while let question = wizard.nextQuestion() { + print(question) + if let answer = readLine() { + try wizard.processAnswer(answer) + } + } + + let privacyManifest = try wizard.createManifest() + print(privacyManifest) + } +}