felixherrmann/swift-package-list
A command-line tool to get all used Swift Package dependencies.
Command-Line Tool
Installation
Using Homebrew
brew tap FelixHerrmann/tap
brew install swift-package-listUsing Mint:
mint install FelixHerrmann/swift-package-listUsing Mise
mise use spm:FelixHerrmann/swift-package-listInstalling from source:
Clone or download this repository and run make install, make update or make uninstall.
Usage
Open the terminal and run swift-package-list <project-path> with the path to the project file you want to generate the list from. Currently supported are:
*.xcodeprojfor Xcode projects*.xcworkspacefor Xcode workspacesPackage.swiftfor Swift packagesProject.swiftfor Tuist projectsDependencies.swiftfor Tuist 3 projects with external dependencies (deprecated)
In addition to that you can specify the following options:
| Option | Description | | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | --custom-derived-data-path \<custom-derived-data-path\> | A custom path to your DerivedData-folder. | | --custom-source-packages-path \<custom-source-packages-path\> | A custom path to the SourcePackages-folder. | | --custom-packages-file-path \<custom-packages-file-path\> | A path to a file containing custom packages in the same format as the JSON-output. (This option may be repeated multiple times) | | --output-type \<output-type\> | The type of output for the package-list. (values: stdout, json, plist, settings-bundle, pdf; default: stdout) | | --output-path \<output-path\> | The path where the package-list file will be stored. (Not required for stdout output-type) | | --custom-file-name \<custom-file-name\> | A custom filename to be used instead of the default ones. | | --package-order \<package-order\> | The order in which the packages will be listed. (values: source, name-ascending, name-descending, identity-ascending, identity-descending; default: source) | | --requires-license | Will skip the packages without a license-file. | | --ignore-package \<package-identity\> | Will skip a package with the specified identity. (This option may be repeated multiple times) | | --version | Show the version. | | -h, --help | Show help information. |
Build Tool Plugin
The easiest way to add this tool to your project is using the provided build-tool plugin, available for both Xcode projects and Swift packages.
For Xcode projects simply add it under the Run Build Tool Plug-ins section in the Target's Build Phases tab after you have added this package to the project's Package Dependencies; for Swift packages configure it in the Package.swift manifest, as described here.
By default this will use the JSON output with --requires-license but you can create a swift-package-list-config.json in your project's root to configure that behavior, both project and target specific (target configs have precedence over the project one). Everything in the configuration is optional and has the following format:
// SwiftPackageList configuration file
// Check out https://github.com/FelixHerrmann/swift-package-list#build-tool-plugin for all possible configuration options.
{
projectPath: "Project.xcworkspace",
project: {
outputType: "plist",
requiresLicense: false,
},
targets: {
"Target 1": {
outputType: "settings-bundle",
packageOrder: "name-ascending",
requiresLicense: true,
},
"Target 2": {
outputType: "json",
requiresLicense: true,
ignorePackages: [
"swift-package-list",
"swift-argument-parser",
],
customPackagesFilePaths: [
"custom-packages.json",
],
},
},
}Once added and configured the file(s) will get generated during every build process and are available in the App's bundle. You can then open them manually or use the various options in the included Swift Package.
[!NOTE] When using Xcode Cloud add
defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YEStoci_post_clone.shwhich disables the plugin validation.
Run Script Phase
You can easily set up a Run Script Phase in your target of your Xcode project to keep the package-list file up to date automatically:
- open the corresponding target and click on the plus under the Build Phases section
- select New Run Script Phase and add the following script into the code box:
if command -v swift-package-list &> /dev/null; then
OUTPUT_PATH=$SOURCE_ROOT/$TARGETNAME
swift-package-list "$PROJECT_FILE_PATH" --output-type json --output-path "$OUTPUT_PATH" --requires-license
else
echo "warning: swift-package-list not installed"
fi- move the Phase above the
Copy Bundle Resources-phase - optionally you can rename the Phase by double-clicking on the title
- build your project (<kbd>cmd</kbd> + <kbd>b</kbd>)
- right-click on the targets-folder in the sidebar and select Add Files to "\<project-name\>"
- select
package-list.jsonin the Finder-window
The package-list file will be updated now on every build and can be opened from the bundle in your app. You can do that manually or use the Swift Package for that.
Xcode Workspace (CocoaPods)
If you have an Xcode workspace instead of a standard Xcode project everything works exactly the same, you just need a slightly modified script for the Run Script Phase:
if command -v swift-package-list &> /dev/null; then
OUTPUT_PATH=$SOURCE_ROOT/$TARGETNAME
WORKSPACE_FILE_PATH=${PROJECT_FILE_PATH%.xcodeproj}.xcworkspace
swift-package-list "$WORKSPACE_FILE_PATH" --output-type json --output-path "$OUTPUT_PATH" --requires-license
else
echo "warning: swift-package-list not installed"
fiHomebrew Troubleshooting on Apple Silicon
If you used Homebrew to install the Command-Line Tool on an Apple Silicon Mac, Xcode will not recognize the swift-package-list command. This is because Homebrew uses it's own /bin directory and Xcode's PATH environment variable is not aware of that. There are 2 easy ways to fix this issue:
- add
export PATH="$PATH:/opt/homebrew/bin"as the first line to your build script - execute
ln -s /opt/homebrew/bin/swift-package-list /usr/local/bin/swift-package-listin your Terminal
Mint Troubleshooting
If you used Mint to install the Command-Line Tool, Xcode will not recognize the swift-package-list command. This is because Mint uses it's own /bin directory and Xcode's PATH environment variable is not aware of that. There are 2 easy ways to fix this issue:
- add
export PATH="$PATH:$HOME/.mint/bin/"as the first line to your build script - execute
ln -s $HOME/.mint/bin/swift-package-list /usr/local/bin/swift-package-listin your Terminal
Tuist
This tool supports the following Tuist external dependency setups:
| Setup | Command | |--------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| | XcodeProj-based at root | swift-package-list Package.swift --custom-source-packages-path .build | | XcodeProj-based at /Tuist | swift-package-list Tuist/Package.swift --custom-source-packages-path Tuist/.build | | Xcode's default | swift-package-list Project.swift | | Tuist 3 with external dependencies (deprecated) | swift-package-list Dependencies.swift |
Settings Bundle
You can also generate a Settings.bundle file to show the acknowledgements in the Settings app. This works slightly different than the other file types, because a Settings Bundle is a collection of several files and might already exist in your app. Just specify --output-type settings-bundle on the command execution.
Important: The Root.plist and Root.strings files will (unlike the other files) only be created if they not already exists, otherwise it would remove existing configurations. Make sure you set up the Acknowledgements.plist correctly as a Child Pane as shown below:
<dict>
<key>Type</key>
<string>PSChildPaneSpecifier</string>
<key>Title</key>
<string>Acknowledgements</string>
<key>File</key>
<string>Acknowledgements</string>
</dict>For more information on how to set up and use a Settings Bundle, take a look at Apple's documentation.
On macOS it is more common to show a Acknowledgments.pdf file. Therefore you have the option to generate a PDF with all licenses. Just specify --output-type pdf on the command execution.
It uses the project's file name (without extension) as the product name and, if present, the organization-name from the project file. You can set that in your project's file inspector as shown here.
Once created and added to the project, it can be easily accessed from the application's bundle like the following:
import SwiftPackageList
let url = Bundle.main.acknowledgementsURLYou can then use QuickLook, NSWorkspace.open(\_:) or any other method to display the PDF.
Custom Packages
To provide custom packages or other items with licenses, you can use the --custom-packages-file-path option with a JSON file in the following format:
[
{
"branch" : null,
"identity" : "custom-package-example",
"kind" : "custom",
"license" : null,
"location" : "",
"name" : "CustomPackageExample",
"revision" : null,
"version" : null
}
]All optional fields have null values in this example and can be left out, the other ones are required.
Swift Package
Load the generated package-list file from the bundle or use some pre-build UI components.
Requirements
- macOS 10.15
- iOS 13.0
- tvOS 13.0
- watchOS 6.0
- visionOS 1.0
Usage
Add the package to your project as shown here.
It contains 2 libraries; SwiftPackageList for loading the Data and SwiftPackageListUI to get an iOS Settings-like user interface.
SwiftPackageList
import SwiftPackageList
let packageProvider = JSONPackageProvider()
do {
let packages = try packageProvider.packages()
// use packages
} catch {
print(error)
}SwiftPackageListUI
import SwiftPackageListUI
let acknowledgmentsViewController = SPLAcknowledgmentsTableViewController()
acknowledgmentsViewController.canOpenRepositoryLink = true
navigationController.pushViewController(acknowledgmentsViewController, animated: true)import SwiftPackageListUI
var body: some View {
NavigationStack {
AcknowledgmentsList()
}
}Localization
The Settings Bundle and the UI-components are currently localized in the following languages:
| Name | Code | | -------------------- | ------- | | Arabic | ar | | Chinese, Simplified | zh-Hans | | Chinese, Traditional | zh-Hant | | English | en | | French | fr | | German | de | | Hindi | hi | | Italian | it | | Japanese | ja | | Polish | pl | | Portuguese | pt | | Russian | ru | | Spanish | es | | Turkish | tr | | Ukrainian | uk |
If a language has mistakes or is missing, feel free to create an issue or open a pull request.
Known limitations
- SwiftPackageList won't include license files from packages that are located in a registry like Artifactory.
License
SwiftPackageList is available under the MIT license. See the LICENSE file for more info.
Package Metadata
Repository: felixherrmann/swift-package-list
Default branch: master
README: README.md