Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Felix/restructure command target #36

Merged
merged 5 commits into from
May 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions Sources/SwiftPackageListCommand/Models/FileType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,51 @@

import Foundation
import ArgumentParser
import SwiftPackageList

enum FileType: String, CaseIterable, ExpressibleByArgument {
case json
case plist
case settingsBundle = "settings-bundle"
case pdf
}

extension FileType {

private var fileExtension: String {
switch self {
case .json: return "json"
case .plist: return "plist"
case .settingsBundle: return "bundle"
case .pdf: return "pdf"
}
}

private var defaultFileName: String {
switch self {
case .json: return "package-list"
case .plist: return "package-list"
case .settingsBundle: return "Settings"
case .pdf: return "Acknowledgements"
}
}
}

extension FileType {

func outputURL(at outputPath: String, customFileName: String?) -> URL {
let fileName = customFileName ?? defaultFileName
return URL(fileURLWithPath: outputPath)
.appendingPathComponent(fileName)
.appendingPathExtension(fileExtension)
}

func outputGenerator(outputURL: URL, packages: [Package], project: Project) -> any OutputGenerator {
switch self {
case .json: return JSONGenerator(outputURL: outputURL, packages: packages, project: project)
case .plist: return PropertyListGenerator(outputURL: outputURL, packages: packages, project: project)
case .settingsBundle: return SettingsBundleGenerator(outputURL: outputURL, packages: packages, project: project)
case .pdf: return PDFGenerator(outputURL: outputURL, packages: packages, project: project)
}
}
}
73 changes: 69 additions & 4 deletions Sources/SwiftPackageListCommand/Models/PackageResolved.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,77 @@
//

import Foundation
import SwiftPackageList

// MARK: - Version
enum PackageResolved {
case v1(PackageResolved_V1)
case v2(PackageResolved_V2)
}

enum PackageResolvedVersion: Int {
case v1 = 1
case v2
extension PackageResolved {

init(at url: URL) throws {
let packageResolvedData = try Data(contentsOf: url)
let packageResolvedJSON = try JSONSerialization.jsonObject(with: packageResolvedData) as? [String: Any]
let version = packageResolvedJSON?["version"] as? Int

switch version {
case 1:
let packageResolved = try JSONDecoder().decode(PackageResolved_V1.self, from: packageResolvedData)
self = .v1(packageResolved)
case 2:
let packageResolved = try JSONDecoder().decode(PackageResolved_V2.self, from: packageResolvedData)
self = .v2(packageResolved)
default:
throw RuntimeError("The version of the Package.resolved is not supported")
}
}
}

extension PackageResolved {

func packages(in checkoutsDirectory: URL, requiresLicense: Bool) throws -> [Package] {
switch self {
case .v1(let packageResolved):
return try packageResolved.object.pins.compactMap { pin -> Package? in
guard let checkoutURL = pin.checkoutURL else { return nil }
let name = checkoutURL.lastPathComponent
if let licensePath = try licensePath(for: checkoutURL, in: checkoutsDirectory) {
let license = try String(contentsOf: licensePath, encoding: .utf8)
return Package(name: name, version: pin.state.version, branch: pin.state.branch, revision: pin.state.revision, repositoryURL: checkoutURL, license: license)
} else if !requiresLicense {
return Package(name: name, version: pin.state.version, branch: pin.state.branch, revision: pin.state.revision, repositoryURL: checkoutURL, license: nil)
}
return nil
}
case .v2(let packageResolved):
return try packageResolved.pins.compactMap { pin -> Package? in
guard let checkoutURL = pin.checkoutURL else { return nil }
let name = checkoutURL.lastPathComponent
if let licensePath = try licensePath(for: checkoutURL, in: checkoutsDirectory) {
let license = try String(contentsOf: licensePath, encoding: .utf8)
return Package(name: name, version: pin.state.version, branch: pin.state.branch, revision: pin.state.revision, repositoryURL: checkoutURL, license: license)
} else if !requiresLicense {
return Package(name: name, version: pin.state.version, branch: pin.state.branch, revision: pin.state.revision, repositoryURL: checkoutURL, license: nil)
}
return nil
}
}
}

private func licensePath(for checkoutURL: URL, in checkoutsDirectory: URL) throws -> URL? {
let checkoutName = checkoutURL.lastPathComponent
let checkoutPath = checkoutsDirectory.appendingPathComponent(checkoutName)
let packageFiles = try FileManager.default.contentsOfDirectory(at: checkoutPath, includingPropertiesForKeys: [.isRegularFileKey, .localizedNameKey], options: .skipsHiddenFiles)

for packageFile in packageFiles {
if packageFile.deletingPathExtension().lastPathComponent.lowercased() == "license" {
return packageFile
}
}

return nil
}
}

// MARK: - V1
Expand Down
20 changes: 20 additions & 0 deletions Sources/SwiftPackageListCommand/Models/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ extension Project {
}
}

extension Project {

func checkoutsDirectory(in derivedDataPath: String) throws -> URL? {
let derivedDataDirectories = try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: derivedDataPath), includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])

