From 20e113a2be6104a16ee7294cba10f798616359f8 Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Tue, 7 Nov 2023 17:35:31 +0100 Subject: [PATCH 1/6] support licenses csv generation --- Sources/LicensePlist/main.swift | 5 ++ .../Entity/GeneralOptions.swift | 5 ++ .../Entity/LicenseCSVHolder.swift | 64 +++++++++++++++++++ Sources/LicensePlistCore/Entity/Options.swift | 4 ++ .../LicensePlistCore/Entity/PlistInfo.swift | 5 ++ 5 files changed, 83 insertions(+) create mode 100644 Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift diff --git a/Sources/LicensePlist/main.swift b/Sources/LicensePlist/main.swift index cae00348..58b1c1df 100644 --- a/Sources/LicensePlist/main.swift +++ b/Sources/LicensePlist/main.swift @@ -64,6 +64,9 @@ struct LicensePlist: ParsableCommand { @Option(name: .long, completion: .file()) var markdownPath: String? + @Option(name: .long, completion: .file()) + var csvPath: String? + @Option(name: .long, parsing: .upToNextOption, completion: .empty) var licenseFileNames = [String]() @@ -121,6 +124,7 @@ struct LicensePlist: ParsableCommand { let prefix = prefix ?? config.options.prefix ?? Consts.prefix let htmlPath = htmlPath.asPathURL(other: config.options.htmlPath) let markdownPath = markdownPath.asPathURL(other: config.options.markdownPath) + let csvPath = csvPath.asPathURL(other: config.options.csvPath) let configLicenseFileNames = config.options.licenseFileNames ?? Consts.licenseFileNames let licenseFileNames = licenseFileNames.isEmpty ? configLicenseFileNames : licenseFileNames let options = Options(outputPath: outputPath, @@ -135,6 +139,7 @@ struct LicensePlist: ParsableCommand { gitHubToken: githubToken, htmlPath: htmlPath, markdownPath: markdownPath, + csvPath: csvPath, licenseFileNames: licenseFileNames, config: config) let tool = LicensePlistCore.LicensePlist() diff --git a/Sources/LicensePlistCore/Entity/GeneralOptions.swift b/Sources/LicensePlistCore/Entity/GeneralOptions.swift index 0b3aba0c..ffe3298e 100644 --- a/Sources/LicensePlistCore/Entity/GeneralOptions.swift +++ b/Sources/LicensePlistCore/Entity/GeneralOptions.swift @@ -15,6 +15,7 @@ public struct GeneralOptions { public let gitHubToken: String? public let htmlPath: URL? public let markdownPath: URL? + public let csvPath: URL? public let licenseFileNames: [String]? public let force: Bool? public let addVersionNumbers: Bool? @@ -36,6 +37,7 @@ public struct GeneralOptions { gitHubToken: nil, htmlPath: nil, markdownPath: nil, + csvPath: nil, licenseFileNames: nil, force: nil, addVersionNumbers: nil, @@ -57,6 +59,7 @@ public struct GeneralOptions { gitHubToken: String?, htmlPath: URL?, markdownPath: URL?, + csvPath: URL?, licenseFileNames: [String]?, force: Bool?, addVersionNumbers: Bool?, @@ -77,6 +80,7 @@ public struct GeneralOptions { self.gitHubToken = gitHubToken self.htmlPath = htmlPath self.markdownPath = markdownPath + self.csvPath = csvPath self.licenseFileNames = licenseFileNames self.force = force self.addVersionNumbers = addVersionNumbers @@ -128,6 +132,7 @@ extension GeneralOptions { gitHubToken: raw["gitHubToken"]?.string, htmlPath: raw["htmlPath"]?.string.asPathURL(in: configBasePath), markdownPath: raw["markdownPath"]?.string.asPathURL(in: configBasePath), + csvPath: raw["csvPath"]?.string.asPathURL(in: configBasePath), licenseFileNames: raw["licenseFileNames"]?.sequence?.compactMap { $0.string }, force: raw["force"]?.bool, addVersionNumbers: raw["addVersionNumbers"]?.bool, diff --git a/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift b/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift new file mode 100644 index 00000000..2a9239ad --- /dev/null +++ b/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift @@ -0,0 +1,64 @@ +import Foundation +import LoggerAPI + +struct LicenseCSVHolder { + let csv: String + static func load(licenses: [LicenseInfo], options: Options) -> LicenseCSVHolder { + var csv = [ + "Component", + "License", + options.config.addSources ? "Origin" : nil, + "Copyright", + ] + .compactMap { $0 } + .joined(separator: .delemiter) + .newLine + + for license in licenses { + let component = license.name(withVersion: options.config.addVersionNumbers) + let licenseType = license.licenseType.rawValue + let copyright = license.copyright.quoted + if options.config.addSources, let source = license.source { + csv += [ + component, + licenseType, + source, + copyright, + ].joined(separator: .delemiter) + } else { + csv += [ + component, + licenseType, + copyright, + ].joined(separator: .delemiter) + } + csv += .newLine + } + return LicenseCSVHolder(csv: csv) + } + + func write(to csvPath: URL) { + do { + try csv.data(using: .utf8)!.write(to: csvPath) + } catch { + Log.error("Failed to write to (csvPath: \(csvPath)).\nerror: \(error)") + } + } +} + +extension LicenseInfo { + fileprivate var copyright: String { + let copyrightRange = body.range( + of: #"Copyright \(c\) .*"#, + options: .regularExpression + ) + return copyrightRange.map { String(body[$0]) } ?? "" + } +} + +extension String { + fileprivate static let newLine = "\n" + fileprivate static let delemiter = "," + fileprivate var quoted: String { + "\"" + self + "\"" + } +} diff --git a/Sources/LicensePlistCore/Entity/Options.swift b/Sources/LicensePlistCore/Entity/Options.swift index 649c19d6..8c859e5b 100644 --- a/Sources/LicensePlistCore/Entity/Options.swift +++ b/Sources/LicensePlistCore/Entity/Options.swift @@ -13,6 +13,7 @@ public struct Options { public let gitHubToken: String? public let htmlPath: URL? public let markdownPath: URL? + public let csvPath: URL? public let licenseFileNames: [String] public let config: Config @@ -28,6 +29,7 @@ public struct Options { gitHubToken: nil, htmlPath: nil, markdownPath: nil, + csvPath: nil, licenseFileNames: [], config: Config.empty) @@ -43,6 +45,7 @@ public struct Options { gitHubToken: String?, htmlPath: URL?, markdownPath: URL?, + csvPath: URL?, licenseFileNames: [String], config: Config) { self.outputPath = outputPath @@ -57,6 +60,7 @@ public struct Options { self.gitHubToken = gitHubToken self.htmlPath = htmlPath self.markdownPath = markdownPath + self.csvPath = csvPath self.licenseFileNames = licenseFileNames self.config = config } diff --git a/Sources/LicensePlistCore/Entity/PlistInfo.swift b/Sources/LicensePlistCore/Entity/PlistInfo.swift index 7b5db6dc..c92ba845 100644 --- a/Sources/LicensePlistCore/Entity/PlistInfo.swift +++ b/Sources/LicensePlistCore/Entity/PlistInfo.swift @@ -129,6 +129,11 @@ struct PlistInfo { markdownHolder.write(to: markdownPath) } + if let csvPath = options.csvPath { + let csvHolder = LicenseCSVHolder.load(licenses: licenses, options: options) + csvHolder.write(to: csvPath) + } + if let htmlPath = options.htmlPath { let htmlHolder = LicenseHTMLHolder.load(licenses: licenses, options: options) htmlHolder.write(to: htmlPath) From 240ae191d98e2607c6876ebb5ed97a5e700f0d6a Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Tue, 7 Nov 2023 18:13:00 +0100 Subject: [PATCH 2/6] updated doc --- Assets/acknowledgements.csv | 6 ++++++ README.md | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 Assets/acknowledgements.csv diff --git a/Assets/acknowledgements.csv b/Assets/acknowledgements.csv new file mode 100644 index 00000000..e690c084 --- /dev/null +++ b/Assets/acknowledgements.csv @@ -0,0 +1,6 @@ +Component,License,Origin,Copyright +SwiftDate,MIT,https://github.com/malcommac/SwiftDate,"Copyright (c) 2018 Daniele Margutti" +leveldb,BSD-3-Clause,https://github.com/firebase/leveldb,"Copyright (c) 2011 The LevelDB Authors. All rights reserved." +swift-composable-architecture,MIT,https://github.com/pointfreeco/swift-composable-architecture,"Copyright (c) 2020 Point-Free, Inc." +GoogleUtilities,Apache-2.0,https://github.com/google/GoogleUtilities,"Copyright (c) 2017 Landon J. Fuller " +MSAL,MIT,https://github.com/AzureAD/microsoft-authentication-library-for-objc,"Copyright (c) Microsoft Corporation" diff --git a/README.md b/README.md index b2810469..6b3c7a76 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,12 @@ You can see options by `license-plist --help`. - If this path is specified, a markdown acknowledgements file will be generated. - [Example is here](https://github.com/mono0926/LicensePlist/blob/master/Assets/acknowledgements.md) +#### `--csv-path` + +- Default: None. +- If this path is specified, a csv acknowledgements file will be generated. + - [Example is here](https://github.com/mono0926/LicensePlist/blob/master/Assets/acknowledgements.csv) + #### `--license-file-names` - Default: `LICENSE, LICENSE.*`. From 9de2f610706f3fe8707d8193e8db3b736ae71cfd Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Wed, 8 Nov 2023 10:48:23 +0100 Subject: [PATCH 3/6] fix missing calls to csvPath --- Sources/LicensePlistCore/Entity/GeneralOptions.swift | 1 + Tests/LicensePlistTests/Entity/LicensePlistHolderTests.swift | 1 + Tests/LicensePlistTests/Entity/PlistInfoTests.swift | 1 + .../Entity/PlistInfoWithSourcePackagesTests.swift | 1 + 4 files changed, 4 insertions(+) diff --git a/Sources/LicensePlistCore/Entity/GeneralOptions.swift b/Sources/LicensePlistCore/Entity/GeneralOptions.swift index ffe3298e..fa0bea8e 100644 --- a/Sources/LicensePlistCore/Entity/GeneralOptions.swift +++ b/Sources/LicensePlistCore/Entity/GeneralOptions.swift @@ -106,6 +106,7 @@ extension GeneralOptions { lhs.gitHubToken == rhs.gitHubToken && lhs.htmlPath == rhs.htmlPath && lhs.markdownPath == rhs.markdownPath && + lhs.csvPath == rhs.csvPath && lhs.licenseFileNames == rhs.licenseFileNames && lhs.force == rhs.force && lhs.addVersionNumbers == rhs.addVersionNumbers && diff --git a/Tests/LicensePlistTests/Entity/LicensePlistHolderTests.swift b/Tests/LicensePlistTests/Entity/LicensePlistHolderTests.swift index 699065bb..db7e96f9 100644 --- a/Tests/LicensePlistTests/Entity/LicensePlistHolderTests.swift +++ b/Tests/LicensePlistTests/Entity/LicensePlistHolderTests.swift @@ -121,6 +121,7 @@ extension Options { gitHubToken: nil, htmlPath: nil, markdownPath: nil, + csvPath: nil, licenseFileNames: [], config: config ) diff --git a/Tests/LicensePlistTests/Entity/PlistInfoTests.swift b/Tests/LicensePlistTests/Entity/PlistInfoTests.swift index 5ce06dd8..b542f8a6 100644 --- a/Tests/LicensePlistTests/Entity/PlistInfoTests.swift +++ b/Tests/LicensePlistTests/Entity/PlistInfoTests.swift @@ -21,6 +21,7 @@ class PlistInfoTests: XCTestCase { gitHubToken: nil, htmlPath: nil, markdownPath: nil, + csvPath: nil, licenseFileNames: [], config: Config(githubs: [GitHub(name: "facebook-ios-sdk", nameSpecified: nil, diff --git a/Tests/LicensePlistTests/Entity/PlistInfoWithSourcePackagesTests.swift b/Tests/LicensePlistTests/Entity/PlistInfoWithSourcePackagesTests.swift index 5482a33a..cd74af87 100644 --- a/Tests/LicensePlistTests/Entity/PlistInfoWithSourcePackagesTests.swift +++ b/Tests/LicensePlistTests/Entity/PlistInfoWithSourcePackagesTests.swift @@ -68,6 +68,7 @@ final class PlistInfoWithSourcePackagesTests: XCTestCase { gitHubToken: nil, htmlPath: nil, markdownPath: nil, + csvPath: nil, licenseFileNames: licenseFileNames, config: .empty) } From ff2f002a552c88131599197eb4db4c5a121f2094 Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Wed, 8 Nov 2023 10:58:16 +0100 Subject: [PATCH 4/6] temp fix (yaml test) --- Tests/LicensePlistTests/Entity/ConfigTests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/LicensePlistTests/Entity/ConfigTests.swift b/Tests/LicensePlistTests/Entity/ConfigTests.swift index 6a11b96d..14caa0b7 100644 --- a/Tests/LicensePlistTests/Entity/ConfigTests.swift +++ b/Tests/LicensePlistTests/Entity/ConfigTests.swift @@ -36,6 +36,7 @@ class ConfigTests: XCTestCase { gitHubToken: "YOUR_GITHUB_TOKEN", htmlPath: URL(fileURLWithPath: "acknowledgements.html", relativeTo: configBasePath), markdownPath: URL(fileURLWithPath: "acknowledgements.md", relativeTo: configBasePath), + csvPath: nil, licenseFileNames: ["LICENSE", "LICENSE.*"], force: false, addVersionNumbers: false, From 5a4e8473ce9ee0d6ae7261679dbae4928c66ade6 Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Wed, 8 Nov 2023 11:22:53 +0100 Subject: [PATCH 5/6] lint func body > 40: split --- Sources/LicensePlist/main.swift | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Sources/LicensePlist/main.swift b/Sources/LicensePlist/main.swift index 58b1c1df..d0449e71 100644 --- a/Sources/LicensePlist/main.swift +++ b/Sources/LicensePlist/main.swift @@ -103,14 +103,7 @@ struct LicensePlist: ParsableCommand { func run() throws { Logger.configure(logLevel: logLevel, colorCommandLineFlag: color) - var config = loadConfig(configPath: URL(fileURLWithPath: configPath)) - config.force = force ?? config.options.force ?? false - config.addVersionNumbers = addVersionNumbers ?? config.options.addVersionNumbers ?? false - config.sandboxMode = sandboxMode ?? config.options.sandboxMode ?? false - config.suppressOpeningDirectory = (suppressOpeningDirectory ?? config.options.suppressOpeningDirectory ?? false) || config.sandboxMode - config.singlePage = singlePage ?? config.options.singlePage ?? false - config.failIfMissingLicense = failIfMissingLicense ?? config.options.failIfMissingLicense ?? false - config.addSources = addSources ?? config.options.addSources ?? false + let config = getConfig() let cartfilePath = cartfilePath.asPathURL(other: config.options.cartfilePath, default: Consts.cartfileName) let mintfilePath = mintfilePath.asPathURL(other: config.options.mintfilePath, default: Consts.mintfileName) let podsPath = podsPath.asPathURL(other: config.options.podsPath, default: Consts.podsDirectoryName) @@ -145,6 +138,19 @@ struct LicensePlist: ParsableCommand { let tool = LicensePlistCore.LicensePlist() tool.process(options: options) } + + /// Provided cli config options. Defaults to Yaml config file. + private func getConfig() -> Config { + var config = loadConfig(configPath: URL(fileURLWithPath: configPath)) + config.force = force ?? config.options.force ?? false + config.addVersionNumbers = addVersionNumbers ?? config.options.addVersionNumbers ?? false + config.sandboxMode = sandboxMode ?? config.options.sandboxMode ?? false + config.suppressOpeningDirectory = (suppressOpeningDirectory ?? config.options.suppressOpeningDirectory ?? false) || config.sandboxMode + config.singlePage = singlePage ?? config.options.singlePage ?? false + config.failIfMissingLicense = failIfMissingLicense ?? config.options.failIfMissingLicense ?? false + config.addSources = addSources ?? config.options.addSources ?? false + return config + } } LicensePlist.main() From 94cd471c36f730c25558df4f0f42dfcc0d7afa7c Mon Sep 17 00:00:00 2001 From: Yassir Ramdani Date: Wed, 8 Nov 2023 11:23:43 +0100 Subject: [PATCH 6/6] lint trailing commas --- Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift b/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift index 2a9239ad..ea0c9244 100644 --- a/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift +++ b/Sources/LicensePlistCore/Entity/LicenseCSVHolder.swift @@ -8,7 +8,7 @@ struct LicenseCSVHolder { "Component", "License", options.config.addSources ? "Origin" : nil, - "Copyright", + "Copyright" ] .compactMap { $0 } .joined(separator: .delemiter) + .newLine @@ -22,13 +22,13 @@ struct LicenseCSVHolder { component, licenseType, source, - copyright, + copyright ].joined(separator: .delemiter) } else { csv += [ component, licenseType, - copyright, + copyright ].joined(separator: .delemiter) } csv += .newLine