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

Adds --xcworkspace-path option and "file parser" #166

Merged
merged 3 commits into from
Nov 24, 2021
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
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,24 @@ You can see options by `license-plist --help`.
#### `--package-path`

- Default: `Package.swift`
- `LicensePlist` tries to find `YourProjectName.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved` and `YourProjectName.xcworkspace/xcshareddata/swiftpm/Package.resolved`, then uses new one. If you make anothor workspace in custom directory, you can use `--package-path PathToYourCustomWorkspace/CustomWorkspaceName.xcworkspace/xcshareddata/swiftpm/Package.swift` inside your `Run script`.
- `LicensePlist` tries to find `YourProjectName.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved` and `YourProjectName.xcworkspace/xcshareddata/swiftpm/Package.resolved`, then uses new one.

### `--xcodeproj-path`

- Default: `"*.xcodeproj"`
- By specifiying the path to the `.xcodeproj` `LicensePlist` will attempt to load the `Package.resolved` from that Xcode project. If you specify `somedir/*.xcodeproj` then `LicensePlist` will load from the first `xcodeproj` it finds in `somedir`.

#### `--xcworkspace-path`

- Default: `"*.xcworkspace"`
- By specifying the path to the `.xcworkspace` `LicensePlist` will load the `Package.resolved` from that Xcode workspace. If you specify `somedir/*.xcworkspace` then `LicensePlist` will load from the first `xcworkspace` it finds in `somedir`.
- `--xcworkspace-path` supersedes any provided `--xcodeproj-path`.

#### `--output-path`

- Default: `com.mono0926.LicensePlist.Output`
- Recommended: `--output-path YOUR_PRODUCT_DIR/Settings.bundle`


#### `--github-token`

- Default: None.
Expand Down
152 changes: 78 additions & 74 deletions Sources/LicensePlist/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,84 +11,88 @@ private func loadConfig(configPath: URL) -> Config {
}

extension CompletionKind {
static var empty: CompletionKind {
return .custom { _ in return [] }
}
static var empty: CompletionKind {
return .custom { _ in return [] }
}
}