for derivedDataDirectory in derivedDataDirectories {
let projectFiles = try FileManager.default.contentsOfDirectory(at: derivedDataDirectory, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles])
guard let infoDotPlist = projectFiles.first(where: { $0.lastPathComponent == "info.plist" }) else { continue }
let infoPlistData = try Data(contentsOf: infoDotPlist)
let infoPlist = try PropertyListDecoder().decode(InfoPlist.self, from: infoPlistData)
if infoPlist.WorkspacePath == fileURL.path {
let checkoutsDirectory = derivedDataDirectory.appendingPathComponent("/SourcePackages/checkouts")
return checkoutsDirectory
}
}

return nil
}
}

extension Project {

func findOrganizationName() -> String? {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// JSONGenerator.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 15.05.22.
//

import Foundation
import SwiftPackageList

struct JSONGenerator: OutputGenerator {

private let outputURL: URL
private let packages: [Package]

private let jsonEncoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
return encoder
}()

init(outputURL: URL, packages: [Package], project: Project) {
self.outputURL = outputURL
self.packages = packages
}

func generateOutput() throws {
let jsonData = try jsonEncoder.encode(packages)
try jsonData.write(to: outputURL)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// OutputGenerator.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 15.05.22.
//

import Foundation
import SwiftPackageList

protocol OutputGenerator {
init(outputURL: URL, packages: [Package], project: Project)
func generateOutput() throws
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// PDFBuilder.swift
// PDFGenerator.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 11.04.22.
Expand All @@ -8,22 +8,22 @@
import AppKit
import SwiftPackageList

struct PDFBuilder {
struct PDFGenerator: OutputGenerator {

private let url: URL
private let outputURL: URL
private let packages: [Package]
private let project: Project
private let organizationName: String?

init(url: URL, packages: [Package], project: Project) {
self.url = url
init(outputURL: URL, packages: [Package], project: Project) {
self.outputURL = outputURL
self.packages = packages
self.project = project
self.organizationName = project.findOrganizationName()
}

func build() throws {
guard let consumer = CGDataConsumer(url: url as CFURL) else {
func generateOutput() throws {
guard let consumer = CGDataConsumer(url: outputURL as CFURL) else {
throw RuntimeError("Something is wrong with the output-path")
}
let auxiliaryInfo = createAuxiliaryInfo()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// PropertyListGenerator.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 15.05.22.
//

import Foundation
import SwiftPackageList

struct PropertyListGenerator: OutputGenerator {

private let outputURL: URL
private let packages: [Package]

private let propertyListEncoder: PropertyListEncoder = {
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
return encoder
}()

init(outputURL: URL, packages: [Package], project: Project) {
self.outputURL = outputURL
self.packages = packages
}

func generateOutput() throws {
let propertyListData = try propertyListEncoder.encode(packages)
try propertyListData.write(to: outputURL)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//
// SettingsBundleBuilder+Language.swift
// SettingsBundleGenerator+Language.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 08.04.22.
//

import Foundation

extension SettingsBundleBuilder {
extension SettingsBundleGenerator {

enum Language: String, CaseIterable {
case ar
Expand All @@ -24,7 +24,7 @@ extension SettingsBundleBuilder {
}
}

extension SettingsBundleBuilder.Language {
extension SettingsBundleGenerator.Language {

private enum RootStringsKey: String {
case acknowledgements = "Acknowledgements"
Expand Down Expand Up @@ -80,7 +80,7 @@ extension SettingsBundleBuilder.Language {
}
}

extension SettingsBundleBuilder.Language {
extension SettingsBundleGenerator.Language {

private enum AcknowledgementsStringsKey: String {
case licenses = "Licenses"
Expand Down Expand Up @@ -136,7 +136,7 @@ extension SettingsBundleBuilder.Language {
}
}

extension SettingsBundleBuilder.Language {
extension SettingsBundleGenerator.Language {

var rootFileData: Data {
let fileString = rootStrings
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//
// SettingsBundleBuilder+PropertyList.swift
// SettingsBundleGenerator+PropertyList.swift
// SwiftPackageListCommand
//
// Created by Felix Herrmann on 08.04.22.
//

import Foundation

extension SettingsBundleBuilder {
extension SettingsBundleGenerator {

enum SpecifierType: String, Encodable {
case group = "PSGroupSpecifier"
Expand All @@ -27,13 +27,13 @@ extension SettingsBundleBuilder {
}
}

extension SettingsBundleBuilder.Specifier {
extension SettingsBundleGenerator.Specifier {

static func group(title: String? = nil, footerText: String? = nil) -> SettingsBundleBuilder.Specifier {
return SettingsBundleBuilder.Specifier(Type: .group, Title: title, FooterText: footerText)
static func group(title: String? = nil, footerText: String? = nil) -> SettingsBundleGenerator.Specifier {
return SettingsBundleGenerator.Specifier(Type: .group, Title: title, FooterText: footerText)
}

static func childPane(title: String, file: String) -> SettingsBundleBuilder.Specifier {
return SettingsBundleBuilder.Specifier(Type: .childPane, Title: title, File: file)
static func childPane(title: String, file: String) -> SettingsBundleGenerator.Specifier {
return SettingsBundleGenerator.Specifier(Type: .childPane, Title: title, File: file)
}
}
Loading