Skip to content

Commit

Permalink
Merge pull request #166 from orj/main
Browse files Browse the repository at this point in the history
Adds --xcworkspace-path option and "file parser"
  • Loading branch information
mono0926 authored Nov 24, 2021
2 parents f825453 + 24a7530 commit a7b6936
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 82 deletions.
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

0 comments on commit a7b6936

Please sign in to comment.