// Typename used for usage in help command
struct LicensePlist: ParsableCommand {
@Option(name: .long, completion: .file())
var cartfilePath = Consts.cartfileName

@Option(name: .long, completion: .file())
var mintfilePath = Consts.mintfileName

@Option(name: .long, completion: .directory)
var podsPath = Consts.podsDirectoryName

@Option(name: [.customLong("package-path"), .customLong("swift-package-path"), .long, .customLong("swift-package-paths")], parsing: .upToNextOption, completion: .file())
var packagePaths = [Consts.packageName]

@Option(name: .long, completion: .file())
var xcodeprojPath = "*.xcodeproj"

@Option(name: .long, completion: .file())
var outputPath = Consts.outputPath

static let githubTokenEnv = "LICENSE_PLIST_GITHUB_TOKEN"
@Option(name: .long, help: "You can also pass the token via the '\(Self.githubTokenEnv)' environment variable.", completion: .empty)
var githubToken: String?

@Option(name: .long, completion: .file())
var configPath = Consts.configPath

@Option(name: .long, completion: .empty)
var prefix = Consts.prefix

@Option(name: .long, completion: .file())
var htmlPath: String?

@Option(name: .long, completion: .file())
var markdownPath: String?

@Flag(name: .long)
var force = false

@Flag(name: .long)
var addVersionNumbers = false

@Flag(name: .long)
var suppressOpeningDirectory = false

@Flag(name: .long)
var singlePage = false

@Flag(name: .long)
var failIfMissingLicense = false

func run() throws {
Logger.configure()
var config = loadConfig(configPath: URL(fileURLWithPath: configPath))
config.force = force
config.addVersionNumbers = addVersionNumbers
config.suppressOpeningDirectory = suppressOpeningDirectory
config.singlePage = singlePage
config.failIfMissingLicense = failIfMissingLicense
let options = Options(outputPath: URL(fileURLWithPath: outputPath),
cartfilePath: URL(fileURLWithPath: cartfilePath),
mintfilePath: URL(fileURLWithPath: mintfilePath),
podsPath: URL(fileURLWithPath: podsPath),
packagePaths: packagePaths.map { URL(fileURLWithPath: $0) },
xcodeprojPath: URL(fileURLWithPath: xcodeprojPath),
prefix: prefix,
gitHubToken: githubToken ?? ProcessInfo.processInfo.environment[Self.githubTokenEnv],
htmlPath: htmlPath.map { return URL(fileURLWithPath: $0) },
markdownPath: markdownPath.map { return URL(fileURLWithPath: $0) },
config: config)
let tool = LicensePlistCore.LicensePlist()
tool.process(options: options)
}
@Option(name: .long, completion: .file())
var cartfilePath = Consts.cartfileName

@Option(name: .long, completion: .file())
var mintfilePath = Consts.mintfileName

@Option(name: .long, completion: .directory)
var podsPath = Consts.podsDirectoryName

@Option(name: [.customLong("package-path"), .customLong("swift-package-path"), .long, .customLong("swift-package-paths")], parsing: .upToNextOption, completion: .file())
var packagePaths = [Consts.packageName]

@Option(name: .long, completion: .file())
var xcworkspacePath = "*.xcworkspace"

@Option(name: .long, completion: .file())
var xcodeprojPath = "*.xcodeproj"

@Option(name: .long, completion: .file())
var outputPath = Consts.outputPath

static let githubTokenEnv = "LICENSE_PLIST_GITHUB_TOKEN"
@Option(name: .long, help: "You can also pass the token via the '\(Self.githubTokenEnv)' environment variable.", completion: .empty)
var githubToken: String?

@Option(name: .long, completion: .file())
var configPath = Consts.configPath

@Option(name: .long, completion: .empty)
var prefix = Consts.prefix

@Option(name: .long, completion: .file())
var htmlPath: String?

@Option(name: .long, completion: .file())
var markdownPath: String?

@Flag(name: .long)
var force = false

@Flag(name: .long)
var addVersionNumbers = false

@Flag(name: .long)
var suppressOpeningDirectory = false

@Flag(name: .long)
var singlePage = false

@Flag(name: .long)
var failIfMissingLicense = false

func run() throws {
Logger.configure()
var config = loadConfig(configPath: URL(fileURLWithPath: configPath))
config.force = force
config.addVersionNumbers = addVersionNumbers
config.suppressOpeningDirectory = suppressOpeningDirectory
config.singlePage = singlePage
config.failIfMissingLicense = failIfMissingLicense
let options = Options(outputPath: URL(fileURLWithPath: outputPath),
cartfilePath: URL(fileURLWithPath: cartfilePath),
mintfilePath: URL(fileURLWithPath: mintfilePath),
podsPath: URL(fileURLWithPath: podsPath),
packagePaths: packagePaths.map { URL(fileURLWithPath: $0) },
xcworkspacePath: URL(fileURLWithPath: xcworkspacePath),
xcodeprojPath: URL(fileURLWithPath: xcodeprojPath),
prefix: prefix,
gitHubToken: githubToken ?? ProcessInfo.processInfo.environment[Self.githubTokenEnv],
htmlPath: htmlPath.map { return URL(fileURLWithPath: $0) },
markdownPath: markdownPath.map { return URL(fileURLWithPath: $0) },
config: config)
let tool = LicensePlistCore.LicensePlist()
tool.process(options: options)
}
}

