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

Support for Swift Package Manager (Package.swift) dependencies #108

Merged
merged 4 commits into from
Sep 24, 2019
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
4 changes: 3 additions & 1 deletion Sources/LicensePlist/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ private func loadConfig(configPath: URL) -> Config {

let main = command(Option("cartfile-path", default: Consts.cartfileName),
Option("pods-path", default: Consts.podsDirectoryName),
Option("package-path", default: Consts.packageName),
Option("output-path", default: Consts.outputPath),
Option("github-token", default: ""),
Option("config-path", default: Consts.configPath),
Expand All @@ -20,7 +21,7 @@ let main = command(Option("cartfile-path", default: Consts.cartfileName),
Option("markdown-path", default: ""),
Flag("force"),
Flag("add-version-numbers"),
Flag("suppress-opening-directory")) { cartfile, podsPath, output, gitHubToken, configPath, prefix, htmlPath, markdownPath, force, version, suppressOpen in
Flag("suppress-opening-directory")) { cartfile, podsPath, packagePath, output, gitHubToken, configPath, prefix, htmlPath, markdownPath, force, version, suppressOpen in

Logger.configure()
var config = loadConfig(configPath: URL(fileURLWithPath: configPath))
Expand All @@ -30,6 +31,7 @@ let main = command(Option("cartfile-path", default: Consts.cartfileName),
let options = Options(outputPath: URL(fileURLWithPath: output),
cartfilePath: URL(fileURLWithPath: cartfile),
podsPath: URL(fileURLWithPath: podsPath),
packagePath: URL(fileURLWithPath: packagePath),
prefix: prefix,
gitHubToken: gitHubToken.isEmpty ? nil : gitHubToken,
htmlPath: htmlPath.isEmpty ? nil : URL(fileURLWithPath: htmlPath),
Expand Down
1 change: 1 addition & 0 deletions Sources/LicensePlistCore/Consts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation
public struct Consts {
public static let cartfileName = "Cartfile"
public static let podsDirectoryName = "Pods"
public static let packageName = "Package.swift"
public static let prefix = "com.mono0926.LicensePlist"
public static let outputPath = "\(prefix).Output"
public static let configPath = "license_plist.yml"
Expand Down
2 changes: 2 additions & 0 deletions Sources/LicensePlistCore/Entity/GitHub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ extension GitHub {
public static func load(_ content: String, renames: [String: String] = [:]) -> [GitHub] {
return load(content, renames: renames, mark: "github ")
}

public static func load(_ content: String, renames: [String: String], mark: String, quotes: String = "\"") -> [GitHub] {
let r = load(content, renames: renames, mark: mark, quotes: quotes, version: true)
if !r.isEmpty {
return r
}
return load(content, renames: renames, mark: mark, quotes: quotes, version: false)
}

public static func load(_ content: String,
renames: [String: String],
mark: String,
Expand Down
4 changes: 4 additions & 0 deletions Sources/LicensePlistCore/Entity/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public struct Options {
public let outputPath: URL
public let cartfilePath: URL
public let podsPath: URL
public let packagePath: URL
public let prefix: String
public let gitHubToken: String?
public let htmlPath: URL?
Expand All @@ -13,6 +14,7 @@ public struct Options {
public static let empty = Options(outputPath: URL(fileURLWithPath: ""),
cartfilePath: URL(fileURLWithPath: ""),
podsPath: URL(fileURLWithPath: ""),
packagePath: URL(fileURLWithPath: ""),
prefix: Consts.prefix,
gitHubToken: nil,
htmlPath: nil,
Expand All @@ -22,6 +24,7 @@ public struct Options {
public init(outputPath: URL,
cartfilePath: URL,
podsPath: URL,
packagePath: URL,
prefix: String,
gitHubToken: String?,
htmlPath: URL?,
Expand All @@ -30,6 +33,7 @@ public struct Options {
self.outputPath = outputPath
self.cartfilePath = cartfilePath
self.podsPath = podsPath
self.packagePath = packagePath
self.prefix = prefix
self.gitHubToken = gitHubToken
self.htmlPath = htmlPath
Expand Down
9 changes: 9 additions & 0 deletions Sources/LicensePlistCore/Entity/PlistInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ struct PlistInfo {
Log.info("Carthage License collect start")
githubLibraries = options.config.apply(githubs: GitHub.load(cartfile ?? "", renames: options.config.renames)).sorted()
}

mutating func loadSwiftPackageLibraries(packageFile: String?) {
Log.info("Swift Package Manager License collect start")

let packages = SwiftPackage.loadPackages(packageFile ?? "")
let packagesAsGithubLibraries = packages.compactMap { $0.toGitHub(renames: options.config.renames) }.sorted()

githubLibraries = (githubLibraries ?? []) + packagesAsGithubLibraries
}

mutating func loadManualLibraries() {
Log.info("Manual License start")
Expand Down
58 changes: 58 additions & 0 deletions Sources/LicensePlistCore/Entity/SwiftPackage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// SwiftPackage.swift
// LicensePlistCore
//
// Created by Matthias Buchetics on 20.09.19.
//

import Foundation

public struct SwiftPackage: Decodable, Equatable {
struct State: Decodable, Equatable {
let branch: String?
let revision: String?
let version: String
}

let package: String
let repositoryURL: String
let state: State
}

fileprivate struct ResolvedPackages: Decodable {
struct Pins: Decodable {
let pins: [SwiftPackage]
}

let object: Pins
let version: Int
}

extension SwiftPackage {

static func loadPackages(_ content: String) -> [SwiftPackage] {
guard let data = content.data(using: .utf8) else { return [] }
guard let resolvedPackages = try? JSONDecoder().decode(ResolvedPackages.self, from: data) else { return [] }

return resolvedPackages.object.pins
}

func toGitHub(renames: [String: String]) -> GitHub? {
guard repositoryURL.contains("github.com") else { return nil }

let urlParts = repositoryURL
.replacingOccurrences(of: "https://", with: "")
.replacingOccurrences(of: "http://", with: "")
.components(separatedBy: "/")

guard urlParts.count >= 3 else { return nil }

let name = urlParts.last?.components(separatedBy: ".").first ?? ""
let owner = urlParts[urlParts.count - 2]

return GitHub(name: name,
nameSpecified: renames[name],
owner: owner,
version: state.version)
}
}
11 changes: 11 additions & 0 deletions Sources/LicensePlistCore/LicensePlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public final class LicensePlist {
var info = PlistInfo(options: options)
info.loadCocoaPodsLicense(acknowledgements: readPodsAcknowledgements(path: options.podsPath))
info.loadGitHubLibraries(cartfile: readCartfile(path: options.cartfilePath))
info.loadSwiftPackageLibraries(packageFile: readSwiftPackages(path: options.packagePath))
info.loadManualLibraries()
info.compareWithLatestSummary()
info.downloadGitHubLicenses()
Expand All @@ -35,6 +36,16 @@ private func readCartfile(path: URL) -> String? {
return path.lp.read()
}

private func readSwiftPackages(path: URL) -> String? {
if path.lastPathComponent != Consts.packageName {
fatalError("Invalid Package.swift name: \(path.lastPathComponent)")
}
if let content = path.deletingPathExtension().appendingPathExtension("resolved").lp.read() {
return content
}
return path.lp.read()
}

private func readPodsAcknowledgements(path: URL) -> [String] {
if path.lastPathComponent != Consts.podsDirectoryName {
fatalError("Invalid Pods name: \(path.lastPathComponent)")
Expand Down
1 change: 1 addition & 0 deletions Tests/LicensePlistTests/Entity/PlistInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class PlistInfoTests: XCTestCase {
private let options = Options(outputPath: URL(fileURLWithPath: "test_result_dir"),
cartfilePath: URL(fileURLWithPath: "test_result_dir"),
podsPath: URL(fileURLWithPath: "test_result_dir"),
packagePath: URL(fileURLWithPath: "test_result_dir"),
prefix: Consts.prefix,
gitHubToken: nil,
htmlPath: nil,
Expand Down
75 changes: 75 additions & 0 deletions Tests/LicensePlistTests/Entity/SwiftPackageManagerTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// SwiftPackageManagerTests.swift
// APIKit
//
// Created by Matthias Buchetics on 20.09.19.
//

import Foundation
import XCTest
@testable import LicensePlistCore

class SwiftPackageManagerTests: XCTestCase {

func testDecoding() {
let jsonString = """
{
"package": "APIKit",
"repositoryURL": "https://github.com/ishkawa/APIKit.git",
"state": {
"branch": null,
"revision": "86d51ecee0bc0ebdb53fb69b11a24169a69097ba",
"version": "4.1.0"
}
}
"""

let data = jsonString.data(using: .utf8)!
let package = try! JSONDecoder().decode(SwiftPackage.self, from: data)

XCTAssertEqual(package.package, "APIKit")
XCTAssertEqual(package.repositoryURL, "https://github.com/ishkawa/APIKit.git")
XCTAssertEqual(package.state.revision, "86d51ecee0bc0ebdb53fb69b11a24169a69097ba")
XCTAssertEqual(package.state.version, "4.1.0")
}

func testConvertToGithub() {
let package = SwiftPackage(package: "Commander", repositoryURL: "https://github.com/kylef/Commander.git", state: SwiftPackage.State(branch: nil, revision: "e5b50ad7b2e91eeb828393e89b03577b16be7db9", version: "0.8.0"))
let result = package.toGitHub(renames: [:])
XCTAssertEqual(result, GitHub(name: "Commander", nameSpecified: nil, owner: "kylef", version: "0.8.0"))
}

func testRename() {
let package = SwiftPackage(package: "Commander", repositoryURL: "https://github.com/kylef/Commander.git", state: SwiftPackage.State(branch: nil, revision: "e5b50ad7b2e91eeb828393e89b03577b16be7db9", version: "0.8.0"))
let result = package.toGitHub(renames: ["Commander": "RenamedCommander"])
XCTAssertEqual(result, GitHub(name: "Commander", nameSpecified: "RenamedCommander", owner: "kylef", version: "0.8.0"))
}

func testInvalidURL() {
let package = SwiftPackage(package: "Google", repositoryURL: "http://www.google.com", state: SwiftPackage.State(branch: nil, revision: "", version: "0.0.0"))
let result = package.toGitHub(renames: [:])
XCTAssertNil(result)
}

func testNonGithub() {
let package = SwiftPackage(package: "Bitbucket", repositoryURL: "https://[email protected]/mbuchetics/adventofcode2018.git", state: SwiftPackage.State(branch: nil, revision: "", version: "0.0.0"))
let result = package.toGitHub(renames: [:])
XCTAssertNil(result)
}

func testParse() {
let path = "https://raw.githubusercontent.com/mono0926/LicensePlist/master/Package.resolved"
//let path = "https://raw.githubusercontent.com/mono0926/LicensePlist/master/Tests/LicensePlistTests/Resources/Package.resolved"
let content = try! String(contentsOf: URL(string: path)!)
let packages = SwiftPackage.loadPackages(content)

XCTAssertFalse(packages.isEmpty)
XCTAssertEqual(packages.count, 8)

let packageFirst = packages.first!
XCTAssertEqual(packageFirst, SwiftPackage(package: "APIKit", repositoryURL: "https://github.com/ishkawa/APIKit.git", state: SwiftPackage.State(branch: nil, revision: "86d51ecee0bc0ebdb53fb69b11a24169a69097ba", version: "4.1.0")))
let packageLast = packages.last!
XCTAssertEqual(packageLast, SwiftPackage(package: "Yaml", repositoryURL: "https://github.com/behrang/YamlSwift.git", state: SwiftPackage.State(branch: nil, revision: "287f5cab7da0d92eb947b5fd8151b203ae04a9a3", version: "3.4.4")))

}
}
79 changes: 79 additions & 0 deletions Tests/LicensePlistTests/Resources/Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"object": {
"pins": [
{
"package": "APIKit",
"repositoryURL": "https://github.com/ishkawa/APIKit.git",
"state": {
"branch": null,
"revision": "86d51ecee0bc0ebdb53fb69b11a24169a69097ba",
"version": "4.1.0"
}
},
{
"package": "Commander",
"repositoryURL": "https://github.com/kylef/Commander.git",
"state": {
"branch": null,
"revision": "e5b50ad7b2e91eeb828393e89b03577b16be7db9",
"version": "0.8.0"
}
},
{
"package": "HeliumLogger",
"repositoryURL": "https://github.com/IBM-Swift/HeliumLogger.git",
"state": {
"branch": null,
"revision": "779865e83149a59894b14950aa83f70b7e81bc27",
"version": "1.8.1"
}
},
{
"package": "LoggerAPI",
"repositoryURL": "https://github.com/IBM-Swift/LoggerAPI.git",
"state": {
"branch": null,
"revision": "e29073bb7cecf3673e56bcb16180e8fd0cb091f6",
"version": "1.8.1"
}
},
{
"package": "Result",
"repositoryURL": "https://github.com/antitypical/Result.git",
"state": {
"branch": null,
"revision": "2ca499ba456795616fbc471561ff1d963e6ae160",
"version": "4.1.0"
}
},
{
"package": "Spectre",
"repositoryURL": "https://github.com/kylef/Spectre.git",
"state": {
"branch": null,
"revision": "f14ff47f45642aa5703900980b014c2e9394b6e5",
"version": "0.9.0"
}
},
{
"package": "HTMLEntities",
"repositoryURL": "https://github.com/IBM-Swift/swift-html-entities.git",
"state": {
"branch": null,
"revision": "3b778b3ab061684db024eaf38c576887b42918aa",
"version": "3.0.13"
}
},
{
"package": "Yaml",
"repositoryURL": "https://github.com/behrang/YamlSwift.git",
"state": {
"branch": null,
"revision": "287f5cab7da0d92eb947b5fd8151b203ae04a9a3",
"version": "3.4.4"
}
}
]
},
"version": 1
}