LicensePlist.main()
1 change: 1 addition & 0 deletions Sources/LicensePlistCore/Consts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public struct Consts {
public static let mintfileName = "Mintfile"
public static let podsDirectoryName = "Pods"
public static let packageName = "Package.swift"
public static let xcworkspaceExtension = "xcworkspace"
public static let xcodeprojExtension = "xcodeproj"
public static let prefix = "com.mono0926.LicensePlist"
public static let outputPath = "\(prefix).Output"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Foundation

/// An object that reads a xcodeproj file.
struct XcodeWorkspaceFileReader: FileReader {

typealias ResultType = String?

let path: URL

/// The path which specifies `"*.xcworkspace"` file wrapper.
var workspacePath: URL? {
if path.lastPathComponent.contains("*") {
// find first "xcworkspace" in directory
return path.deletingLastPathComponent().lp.listDir().first { $0.pathExtension == Consts.xcworkspaceExtension }
} else {
// use the specified path
return path
}
}

func read() throws -> String? {
guard let validatedPath = workspacePath else { return nil }

if validatedPath.pathExtension != Consts.xcworkspaceExtension {
return nil
}

let packageResolvedPath = validatedPath
.appendingPathComponent("xcshareddata")
.appendingPathComponent("swiftpm")
.appendingPathComponent("Package.resolved")

guard packageResolvedPath.lp.isExists else {
return nil
}

return try SwiftPackageFileReader(path: packageResolvedPath).read()
}

}
4 changes: 4 additions & 0 deletions Sources/LicensePlistCore/Entity/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public struct Options {
public let mintfilePath: URL
public let podsPath: URL
public let packagePaths: [URL]
public let xcworkspacePath: URL
public let xcodeprojPath: URL
public let prefix: String
public let gitHubToken: String?
Expand All @@ -18,6 +19,7 @@ public struct Options {
mintfilePath: URL(fileURLWithPath: ""),
podsPath: URL(fileURLWithPath: ""),
packagePaths: [],
xcworkspacePath: URL(fileURLWithPath: ""),
xcodeprojPath: URL(fileURLWithPath: ""),
prefix: Consts.prefix,
gitHubToken: nil,
Expand All @@ -30,6 +32,7 @@ public struct Options {
mintfilePath: URL,
podsPath: URL,
packagePaths: [URL],
xcworkspacePath: URL,
xcodeprojPath: URL,
prefix: String,
gitHubToken: String?,
Expand All @@ -41,6 +44,7 @@ public struct Options {
self.mintfilePath = mintfilePath
self.podsPath = podsPath
self.packagePaths = packagePaths
self.xcworkspacePath = xcworkspacePath
self.xcodeprojPath = xcodeprojPath
self.prefix = prefix
self.gitHubToken = gitHubToken
Expand Down
30 changes: 24 additions & 6 deletions Sources/LicensePlistCore/LicensePlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ public final class LicensePlist {
let swiftPackageFileReadResults = try options.packagePaths.compactMap { packagePath in
try SwiftPackageFileReader(path: packagePath).read()
}
let xcodeProjectFileReadResult = try XcodeProjectFileReader(path: options.xcodeprojPath).read()
info.loadSwiftPackageLibraries(
packageFiles: swiftPackageFileReadResults.isEmpty
? [xcodeProjectFileReadResult ?? ""]
: swiftPackageFileReadResults
)

let xcodeFileReadResult = try xcodeFileReadResult(xcworkspacePath: options.xcworkspacePath, xcodeprojPath: options.xcodeprojPath)

let packageFiles = swiftPackageFileReadResults.isEmpty
? [xcodeFileReadResult ?? ""]
: swiftPackageFileReadResults

info.loadSwiftPackageLibraries(packageFiles: packageFiles)
} catch {
fatalError(error.localizedDescription)
}
Expand All @@ -38,6 +40,22 @@ public final class LicensePlist {
Shell.open(options.outputPath.path)
}
}

/// Gets the result of attempting to read the `Package.resolved` from ether a Xcode Workspace or Xcode project.
/// - note: If an Xcode workspace is found it is preferred over a Xcode project.
private func xcodeFileReadResult(xcworkspacePath: URL, xcodeprojPath: URL) throws -> String? {

var result: String?
if xcworkspacePath.path.isEmpty == false {
result = try XcodeWorkspaceFileReader(path: xcworkspacePath).read()
}

if result == nil && xcodeprojPath.path.isEmpty == false {
result = try XcodeProjectFileReader(path: xcodeprojPath).read()
}

return result
}
}

private func readCartfile(path: URL) -> GitHubLibraryConfigFile {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import XCTest
@testable import LicensePlistCore

@available(OSX 10.11, *)
class XcodeWorkspaceFileReaderTests: XCTestCase {

var workspaceFileURL: URL!
var wildcardFileURL: URL!

override func setUpWithError() throws {
workspaceFileURL = URL(fileURLWithPath: "\(TestUtil.testProjectsPath)/SwiftPackageManagerTestProject/SwiftPackageManagerTestProject.xcworkspace")
wildcardFileURL = URL(fileURLWithPath: "\(TestUtil.testProjectsPath)/SwiftPackageManagerTestProject/*")

print("fileURL: \(String(describing: workspaceFileURL))")
print("wildcardURL: \(String(describing: wildcardFileURL))")
}

override func tearDownWithError() throws {
workspaceFileURL = nil
wildcardFileURL = nil
}

func testProjectPathWhenSpecifiesCorrectFilePath() throws {
let fileReader = XcodeWorkspaceFileReader(path: workspaceFileURL)
XCTAssertEqual(fileReader.workspacePath, workspaceFileURL)
}

func testProjectPathWhenSpecifiesWildcard() throws {
let fileReader = XcodeWorkspaceFileReader(path: wildcardFileURL)
XCTAssertEqual(fileReader.workspacePath, workspaceFileURL)
}

func testReadNotNil() throws {
let fileReader = XcodeWorkspaceFileReader(path: workspaceFileURL)
XCTAssertNotNil(try fileReader.read())
}
}
1 change: 1 addition & 0 deletions Tests/LicensePlistTests/Entity/PlistInfoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class PlistInfoTests: XCTestCase {
mintfilePath: URL(fileURLWithPath: "test_result_dir"),
podsPath: URL(fileURLWithPath: "test_result_dir"),
packagePaths: [URL(fileURLWithPath: "test_result_dir")],
xcworkspacePath: URL(fileURLWithPath: "test_result_dir"),
xcodeprojPath: URL(fileURLWithPath: "test_result_dir"),
prefix: Consts.prefix,
gitHubToken: nil,
Expand Down