Repository: swiftlang/swift-package-manager Branch: main Commit: 3fbef9a57628 Files: 2183 Total size: 15.2 MB Directory structure: gitextract_zj1y_jdi/ ├── .devcontainer/ │ ├── devcontainer.json │ ├── docker-compose.yaml │ └── init.sh ├── .dir-locals.el ├── .editorconfig ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── BUG_REPORT.yml │ │ └── FEATURE_REQUEST.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ ├── scripts/ │ │ ├── prebuild.ps1 │ │ └── prebuild.sh │ └── workflows/ │ ├── automerge.yml │ └── pull_request.yml ├── .gitignore ├── .license_header_template ├── .licenseignore ├── .mailfilter ├── .mailmap ├── .pep8 ├── .swift-version ├── .swiftformat ├── Benchmarks/ │ ├── Benchmarks/ │ │ └── PackageGraphBenchmarks/ │ │ └── PackageGraphBenchmarks.swift │ ├── Package.swift │ ├── README.md │ └── Thresholds/ │ ├── macos-arm64/ │ │ ├── PackageGraphBenchmarks.SwiftPMWorkspaceModulesGraph.p90.json │ │ ├── PackageGraphBenchmarks.SyntheticModulesGraph.p90.json │ │ └── PackageGraphBenchmarks.SyntheticModulesGraphWithMacros.p90.json │ └── macosx-arm64/ │ ├── PackageGraphBenchmarks.SwiftPMWorkspaceModulesGraph.p90.json │ └── PackageGraphBenchmarks.SyntheticModulesGraph.p90.json ├── BuildSupport/ │ └── SwiftSyntax/ │ └── CMakeLists.txt ├── CHANGELOG.md ├── CMakeLists.txt ├── CONTRIBUTING.md ├── CONTRIBUTORS.txt ├── Documentation/ │ ├── Design/ │ │ ├── EvolutionIdeas.md │ │ ├── README.md │ │ └── SwiftBasedManifestFormat.md │ ├── PackageRegistry/ │ │ ├── PackageRegistryUsage.md │ │ ├── Registry.md │ │ └── registry.openapi.yaml │ ├── README.md │ ├── ReleaseNotes/ │ │ ├── 5.3.md │ │ ├── 5.4.md │ │ ├── 5.5.md │ │ ├── 5.6.md │ │ ├── 5.7.md │ │ ├── 5.8.md │ │ ├── 5.9.md │ │ └── 6.3.md │ └── libSwiftPM.md ├── Examples/ │ └── package-info/ │ ├── Package.swift │ ├── README.md │ └── Sources/ │ └── package-info/ │ └── example.swift ├── Fixtures/ │ ├── BinaryLibraries/ │ │ └── Static/ │ │ └── Package1/ │ │ ├── Package.swift │ │ ├── Simple.artifactbundle/ │ │ │ ├── Makefile │ │ │ ├── Package.swift │ │ │ ├── build.sh │ │ │ ├── dist/ │ │ │ │ ├── linux/ │ │ │ │ │ ├── libSimple_arm64.a │ │ │ │ │ └── libSimple_x86_64.a │ │ │ │ ├── macos/ │ │ │ │ │ ├── libSimple.a │ │ │ │ │ ├── libSimple_arm64.a │ │ │ │ │ └── libSimple_x86_64.a │ │ │ │ └── windows/ │ │ │ │ ├── Simple_arm64.lib │ │ │ │ └── Simple_x86_64.lib │ │ │ ├── include/ │ │ │ │ ├── simple.h │ │ │ │ └── simple.modulemap │ │ │ ├── info.json │ │ │ └── simple.c │ │ └── Sources/ │ │ ├── Example/ │ │ │ └── Example.swift │ │ └── Wrapper/ │ │ ├── include/ │ │ │ └── wrapper.h │ │ └── wrapper.c │ ├── BinaryTargets/ │ │ ├── Inputs/ │ │ │ ├── DynamicLibrary/ │ │ │ │ ├── DynamicLibrary.m │ │ │ │ └── include/ │ │ │ │ └── DynamicLibrary.h │ │ │ ├── StaticLibrary/ │ │ │ │ ├── StaticLibrary.m │ │ │ │ └── include/ │ │ │ │ └── StaticLibrary.h │ │ │ └── SwiftFramework/ │ │ │ └── SwiftFramework/ │ │ │ ├── Info.plist │ │ │ ├── SwiftFramework.h │ │ │ └── SwiftFramework.swift │ │ └── TestBinary/ │ │ ├── Package.swift │ │ └── Sources/ │ │ ├── CLibrary/ │ │ │ ├── CLibrary.m │ │ │ └── include/ │ │ │ └── CLibrary.h │ │ ├── Library/ │ │ │ └── Library.swift │ │ ├── cexe/ │ │ │ └── main.m │ │ └── exe/ │ │ └── main.swift │ ├── CFamilyTargets/ │ │ ├── CDynamicLookup/ │ │ │ ├── Foo.c │ │ │ ├── Package.swift │ │ │ └── include/ │ │ │ └── Foo.h │ │ ├── CLibraryNoIncludeDir/ │ │ │ ├── Cfactorial/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── factorial/ │ │ │ │ ├── factorial.c │ │ │ │ └── factorial.h │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Client/ │ │ │ └── main.swift │ │ ├── CLibraryParentSearchPath/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── CHeaderInclude/ │ │ │ │ ├── answers.c │ │ │ │ └── include/ │ │ │ │ └── answers.h │ │ │ ├── Constants/ │ │ │ │ └── Constants.h │ │ │ └── HeaderInclude/ │ │ │ └── FinalForm.swift │ │ ├── CLibrarySources/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ ├── Foo.c │ │ │ │ └── include/ │ │ │ │ └── Foo.h │ │ │ └── Tests/ │ │ │ ├── CLibrarySourcesTests/ │ │ │ │ └── foo.swift │ │ │ └── LinuxMain.swift │ │ ├── CLibraryWithSpaces/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Bar/ │ │ │ │ ├── Bar.c │ │ │ │ └── include/ │ │ │ │ └── Bar/ │ │ │ │ └── Bar.h │ │ │ ├── Bar with spaces/ │ │ │ │ ├── Bar.c │ │ │ │ └── include/ │ │ │ │ └── Bar/ │ │ │ │ └── Bar.h │ │ │ ├── Baz/ │ │ │ │ └── main.swift │ │ │ └── Foo/ │ │ │ ├── Foo.c │ │ │ └── include/ │ │ │ └── Foo/ │ │ │ └── Foo.h │ │ ├── ModuleMapGenerationCases/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Baz/ │ │ │ │ └── main.swift │ │ │ ├── CustomModuleMap/ │ │ │ │ ├── CustomModuleMap.c │ │ │ │ └── include/ │ │ │ │ ├── CustomModuleMap.h │ │ │ │ └── module.modulemap │ │ │ ├── FlatInclude/ │ │ │ │ ├── FlatInclude.c │ │ │ │ └── include/ │ │ │ │ └── FlatIncludeHeader.h │ │ │ ├── NoIncludeDir/ │ │ │ │ └── Jaz.c │ │ │ ├── NonModuleDirectoryInclude/ │ │ │ │ ├── Maz.c │ │ │ │ └── include/ │ │ │ │ └── NonModuleDirectoryInclude/ │ │ │ │ └── Maz.h │ │ │ ├── UmbrellaDirectoryInclude/ │ │ │ │ ├── Jaz.c │ │ │ │ └── include/ │ │ │ │ └── Paz.h │ │ │ ├── UmbrellaHeader/ │ │ │ │ ├── UmbrellaHeader.c │ │ │ │ └── include/ │ │ │ │ └── UmbrellaHeader/ │ │ │ │ └── UmbrellaHeader.h │ │ │ └── UmbrellaHeaderFlat/ │ │ │ ├── UmbrellaHeader.c │ │ │ └── include/ │ │ │ └── UmbrellaHeaderFlat.h │ │ ├── ObjCmacOSPackage/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ ├── HelloWorldExample.m │ │ │ │ └── include/ │ │ │ │ └── HelloWorldExample.h │ │ │ └── Tests/ │ │ │ └── ObjCmacOSPackageTests/ │ │ │ └── HelloWorldTest.m │ │ └── SwiftCMixed/ │ │ ├── Package.swift │ │ └── Sources/ │ │ ├── CExec/ │ │ │ └── main.c │ │ ├── SeaExec/ │ │ │ └── main.swift │ │ └── SeaLib/ │ │ ├── Foo.c │ │ └── include/ │ │ └── Foo.h │ ├── Collections/ │ │ ├── GitHub/ │ │ │ ├── contributors.json │ │ │ ├── languages.json │ │ │ ├── license.json │ │ │ ├── metadata.json │ │ │ ├── readme.json │ │ │ └── releases.json │ │ ├── JSON/ │ │ │ ├── good.json │ │ │ └── good_signed.json │ │ └── Signing/ │ │ ├── TestIntermediateCA.cer │ │ ├── TestRootCA.cer │ │ ├── Test_ec.cer │ │ ├── Test_ec_key.pem │ │ ├── Test_rsa.cer │ │ └── Test_rsa_key.pem │ ├── Coverage/ │ │ └── Simple/ │ │ ├── Package.swift │ │ ├── Sources/ │ │ │ └── Simple/ │ │ │ └── Simple.swift │ │ └── Tests/ │ │ └── SimpleTests/ │ │ └── SimpleTests.swift │ ├── DependencyResolution/ │ │ ├── External/ │ │ │ ├── Branch/ │ │ │ │ ├── Bar/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Sources/ │ │ │ │ │ └── Bar/ │ │ │ │ │ └── Bar.swift │ │ │ │ └── Foo/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── Foo/ │ │ │ │ └── Foo.swift │ │ │ ├── CUsingCDep/ │ │ │ │ ├── Bar/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Sources/ │ │ │ │ │ ├── SeaLover/ │ │ │ │ │ │ ├── Sea.c │ │ │ │ │ │ └── include/ │ │ │ │ │ │ └── Sea.h │ │ │ │ │ └── SwiftExec/ │ │ │ │ │ └── main.swift │ │ │ │ └── Foo/ │ │ │ │ ├── Foo.c │ │ │ │ ├── Package.swift │ │ │ │ └── include/ │ │ │ │ └── Foo/ │ │ │ │ └── Foo.h │ │ │ ├── Complex/ │ │ │ │ ├── FisherYates/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── src/ │ │ │ │ │ └── Fisher-Yates_Shuffle.swift │ │ │ │ ├── PlayingCard/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── src/ │ │ │ │ │ ├── PlayingCard.swift │ │ │ │ │ ├── Rank.swift │ │ │ │ │ └── Suit.swift │ │ │ │ ├── app/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── main.swift │ │ │ │ ├── deck-of-playing-cards/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── src/ │ │ │ │ │ └── Deck.swift │ │ │ │ └── deck-of-playing-cards-local/ │ │ │ │ ├── Package.swift │ │ │ │ └── src/ │ │ │ │ └── Deck.swift │ │ │ ├── Mirror/ │ │ │ │ ├── App/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── main.swift │ │ │ │ ├── Bar/ │ │ │ │ │ ├── Bar.swift │ │ │ │ │ └── Package.swift │ │ │ │ ├── BarMirror/ │ │ │ │ │ ├── Bar.swift │ │ │ │ │ └── Package.swift │ │ │ │ └── Foo/ │ │ │ │ ├── Foo.swift │ │ │ │ └── Package.swift │ │ │ ├── PackageLookupCaseInsensitive/ │ │ │ │ ├── dep/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Sources/ │ │ │ │ │ └── Dep/ │ │ │ │ │ └── dep.swift │ │ │ │ └── pkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── pkg/ │ │ │ │ └── pkg.swift │ │ │ ├── Simple/ │ │ │ │ ├── Bar/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── main.swift │ │ │ │ └── Foo/ │ │ │ │ ├── Foo.swift │ │ │ │ └── Package.swift │ │ │ └── XCFramework/ │ │ │ ├── Bar.xcframework/ │ │ │ │ └── Info.plist │ │ │ ├── Foo/ │ │ │ │ └── Foo.swift │ │ │ └── Package.swift │ │ └── Internal/ │ │ ├── Complex/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Bar/ │ │ │ │ └── Bar.swift │ │ │ ├── Baz/ │ │ │ │ └── Baz.swift │ │ │ ├── Cat/ │ │ │ │ └── Cat.swift │ │ │ ├── Foo/ │ │ │ │ ├── Foo.swift │ │ │ │ └── main.swift │ │ │ └── Sound/ │ │ │ └── Sound.swift │ │ ├── InternalExecutableAsDependency/ │ │ │ ├── Bar/ │ │ │ │ ├── Bar.swift │ │ │ │ └── main.swift │ │ │ ├── Foo/ │ │ │ │ ├── Foo.swift │ │ │ │ └── main.swift │ │ │ └── Package.swift │ │ └── Simple/ │ │ ├── Bar/ │ │ │ └── Bar.swift │ │ ├── Foo/ │ │ │ ├── Foo.swift │ │ │ └── main.swift │ │ └── Package.swift │ ├── Macros/ │ │ ├── MacroPackage/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── MacroClient/ │ │ │ │ └── client.swift │ │ │ ├── MacroDef/ │ │ │ │ └── definition.swift │ │ │ └── MacroImpl/ │ │ │ └── macro.swift │ │ └── MinimalMacroPackage/ │ │ ├── Package.swift │ │ └── Sources/ │ │ ├── MacroClient/ │ │ │ └── main.swift │ │ ├── MacroDef/ │ │ │ └── MacroDef.swift │ │ └── MacroImpl/ │ │ └── StringifyMacro.swift │ ├── Metal/ │ │ └── SimpleLibrary/ │ │ ├── Package.swift │ │ ├── Sources/ │ │ │ ├── MyRenderer/ │ │ │ │ ├── Renderer.swift │ │ │ │ └── Shaders.metal │ │ │ └── MySharedTypes/ │ │ │ └── include/ │ │ │ └── SharedTypes.h │ │ └── Tests/ │ │ └── MyRendererTests/ │ │ └── MyRendererTests.swift │ ├── Miscellaneous/ │ │ ├── -DSWIFT_PACKAGE/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── CLib/ │ │ │ │ ├── foo.c │ │ │ │ └── include/ │ │ │ │ └── CLib.h │ │ │ └── SwiftExec/ │ │ │ └── main.swift │ │ ├── APIDiff/ │ │ │ ├── Bar/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Baz/ │ │ │ │ │ └── Baz.swift │ │ │ │ └── Qux/ │ │ │ │ └── Qux.swift │ │ │ ├── BrokenPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── BrokenPkg/ │ │ │ │ │ ├── bestHeaders/ │ │ │ │ │ │ └── header.h │ │ │ │ │ └── code.m │ │ │ │ └── Swift2/ │ │ │ │ └── file.swift │ │ │ ├── CIncludePath/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── CSample/ │ │ │ │ │ ├── include/ │ │ │ │ │ │ ├── CSample.h │ │ │ │ │ │ └── config.h │ │ │ │ │ └── vendorsrc/ │ │ │ │ │ ├── include/ │ │ │ │ │ │ └── vendor.h │ │ │ │ │ └── src/ │ │ │ │ │ └── vendor.c │ │ │ │ └── Sample/ │ │ │ │ └── Sample.swift │ │ │ ├── CTargetDep/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Bar/ │ │ │ │ │ └── Bar.swift │ │ │ │ └── Foo/ │ │ │ │ ├── Foo.c │ │ │ │ └── include/ │ │ │ │ └── Foo.h │ │ │ ├── Foo/ │ │ │ │ ├── Foo.swift │ │ │ │ └── Package.swift │ │ │ ├── NonAPILibraryTargets/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Bar/ │ │ │ │ │ └── Bar.swift │ │ │ │ ├── Baz/ │ │ │ │ │ └── Baz.swift │ │ │ │ ├── Exec/ │ │ │ │ │ └── main.swift │ │ │ │ ├── Foo/ │ │ │ │ │ └── Foo.swift │ │ │ │ └── Qux/ │ │ │ │ └── Qux.swift │ │ │ └── WithPlugin/ │ │ │ ├── Package.swift │ │ │ ├── Plugins/ │ │ │ │ └── BuildPlugin/ │ │ │ │ └── BuildToolPlugin.swift │ │ │ └── Sources/ │ │ │ ├── BuildTool/ │ │ │ │ └── BuildTool.swift │ │ │ └── TargetLib/ │ │ │ └── TargetLib.swift │ │ ├── AtMainSupport/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── ClangExecSingleFile/ │ │ │ │ └── NotMain.c │ │ │ ├── SwiftExecMultiFile/ │ │ │ │ ├── NotMain.swift │ │ │ │ └── OtherFile.swift │ │ │ └── SwiftExecSingleFile/ │ │ │ └── NotMain.swift │ │ ├── CXX17CompilerCrash/ │ │ │ ├── v5_7/ │ │ │ │ ├── Package.swift │ │ │ │ ├── include/ │ │ │ │ │ └── user_objects.h │ │ │ │ ├── lodepng/ │ │ │ │ │ ├── include/ │ │ │ │ │ │ └── lodepng.h │ │ │ │ │ └── lodepng.cpp │ │ │ │ └── src/ │ │ │ │ └── user_objects.cc │ │ │ └── v5_8/ │ │ │ ├── Package.swift │ │ │ ├── include/ │ │ │ │ └── user_objects.h │ │ │ ├── lodepng/ │ │ │ │ ├── include/ │ │ │ │ │ └── lodepng.h │ │ │ │ └── lodepng.cpp │ │ │ └── src/ │ │ │ └── user_objects.cc │ │ ├── CaseCollision/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Foo/ │ │ │ │ └── Foo.swift │ │ │ └── footool/ │ │ │ └── main.swift │ │ ├── CheckTestLibraryEnvironmentVariable/ │ │ │ ├── Package.swift │ │ │ └── Tests/ │ │ │ └── CheckTestLibraryEnvironmentVariableTests/ │ │ │ └── CheckTestLibraryEnvironmentVariableTests.swift │ │ ├── CompileFails/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── DependenciesWarnings/ │ │ │ ├── app/ │ │ │ │ ├── Package.swift │ │ │ │ └── app.swift │ │ │ ├── dep1/ │ │ │ │ ├── Package.swift │ │ │ │ └── code.swift │ │ │ └── dep2/ │ │ │ ├── Package.swift │ │ │ └── code.swift │ │ ├── DependenciesWarnings2/ │ │ │ ├── app/ │ │ │ │ ├── Package.swift │ │ │ │ └── app.swift │ │ │ ├── dep1/ │ │ │ │ ├── Package.swift │ │ │ │ └── code.swift │ │ │ └── dep2/ │ │ │ ├── Package.swift │ │ │ └── code.swift │ │ ├── DependencyEdges/ │ │ │ ├── External/ │ │ │ │ ├── dep1/ │ │ │ │ │ ├── Foo.swift │ │ │ │ │ └── Package.swift │ │ │ │ ├── dep2/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── main.swift │ │ │ │ └── root/ │ │ │ │ ├── Bar.swift │ │ │ │ └── Package.swift │ │ │ └── Internal/ │ │ │ ├── Bar/ │ │ │ │ └── Bar.swift │ │ │ ├── Foo/ │ │ │ │ └── main.swift │ │ │ └── Package.swift │ │ ├── DifferentProductTargetName/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── DistantFutureDeploymentTarget/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── main.swift │ │ ├── DoNotFilterLinkerDiagnostics/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── DoNotFilterLinkerDiagnostics/ │ │ │ └── main.swift │ │ ├── DumpPackage/ │ │ │ ├── PlayingCard/ │ │ │ │ ├── Package.swift │ │ │ │ └── src/ │ │ │ │ ├── PlayingCard.swift │ │ │ │ ├── Rank.swift │ │ │ │ └── Suit.swift │ │ │ └── app/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── DynamicProduct/ │ │ │ ├── exec/ │ │ │ │ ├── Package.swift │ │ │ │ ├── README.md │ │ │ │ ├── Sources/ │ │ │ │ │ └── exec/ │ │ │ │ │ └── main.swift │ │ │ │ └── Tests/ │ │ │ │ └── DynaTests/ │ │ │ │ └── Tests.swift │ │ │ ├── firstDyna/ │ │ │ │ ├── Package.swift │ │ │ │ ├── README.md │ │ │ │ └── Sources/ │ │ │ │ ├── Core/ │ │ │ │ │ ├── Core.c │ │ │ │ │ └── include/ │ │ │ │ │ └── Core.h │ │ │ │ └── firstDyna/ │ │ │ │ └── firstDyna.swift │ │ │ └── secondDyna/ │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ └── secondDyna/ │ │ │ └── secondDyna.swift │ │ ├── EchoExecutable/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── secho/ │ │ │ │ └── main.swift │ │ │ ├── Tests/ │ │ │ │ └── TestSuite/ │ │ │ │ └── Tests.swift │ │ │ ├── echo.bat │ │ │ ├── echo.sh │ │ │ ├── toolset.json │ │ │ └── toolset.win32.json │ │ ├── Edit/ │ │ │ ├── App/ │ │ │ │ ├── Package.swift │ │ │ │ └── src/ │ │ │ │ └── main.swift │ │ │ ├── Bar/ │ │ │ │ ├── Bar.swift │ │ │ │ └── Package.swift │ │ │ └── Foo/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── EmptyTestsPkg/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── EmptyTestsPkg/ │ │ │ │ └── EmptyTestsPkg.swift │ │ │ └── Tests/ │ │ │ └── EmptyTestsPkgTests/ │ │ │ └── EmptyTestsTests.swift │ │ ├── Errors/ │ │ │ └── FatalErrorInSingleXCTest/ │ │ │ └── TypeLibrary/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── TypeLibrary/ │ │ │ │ └── TypeLibrary.swift │ │ │ └── Tests/ │ │ │ └── TypeLibraryTests/ │ │ │ └── TypeLibraryTests.swift │ │ ├── ExactDependencies/ │ │ │ ├── FooExec/ │ │ │ │ ├── FooExec.swift │ │ │ │ ├── Package.swift │ │ │ │ └── main.swift │ │ │ ├── FooLib1/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── FooLib1/ │ │ │ │ │ └── FooLib1.swift │ │ │ │ └── cli/ │ │ │ │ └── main.swift │ │ │ ├── FooLib2/ │ │ │ │ ├── FooLib2.swift │ │ │ │ └── Package.swift │ │ │ └── app/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── ExeTest/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── Exe/ │ │ │ │ └── main.swift │ │ │ └── Tests/ │ │ │ └── ExeTests/ │ │ │ └── ExeTests.swift │ │ ├── ExecutableTargetWithTwoProducts/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── FlatPackage/ │ │ │ ├── MyExec.swift │ │ │ ├── MyTest.swift │ │ │ ├── Package.swift │ │ │ └── README.md │ │ ├── ImportOfMissingDependency/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── A/ │ │ │ │ └── A.swift │ │ │ └── B/ │ │ │ ├── B.swift │ │ │ └── main.swift │ │ ├── LTO/ │ │ │ └── SwiftAndCTargets/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── cLib/ │ │ │ │ ├── cLib.c │ │ │ │ └── include/ │ │ │ │ └── cLib.h │ │ │ ├── exe/ │ │ │ │ └── main.swift │ │ │ └── swiftLib/ │ │ │ └── swiftLib.swift │ │ ├── LibraryEvolution/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── A/ │ │ │ │ └── A.swift │ │ │ └── B/ │ │ │ └── B.swift │ │ ├── LibraryEvolutionLinuxXCF/ │ │ │ ├── SwiftFramework/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── SwiftFramework/ │ │ │ │ └── SwiftFramework.swift │ │ │ └── TestBinary/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── TestBinary/ │ │ │ └── Main.swift │ │ ├── LocalPackageAsURL/ │ │ │ ├── Bar/ │ │ │ │ ├── Package.swift │ │ │ │ └── main.swift │ │ │ └── Foo/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── MissingDependency/ │ │ │ └── Bar/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── MultipleExecutables/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── exec1/ │ │ │ │ └── main.swift │ │ │ ├── exec2/ │ │ │ │ └── main.swift │ │ │ └── lib1/ │ │ │ └── lib.swift │ │ ├── PackageEdit/ │ │ │ ├── bar/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── bar.swift │ │ │ ├── baz/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── baz.swift │ │ │ └── foo/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── main.swift │ │ ├── PackageNameFlag/ │ │ │ ├── appPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── App/ │ │ │ │ │ └── file.swift │ │ │ │ └── exe/ │ │ │ │ └── main.swift │ │ │ ├── barPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Bar/ │ │ │ │ │ └── file.swift │ │ │ │ └── Baz/ │ │ │ │ └── file.swift │ │ │ └── fooPkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Foo/ │ │ │ │ └── file.swift │ │ │ └── Zoo/ │ │ │ └── file.swift │ │ ├── PackageWithMalformedLibraryProduct/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── PackageWithMalformedLibraryProduct/ │ │ │ └── main.swift │ │ ├── PackageWithNonc99NameModules/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── A-B/ │ │ │ │ └── ab.swift │ │ │ ├── B-C/ │ │ │ │ └── bc.swift │ │ │ └── C D/ │ │ │ └── cd.swift │ │ ├── PackageWithResource/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── AwesomeResources/ │ │ │ │ ├── AwesomeResource.swift │ │ │ │ └── hello.txt │ │ │ └── Tests/ │ │ │ └── AwesomeResourcesTest/ │ │ │ ├── MyTests.swift │ │ │ └── world.txt │ │ ├── ParallelTestsPkg/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── ParallelTestsPkg/ │ │ │ │ └── ParallelTestsPkg.swift │ │ │ └── Tests/ │ │ │ └── ParallelTestsPkgTests/ │ │ │ ├── ParallelTestsFailureTests.swift │ │ │ └── ParallelTestsTests.swift │ │ ├── ParseAsLibrary/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── ExecutableTargetOneFileNamedMainMainAttr/ │ │ │ │ └── main.swift │ │ │ ├── ExecutableTargetOneFileNamedMainNoMainAttr/ │ │ │ │ └── main.swift │ │ │ ├── ExecutableTargetOneFileNotNamedMainMainAttr/ │ │ │ │ └── othername.swift │ │ │ ├── ExecutableTargetOneFileNotNamedMainNoMainAttr/ │ │ │ │ └── othername.swift │ │ │ └── ExecutableTargetTwoFiles/ │ │ │ ├── one.swift │ │ │ └── two.swift │ │ ├── ParseableInterfaces/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── A/ │ │ │ │ └── A.swift │ │ │ └── B/ │ │ │ └── B.swift │ │ ├── PkgConfig/ │ │ │ ├── CSystemModule/ │ │ │ │ ├── Package.swift │ │ │ │ ├── module.modulemap │ │ │ │ └── shim.h │ │ │ ├── SystemModule/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── SystemModule.c │ │ │ │ └── include/ │ │ │ │ └── SystemModule.h │ │ │ ├── SystemModuleUser/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── main.swift │ │ │ └── SystemModuleUserClang/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── main.c │ │ ├── PluginGeneratedResources/ │ │ │ ├── Package.swift │ │ │ ├── Plugins/ │ │ │ │ └── Generator/ │ │ │ │ └── plugin.swift │ │ │ └── Sources/ │ │ │ └── PluginGeneratedResources/ │ │ │ └── PluginGeneratedResources.swift │ │ ├── Plugins/ │ │ │ ├── AmbiguousCommands/ │ │ │ │ ├── Dependencies/ │ │ │ │ │ ├── A/ │ │ │ │ │ │ ├── Package.swift │ │ │ │ │ │ └── Plugins/ │ │ │ │ │ │ └── A.swift │ │ │ │ │ └── B/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Plugins/ │ │ │ │ │ └── B.swift │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── main.swift │ │ │ ├── BinaryTargetExePlugin/ │ │ │ │ ├── Dependency/ │ │ │ │ │ └── MyBinaryTargetExeArtifactBundle.artifactbundle/ │ │ │ │ │ ├── info.json │ │ │ │ │ ├── mytool-linux/ │ │ │ │ │ │ └── mytool │ │ │ │ │ └── mytool-macos/ │ │ │ │ │ └── mytool │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyPluginExe/ │ │ │ │ └── main.swift │ │ │ ├── BinaryToolProductPlugin/ │ │ │ │ ├── Dependency/ │ │ │ │ │ ├── Binaries/ │ │ │ │ │ │ └── MyVendedSourceGenBuildTool.artifactbundle/ │ │ │ │ │ │ ├── info.json │ │ │ │ │ │ ├── mytool-linux/ │ │ │ │ │ │ │ └── mytool │ │ │ │ │ │ └── mytool-macos/ │ │ │ │ │ │ └── mytool │ │ │ │ │ └── Package.swift │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyLocalTool/ │ │ │ │ └── main.swift │ │ │ ├── BuildToolPluginCompilationError/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyLibrary/ │ │ │ │ └── library.swift │ │ │ ├── ClientOfPluginWithInternalExecutable/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── RootTarget/ │ │ │ │ └── main.swift │ │ │ ├── CommandPluginCompilationError/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── MyBuildToolPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── MyCommandPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── MyExecutable/ │ │ │ │ │ └── main.swift │ │ │ │ └── MyLibrary/ │ │ │ │ └── library.swift │ │ │ ├── CommandPluginTestStub/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── check-testability/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── diagnostics-stub/ │ │ │ │ │ │ └── diagnostics_stub.swift │ │ │ │ │ ├── plugin-dependencies-stub/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ └── targetbuild-stub/ │ │ │ │ │ └── targetbuild_stub.swift │ │ │ │ ├── Sources/ │ │ │ │ │ ├── InternalModule/ │ │ │ │ │ │ └── InternalModule.swift │ │ │ │ │ ├── placeholder/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ └── plugintool/ │ │ │ │ │ └── main.swift │ │ │ │ └── Tests/ │ │ │ │ └── InternalModuleTests/ │ │ │ │ └── InternalModuleTests.swift │ │ │ ├── ContrivedTestPlugin/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── MyAmbiguouslyNamedCommandPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── MyLocalTool/ │ │ │ │ │ └── main.swift │ │ │ │ ├── MySourceGenBuildTool/ │ │ │ │ │ └── main.swift │ │ │ │ └── libpcre/ │ │ │ │ ├── module.modulemap │ │ │ │ └── sdk_libpcre.h │ │ │ ├── DependentPlugins/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── MyPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── MyPlugin2/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── MyClient/ │ │ │ │ │ └── client.swift │ │ │ │ ├── MyExecutable/ │ │ │ │ │ └── tool.swift │ │ │ │ └── MyExecutable2/ │ │ │ │ └── tool.swift │ │ │ ├── IncorrectDependencies/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ └── MyPlugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ ├── MyExecutable/ │ │ │ │ │ │ └── MyExecutable.swift │ │ │ │ │ ├── MyLibrary/ │ │ │ │ │ │ └── Empty.swift │ │ │ │ │ └── MyPluginExecutable/ │ │ │ │ │ └── MyPluginExecutable.swift │ │ │ │ └── Tests/ │ │ │ │ └── MyExecutableTests/ │ │ │ │ └── MyExecutableTests.swift │ │ │ ├── InvalidUseOfInternalPluginExecutable/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── RootTarget/ │ │ │ │ └── main.swift │ │ │ ├── LibraryWithLocalBuildToolPluginUsingRemoteTool/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyLocalSourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── MyLibrary/ │ │ │ │ │ └── library.swift │ │ │ │ └── Tests/ │ │ │ │ └── MyLibraryTests/ │ │ │ │ └── test.swift │ │ │ ├── MissingPlugin/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── MissingPlugin/ │ │ │ │ └── MissingPlugin.swift │ │ │ ├── MyBinaryToolPlugin/ │ │ │ │ ├── Binaries/ │ │ │ │ │ └── MyVendedSourceGenBuildTool.artifactbundle/ │ │ │ │ │ ├── info.json │ │ │ │ │ ├── mytool-linux/ │ │ │ │ │ │ └── mytool │ │ │ │ │ ├── mytool-macos/ │ │ │ │ │ │ └── mytool │ │ │ │ │ └── mytool-windows/ │ │ │ │ │ └── mytool.bat │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyLocalTool/ │ │ │ │ ├── bar.in │ │ │ │ └── main.swift │ │ │ ├── MyBuildToolPluginDependencies/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── MyLocalTool/ │ │ │ │ │ └── main.swift │ │ │ │ ├── MySourceGenBuildTool/ │ │ │ │ │ └── main.swift │ │ │ │ └── MySourceGenBuildToolLib/ │ │ │ │ └── library.swift │ │ │ ├── MySourceGenClient/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── MyTool/ │ │ │ │ │ └── main.swift │ │ │ │ └── Tests/ │ │ │ │ └── MyTests/ │ │ │ │ └── MyTests.swift │ │ │ ├── MySourceGenPlugin/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── MySourceGenBuildToolPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── MySourceGenPrebuildPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ ├── MyLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MyOtherLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildToolLib/ │ │ │ │ │ │ └── library.swift │ │ │ │ │ └── MySourceGenRuntimeLib/ │ │ │ │ │ └── library.swift │ │ │ │ └── Tests/ │ │ │ │ └── MySourceGenPluginTests/ │ │ │ │ └── MySourceGenPluginTests.swift │ │ │ ├── MySourceGenPluginNoPreBuildCommands/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ ├── MyLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MyOtherLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildToolLib/ │ │ │ │ │ │ └── library.swift │ │ │ │ │ └── MySourceGenRuntimeLib/ │ │ │ │ │ └── library.swift │ │ │ │ └── Tests/ │ │ │ │ └── MySourceGenPluginNoPreBuildCommandsTests/ │ │ │ │ ├── MySourceGenPluginNoPreBuildCommandsTests.swift │ │ │ │ └── lunch.txt │ │ │ ├── MySourceGenPluginUsingURLBasedAPI/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ ├── MySourceGenBuildToolPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── MySourceGenPrebuildPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ ├── MyLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MyOtherLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ ├── MySourceGenBuildToolLib/ │ │ │ │ │ │ └── library.swift │ │ │ │ │ └── MySourceGenRuntimeLib/ │ │ │ │ │ └── library.swift │ │ │ │ └── Tests/ │ │ │ │ └── MySourceGenPluginTests/ │ │ │ │ └── MySourceGenPluginTests.swift │ │ │ ├── PluginCanBeReferencedByProductName/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Exec/ │ │ │ │ │ └── main.swift │ │ │ │ └── PluginCanBeReferencedByProductName/ │ │ │ │ └── PluginCanBeReferencedByProductName.swift │ │ │ ├── PluginUsingLocalAndRemoteTool/ │ │ │ │ ├── MyLibrary/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ ├── Sources/ │ │ │ │ │ │ └── MyLibrary/ │ │ │ │ │ │ └── library.swift │ │ │ │ │ └── Tests/ │ │ │ │ │ └── MyLibraryTests/ │ │ │ │ │ └── test.swift │ │ │ │ ├── MyPlugin/ │ │ │ │ │ ├── Libraries/ │ │ │ │ │ │ └── LocalToolHelperLibrary/ │ │ │ │ │ │ └── library.swift │ │ │ │ │ ├── Package.swift │ │ │ │ │ ├── Plugins/ │ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ │ └── plugin.swift │ │ │ │ │ └── Tools/ │ │ │ │ │ ├── ImpliedLocalTool/ │ │ │ │ │ │ └── main.swift │ │ │ │ │ └── LocalTool/ │ │ │ │ │ └── main.swift │ │ │ │ └── RemoteTool/ │ │ │ │ ├── Libraries/ │ │ │ │ │ └── RemoteToolHelperLibrary/ │ │ │ │ │ └── library.swift │ │ │ │ ├── Package.swift │ │ │ │ └── Tools/ │ │ │ │ └── RemoteTool/ │ │ │ │ └── main.swift │ │ │ ├── PluginWithInternalExecutable/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── PluginScriptTarget/ │ │ │ │ │ └── Script.swift │ │ │ │ └── Sources/ │ │ │ │ └── PluginExecutable/ │ │ │ │ ├── Utilities.swift │ │ │ │ └── main.swift │ │ │ ├── PluginsAndSnippets/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── PluginScriptTarget/ │ │ │ │ │ └── Script.swift │ │ │ │ ├── Snippets/ │ │ │ │ │ ├── ContainsMain.swift │ │ │ │ │ ├── ImportsProductTarget.swift │ │ │ │ │ ├── MySnippet.swift │ │ │ │ │ └── SubDirectory/ │ │ │ │ │ └── main.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyLib/ │ │ │ │ └── MyLib.swift │ │ │ ├── PrebuildDependsExecutableTarget/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ ├── MyClient/ │ │ │ │ │ └── client.swift │ │ │ │ └── MyExecutable/ │ │ │ │ └── tool.swift │ │ │ ├── SandboxTesterPlugin/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MySourceGenBuildToolPlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ └── Sources/ │ │ │ │ └── MyLocalTool/ │ │ │ │ └── main.swift │ │ │ ├── SandboxViolatingBuildToolPluginCommands/ │ │ │ │ ├── MyLibrary/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Sources/ │ │ │ │ │ └── MyLibrary/ │ │ │ │ │ └── library.swift │ │ │ │ └── MyPlugin/ │ │ │ │ ├── Package.swift │ │ │ │ └── Plugins/ │ │ │ │ └── PackageScribblerPlugin/ │ │ │ │ └── plugin.swift │ │ │ ├── SwiftFilePlugin/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── MyCustomBuildTool/ │ │ │ │ │ └── SwiftToolsBuildPlugin.swift │ │ │ │ ├── SimpleSwiftScript.swift │ │ │ │ └── Sources/ │ │ │ │ └── SwiftFilePluginFixture/ │ │ │ │ └── SwiftFilePluginFixture.swift │ │ │ └── TransitivePluginOnlyDependency/ │ │ │ ├── Dependencies/ │ │ │ │ ├── Library/ │ │ │ │ │ ├── Package.swift │ │ │ │ │ └── Sources/ │ │ │ │ │ └── Library/ │ │ │ │ │ └── Library.swift │ │ │ │ └── PluginOnly/ │ │ │ │ ├── Package.swift │ │ │ │ └── Plugins/ │ │ │ │ └── MyPlugin/ │ │ │ │ └── plugin.swift │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── TransitivePluginOnlyDependency/ │ │ │ └── TransitivePluginOnlyDependency.swift │ │ ├── RequiresOlderDeploymentTarget/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── RootPackageWithConditionals/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── client/ │ │ │ │ └── client.swift │ │ │ └── linuxOnly/ │ │ │ └── linuxOnly.swift │ │ ├── ShowExecutables/ │ │ │ ├── app/ │ │ │ │ ├── Package.swift │ │ │ │ └── main.swift │ │ │ └── deck-of-playing-cards/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── ShowTraits/ │ │ │ ├── app/ │ │ │ │ ├── Package.swift │ │ │ │ └── main.swift │ │ │ └── deck-of-playing-cards/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── Simple/ │ │ │ ├── Foo.swift │ │ │ └── Package.swift │ │ ├── SkipTests/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── Example/ │ │ │ │ └── Example.swift │ │ │ └── Tests/ │ │ │ └── ExampleTests/ │ │ │ ├── MoreTests.swift │ │ │ └── Tests.swift │ │ ├── Spaces Fixture/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Module Name 1/ │ │ │ │ └── Foo.swift │ │ │ └── Module Name 2/ │ │ │ └── main.swift │ │ ├── SwiftBuild/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── SwiftPMXCTestHelper/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── SwiftPMXCTestHelper.swift │ │ │ └── Tests/ │ │ │ ├── ObjCTests/ │ │ │ │ └── ObjCTests.m │ │ │ └── SwiftPMXCTestHelperTests/ │ │ │ └── SwiftPMXCTestHelperTests.swift │ │ ├── SwiftRun/ │ │ │ ├── Package.swift │ │ │ └── main.swift │ │ ├── SystemModules/ │ │ │ ├── CFake/ │ │ │ │ ├── Package.swift │ │ │ │ └── module.modulemap │ │ │ └── TestExec/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── main.swift │ │ ├── TIF/ │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ └── TIF/ │ │ │ ├── SomeAlert.swift │ │ │ ├── SomeAlert.xib │ │ │ ├── SomeAssets.xcassets/ │ │ │ │ ├── Contents.json │ │ │ │ └── this_is_fine.imageset/ │ │ │ │ └── Contents.json │ │ │ └── some.txt │ │ ├── TargetMismatch/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Sample/ │ │ │ └── main.swift │ │ ├── TargetPackageAccess/ │ │ │ └── libPkg/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ ├── Core/ │ │ │ │ │ └── Core.swift │ │ │ │ ├── DataManager/ │ │ │ │ │ └── File.swift │ │ │ │ ├── DataModel/ │ │ │ │ │ └── File.swift │ │ │ │ ├── ExampleApp/ │ │ │ │ │ └── main.swift │ │ │ │ └── MainLib/ │ │ │ │ └── Lib.swift │ │ │ └── Tests/ │ │ │ ├── BlackBoxTests/ │ │ │ │ └── BlackBoxTests.swift │ │ │ └── MainLibTests/ │ │ │ └── MainLibTests.swift │ │ ├── TestDiscovery/ │ │ │ ├── Async/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Async/ │ │ │ │ │ └── Async.swift │ │ │ │ └── Tests/ │ │ │ │ └── AsyncTests/ │ │ │ │ └── SwiftTests.swift │ │ │ ├── Deprecation/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Simple/ │ │ │ │ │ └── Simple.swift │ │ │ │ └── Tests/ │ │ │ │ └── SimpleTests/ │ │ │ │ └── SwiftTests.swift │ │ │ ├── Extensions/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Simple/ │ │ │ │ │ └── Simple.swift │ │ │ │ └── Tests/ │ │ │ │ └── SimpleTests/ │ │ │ │ ├── SwiftTests1.swift │ │ │ │ ├── SwiftTests2.swift │ │ │ │ ├── SwiftTests3.swift │ │ │ │ └── SwiftTests4.swift │ │ │ ├── IgnoresLinuxMain/ │ │ │ │ ├── Package.swift │ │ │ │ └── Tests/ │ │ │ │ ├── IgnoresLinuxMainTests/ │ │ │ │ │ └── SomeTest.swift │ │ │ │ └── LinuxMain.swift │ │ │ ├── NoTests/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Simple/ │ │ │ │ │ └── Simple.swift │ │ │ │ └── Tests/ │ │ │ │ └── SimpleTests/ │ │ │ │ └── SwiftTests.swift │ │ │ ├── Simple/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Plugins/ │ │ │ │ │ └── SimplePlugin/ │ │ │ │ │ └── plugin.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Simple/ │ │ │ │ │ └── Simple.swift │ │ │ │ └── Tests/ │ │ │ │ └── SimpleTests/ │ │ │ │ └── SwiftTests.swift │ │ │ ├── Subclass/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── Subclass/ │ │ │ │ │ └── Subclass.swift │ │ │ │ └── Tests/ │ │ │ │ ├── Module1Tests/ │ │ │ │ │ ├── Tests1.swift │ │ │ │ │ └── Tests2.swift │ │ │ │ └── Module2Tests/ │ │ │ │ └── Test1.swift │ │ │ ├── SwiftTesting/ │ │ │ │ ├── Package.swift │ │ │ │ ├── Sources/ │ │ │ │ │ └── SwiftTesting/ │ │ │ │ │ └── SwiftTesting.swift │ │ │ │ └── Tests/ │ │ │ │ └── SwiftTestingTests/ │ │ │ │ └── SwiftTestingTests.swift │ │ │ └── hello world/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── hello world/ │ │ │ │ └── hello world.swift │ │ │ └── Tests/ │ │ │ └── hello world tests/ │ │ │ └── hello world tests.swift │ │ ├── TestMultipleFailureSwiftTesting/ │ │ │ ├── Package.swift │ │ │ └── Tests/ │ │ │ └── TestMultipleFailureSwiftTestingTests/ │ │ │ └── TestMultipleFailureSwiftTestingTests.swift │ │ ├── TestMultipleFailureXCTest/ │ │ │ ├── Package.swift │ │ │ └── Tests/ │ │ │ └── TestMultipleFailureXCTestTests/ │ │ │ └── TestMultipleFailureXCTestTests.swift │ │ ├── TestSingleFailureSwiftTesting/ │ │ │ ├── Package.swift │ │ │ └── Tests/ │ │ │ └── TestFailuresSwiftTestingTests/ │ │ │ └── TestFailuresSwiftTestingTests.swift │ │ ├── TestSingleFailureXCTest/ │ │ │ ├── Package.swift │ │ │ └── Tests/ │ │ │ └── TestFailuresTests/ │ │ │ └── TestFailuresTests.swift │ │ ├── TestableAsyncExe/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ ├── TestableAsyncExe1/ │ │ │ │ │ └── main.swift │ │ │ │ ├── TestableAsyncExe2/ │ │ │ │ │ └── main.swift │ │ │ │ ├── TestableAsyncExe3/ │ │ │ │ │ └── NonMain.swift │ │ │ │ └── TestableAsyncExe4/ │ │ │ │ └── NonMain.swift │ │ │ └── Tests/ │ │ │ └── TestableAsyncExeTests/ │ │ │ └── TestableAsyncExeTests.swift │ │ ├── TestableExe/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ ├── TestableExe1/ │ │ │ │ │ └── main.swift │ │ │ │ ├── TestableExe2/ │ │ │ │ │ └── main.swift │ │ │ │ └── TestableExe3/ │ │ │ │ ├── include/ │ │ │ │ │ └── TestableExe3.h │ │ │ │ └── main.c │ │ │ └── Tests/ │ │ │ └── TestableExeTests/ │ │ │ └── TestableExeTests.swift │ │ ├── TestableExeWithDifferentProductName/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── TestableExe/ │ │ │ │ └── main.swift │ │ │ └── Tests/ │ │ │ └── TestableExeTests/ │ │ │ └── TestableExeTests.swift │ │ ├── TestableExeWithResources/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── TestableExe/ │ │ │ │ ├── foo.txt │ │ │ │ └── main.swift │ │ │ └── Tests/ │ │ │ └── TestableExeTests/ │ │ │ └── TestableExeTests.swift │ │ ├── Unicode/ │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ ├── Sources/ │ │ │ │ ├── πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/ │ │ │ │ │ └── πשּׁµ𝄞🇺🇳x̱̱̱̱̱̄̄̄̄̄.swift │ │ │ │ └── πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄‐tool/ │ │ │ │ └── main.swift │ │ │ ├── Tests/ │ │ │ │ ├── LinuxMain.swift │ │ │ │ └── πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests/ │ │ │ │ ├── XCTestManifests.swift │ │ │ │ └── πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests.swift │ │ │ └── Utilities/ │ │ │ └── SomeOtherPackage/ │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ └── SomeOtherPackage/ │ │ │ └── main.swift │ │ ├── UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/ │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ └── UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/ │ │ │ └── UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄.swift │ │ ├── UnreachableTargets/ │ │ │ ├── A/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── ATarget/ │ │ │ │ └── main.swift │ │ │ ├── B/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── BTarget1/ │ │ │ │ │ └── BTarget1.swift │ │ │ │ └── BTarget2/ │ │ │ │ └── main.swift │ │ │ └── C/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── CTarget/ │ │ │ └── main.swift │ │ ├── VersionSpecificManifest/ │ │ │ ├── Foo.swift │ │ │ ├── Package.swift │ │ │ └── Package@swift-5.0.swift │ │ └── WarningWithinFunction/ │ │ ├── Package.swift │ │ └── app.swift │ ├── ModuleAliasing/ │ │ ├── DirectDeps1/ │ │ │ ├── AppPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── App/ │ │ │ │ │ └── main.swift │ │ │ │ └── Utils/ │ │ │ │ └── FileUtils.swift │ │ │ └── UtilsPkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Utils/ │ │ │ └── FileUtils.swift │ │ ├── DirectDeps2/ │ │ │ ├── Apkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── AApp/ │ │ │ │ │ └── main.swift │ │ │ │ └── Utils/ │ │ │ │ └── File.swift │ │ │ ├── AppPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── App/ │ │ │ │ └── main.swift │ │ │ └── Bpkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Utils/ │ │ │ └── File.swift │ │ ├── NestedDeps1/ │ │ │ ├── APkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── A/ │ │ │ │ └── File.swift │ │ │ ├── AppPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── App/ │ │ │ │ └── main.swift │ │ │ ├── BPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── Utils/ │ │ │ │ └── File.swift │ │ │ ├── CPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── Utils/ │ │ │ │ └── File.swift │ │ │ ├── XPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ ├── Utils/ │ │ │ │ │ └── File.swift │ │ │ │ └── X/ │ │ │ │ └── File.swift │ │ │ └── YPkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Utils/ │ │ │ └── File.swift │ │ └── NestedDeps2/ │ │ ├── Apkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── A/ │ │ │ └── File.swift │ │ ├── AppPkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── App/ │ │ │ └── main.swift │ │ ├── Bpkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Utils/ │ │ │ └── File.swift │ │ ├── Cpkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Utils/ │ │ │ └── File.swift │ │ └── Xpkg/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── Utils/ │ │ └── File.swift │ ├── ModuleMaps/ │ │ ├── Direct/ │ │ │ ├── App/ │ │ │ │ ├── Package.swift │ │ │ │ └── main.swift │ │ │ └── CFoo/ │ │ │ ├── C/ │ │ │ │ ├── foo.c │ │ │ │ └── foo.h │ │ │ ├── Package.swift │ │ │ └── module.modulemap │ │ └── Transitive/ │ │ ├── packageA/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── main.swift │ │ ├── packageB/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── y/ │ │ │ └── y.swift │ │ └── packageC/ │ │ ├── .gitignore │ │ ├── Package.swift │ │ └── Sources/ │ │ └── x/ │ │ └── x.swift │ ├── PIFBuilder/ │ │ ├── BasicExecutable/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── BasicExecutable/ │ │ │ └── BasicExecutable.swift │ │ ├── CCPackage/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── CCTarget/ │ │ │ │ ├── include/ │ │ │ │ │ └── test.h │ │ │ │ └── test.cc │ │ │ └── executable/ │ │ │ └── executable.swift │ │ ├── ConditionalBuildSettings/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── ConditionalBuildSettings/ │ │ │ └── ConditionalBuildSettings.swift │ │ ├── Library/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── Library/ │ │ │ │ └── Library.swift │ │ │ └── Tests/ │ │ │ └── LibraryTests/ │ │ │ └── LibraryTests.swift │ │ ├── PackageWithSDKSpecialization/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Executable/ │ │ │ │ └── main.swift │ │ │ └── PackageWithSDKSpecialization/ │ │ │ └── PackageWithSDKSpecialization.swift │ │ ├── Simple/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── Simple/ │ │ │ │ └── Simple.swift │ │ │ └── Tests/ │ │ │ └── SimpleTests/ │ │ │ └── SimpleTests.swift │ │ └── UnknownPlatforms/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── UnknownPlatforms/ │ │ └── UnknownPlatforms.swift │ ├── PartiallyUnusedDependency/ │ │ ├── Dep/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── MyDynamicLibrary/ │ │ │ │ └── Dep.swift │ │ │ └── MySupportExecutable/ │ │ │ └── exe.swift │ │ ├── Package.swift │ │ ├── Plugins/ │ │ │ └── dump-artifacts-plugin.swift │ │ └── Sources/ │ │ └── MyExecutable/ │ │ └── PartiallyUnusedDependency.swift │ ├── Resources/ │ │ ├── EmbedInCodeSimple/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── EmbedInCodeSimple/ │ │ │ ├── best.txt │ │ │ └── main.swift │ │ ├── FoundationlessClient/ │ │ │ ├── AppPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── App/ │ │ │ │ └── main.swift │ │ │ ├── UtilsPkg/ │ │ │ │ ├── Package.swift │ │ │ │ └── Sources/ │ │ │ │ └── Utils/ │ │ │ │ ├── FooUtils.swift │ │ │ │ └── foo.txt │ │ │ └── UtilsWithFoundationPkg/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── UtilsWithFoundationPkg/ │ │ │ ├── FooUtils.swift │ │ │ └── foo.txt │ │ ├── Localized/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── exe/ │ │ │ ├── Resources/ │ │ │ │ ├── de.lproj/ │ │ │ │ │ └── Localizable.strings │ │ │ │ ├── es.lproj/ │ │ │ │ │ └── Localizable.strings │ │ │ │ └── fr.lproj/ │ │ │ │ └── Localizable.strings │ │ │ └── main.swift │ │ ├── Moved/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── SeaResource/ │ │ │ │ ├── foo.txt │ │ │ │ └── main.m │ │ │ └── SwiftyResource/ │ │ │ ├── foo.txt │ │ │ └── main.swift │ │ ├── ResourceRules/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── ResourceRules/ │ │ │ ├── CopiedAssets.xcassets/ │ │ │ │ ├── Contents.json │ │ │ │ └── pixel.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── ProcessedAssets.xcassets/ │ │ │ │ ├── Contents.json │ │ │ │ └── processedpixel.imageset/ │ │ │ │ └── Contents.json │ │ │ └── main.swift │ │ └── Simple/ │ │ ├── Package.swift │ │ ├── Sources/ │ │ │ ├── CPPResource/ │ │ │ │ ├── foo.txt │ │ │ │ └── main.mm │ │ │ ├── ClangResource/ │ │ │ │ ├── Package.m │ │ │ │ ├── foo.txt │ │ │ │ └── include/ │ │ │ │ └── Package.h │ │ │ ├── MixedClangResource/ │ │ │ │ ├── Foo.m │ │ │ │ ├── bar.c │ │ │ │ ├── bar.h │ │ │ │ ├── baz.S │ │ │ │ ├── foo.txt │ │ │ │ ├── include/ │ │ │ │ │ └── Foo.h │ │ │ │ └── qux.cpp │ │ │ ├── SeaResource/ │ │ │ │ ├── foo.txt │ │ │ │ └── main.m │ │ │ └── SwiftyResource/ │ │ │ ├── foo.txt │ │ │ └── main.swift │ │ └── Tests/ │ │ └── ClangResourceTests/ │ │ └── ClangResourceTests.m │ ├── Signing/ │ │ └── Certificates/ │ │ ├── TestIntermediateCA.cer │ │ ├── TestRootCA.cer │ │ ├── Test_ec.cer │ │ ├── Test_ec_key.p8 │ │ ├── Test_ec_key.pem │ │ ├── Test_ec_self_signed.cer │ │ ├── Test_ec_self_signed_key.p8 │ │ ├── Test_rsa.cer │ │ ├── Test_rsa_key.p8 │ │ ├── Test_rsa_key.pem │ │ ├── Test_rsa_self_signed.cer │ │ └── Test_rsa_self_signed_key.p8 │ ├── SwiftMigrate/ │ │ ├── ExistentialAnyMigration/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Fixed/ │ │ │ │ └── Test.swift │ │ │ └── Test.swift │ │ ├── ExistentialAnyWithCommonPluginDependencyMigration/ │ │ │ ├── Package.swift │ │ │ ├── Plugins/ │ │ │ │ └── Plugin/ │ │ │ │ └── Plugin.swift │ │ │ └── Sources/ │ │ │ ├── CommonLibrary/ │ │ │ │ └── Common.swift │ │ │ ├── Library/ │ │ │ │ └── Test.swift │ │ │ └── Tool/ │ │ │ └── tool.swift │ │ ├── ExistentialAnyWithPluginMigration/ │ │ │ ├── Package.swift │ │ │ ├── Plugins/ │ │ │ │ └── Plugin/ │ │ │ │ └── Plugin.swift │ │ │ └── Sources/ │ │ │ ├── Library/ │ │ │ │ └── Test.swift │ │ │ └── Tool/ │ │ │ └── tool.swift │ │ ├── InferIsolatedConformancesMigration/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Fixed/ │ │ │ │ ├── Test.swift │ │ │ │ └── Test2.swift │ │ │ ├── Test.swift │ │ │ └── Test2.swift │ │ ├── StrictMemorySafetyMigration/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── Fixed/ │ │ │ │ └── Test.swift │ │ │ └── Test.swift │ │ └── UpdateManifest/ │ │ ├── Package.swift │ │ ├── Package.updated.targets-A-B.swift │ │ ├── Package.updated.targets-A.swift │ │ ├── Package.updated.targets-all.swift │ │ └── Sources/ │ │ ├── A/ │ │ │ └── File.swift │ │ ├── B/ │ │ │ └── File.swift │ │ ├── CannotFindSettings/ │ │ │ └── File.swift │ │ └── CannotFindTarget/ │ │ └── File.swift │ ├── SwiftSDKs/ │ │ └── Package.swift │ ├── Traits/ │ │ ├── DisablingEmptyDefaultsExample/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── DisablingEmptyDefaultsExample/ │ │ │ └── Example.swift │ │ ├── Example/ │ │ │ ├── Package.swift │ │ │ ├── Sources/ │ │ │ │ └── Example/ │ │ │ │ └── Example.swift │ │ │ └── Tests/ │ │ │ └── ExampleTests/ │ │ │ └── Tests.swift │ │ ├── Package1/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package1Library1/ │ │ │ └── Library.swift │ │ ├── Package10/ │ │ │ ├── Package.swift │ │ │ ├── Plugins/ │ │ │ │ └── SymbolGraphExtract/ │ │ │ │ └── Plugin.swift │ │ │ └── Sources/ │ │ │ ├── Package10Library1/ │ │ │ │ └── Library.swift │ │ │ └── Package10Library2/ │ │ │ └── Library.swift │ │ ├── Package11/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package11Library1/ │ │ │ └── Library.swift │ │ ├── Package2/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package2Library1/ │ │ │ └── Library.swift │ │ ├── Package3/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package3Library1/ │ │ │ └── Library.swift │ │ ├── Package4/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package4Library1/ │ │ │ └── Library.swift │ │ ├── Package5/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package5Library1/ │ │ │ └── Library.swift │ │ ├── Package6/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package6Library1/ │ │ │ └── Library.swift │ │ ├── Package7/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package7Library1/ │ │ │ └── Library.swift │ │ ├── Package8/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package6Library1/ │ │ │ └── Library.swift │ │ ├── Package9/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── Package9Library1/ │ │ │ └── Library.swift │ │ └── PackageConditionalDeps/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── PackageConditionalDeps/ │ │ └── PackageConditionalDeps.swift │ ├── ValidLayouts/ │ │ └── SingleModule/ │ │ ├── ExecutableMixed/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ ├── ExecutableC/ │ │ │ │ └── c.c │ │ │ ├── ExecutableCxx/ │ │ │ │ └── cxx.cpp │ │ │ └── ExecutableSwift/ │ │ │ └── main.swift │ │ ├── ExecutableNew/ │ │ │ ├── .gitignore │ │ │ ├── Package.swift │ │ │ ├── README.md │ │ │ └── Sources/ │ │ │ └── ExecutableNew/ │ │ │ └── main.swift │ │ └── Library/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── Library/ │ │ └── Foo.swift │ └── XCBuild/ │ ├── ExecutableProducts/ │ │ ├── Bar/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── BarLib/ │ │ │ │ └── BarLib.swift │ │ │ ├── bar/ │ │ │ │ └── main.swift │ │ │ └── cbar/ │ │ │ └── main.c │ │ └── Foo/ │ │ ├── Package.swift │ │ └── Sources/ │ │ ├── FooLib/ │ │ │ └── FooLib.swift │ │ ├── cfoo/ │ │ │ └── main.c │ │ └── foo/ │ │ └── main.swift │ ├── Libraries/ │ │ ├── Bar/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ └── BarLib/ │ │ │ └── BarLib.swift │ │ └── Foo/ │ │ ├── Package.swift │ │ └── Sources/ │ │ ├── CFooLib/ │ │ │ ├── CFooLib.m │ │ │ └── include/ │ │ │ └── CFooLib.h │ │ └── FooLib/ │ │ └── FooLib.swift │ ├── SystemTargets/ │ │ ├── Foo/ │ │ │ ├── Package.swift │ │ │ └── Sources/ │ │ │ ├── SystemLib/ │ │ │ │ └── module.modulemap │ │ │ └── foo/ │ │ │ └── main.swift │ │ └── Inputs/ │ │ ├── libsys.c │ │ ├── libsys.h │ │ └── libsys.pc │ └── TestProducts/ │ ├── Bar/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── BarLib/ │ │ ├── BarLib.m │ │ └── include/ │ │ └── BarLib.h │ └── Foo/ │ ├── Package.swift │ ├── Sources/ │ │ └── FooLib/ │ │ └── FooLib.swift │ └── Tests/ │ ├── CFooTests/ │ │ └── tests.m │ └── FooTests/ │ └── FooTests.swift ├── LICENSE.txt ├── NOTICE.txt ├── Package.swift ├── README.md ├── Sources/ │ ├── AppleProductTypes/ │ │ └── Product.swift │ ├── Basics/ │ │ ├── Archiver/ │ │ │ ├── Archiver.swift │ │ │ ├── TarArchiver.swift │ │ │ ├── UniversalArchiver.swift │ │ │ └── ZipArchiver.swift │ │ ├── ArrayHelpers.swift │ │ ├── AuthorizationProvider.swift │ │ ├── CMakeLists.txt │ │ ├── Cancellator.swift │ │ ├── Collections/ │ │ │ ├── ByteString+Extensions.swift │ │ │ ├── Dictionary+Extensions.swift │ │ │ ├── IdentifiableSet.swift │ │ │ └── String+Extensions.swift │ │ ├── Concurrency/ │ │ │ ├── AsyncProcess.swift │ │ │ ├── ConcurrencyHelpers.swift │ │ │ ├── NSLock+Extensions.swift │ │ │ ├── SendableBox.swift │ │ │ ├── ThreadSafeArrayStore.swift │ │ │ ├── ThreadSafeBox.swift │ │ │ ├── ThreadSafeKeyValueStore.swift │ │ │ ├── ThrowingDefer.swift │ │ │ └── TokenBucket.swift │ │ ├── DispatchTimeInterval+Extensions.swift │ │ ├── Environment/ │ │ │ ├── Environment.swift │ │ │ ├── EnvironmentKey.swift │ │ │ └── EnvironmentShims.swift │ │ ├── Errors.swift │ │ ├── FileSystem/ │ │ │ ├── AbsolutePath.swift │ │ │ ├── CommonParentDirectory.swift │ │ │ ├── FileSystem+Extensions.swift │ │ │ ├── InMemoryFileSystem.swift │ │ │ ├── NativePathExtensions.swift │ │ │ ├── RelativePath.swift │ │ │ ├── TSCAdapters.swift │ │ │ ├── TemporaryFile.swift │ │ │ ├── VFSOverlay.swift │ │ │ └── VirtualFileSystem.swift │ │ ├── Graph/ │ │ │ ├── AdjacencyMatrix.swift │ │ │ ├── DirectedGraph.swift │ │ │ ├── GraphAlgorithms.swift │ │ │ └── UndirectedGraph.swift │ │ ├── HTTPClient/ │ │ │ ├── HTTPClient.swift │ │ │ ├── HTTPClientConfiguration.swift │ │ │ ├── HTTPClientError.swift │ │ │ ├── HTTPClientHeaders.swift │ │ │ ├── HTTPClientRequest.swift │ │ │ ├── HTTPClientResponse.swift │ │ │ ├── HTTPMethod.swift │ │ │ ├── LegacyHTTPClient.swift │ │ │ ├── LegacyHTTPClientRequest.swift │ │ │ └── URLSessionHTTPClient.swift │ │ ├── ImportScanning.swift │ │ ├── JSON+Extensions.swift │ │ ├── JSONDecoder+Extensions.swift │ │ ├── Netrc.swift │ │ ├── OSSignpost.swift │ │ ├── Observability.swift │ │ ├── Process.swift │ │ ├── ProgressAnimation/ │ │ │ ├── NinjaProgressAnimation.swift │ │ │ ├── PercentProgressAnimation.swift │ │ │ ├── ProgressAnimationProtocol.swift │ │ │ ├── SingleLinePercentProgressAnimation.swift │ │ │ └── ThrottledProgressAnimation.swift │ │ ├── SQLite.swift │ │ ├── SQLiteBackedCache.swift │ │ ├── Sandbox.swift │ │ ├── SendableTimeInterval.swift │ │ ├── Serialization/ │ │ │ └── SerializedJSON.swift │ │ ├── SourceControlURL.swift │ │ ├── SwiftVersion.swift │ │ ├── TestingLibrary.swift │ │ ├── Triple+Basics.swift │ │ ├── URL.swift │ │ ├── Vendor/ │ │ │ ├── README.md │ │ │ ├── Triple+Platforms.swift │ │ │ └── Triple.swift │ │ ├── Version+Extensions.swift │ │ └── WritableByteStream+Extensions.swift │ ├── BinarySymbols/ │ │ ├── CMakeLists.txt │ │ ├── ClangHostDefaultObjectsDetector.swift │ │ ├── LLVMObjdumpSymbolProvider.swift │ │ ├── ReferencedSymbols.swift │ │ └── SymbolProvider.swift │ ├── Build/ │ │ ├── BuildDescription/ │ │ │ ├── ClangModuleBuildDescription.swift │ │ │ ├── ModuleBuildDescription.swift │ │ │ ├── PluginBuildDescription.swift │ │ │ ├── ProductBuildDescription.swift │ │ │ ├── ResolvedModule+BuildDescription.swift │ │ │ └── SwiftModuleBuildDescription.swift │ │ ├── BuildManifest/ │ │ │ ├── LLBuildManifestBuilder+Clang.swift │ │ │ ├── LLBuildManifestBuilder+Product.swift │ │ │ ├── LLBuildManifestBuilder+Resources.swift │ │ │ ├── LLBuildManifestBuilder+Swift.swift │ │ │ └── LLBuildManifestBuilder.swift │ │ ├── BuildOperation.swift │ │ ├── BuildPlan/ │ │ │ ├── BuildPlan+Clang.swift │ │ │ ├── BuildPlan+Product.swift │ │ │ ├── BuildPlan+Swift.swift │ │ │ ├── BuildPlan+Test.swift │ │ │ └── BuildPlan.swift │ │ ├── CMakeLists.txt │ │ ├── ClangSupport.swift │ │ ├── LLBuildCommands.swift │ │ ├── LLBuildDescription.swift │ │ ├── LLBuildProgressTracker.swift │ │ ├── SwiftCompilerOutputParser.swift │ │ └── TestObservation.swift │ ├── CMakeLists.txt │ ├── Commands/ │ │ ├── CMakeLists.txt │ │ ├── CommandWorkspaceDelegate.swift │ │ ├── PackageCommands/ │ │ │ ├── APIDiff.swift │ │ │ ├── AddDependency.swift │ │ │ ├── AddProduct.swift │ │ │ ├── AddSetting.swift │ │ │ ├── AddTarget.swift │ │ │ ├── AddTargetDependency.swift │ │ │ ├── ArchiveSource.swift │ │ │ ├── AuditBinaryArtifact.swift │ │ │ ├── BuildServer.swift │ │ │ ├── CompletionCommand.swift │ │ │ ├── ComputeChecksum.swift │ │ │ ├── Config.swift │ │ │ ├── Describe.swift │ │ │ ├── DumpCommands.swift │ │ │ ├── EditCommands.swift │ │ │ ├── Format.swift │ │ │ ├── GenerateSBOM.swift │ │ │ ├── Init.swift │ │ │ ├── Install.swift │ │ │ ├── Learn.swift │ │ │ ├── Migrate.swift │ │ │ ├── PluginCommand.swift │ │ │ ├── ResetCommands.swift │ │ │ ├── Resolve.swift │ │ │ ├── ShowDependencies.swift │ │ │ ├── ShowExecutables.swift │ │ │ ├── ShowTraits.swift │ │ │ ├── SwiftPackageCommand.swift │ │ │ ├── ToolsVersionCommand.swift │ │ │ └── Update.swift │ │ ├── README.md │ │ ├── Snippets/ │ │ │ ├── Card.swift │ │ │ ├── CardEvent.swift │ │ │ ├── CardStack.swift │ │ │ ├── Cards/ │ │ │ │ ├── SnippetCard.swift │ │ │ │ ├── SnippetGroupCard.swift │ │ │ │ └── TopCard.swift │ │ │ └── Colorful.swift │ │ ├── SwiftBuildCommand.swift │ │ ├── SwiftRunCommand.swift │ │ ├── SwiftTestCommand.swift │ │ └── Utilities/ │ │ ├── APIDigester.swift │ │ ├── DOTManifestSerializer.swift │ │ ├── DependenciesSerializer.swift │ │ ├── DescribedPackage.swift │ │ ├── MermaidPackageSerializer.swift │ │ ├── MultiRootSupport.swift │ │ ├── PlainTextEncoder.swift │ │ ├── PluginDelegate.swift │ │ ├── RefactoringSupport.swift │ │ ├── SymbolGraphExtract.swift │ │ ├── TestingSupport.swift │ │ └── XCTEvents.swift │ ├── CoreCommands/ │ │ ├── BuildSystemSupport.swift │ │ ├── CMakeLists.txt │ │ ├── Options.swift │ │ ├── SwiftCommandObservabilityHandler.swift │ │ └── SwiftCommandState.swift │ ├── DriverSupport/ │ │ ├── CMakeLists.txt │ │ ├── DriverSupportUtils.swift │ │ └── SPMSwiftDriverExecutor.swift │ ├── LLBuildManifest/ │ │ ├── CMakeLists.txt │ │ ├── Command.swift │ │ ├── LLBuildManifest.swift │ │ ├── LLBuildManifestWriter.swift │ │ ├── Node.swift │ │ ├── Target.swift │ │ └── Tools.swift │ ├── PackageCollections/ │ │ ├── API.swift │ │ ├── CMakeLists.txt │ │ ├── Model/ │ │ │ ├── CVE.swift │ │ │ ├── Collection.swift │ │ │ ├── License.swift │ │ │ ├── PackageList.swift │ │ │ ├── PackageTypes.swift │ │ │ ├── Search.swift │ │ │ └── TargetListResult.swift │ │ ├── PackageCollections+CertificatePolicy.swift │ │ ├── PackageCollections+Configuration.swift │ │ ├── PackageCollections+Storage.swift │ │ ├── PackageCollections+Validation.swift │ │ ├── PackageCollections.swift │ │ ├── PackageIndex+Configuration.swift │ │ ├── PackageIndex.swift │ │ ├── PackageIndexAndCollections.swift │ │ ├── Providers/ │ │ │ ├── GitHubPackageMetadataProvider.swift │ │ │ ├── JSONPackageCollectionProvider.swift │ │ │ ├── PackageCollectionProvider.swift │ │ │ └── PackageMetadataProvider.swift │ │ ├── Storage/ │ │ │ ├── FilePackageCollectionsSourcesStorage.swift │ │ │ ├── PackageCollectionsSourcesStorage.swift │ │ │ ├── PackageCollectionsStorage.swift │ │ │ ├── SQLitePackageCollectionsStorage.swift │ │ │ └── Trie.swift │ │ └── Utility.swift │ ├── PackageCollectionsCommand/ │ │ └── PackageCollectionsCommand.swift │ ├── PackageCollectionsModel/ │ │ ├── CMakeLists.txt │ │ ├── Formats/ │ │ │ └── v1.md │ │ ├── PackageCollectionModel+v1.swift │ │ └── PackageCollectionModel.swift │ ├── PackageCollectionsSigning/ │ │ ├── CMakeLists.txt │ │ ├── CertificatePolicy.swift │ │ ├── PackageCollectionSigning.swift │ │ ├── Signature.swift │ │ ├── Utilities/ │ │ │ ├── Base64URL.swift │ │ │ └── Utilities.swift │ │ ├── X509Extensions.swift │ │ └── embedded_resources.swift │ ├── PackageFingerprint/ │ │ ├── CMakeLists.txt │ │ ├── FilePackageFingerprintStorage.swift │ │ ├── Model.swift │ │ └── PackageFingerprintStorage.swift │ ├── PackageGraph/ │ │ ├── BoundVersion.swift │ │ ├── CMakeLists.txt │ │ ├── DependencyMirrors.swift │ │ ├── Diagnostics.swift │ │ ├── GraphLoadingNode.swift │ │ ├── ModuleAliasTracker.swift │ │ ├── ModulesGraph+Loading.swift │ │ ├── ModulesGraph.swift │ │ ├── PackageContainer.swift │ │ ├── PackageGraphRoot.swift │ │ ├── PackageModel+Extensions.swift │ │ ├── PackageRequirement.swift │ │ ├── README.md │ │ ├── Resolution/ │ │ │ ├── DependencyResolutionNode.swift │ │ │ ├── DependencyResolverBinding.swift │ │ │ ├── DependencyResolverDelegate.swift │ │ │ ├── DependencyResolverError.swift │ │ │ ├── PlatformVersionProvider.swift │ │ │ ├── PubGrub/ │ │ │ │ ├── Assignment.swift │ │ │ │ ├── ContainerProvider.swift │ │ │ │ ├── DiagnosticReportBuilder.swift │ │ │ │ ├── Incompatibility.swift │ │ │ │ ├── PartialSolution.swift │ │ │ │ ├── PubGrubDependencyResolver.swift │ │ │ │ ├── PubGrubPackageContainer.swift │ │ │ │ └── Term.swift │ │ │ ├── ResolvedModule.swift │ │ │ ├── ResolvedPackage.swift │ │ │ └── ResolvedProduct.swift │ │ ├── ResolvedPackagesStore.swift │ │ ├── Version+Extensions.swift │ │ └── VersionSetSpecifier.swift │ ├── PackageLoading/ │ │ ├── CMakeLists.txt │ │ ├── ContextModel.swift │ │ ├── Diagnostics.swift │ │ ├── ManifestJSONParser.swift │ │ ├── ManifestLoader+Validation.swift │ │ ├── ManifestLoader.swift │ │ ├── ManifestSignatureParser.swift │ │ ├── ModuleMapGenerator.swift │ │ ├── PackageBuilder.swift │ │ ├── PkgConfig.swift │ │ ├── Platform.swift │ │ ├── README.md │ │ ├── RegistryReleaseMetadataSerialization.swift │ │ ├── Target+PkgConfig.swift │ │ ├── TargetSourcesBuilder.swift │ │ └── ToolsVersionParser.swift │ ├── PackageManagerDocs/ │ │ ├── Documentation.docc/ │ │ │ ├── BundlingResources.md │ │ │ ├── ContinuousIntegration.md │ │ │ ├── CreatingCLanguageTargets.md │ │ │ ├── CreatingSwiftPackage.md │ │ │ ├── Dependencies/ │ │ │ │ ├── AddingDependencies.md │ │ │ │ ├── AddingSystemLibraryDependency.md │ │ │ │ ├── EditingDependencyPackage.md │ │ │ │ ├── ExampleSystemLibraryPkgConfig.md │ │ │ │ ├── PackageTraits.md │ │ │ │ └── ResolvingDependencyFailures.md │ │ │ ├── Documentation.md │ │ │ ├── GeneratingSBOMs.md │ │ │ ├── GettingStarted.md │ │ │ ├── IntroducingPackages.md │ │ │ ├── ModuleAliasing.md │ │ │ ├── Package/ │ │ │ │ ├── PackageAddDependency.md │ │ │ │ ├── PackageAddProduct.md │ │ │ │ ├── PackageAddSetting.md │ │ │ │ ├── PackageAddTarget.md │ │ │ │ ├── PackageAddTargetDependency.md │ │ │ │ ├── PackageArchiveSource.md │ │ │ │ ├── PackageClean.md │ │ │ │ ├── PackageCompletionTool.md │ │ │ │ ├── PackageComputeChecksum.md │ │ │ │ ├── PackageConfigGetMirror.md │ │ │ │ ├── PackageConfigSetMirror.md │ │ │ │ ├── PackageConfigUnsetMirror.md │ │ │ │ ├── PackageDescribe.md │ │ │ │ ├── PackageDiagnoseAPIBreakingChange.md │ │ │ │ ├── PackageDumpPackage.md │ │ │ │ ├── PackageDumpSymbolGraph.md │ │ │ │ ├── PackageEdit.md │ │ │ │ ├── PackageExperimentalInstall.md │ │ │ │ ├── PackageExperimentalUninstall.md │ │ │ │ ├── PackageGenerateSBOM.md │ │ │ │ ├── PackageInit.md │ │ │ │ ├── PackageMigrate.md │ │ │ │ ├── PackagePlugin.md │ │ │ │ ├── PackagePurgeCache.md │ │ │ │ ├── PackageReset.md │ │ │ │ ├── PackageResolve.md │ │ │ │ ├── PackageShowDependencies.md │ │ │ │ ├── PackageShowExecutables.md │ │ │ │ ├── PackageShowTraits.md │ │ │ │ ├── PackageToolsVersion.md │ │ │ │ ├── PackageUnedit.md │ │ │ │ └── PackageUpdate.md │ │ │ ├── PackageCollections/ │ │ │ │ ├── PackageCollectionAdd.md │ │ │ │ ├── PackageCollectionDescribe.md │ │ │ │ ├── PackageCollectionList.md │ │ │ │ ├── PackageCollectionRefresh.md │ │ │ │ ├── PackageCollectionRemove.md │ │ │ │ └── PackageCollectionSearch.md │ │ │ ├── PackageCollections.md │ │ │ ├── PackageRegistry/ │ │ │ │ ├── PackageRegistryLogin.md │ │ │ │ ├── PackageRegistryLogout.md │ │ │ │ ├── PackageRegistryPublish.md │ │ │ │ ├── PackageRegistrySet.md │ │ │ │ └── PackageRegistryUnset.md │ │ │ ├── PackageSecurity.md │ │ │ ├── Plugins/ │ │ │ │ ├── EnableBuildPlugin.md │ │ │ │ ├── EnableCommandPlugin.md │ │ │ │ ├── WritingBuildToolPlugin.md │ │ │ │ └── WritingCommandPlugin.md │ │ │ ├── Plugins.md │ │ │ ├── RegistryServerSpecification.md │ │ │ ├── ReleasingPublishingAPackage.md │ │ │ ├── ResolvingPackageVersions.md │ │ │ ├── SDK/ │ │ │ │ ├── SDKConfigurationReset.md │ │ │ │ ├── SDKConfigurationSet.md │ │ │ │ ├── SDKConfigurationShow.md │ │ │ │ ├── SDKConfigure.md │ │ │ │ ├── SDKInstall.md │ │ │ │ ├── SDKList.md │ │ │ │ └── SDKRemove.md │ │ │ ├── SettingSwiftToolsVersion.md │ │ │ ├── SwiftBuild.md │ │ │ ├── SwiftBuildPreview.md │ │ │ ├── SwiftPMAsALibrary.md │ │ │ ├── SwiftPackageCollectionCommands.md │ │ │ ├── SwiftPackageCommands.md │ │ │ ├── SwiftPackageRegistryCommands.md │ │ │ ├── SwiftRun.md │ │ │ ├── SwiftSDKCommands.md │ │ │ ├── SwiftTest.md │ │ │ ├── SwiftVersionSpecificPackaging.md │ │ │ ├── UsingBuildConfigurations.md │ │ │ ├── UsingShellCompletion.md │ │ │ └── UsingSwiftPackageRegistry.md │ │ ├── EmptyFile.swift │ │ └── README.md │ ├── PackageMetadata/ │ │ └── PackageMetadata.swift │ ├── PackageModel/ │ │ ├── ArtifactsArchiveMetadata.swift │ │ ├── BuildConfiguration.swift │ │ ├── BuildEnvironment.swift │ │ ├── BuildFlags.swift │ │ ├── BuildSettings.swift │ │ ├── CMakeLists.txt │ │ ├── DependencyMapper.swift │ │ ├── Diagnostics.swift │ │ ├── EnabledTrait.swift │ │ ├── IdentityResolver.swift │ │ ├── InstalledSwiftPMConfiguration.swift │ │ ├── Manifest/ │ │ │ ├── Manifest+Traits.swift │ │ │ ├── Manifest.swift │ │ │ ├── PackageConditionDescription.swift │ │ │ ├── PackageDependencyDescription.swift │ │ │ ├── PlatformDescription.swift │ │ │ ├── ProductDescription.swift │ │ │ ├── SystemPackageProviderDescription.swift │ │ │ ├── TargetBuildSettingDescription.swift │ │ │ ├── TargetDescription.swift │ │ │ ├── TraitConfiguration.swift │ │ │ └── TraitDescription.swift │ │ ├── ManifestSourceGeneration.swift │ │ ├── MinimumDeploymentTarget.swift │ │ ├── Module/ │ │ │ ├── BinaryModule.swift │ │ │ ├── ClangModule.swift │ │ │ ├── Module.swift │ │ │ ├── PluginModule.swift │ │ │ ├── SwiftModule.swift │ │ │ └── SystemLibraryModule.swift │ │ ├── ModuleMapType.swift │ │ ├── PackageIdentity.swift │ │ ├── PackageModel.swift │ │ ├── PackageReference.swift │ │ ├── Platform.swift │ │ ├── PlatformRegistry.swift │ │ ├── PrebuiltLibrary.swift │ │ ├── Product.swift │ │ ├── README.md │ │ ├── Registry.swift │ │ ├── RegistryReleaseMetadata.swift │ │ ├── Resource.swift │ │ ├── Sanitizers.swift │ │ ├── Snippets/ │ │ │ ├── Model/ │ │ │ │ ├── Snippet.swift │ │ │ │ └── SnippetGroup.swift │ │ │ └── Parsing/ │ │ │ └── PlainTextSnippetExtractor.swift │ │ ├── Sources.swift │ │ ├── SupportedLanguageExtension.swift │ │ ├── SwiftLanguageVersion.swift │ │ ├── SwiftSDKs/ │ │ │ ├── SwiftSDK.swift │ │ │ ├── SwiftSDKBundle.swift │ │ │ ├── SwiftSDKBundleStore.swift │ │ │ └── SwiftSDKConfigurationStore.swift │ │ ├── Toolchain+SupportedFeatures.swift │ │ ├── Toolchain.swift │ │ ├── ToolchainConfiguration.swift │ │ ├── ToolsVersion.swift │ │ ├── ToolsVersionSpecificationGeneration.swift │ │ ├── Toolset.swift │ │ ├── UserToolchain.swift │ │ └── WindowsToolchainInfo.swift │ ├── PackageRegistry/ │ │ ├── CMakeLists.txt │ │ ├── ChecksumTOFU.swift │ │ ├── RegistryClient.swift │ │ ├── RegistryConfiguration.swift │ │ ├── RegistryDownloadsManager.swift │ │ ├── SignatureValidation.swift │ │ └── SigningEntityTOFU.swift │ ├── PackageRegistryCommand/ │ │ ├── CMakeLists.txt │ │ ├── PackageRegistryCommand+Auth.swift │ │ ├── PackageRegistryCommand+Publish.swift │ │ └── PackageRegistryCommand.swift │ ├── PackageSigning/ │ │ ├── CMakeLists.txt │ │ ├── CertificateStores.swift │ │ ├── SignatureProvider.swift │ │ ├── SigningEntity/ │ │ │ ├── FilePackageSigningEntityStorage.swift │ │ │ ├── PackageSigningEntityStorage.swift │ │ │ └── SigningEntity.swift │ │ ├── SigningIdentity.swift │ │ ├── VerifierPolicies.swift │ │ ├── X509Extensions.swift │ │ └── embedded_resources.swift │ ├── QueryEngine/ │ │ ├── CMakeLists.txt │ │ ├── CacheKey.swift │ │ ├── FileCacheRecord.swift │ │ ├── Query.swift │ │ └── QueryEngine.swift │ ├── Runtimes/ │ │ ├── CMakeLists.txt │ │ ├── CompilerPluginSupport/ │ │ │ ├── CMakeLists.txt │ │ │ └── TargetExtensions.swift │ │ ├── PackageDescription/ │ │ │ ├── BuildSettings.swift │ │ │ ├── CMakeLists.txt │ │ │ ├── Context.swift │ │ │ ├── LanguageStandardSettings.swift │ │ │ ├── PackageDependency.swift │ │ │ ├── PackageDependencyTrait.swift │ │ │ ├── PackageDescription.docc/ │ │ │ │ ├── Curation/ │ │ │ │ │ ├── BuildConfiguration.md │ │ │ │ │ ├── BuildSettingCondition.md │ │ │ │ │ ├── CLanguageStandard.md │ │ │ │ │ ├── CSetting.md │ │ │ │ │ ├── CXXLanguageStandard.md │ │ │ │ │ ├── CXXSetting.md │ │ │ │ │ ├── Dependency-Trait.md │ │ │ │ │ ├── Dependency.md │ │ │ │ │ ├── Extensions/ │ │ │ │ │ │ ├── CLanguageStandard-hash.md │ │ │ │ │ │ ├── CLanguageStandard-hashValue.md │ │ │ │ │ │ ├── CLanguageStandard-notEqual.md │ │ │ │ │ │ ├── CXXLanguageStandard-hash.md │ │ │ │ │ │ ├── CXXLanguageStandard-hashValue.md │ │ │ │ │ │ ├── CXXLanguageStandard-notEqual.md │ │ │ │ │ │ ├── LanguageTag-hash.md │ │ │ │ │ │ ├── LanguageTag-hashValue.md │ │ │ │ │ │ ├── LanguageTag-initRawValue.md │ │ │ │ │ │ ├── LanguageTag-notEqual.md │ │ │ │ │ │ ├── LanguageTag-rawValue.md │ │ │ │ │ │ ├── Library-LibraryType-hash.md │ │ │ │ │ │ ├── Library-LibraryType-hashValue.md │ │ │ │ │ │ ├── Library-LibraryType-initRawValue.md │ │ │ │ │ │ ├── Library-LibraryType-notEqual.md │ │ │ │ │ │ ├── Library-LibraryType.md │ │ │ │ │ │ ├── Product-Executable.md │ │ │ │ │ │ ├── Resource-Localization-hash.md │ │ │ │ │ │ ├── Resource-Localization-hashValue.md │ │ │ │ │ │ ├── Resource-Localization-notEqual.md │ │ │ │ │ │ ├── Target-TargetType-hash.md │ │ │ │ │ │ ├── Target-TargetType-hashValue.md │ │ │ │ │ │ └── Target-TargetType-notEqual.md │ │ │ │ │ ├── LanguageTag.md │ │ │ │ │ ├── Library.md │ │ │ │ │ ├── LinkerSetting.md │ │ │ │ │ ├── Package.md │ │ │ │ │ ├── Platform-notEqual.md │ │ │ │ │ ├── Platform.md │ │ │ │ │ ├── Plugin.md │ │ │ │ │ ├── PluginCapability.md │ │ │ │ │ ├── PluginCommandIntent.md │ │ │ │ │ ├── PluginPermission.md │ │ │ │ │ ├── PluginUsage.md │ │ │ │ │ ├── Product.md │ │ │ │ │ ├── Resource-Localization.md │ │ │ │ │ ├── Resource.md │ │ │ │ │ ├── SupportedPlatforms-notEqual.md │ │ │ │ │ ├── SupportedPlatforms.md │ │ │ │ │ ├── SwiftLanguageMode.md │ │ │ │ │ ├── SwiftSetting.md │ │ │ │ │ ├── SystemPackageProvider.md │ │ │ │ │ ├── Target-Dependency.md │ │ │ │ │ ├── Target-TargetDependencyCondition.md │ │ │ │ │ ├── Target-TargetType.md │ │ │ │ │ ├── Target.md │ │ │ │ │ ├── Trait.md │ │ │ │ │ └── Version.md │ │ │ │ ├── Info.plist │ │ │ │ └── PackageDescription.md │ │ │ ├── PackageDescription.swift │ │ │ ├── PackageDescriptionSerialization.swift │ │ │ ├── PackageDescriptionSerializationConversion.swift │ │ │ ├── PackageRequirement.swift │ │ │ ├── Product.swift │ │ │ ├── Resource.swift │ │ │ ├── SupportedPlatforms.swift │ │ │ ├── Target.swift │ │ │ ├── Trait.swift │ │ │ ├── Version+StringLiteralConvertible.swift │ │ │ ├── Version.swift │ │ │ └── WarningLevel.swift │ │ ├── PackagePlugin/ │ │ │ ├── ArgumentExtractor.swift │ │ │ ├── CMakeLists.txt │ │ │ ├── Command.swift │ │ │ ├── Context.swift │ │ │ ├── Diagnostics.swift │ │ │ ├── Documentation.docc/ │ │ │ │ ├── Curation/ │ │ │ │ │ ├── ArgumentExtractor.md │ │ │ │ │ ├── BinaryArtifactTarget.md │ │ │ │ │ ├── BuildToolPlugin.md │ │ │ │ │ ├── ClangSourceModuleTarget.md │ │ │ │ │ ├── Command.md │ │ │ │ │ ├── CommandPlugin.md │ │ │ │ │ ├── Diagnostics.md │ │ │ │ │ ├── ExecutableProduct.md │ │ │ │ │ ├── File.md │ │ │ │ │ ├── FileList.md │ │ │ │ │ ├── FileType.md │ │ │ │ │ ├── LibraryProduct.md │ │ │ │ │ ├── LibraryProduct_Kind.md │ │ │ │ │ ├── ModuleKind.md │ │ │ │ │ ├── Package.md │ │ │ │ │ ├── PackageDependency.md │ │ │ │ │ ├── PackageManager.md │ │ │ │ │ ├── PackageManagerProxyError.md │ │ │ │ │ ├── PackageManager_BuildConfiguration.md │ │ │ │ │ ├── PackageManager_BuildLogVerbosity.md │ │ │ │ │ ├── PackageManager_BuildParameters.md │ │ │ │ │ ├── PackageManager_BuildResult.md │ │ │ │ │ ├── PackageManager_BuildResult_BuiltArtifact.md │ │ │ │ │ ├── PackageManager_BuildSubset.md │ │ │ │ │ ├── PackageManager_SymbolGraphOptions.md │ │ │ │ │ ├── PackageManager_SymbolGraphOptions_AccessLevel.md │ │ │ │ │ ├── PackageManager_SymbolGraphResult.md │ │ │ │ │ ├── PackageManager_TestParameters.md │ │ │ │ │ ├── PackageManager_TestResult.md │ │ │ │ │ ├── PackageManager_TestResult_TestTarget.md │ │ │ │ │ ├── PackageManager_TestResult_TestTarget_TestCase.md │ │ │ │ │ ├── PackageManager_TestResult_TestTarget_TestCase_Test.md │ │ │ │ │ ├── PackageManager_TestResult_TestTarget_TestCase_Test_Result.md │ │ │ │ │ ├── PackageManager_TestSubset.md │ │ │ │ │ ├── PackageOrigin.md │ │ │ │ │ ├── Path.md │ │ │ │ │ ├── PathList.md │ │ │ │ │ ├── Plugin.md │ │ │ │ │ ├── PluginContext.md │ │ │ │ │ ├── PluginContextError.md │ │ │ │ │ ├── PluginDeserializationError.md │ │ │ │ │ ├── Product.md │ │ │ │ │ ├── SourceModuleTarget.md │ │ │ │ │ ├── SwiftSourceModuleTarget.md │ │ │ │ │ ├── SystemLibraryTarget.md │ │ │ │ │ ├── Target.md │ │ │ │ │ ├── TargetDependency.md │ │ │ │ │ └── ToolsVersion.md │ │ │ │ ├── Documentation.md │ │ │ │ └── Info.plist │ │ │ ├── Errors.swift │ │ │ ├── PackageManagerProxy.swift │ │ │ ├── PackageModel.swift │ │ │ ├── Path.swift │ │ │ ├── Plugin.swift │ │ │ ├── PluginContextDeserializer.swift │ │ │ ├── PluginMessages.swift │ │ │ ├── Protocols.swift │ │ │ └── Utilities.swift │ │ └── cmake/ │ │ └── modules/ │ │ ├── EmitSwiftInterface.cmake │ │ ├── InstallSwiftInterface.cmake │ │ └── PlatformInfo.cmake │ ├── SBOMModel/ │ │ ├── CMakeLists.txt │ │ ├── Converter/ │ │ │ ├── CycloneDXConverter.swift │ │ │ └── SPDXConverter.swift │ │ ├── Core/ │ │ │ ├── SBOMCommit.swift │ │ │ ├── SBOMComponent.swift │ │ │ ├── SBOMDependencies.swift │ │ │ ├── SBOMDocument.swift │ │ │ ├── SBOMIdentifier.swift │ │ │ ├── SBOMLicense.swift │ │ │ ├── SBOMMetadata.swift │ │ │ ├── SBOMOriginator.swift │ │ │ ├── SBOMPerson.swift │ │ │ ├── SBOMRegistryEntry.swift │ │ │ ├── SBOMRelationship.swift │ │ │ ├── SBOMSpec.swift │ │ │ ├── SBOMTool.swift │ │ │ └── SBOMVersionRegistry.swift │ │ ├── CycloneDX/ │ │ │ ├── CycloneDXComponent.swift │ │ │ ├── CycloneDXConstants.swift │ │ │ ├── CycloneDXDependency.swift │ │ │ ├── CycloneDXDocument.swift │ │ │ ├── CycloneDXExternalReference.swift │ │ │ ├── CycloneDXLicense.swift │ │ │ ├── CycloneDXMetadata.swift │ │ │ ├── CycloneDXPedigree.swift │ │ │ ├── CycloneDXProperty.swift │ │ │ └── Resources/ │ │ │ └── cyclonedx-1.7.schema.json │ │ ├── Encoder/ │ │ │ └── SBOMEncoder.swift │ │ ├── Extractor/ │ │ │ ├── DependencySourceStrategy.swift │ │ │ ├── PURL.swift │ │ │ ├── SBOMCache.swift │ │ │ ├── SBOMDependenciesExtractor.swift │ │ │ ├── SBOMExtractor.swift │ │ │ ├── SBOMFilterStrategy.swift │ │ │ └── SBOMGraphsConverter.swift │ │ ├── README.md │ │ ├── SBOMCreator.swift │ │ ├── SBOMError.swift │ │ ├── SBOMInput.swift │ │ ├── SPDX/ │ │ │ ├── Resources/ │ │ │ │ └── spdx-3.0.1.schema.json │ │ │ ├── SPDXAgent.swift │ │ │ ├── SPDXConstants.swift │ │ │ ├── SPDXCreationInfo.swift │ │ │ ├── SPDXDocument.swift │ │ │ ├── SPDXExternalIdentifier.swift │ │ │ ├── SPDXGraph.swift │ │ │ ├── SPDXLicenseExpression.swift │ │ │ ├── SPDXObject.swift │ │ │ ├── SPDXPackage.swift │ │ │ ├── SPDXRelationship.swift │ │ │ ├── SPDXSBOM.swift │ │ │ └── SPDXType.swift │ │ └── Validator/ │ │ ├── CycloneDXValidator.swift │ │ ├── SBOMValidator.swift │ │ ├── SBOMValidatorProtocol.swift │ │ └── SPDXValidator.swift │ ├── SPMBuildCore/ │ │ ├── BinaryTarget+Extensions.swift │ │ ├── BuildParameters/ │ │ │ ├── BuildParameters+APIDigester.swift │ │ │ ├── BuildParameters+Debugging.swift │ │ │ ├── BuildParameters+Driver.swift │ │ │ ├── BuildParameters+Linking.swift │ │ │ ├── BuildParameters+Output.swift │ │ │ ├── BuildParameters+Testing.swift │ │ │ └── BuildParameters.swift │ │ ├── BuildSystem/ │ │ │ ├── BuildSystem.swift │ │ │ ├── BuildSystemCommand.swift │ │ │ ├── BuildSystemDelegate.swift │ │ │ └── DiagnosticsCapturingBuildSystemDelegate.swift │ │ ├── BuiltTestProduct.swift │ │ ├── CMakeLists.txt │ │ ├── CommandPluginResult.swift │ │ ├── ConfigurableEnvVar.swift │ │ ├── MainAttrDetection.swift │ │ ├── Plugins/ │ │ │ ├── DefaultPluginScriptRunner.swift │ │ │ ├── PluginContextSerializer.swift │ │ │ ├── PluginInvocation.swift │ │ │ └── PluginScriptRunner.swift │ │ ├── ResolvedPackage+Extensions.swift │ │ ├── Triple+Extensions.swift │ │ ├── WarningControlFlags.swift │ │ ├── XCFrameworkMetadata.swift │ │ └── XcodeProjectRepresentation.swift │ ├── SPMLLBuild/ │ │ ├── CMakeLists.txt │ │ └── llbuild.swift │ ├── SPMSQLite3/ │ │ ├── CMakeLists.txt │ │ ├── module.modulemap │ │ └── sqlite.h │ ├── SourceControl/ │ │ ├── CMakeLists.txt │ │ ├── GitRepository.swift │ │ ├── Repository.swift │ │ └── RepositoryManager.swift │ ├── SourceKitLSPAPI/ │ │ ├── BuildDescription.swift │ │ ├── CMakeLists.txt │ │ └── PluginTargetBuildDescription.swift │ ├── SwiftBuildSupport/ │ │ ├── BuildSystem.swift │ │ ├── CMakeLists.txt │ │ ├── Diagnostics+Extensions.swift │ │ ├── DotPIFSerializer.swift │ │ ├── PIF.swift │ │ ├── PIFBuilder.swift │ │ ├── PackagePIFBuilder+Helpers.swift │ │ ├── PackagePIFBuilder+Plugins.swift │ │ ├── PackagePIFBuilder.swift │ │ ├── PackagePIFProjectBuilder+Modules.swift │ │ ├── PackagePIFProjectBuilder+Products.swift │ │ ├── PackagePIFProjectBuilder.swift │ │ ├── PluginConfiguration.swift │ │ ├── README.md │ │ ├── SwiftBuildSystem.swift │ │ └── SwiftBuildSystemMessageHandler.swift │ ├── SwiftFixIt/ │ │ ├── CMakeLists.txt │ │ └── SwiftFixIt.swift │ ├── SwiftPMBuildServer/ │ │ ├── CMakeLists.txt │ │ ├── DisableSigpipe.swift │ │ └── SwiftPMBuildServer.swift │ ├── SwiftSDKCommand/ │ │ ├── CMakeLists.txt │ │ ├── Configuration/ │ │ │ ├── ConfigurationSubcommand.swift │ │ │ ├── DeprecatedSwiftSDKConfigurationCommand.swift │ │ │ ├── ResetConfiguration.swift │ │ │ ├── SetConfiguration.swift │ │ │ └── ShowConfiguration.swift │ │ ├── ConfigureSwiftSDK.swift │ │ ├── InstallSwiftSDK.swift │ │ ├── ListSwiftSDKs.swift │ │ ├── README.md │ │ ├── RemoveSwiftSDK.swift │ │ ├── SwiftSDKCommand.swift │ │ └── SwiftSDKSubcommand.swift │ ├── Workspace/ │ │ ├── CMakeLists.txt │ │ ├── CheckoutState.swift │ │ ├── Diagnostics.swift │ │ ├── InitPackage.swift │ │ ├── LoadableResult.swift │ │ ├── ManagedArtifact.swift │ │ ├── ManagedDependency.swift │ │ ├── ManagedPrebuilt.swift │ │ ├── ManifestSigning/ │ │ │ ├── Base64URL.swift │ │ │ ├── CertificatePolicy.swift │ │ │ ├── ManifestSigning.swift │ │ │ ├── Signature.swift │ │ │ ├── Utilities.swift │ │ │ ├── X509Extensions.swift │ │ │ └── embedded_resources.swift │ │ ├── PackageContainer/ │ │ │ ├── FileSystemPackageContainer.swift │ │ │ ├── RegistryPackageContainer.swift │ │ │ └── SourceControlPackageContainer.swift │ │ ├── ResolvedFileWatcher.swift │ │ ├── ResolverPrecomputationProvider.swift │ │ ├── ToolsVersionSpecificationRewriter.swift │ │ ├── Workspace+BinaryArtifacts.swift │ │ ├── Workspace+Configuration.swift │ │ ├── Workspace+Delegation.swift │ │ ├── Workspace+Dependencies.swift │ │ ├── Workspace+Editing.swift │ │ ├── Workspace+Manifests.swift │ │ ├── Workspace+PackageContainer.swift │ │ ├── Workspace+Prebuilts.swift │ │ ├── Workspace+Registry.swift │ │ ├── Workspace+ResolvedPackages.swift │ │ ├── Workspace+Signing.swift │ │ ├── Workspace+SourceControl.swift │ │ ├── Workspace+State.swift │ │ ├── Workspace+Traits.swift │ │ └── Workspace.swift │ ├── XCBuildSupport/ │ │ ├── CMakeLists.txt │ │ ├── PIF.swift │ │ ├── PIFBuilder.swift │ │ ├── XCBuildDelegate.swift │ │ ├── XCBuildMessage.swift │ │ ├── XCBuildOutputParser.swift │ │ └── XcodeBuildSystem.swift │ ├── _AsyncFileSystem/ │ │ ├── AsyncFileSystem.swift │ │ ├── CMakeLists.txt │ │ ├── ConcurrencySupport.swift │ │ ├── MockFileSystem.swift │ │ ├── OSFileSystem.swift │ │ ├── OpenReadableFile.swift │ │ ├── OpenWritableFile.swift │ │ ├── ReadableFileStream.swift │ │ └── WritableStream.swift │ ├── _IntegrationTestSupport/ │ │ ├── Filesystem.swift │ │ └── Helpers.swift │ ├── _InternalBuildTestSupport/ │ │ ├── MockBuildTestHelper.swift │ │ └── PIFTester.swift │ ├── _InternalTestSupport/ │ │ ├── BuildConfiguration+Helpers.swift │ │ ├── BuildSystemProvider+Configuration.swift │ │ ├── BuildSystemProvider+Supported.swift │ │ ├── CombinationsWithRepetition.swift │ │ ├── Commands.swift │ │ ├── FileSystemHelpers.swift │ │ ├── GitRepositoryExtensions.swift │ │ ├── InMemoryGitRepository.swift │ │ ├── ManifestExtensions.swift │ │ ├── MockArchiver.swift │ │ ├── MockBuildTestHelper.swift │ │ ├── MockDependency.swift │ │ ├── MockDependencyGraph.swift │ │ ├── MockHTTPClient.swift │ │ ├── MockHashAlgorithm.swift │ │ ├── MockManifestLoader.swift │ │ ├── MockPackage.swift │ │ ├── MockPackageContainer.swift │ │ ├── MockPackageFingerprintStorage.swift │ │ ├── MockPackageGraphs.swift │ │ ├── MockPackageSigningEntityStorage.swift │ │ ├── MockProduct.swift │ │ ├── MockRegistry.swift │ │ ├── MockTarget.swift │ │ ├── MockWorkspace.swift │ │ ├── Observability.swift │ │ ├── PackageDependencyDescriptionExtensions.swift │ │ ├── PackageGraphTester.swift │ │ ├── PackageGraphTesterXCTest.swift │ │ ├── ProcessInfo+hostutils.swift │ │ ├── ResolvedModule+Mock.swift │ │ ├── SwiftPMProduct.swift │ │ ├── SwiftTesting+Data.swift │ │ ├── SwiftTesting+Helpers.swift │ │ ├── SwiftTesting+Tags.swift │ │ ├── SwiftTesting+TraitArgumentData.swift │ │ ├── SwiftTesting+TraitConditional.swift │ │ ├── SwiftTesting+Traits.swift │ │ ├── SwiftTesting+TraitsBug.swift │ │ ├── Toolchain.swift │ │ ├── XCTAssertHelpers.swift │ │ └── misc.swift │ ├── dummy-swiftc/ │ │ └── main.swift │ ├── swift-bootstrap/ │ │ ├── CMakeLists.txt │ │ └── main.swift │ ├── swift-build/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swift-build-prebuilts/ │ │ ├── BuildPrebuilts.swift │ │ └── build.sh │ ├── swift-experimental-sdk/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swift-package/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swift-package-collection/ │ │ └── Entrypoint.swift │ ├── swift-package-manager/ │ │ └── SwiftPM.swift │ ├── swift-package-registry/ │ │ └── runner.swift │ ├── swift-run/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swift-sdk/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swift-test/ │ │ ├── CMakeLists.txt │ │ └── Entrypoint.swift │ ├── swiftpm-testing-helper/ │ │ └── Entrypoint.swift │ └── tsan_utils/ │ ├── CMakeLists.txt │ ├── include/ │ │ ├── module.modulemap │ │ └── tsan_utils.h │ └── tsan_utils.c ├── Tests/ │ ├── BasicsTests/ │ │ ├── Archiver/ │ │ │ ├── TarArchiverTests.swift │ │ │ ├── UniversalArchiverTests.swift │ │ │ └── ZipArchiverTests.swift │ │ ├── ArrayHelpersTests.swift │ │ ├── AsyncProcessTests.swift │ │ ├── AuthorizationProviderTests.swift │ │ ├── ByteStringExtensionsTests.swift │ │ ├── CancellatorTests.swift │ │ ├── ConcurrencyHelpersTests.swift │ │ ├── DictionaryTest.swift │ │ ├── DispatchTimeTests.swift │ │ ├── Environment/ │ │ │ ├── EnvironmentKeyTests.swift │ │ │ └── EnvironmentTests.swift │ │ ├── FileSystem/ │ │ │ ├── CommonParentDirectoryTests.swift │ │ │ ├── FileSystemTests.swift │ │ │ ├── InMemoryFilesSystemTests.swift │ │ │ ├── PathShimTests.swift │ │ │ ├── PathTests.swift │ │ │ ├── TemporaryFileTests.swift │ │ │ └── VFSTests.swift │ │ ├── Graph/ │ │ │ ├── AdjacencyMatrixTests.swift │ │ │ ├── DirectedGraphTests.swift │ │ │ └── UndirectedGraphTests.swift │ │ ├── HTTPClientTests.swift │ │ ├── LegacyHTTPClientTests.swift │ │ ├── NetrcTests.swift │ │ ├── ObservabilitySystemTests.swift │ │ ├── ProcessInfoTests.swift │ │ ├── ProgressAnimationTests.swift │ │ ├── SQLiteBackedCacheTests.swift │ │ ├── SandboxTests.swift │ │ ├── Serialization/ │ │ │ └── SerializedJSONTests.swift │ │ ├── StringExtensionsTests.swift │ │ ├── TripleTests.swift │ │ ├── URLSessionHTTPClientTests.swift │ │ └── processInputs/ │ │ ├── deadlock-if-blocking-io │ │ ├── deadlock-if-blocking-io.bat │ │ ├── echo │ │ ├── echo.bat │ │ ├── exit4 │ │ ├── exit4.bat │ │ ├── in-to-out │ │ ├── in-to-out.bat │ │ ├── long-stdout-stderr │ │ ├── long-stdout-stderr.bat │ │ ├── simple-stdout-stderr │ │ └── simple-stdout-stderr.bat │ ├── BinarySymbolsTests/ │ │ └── LLVMObjdumpSymbolProviderTests.swift │ ├── BuildMetalTests/ │ │ └── BuildMetalTests.swift │ ├── BuildTests/ │ │ ├── BuildOperationTests.swift │ │ ├── BuildPlanTests.swift │ │ ├── BuildPlanTraversalTests.swift │ │ ├── BuildSystemDelegateTests.swift │ │ ├── CGenPluginsBuildPlanTests.swift │ │ ├── ClangTargetBuildDescriptionTests.swift │ │ ├── CrossCompilationBuildPlanTests.swift │ │ ├── IncrementalBuildTests.swift │ │ ├── LLBuildManifestBuilderTests.swift │ │ ├── ModuleAliasingBuildTests.swift │ │ ├── PluginInvocationTests.swift │ │ ├── PluginsBuildPlanTests.swift │ │ ├── PrebuiltsBuildPlanTests.swift │ │ ├── PrepareForIndexTests.swift │ │ ├── ProductBuildDescriptionTests.swift │ │ ├── SwiftCompilerOutputParserTests.swift │ │ └── WindowsBuildPlanTests.swift │ ├── CommandsTests/ │ │ ├── APIDiffTests.swift │ │ ├── BuildCommandTests.swift │ │ ├── CoverageTests.swift │ │ ├── MermaidPackageSerializerTests.swift │ │ ├── MultiRootSupportTests.swift │ │ ├── PackageCommandTests.swift │ │ ├── PackageRegistryCommandTests.swift │ │ ├── RunCommandTests.swift │ │ ├── Sanitizer+ExtensionsTests.swift │ │ ├── SwiftCommandStateTests.swift │ │ ├── SwiftSDKCommandTests.swift │ │ └── TestCommandTests.swift │ ├── ExtraTests/ │ │ ├── .gitignore │ │ ├── Package.swift │ │ ├── README.md │ │ └── Tests/ │ │ ├── ExtraTests/ │ │ │ └── FSWatchTests.swift │ │ └── LinuxMain.swift │ ├── FunctionalPerformanceTests/ │ │ └── BuildPerfTests.swift │ ├── FunctionalTests/ │ │ ├── CFamilyTargetTests.swift │ │ ├── DependencyResolutionTests.swift │ │ ├── LibraryEvolutionXCFLinuxTests.swift │ │ ├── MacroTests.swift │ │ ├── MiscellaneousTests.swift │ │ ├── ModuleAliasingFixtureTests.swift │ │ ├── ModuleMapTests.swift │ │ ├── PluginTests.swift │ │ ├── ResourcesTests.swift │ │ ├── StaticBinaryLibrary.swift │ │ ├── TaskBacktracesTests.swift │ │ ├── TestDiscoveryTests.swift │ │ ├── ToolsVersionTests.swift │ │ ├── TraitTests.swift │ │ └── VersionSpecificTests.swift │ ├── IntegrationTests/ │ │ ├── BasicTests.swift │ │ ├── SwiftPMTests.swift │ │ └── XCBuildTests.swift │ ├── LLBuildManifestTests/ │ │ └── LLBuildManifestTests.swift │ ├── PackageCollectionsModelTests/ │ │ └── PackageCollectionModelTests.swift │ ├── PackageCollectionsSigningTests/ │ │ ├── CertificatePolicyTests.swift │ │ ├── PackageCollectionSigningTests.swift │ │ ├── SignatureTests.swift │ │ └── Utilities.swift │ ├── PackageCollectionsTests/ │ │ ├── GitHubPackageMetadataProviderTests.swift │ │ ├── JSONPackageCollectionProviderTests.swift │ │ ├── PackageCollectionSourceCertificatePolicyTests.swift │ │ ├── PackageCollectionValidationTests.swift │ │ ├── PackageCollectionsModelTests.swift │ │ ├── PackageCollectionsSourcesStorageTest.swift │ │ ├── PackageCollectionsStorageTests.swift │ │ ├── PackageCollectionsTests.swift │ │ ├── PackageIndexAndCollectionsTests.swift │ │ ├── PackageIndexConfigurationTests.swift │ │ ├── PackageIndexTests.swift │ │ ├── TrieTests.swift │ │ ├── Utility.swift │ │ └── ValidationMessageTests.swift │ ├── PackageDescriptionTests/ │ │ └── VersionTests.swift │ ├── PackageFingerprintTests/ │ │ └── FilePackageFingerprintStorageTests.swift │ ├── PackageGraphPerformanceTests/ │ │ ├── DependencyResolverPerfTests.swift │ │ ├── Inputs/ │ │ │ ├── PerfectHTTPServer.json │ │ │ ├── SourceKitten.json │ │ │ ├── ZewoHTTPServer.json │ │ │ └── kitura.json │ │ └── PackageGraphPerfTests.swift │ ├── PackageGraphTests/ │ │ ├── CrossCompilationPackageGraphTests.swift │ │ ├── DependencyResolverTests.swift │ │ ├── ModulesGraphTests+Traits.swift │ │ ├── ModulesGraphTests.swift │ │ ├── PubGrubTests.swift │ │ ├── ResolvedTargetTests.swift │ │ ├── TopologicalSortTests.swift │ │ └── VersionSetSpecifierTests.swift │ ├── PackageLoadingTests/ │ │ ├── Inputs/ │ │ │ ├── Bar.pc │ │ │ ├── Dependency.pc │ │ │ ├── Dependent.pc │ │ │ ├── Foo.pc │ │ │ ├── Framework.pc │ │ │ ├── package-deps-manifest.swift │ │ │ ├── target-deps-manifest.swift │ │ │ └── trivial-manifest.swift │ │ ├── ManifestLoaderCacheTests.swift │ │ ├── ManifestSignatureParserTests.swift │ │ ├── ModuleMapGenerationTests.swift │ │ ├── PDAppleProductLoadingTests.swift │ │ ├── PDLoadingTests.swift │ │ ├── PD_4_0_LoadingTests.swift │ │ ├── PD_4_2_LoadingTests.swift │ │ ├── PD_5_0_LoadingTests.swift │ │ ├── PD_5_2_LoadingTests.swift │ │ ├── PD_5_3_LoadingTests.swift │ │ ├── PD_5_4_LoadingTests.swift │ │ ├── PD_5_5_LoadingTests.swift │ │ ├── PD_5_6_LoadingTests.swift │ │ ├── PD_5_7_LoadingTests.swift │ │ ├── PD_5_9_LoadingTests.swift │ │ ├── PD_6_0_LoadingTests.swift │ │ ├── PD_6_2_LoadingTests.swift │ │ ├── PD_Next_LoadingTests.swift │ │ ├── PackageBuilderTests.swift │ │ ├── PkgConfigAllowlistTests.swift │ │ ├── PkgConfigParserTests.swift │ │ ├── PkgConfigTests.swift │ │ ├── TargetSourcesBuilderTests.swift │ │ ├── ToolsVersionParserTests.swift │ │ ├── TraitLoadingTests.swift │ │ └── pkgconfigInputs/ │ │ ├── case_insensitive.pc │ │ ├── deps_variable.pc │ │ ├── double_sysroot.pc │ │ ├── dummy_dependency.pc │ │ ├── empty_cflags.pc │ │ ├── escaped_spaces.pc │ │ ├── failure_case.pc │ │ ├── freetype2.pc │ │ ├── gobject-2.0.pc │ │ ├── gtk+-3.0.pc │ │ ├── harfbuzz.pc │ │ ├── libffi.pc │ │ ├── not_double_sysroot.pc │ │ └── quotes_failure.pc │ ├── PackageModelTests/ │ │ ├── CanonicalPackageLocationTests.swift │ │ ├── EnabledTraitTests.swift │ │ ├── InstalledSwiftPMConfigurationTests.swift │ │ ├── ManifestTests.swift │ │ ├── MinimumDeploymentTargetTests.swift │ │ ├── PackageIdentityNameTests.swift │ │ ├── PackageIdentityParser.swift │ │ ├── PackageIdentityScopeTests.swift │ │ ├── PackageModelTests.swift │ │ ├── SnippetTests.swift │ │ ├── SwiftLanguageVersionTests.swift │ │ ├── SwiftSDKBundleTests.swift │ │ ├── SwiftSDKTests.swift │ │ ├── ToolsVersionTests.swift │ │ └── ToolsetTests.swift │ ├── PackagePluginAPITests/ │ │ ├── ArgumentExtractorTests.swift │ │ └── PathTests.swift │ ├── PackageRegistryTests/ │ │ ├── PackageSigningEntityTOFUTests.swift │ │ ├── PackageVersionChecksumTOFUTests.swift │ │ ├── RegistryClientTests.swift │ │ ├── RegistryConfigurationTests.swift │ │ ├── RegistryDownloadsManagerTests.swift │ │ └── SignatureValidationTests.swift │ ├── PackageSigningTests/ │ │ ├── FilePackageSigningEntityStorageTests.swift │ │ ├── SigningEntityTests.swift │ │ ├── SigningIdentityTests.swift │ │ ├── SigningTests.swift │ │ └── Utilities.swift │ ├── QueryEngineTests/ │ │ └── QueryEngineTests.swift │ ├── SBOMModelTests/ │ │ ├── CycloneDXConverterTests.swift │ │ ├── PURLTests.swift │ │ ├── SBOMEncoderTests.swift │ │ ├── SBOMExtractCategoryTests.swift │ │ ├── SBOMExtractComponentsTests.swift │ │ ├── SBOMExtractDependenciesTests.swift │ │ ├── SBOMExtractMetadataTests.swift │ │ ├── SBOMExtractPrimaryComponentTests.swift │ │ ├── SBOMExtractScopeTests.swift │ │ ├── SBOMExtractTests.swift │ │ ├── SBOMFilterStrategyTests.swift │ │ ├── SBOMGetSpecTests.swift │ │ ├── SBOMGraphsConverterTests.swift │ │ ├── SBOMTestDependencyGraphHelpers.swift │ │ ├── SBOMTestDependencyGraphSPM.swift │ │ ├── SBOMTestDependencyGraphSimple.swift │ │ ├── SBOMTestDependencyGraphSimpleDifferent.swift │ │ ├── SBOMTestDependencyGraphSwiftly.swift │ │ ├── SBOMTestError.swift │ │ ├── SBOMTestModulesGraphConditional.swift │ │ ├── SBOMTestModulesGraphHelpers.swift │ │ ├── SBOMTestModulesGraphSPM.swift │ │ ├── SBOMTestModulesGraphSimple.swift │ │ ├── SBOMTestModulesGraphSwiftly.swift │ │ ├── SBOMTestRepo.swift │ │ ├── SBOMTestStore.swift │ │ ├── SBOMTestTraits.swift │ │ ├── SBOMValidationTests.swift │ │ ├── SPDXConverterTests.swift │ │ ├── SPMFixtures/ │ │ │ ├── SBOMSPMBuildToolingPackages.swift │ │ │ ├── SBOMSPMDocumentationPackages.swift │ │ │ ├── SBOMSPMFoundationPackages.swift │ │ │ ├── SBOMSPMRootPackageAssembly.swift │ │ │ ├── SBOMSPMRootPackageCommand.swift │ │ │ ├── SBOMSPMRootPackageCore.swift │ │ │ ├── SBOMSPMRootPackageExecutable.swift │ │ │ ├── SBOMSPMSecurityPackages.swift │ │ │ ├── SBOMSPMSwiftBuildPackage.swift │ │ │ └── SBOMSPMSwiftSyntaxPackage.swift │ │ ├── SwiftlyFixtures/ │ │ │ ├── SBOMSwiftlyCollectionsPackages.swift │ │ │ ├── SBOMSwiftlyFoundationPackages.swift │ │ │ ├── SBOMSwiftlyNIOPackages.swift │ │ │ ├── SBOMSwiftlyOpenAPIPackages.swift │ │ │ ├── SBOMSwiftlyRootPackage.swift │ │ │ ├── SBOMSwiftlySecurityPackages.swift │ │ │ └── SBOMSwiftlyUtilityPackages.swift │ │ └── testfiles/ │ │ ├── invalid-cyclonedx-1-missing-fields.json │ │ ├── invalid-cyclonedx-1-small.json │ │ ├── invalid-cyclonedx-1.7-uppercase-uuid.json │ │ ├── invalid-cyclonedx-1.7-wrong-bomformat.json │ │ ├── invalid-spdx-3-small.json │ │ ├── invalid-spdx-3.0.1-no-iri.json │ │ ├── invalid-spdx-3.0.1-spm.json │ │ ├── invalid-spdx-3.0.1-wrong-relationshiptype.json │ │ ├── valid-cyclonedx-1.7-empty-comps.json │ │ ├── valid-cyclonedx-1.7-minimal.json │ │ ├── valid-cyclonedx-1.7-spm.json │ │ ├── valid-cyclonedx-1.7-unicode.json │ │ ├── valid-cyclonedx-1.7-versions.json │ │ └── valid-spdx-3.0.1-spm.json │ ├── SPMBuildCoreTests/ │ │ ├── ArtifactsArchiveMetadataTests.swift │ │ ├── BuildParametersTests.swift │ │ ├── MainAttrDetectionTests.swift │ │ └── XCFrameworkMetadataTests.swift │ ├── SourceControlTests/ │ │ ├── GitRepositoryProviderTests.swift │ │ ├── GitRepositoryTests.swift │ │ ├── InMemoryGitRepositoryTests.swift │ │ ├── Inputs/ │ │ │ └── TestRepo.tgz │ │ └── RepositoryManagerTests.swift │ ├── SourceKitLSPAPITests/ │ │ └── SourceKitLSPAPITests.swift │ ├── SwiftBuildSupportTests/ │ │ ├── CGenPIFTests.swift │ │ ├── PIFBuilderTests.swift │ │ ├── PackagePIFBuilderHelpersTests.swift │ │ ├── PrebuiltsPIFTests.swift │ │ ├── ProductTests.swift │ │ ├── SwiftBuildSystemMessageHandlerTests.swift │ │ └── SwiftBuildSystemTests.swift │ ├── SwiftFixItTests/ │ │ ├── BasicTests.swift │ │ ├── CategoryTests.swift │ │ ├── FilteringTests.swift │ │ └── Utilities.swift │ ├── SwiftPMBuildServerTests/ │ │ └── BuildServerTests.swift │ ├── WorkspaceTests/ │ │ ├── AuthorizationProviderTests.swift │ │ ├── InitTests.swift │ │ ├── ManifestSourceGenerationTests.swift │ │ ├── MirrorsConfigurationTests.swift │ │ ├── PrebuiltsTests.swift │ │ ├── RegistryPackageContainerTests.swift │ │ ├── ResolvedPackagesStoreTests.swift │ │ ├── SourceControlPackageContainerTests.swift │ │ ├── ToolsVersionSpecificationGenerationTests.swift │ │ ├── ToolsVersionSpecificationRewriterTests.swift │ │ ├── WorkspaceStateTests.swift │ │ ├── WorkspaceTests+Traits.swift │ │ └── WorkspaceTests.swift │ ├── XCBuildSupportTests/ │ │ ├── Inputs/ │ │ │ └── Foo.pc │ │ ├── PIFBuilderTests.swift │ │ └── PIFTests.swift │ ├── _AsyncFileSystemTests/ │ │ └── AsyncFileSystemTests.swift │ └── _InternalTestSupportTests/ │ ├── FileSystemHelpersTests.swift │ ├── MiscTests.swift │ └── XCTAssertHelpersTests.swift ├── Utilities/ │ ├── Certificates/ │ │ ├── Intermediates/ │ │ │ ├── AppleWWDRCAG2.cer │ │ │ ├── AppleWWDRCAG3.cer │ │ │ ├── AppleWWDRCAG4.cer │ │ │ ├── AppleWWDRCAG5.cer │ │ │ ├── AppleWWDRCAG6.cer │ │ │ ├── AppleWWDRCAG7.cer │ │ │ └── AppleWWDRCAG8.cer │ │ ├── Package.swift │ │ ├── README.md │ │ ├── Roots/ │ │ │ ├── AppleComputerRootCertificate.cer │ │ │ ├── AppleIncRootCertificate.cer │ │ │ ├── AppleRootCA-G2.cer │ │ │ └── AppleRootCA-G3.cer │ │ ├── empty.swift │ │ └── generate.sh │ ├── Docker/ │ │ ├── Dockerfile │ │ ├── docker-compose.1604.53.yaml │ │ ├── docker-compose.1804.53.yaml │ │ ├── docker-compose.2004.54.yaml │ │ ├── docker-compose.2004.55.yaml │ │ ├── docker-compose.2004.56.yaml │ │ ├── docker-compose.2004.57.yaml │ │ ├── docker-compose.2004.main.yaml │ │ ├── docker-compose.2204.58.yaml │ │ ├── docker-compose.2204.59.yaml │ │ └── docker-compose.yaml │ ├── InstalledSwiftPMConfiguration/ │ │ ├── Package.swift │ │ └── Sources/ │ │ └── exec.swift │ ├── README.md │ ├── SwiftPM+SwiftBuild.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── bootstrap │ ├── build-using-self │ ├── config.json │ ├── generate_contributors_list.sh │ ├── helpers.py │ ├── new-bootstrap │ ├── soundness.sh │ └── test-toolchain ├── cmake/ │ └── modules/ │ ├── CMakeLists.txt │ └── FindLLBuild.cmake ├── swiftbuild_specific_issues.md ├── withKnownIssue_tests_report.md └── xcode/ └── SwiftPM-Package.xctestplan ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "Swift Nightly Main", "dockerComposeFile": "docker-compose.yaml", "service": "devcontainer", "workspaceFolder": "${localWorkspaceFolder}", "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installZsh": "false", "username": "root", "upgradePackages": "false" }, "ghcr.io/devcontainers/features/git:1": { "version": "os-provided", "ppa": "false" } }, "initializeCommand": ".devcontainer/init.sh", "postCreateCommand": "apt-get update && apt-get install -y curl sqlite3 libsqlite3-dev libncurses5-dev python3 build-essential", "postStartCommand": "cd ${WORKSPACE_DIR}", "customizations": { "vscode": { "settings": { "lldb.library": "/usr/lib/liblldb.so" }, "extensions": [ "swiftlang.swift-vscode" ] } }, // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], "remoteUser": "root" } ================================================ FILE: .devcontainer/docker-compose.yaml ================================================ services: devcontainer: # Use your desired image or Dockerfile here image: "swiftlang/swift:nightly-main" env_file: - .env cap_add: - SYS_PTRACE security_opt: - seccomp=unconfined volumes: # Mount the main git repo dir and the current worktree dir at the same absolute path as the host - ${GIT_REPO}:${GIT_REPO}:rw - ${WORKSPACE_DIR}:${WORKSPACE_DIR}:rw command: sleep infinity ================================================ FILE: .devcontainer/init.sh ================================================ #!/bin/bash ##===----------------------------------------------------------------------===## ## ## This source file is part of the Swift open source project ## ## Copyright (c) 2022 Apple Inc. and the Swift project authors ## Licensed under Apache License v2.0 with Runtime Library Exception ## ## See http://swift.org/LICENSE.txt for license information ## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## # Calculates absolute paths for the git repo root and current workspace SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) GIT_COMMON_DIR=$(git rev-parse --git-common-dir) case "$GIT_COMMON_DIR" in /*) ;; *) GIT_COMMON_DIR="$PWD/$GIT_COMMON_DIR" ;; esac env_file="${SCRIPT_DIR}/.env" # Ensure the paths are absolute for Docker mounting echo "GIT_REPO=$(realpath "$GIT_COMMON_DIR")" > "${env_file}" echo "WORKSPACE_DIR=$(realpath "$PWD")" >> "${env_file}" ================================================ FILE: .dir-locals.el ================================================ ;;; Directory Local Variables -*- no-byte-compile: t -*- ;;; For more information see (info "(emacs) Directory Variables") ((nil . ((c-basic-offset . 4))) (swift-mode . ((swift-mode:basic-offset . 4)))) ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = space insert_final_newline = true trim_trailing_whitespace = true xcode_trim_whitespace_on_empty_lines = true [*.{yml,yaml}] indent_size = 2 ================================================ FILE: .github/CODEOWNERS ================================================ # This file is a list of the people responsible for ensuring that patches for a # particular part of Swift are reviewed, either by themselves or by someone else. # They are also the gatekeepers for their part of Swift, with the final word on # what goes in or not. # # The list is sorted by surname and formatted to allow easy grepping and # beautification by scripts. The fields are: name (N), email (E), web-address # (W), PGP key ID and fingerprint (P), description (D), and snail-mail address # (S). # N: Tomer Doron # E: tomer@apple.com # D: Package Manager # N: Max Desiatov # E: m_desiatov@apple.com # D: Package Manager # N: Ben Barham # E: ben_barham@apple.com # D: Package Manager ### # The following lines are used by GitHub to automatically recommend reviewers. * @jakepetroules @dschaefer2 @bripeticca @plemarquand @owenv @bkhouri @cmcgee1024 @daveyc123 @rconnell9 @daveinglis Sources/Commands/PackageCommands/Migrate.swift @AnthonyLatsis @xedin @jakepetroules @dschaefer2 @bripeticca @plemarquand @owenv @bkhouri @cmcgee1024 @daveyc123 @rconnell9 @daveinglis Sources/SwiftFixIt/* @AnthonyLatsis @xedin @jakepetroules @dschaefer2 @bripeticca @plemarquand @owenv @bkhouri @cmcgee1024 @daveyc123 @rconnell9 @daveinglis Tests/SwiftFixItTests/* @AnthonyLatsis @xedin @jakepetroules @dschaefer2 @bripeticca @plemarquand @owenv @bkhouri @cmcgee1024 @daveyc123 @rconnell9 @daveinglis ================================================ FILE: .github/ISSUE_TEMPLATE/BUG_REPORT.yml ================================================ name: Bug Report description: Something isn't working as expected labels: [bug] body: - type: checkboxes id: cat-preferences attributes: label: >- Is it reproducible with SwiftPM command-line tools: `swift build`, `swift test`, `swift package` etc? description: >- Issues related to closed-source software are not tracked by this repository and will be closed. For Xcode and `xcodebuild`, please file a feedback at https://feedbackassistant.apple.com instead." options: - label: >- Confirmed reproduction steps with SwiftPM CLI. The description text _must_ include reproduction steps with either of command-line SwiftPM commands, `swift build`, `swift test`, `swift package` etc. required: true - type: textarea attributes: label: Description validations: required: true - type: textarea attributes: label: Expected behavior description: What you expected to happen. validations: required: false - type: textarea attributes: label: Actual behavior description: What actually happened. validations: required: false - type: textarea attributes: label: Steps to reproduce placeholder: | 1. ... 2. ... validations: required: false - type: input attributes: label: Swift Package Manager version/commit hash validations: required: false - type: textarea attributes: label: Swift & OS version (output of `swift --version ; uname -a`) validations: required: false ================================================ FILE: .github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml ================================================ name: Feature Request description: A suggestion for a new feature labels: [enhancement] body: - type: textarea attributes: label: Description validations: required: true - type: textarea attributes: label: Expected behavior description: What you expected to happen. validations: required: false - type: textarea attributes: label: Actual behavior description: What actually happened. validations: required: false - type: textarea attributes: label: Steps to reproduce placeholder: | 1. ... 2. ... validations: required: false - type: input attributes: label: Swift Package Manager version/commit hash validations: required: false - type: textarea attributes: label: Swift & OS version (output of `swift --version && uname -a`) validations: required: false ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ _[One line description of your change]_ ### Motivation: _[Explain here the context, and why you're making that change. What is the problem you're trying to solve.]_ ### Modifications: _[Describe the modifications you've done.]_ ### Result: _[After your change, what will change.]_ ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/scripts/prebuild.ps1 ================================================ ##===----------------------------------------------------------------------===## ## ## This source file is part of the Swift open source project ## ## Copyright (c) 2025 Apple Inc. and the Swift project authors ## Licensed under Apache License v2.0 with Runtime Library Exception ## ## See http://swift.org/LICENSE.txt for license information ## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## param ( [switch]$SkipAndroid, [switch]$InstallCMake ) # winget isn't easily made available in containers, so use chocolatey Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) if ($InstallCMake) { choco install -y cmake --installargs 'ADD_CMAKE_TO_PATH=System' --apply-install-arguments-to-dependencies choco install -y ninja Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 refreshenv # Let swiftc find the path to link.exe in the CMake smoke test $env:Path += ";$(Split-Path -Path "$(& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" "-latest" -products Microsoft.VisualStudio.Product.BuildTools -find VC\Tools\MSVC\*\bin\HostX64\x64\link.exe)" -Parent)" } if (-not $SkipAndroid) { choco install -y android-ndk Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 refreshenv # Work around a bug in the package causing the env var to be set incorrectly $env:ANDROID_NDK_ROOT = $env:ANDROID_NDK_ROOT.replace('-windows.zip','') } ================================================ FILE: .github/scripts/prebuild.sh ================================================ #!/bin/bash ##===----------------------------------------------------------------------===## ## ## This source file is part of the Swift open source project ## ## Copyright (c) 2025 Apple Inc. and the Swift project authors ## Licensed under Apache License v2.0 with Runtime Library Exception ## ## See http://swift.org/LICENSE.txt for license information ## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## set -e if [[ $(uname) == Darwin ]] ; then if [[ "$INSTALL_CMAKE" == "1" ]] ; then mkdir -p "$RUNNER_TOOL_CACHE" if ! command -v cmake >/dev/null 2>&1 ; then curl -fsSLO https://github.com/Kitware/CMake/releases/download/v4.1.2/cmake-4.1.2-macos-universal.tar.gz echo '3be85f5b999e327b1ac7d804cbc9acd767059e9f603c42ec2765f6ab68fbd367 cmake-4.1.2-macos-universal.tar.gz' > cmake-4.1.2-macos-universal.tar.gz.sha256 sha256sum -c cmake-4.1.2-macos-universal.tar.gz.sha256 tar -xf cmake-4.1.2-macos-universal.tar.gz ln -s "$PWD/cmake-4.1.2-macos-universal/CMake.app/Contents/bin/cmake" "$RUNNER_TOOL_CACHE/cmake" fi if ! command -v ninja >/dev/null 2>&1 ; then curl -fsSLO https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-mac.zip echo 'da7797794153629aca5570ef7c813342d0be214ba84632af886856e8f0063dd9 ninja-mac.zip' > ninja-mac.zip.sha256 sha256sum -c ninja-mac.zip.sha256 unzip ninja-mac.zip rm -f ninja-mac.zip mv ninja "$RUNNER_TOOL_CACHE/ninja" fi fi elif command -v apt-get >/dev/null 2>&1 ; then # bookworm, noble, jammy export DEBIAN_FRONTEND=noninteractive apt-get update -y # Build dependencies apt-get install -y libsqlite3-dev libncurses-dev # Debug symbols apt-get install -y libc6-dbg if [[ "$INSTALL_CMAKE" == "1" ]] ; then apt-get install -y cmake ninja-build fi # Android NDK dpkg_architecture="$(dpkg --print-architecture)" if [[ "$SKIP_ANDROID" != "1" ]] && [[ "$dpkg_architecture" == amd64 ]] ; then eval "$(cat /etc/os-release)" case "$VERSION_CODENAME" in bookworm|jammy) : # Not available ;; noble) apt-get install -y google-android-ndk-r26c-installer ;; *) echo "Unable to fetch Android NDK for unknown Linux distribution: $VERSION_CODENAME" >&2 exit 1 esac else echo "Skipping Android NDK installation on $dpkg_architecture" >&2 fi elif command -v dnf >/dev/null 2>&1 ; then # rhel-ubi9 dnf update -y # Build dependencies dnf install -y sqlite-devel ncurses-devel # Debug symbols dnf debuginfo-install -y glibc elif command -v yum >/dev/null 2>&1 ; then # amazonlinux2 yum update -y # Build dependencies yum install -y sqlite-devel ncurses-devel # Debug symbols yum install -y yum-utils debuginfo-install -y glibc fi ================================================ FILE: .github/workflows/automerge.yml ================================================ name: Create PR to merge main into release branch # In the first period after branching the release branch, # we typically want to include many changes from `main` in the release branch. # This workflow automatically creates a PR to merge the main into the release branch. # Later in the release cycle we should stop this practice to avoid landing risky changes by disabling this workflow. # To do so, disable the workflow as described in https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/disabling-and-enabling-a-workflow permissions: contents: read on: workflow_dispatch: jobs: create_merge_pr: name: Create PR to merge main into release branch uses: swiftlang/github-workflows/.github/workflows/create_automerge_pr.yml@0.0.8 with: head_branch: main base_branch: release/6.3 permissions: contents: write pull-requests: write if: (github.event_name == 'schedule' && github.repository == 'swiftlang/swift-package-manager') || (github.event_name != 'schedule') # Ensure that we don't run this on a schedule in a fork ================================================ FILE: .github/workflows/pull_request.yml ================================================ name: Pull request permissions: contents: read on: pull_request: types: [opened, reopened, synchronize] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: needs: [soundness] strategy: fail-fast: false matrix: executableTargetBuildSystem: ["native"] buildSystem: ["native", "swiftbuild"] linuxSwiftVersion: ['["nightly-main", "nightly-6.2"]', '["nightly-main"]'] exclude: - buildSystem: "swiftbuild" linuxSwiftVersion: '["nightly-main", "nightly-6.2"]' - buildSystem: "native" linuxSwiftVersion: '["nightly-main"]' name: Build (${{ matrix.buildSystem }}) (exectable target built using ${{ matrix.executableTargetBuildSystem }}) uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@0.0.8 with: linux_os_versions: '["amazonlinux2", "bookworm", "noble", "jammy", "rhel-ubi9"]' linux_swift_versions: ${{ matrix.linuxSwiftVersion }} linux_pre_build_command: ./.github/scripts/prebuild.sh linux_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}}' # linux_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}} && swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-test --parallel --build-system ${{ matrix.buildSystem}}' windows_build_timeout: 180 windows_swift_versions: '["nightly-main"]' windows_pre_build_command: 'Invoke-Program .\.github\scripts\prebuild.ps1' windows_build_command: 'Invoke-Program swift run -Xlinker /ignore:4217 --configuration release --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests -Xlinker /ignore:4217 --build-system ${{ matrix.buildSystem}}' # windows_build_command: 'Invoke-Program swift run -Xlinker /ignore:4217 --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests -Xlinker /ignore:4217 --build-system ${{ matrix.buildSystem}}; Invoke-Program swift run --build-system ${{ matrix.executableTargetBuildSystem }} -Xlinker /ignore:4217 swift-test -Xlinker /ignore:4217 --parallel --build-system ${{ matrix.buildSystem}}' enable_windows_checks: true enable_ios_checks: false enable_macos_checks: true macos_exclude_xcode_versions: "[{\"xcode_version\": \"16.3\"}, {\"xcode_version\": \"16.4\"}]" macos_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}}' # macos_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}} && swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-test --parallel --build-system ${{ matrix.buildSystem}}' ios_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}} --sdk \"$(xcrun --sdk iphoneos --show-sdk-path)\" --triple arm64-apple-ios' # ios_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem}} --sdk \"$(xcrun --sdk iphoneos --show-sdk-path)\" --triple arm64-apple-ios && swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-test --parallel --build-system ${{ matrix.buildSystem }} --sdk \"$(xcrun --sdk iphoneos --show-sdk-path)\" --triple arm64-apple-ios' build-using-swiftbuild: strategy: fail-fast: false matrix: executableTargetBuildSystem: ["swiftbuild"] buildSystem: ["swiftbuild"] name: Build (${{ matrix.buildSystem }}) (exectable target built using ${{ matrix.executableTargetBuildSystem }}) needs: [soundness] uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@0.0.8 with: linux_os_versions: '["amazonlinux2", "bookworm", "noble", "jammy", "rhel-ubi9"]' linux_swift_versions: '["nightly-main"]' linux_pre_build_command: ./.github/scripts/prebuild.sh linux_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem }}' enable_windows_checks: false windows_build_timeout: 180 windows_swift_versions: '["nightly-main"]' windows_pre_build_command: 'Invoke-Program .\.github\scripts\prebuild.ps1' windows_build_command: 'Invoke-Program swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem }}' enable_ios_checks: false enable_macos_checks: true macos_exclude_xcode_versions: "[{\"xcode_version\": \"16.3\"}, {\"xcode_version\": \"16.4\"}]" macos_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem }}' ios_build_command: 'swift run --build-system ${{ matrix.executableTargetBuildSystem }} swift-build --build-tests --build-system ${{ matrix.buildSystem }} --sdk \"$(xcrun --sdk iphoneos --show-sdk-path)\" --triple arm64-apple-ios' soundness: name: Soundness uses: swiftlang/github-workflows/.github/workflows/soundness.yml@0.0.8 with: license_header_check_project_name: "Swift" license_header_check_enabled: true unacceptable_language_check_enabled: true api_breakage_check_enabled: false format_check_enabled: false shell_check_enabled: false docs_check_enabled: true broken_symlink_check_enabled: true python_lint_check_enabled: true yamllint_check_enabled: true ================================================ FILE: .gitignore ================================================ .build .test .index-build .devcontainer/.env DerivedData /.previous-build xcuserdata .DS_Store *~ \#* .\#* .*.sw[nop] *.xcscmblueprint /default.profraw *.xcodeproj Utilities/Docker/*.tar.gz .swiftpm Package.resolved /build *.pyc .docc-build .vscode /stage/ Utilities/InstalledSwiftPMConfiguration/config.json Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/build ================================================ FILE: .license_header_template ================================================ @@===----------------------------------------------------------------------===@@ @@ @@ This source file is part of the Swift open source project @@ @@ Copyright (c) YEARS Apple Inc. and the Swift project authors @@ Licensed under Apache License v2.0 with Runtime Library Exception @@ @@ See http://swift.org/LICENSE.txt for license information @@ See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors @@ @@===----------------------------------------------------------------------===@@ ================================================ FILE: .licenseignore ================================================ **/*.mlmodel **/*.pbxproj **/*.png **/*.xcworkspacedata **/Package.swift .dir-locals.el .editorconfig .swift-version .swiftformat .pep8 .mailmap .mailfilter CODEOWNERS Package.swift Fixtures/**/*.* **/*.pc **/*.cer **/*.zip **/*.tar **/*.tgz **/*.gz **/*.svg **/*.bat **/*.xctestplan **/processInputs/** Utilities/bootstrap Utilities/build-using-self Utilities/new-bootstrap Utilities/test-toolchain ================================================ FILE: .mailfilter ================================================ # This is a list of `shasum` hashed email addresses which are filtered from CONTRIBUTORS.txt, typically for privacy. # Lines can be generated by running `echo -n 'My Name ' | shasum | head -c 40`. 03a39e53ca4764a094b9f6e548e8d1ce0d941d7b 38268a29b340ecfb435c5e6c5827a596acb71cc6 43b012c0b4e67962522a02e12d07cb5d5c5ba036 886d1da6503c6de1d630beaf6acb667e4ce3e2a0 ================================================ FILE: .mailmap ================================================ Alex Blewitt Alex Blewitt Alex Hoppen Alex Hoppen Ankit Aggarwal Ankit Aggarwal Ankit Aggarwal Ankit Aggarwal Ben Chatelain Ben Chatelain Ben Cohen Ben Cohen Ben Langmuir Ben Langmuir Benjamin Herzog Benjamin Herzog Benjamin Scholtysik Benjamin Scholtysik (Reimold) Benjamin Scholtysik Boris Buegling Boris Buegling Braden Scothern Braden Scothern Brandon Titus Brandon Titus Brian Croom Brian Croom Brian Gesiak Brian Gesiak Chris Lattner Chris Lattner Dan Zheng Dan Zheng Daniel Duan Daniel Duan Daniel Duan Daniel Dunbar Daniel Dunbar Dario Rexin Dario Rexin Dave Abrahams Dave Abrahams David Hart David Hart Harlan Haskins Harlan Haskins Helge Hess Honza Dvorsky Honza Dvorsky Honza Dvorsky J. Cheyo Jimenez J. Cheyo Jimenez Johannes Weiss Johannes Weiss Johannes Weiss Kilian Koeltzsch Kilian Koeltzsch Kyle Jessup Kyle Jessup Lev Walkin Lev Walkin Marcin Krzyzanowski Marcin Krzyzanowski <758033+krzyzanowskim@users.noreply.github.com> Marcin Krzyzanowski Marcin Krzyzanowski Matthew Seaman Matthew Seaman Mattt Thompson Mattt Thompson Mattt Thompson Max Howell Max Howell Max Liberman Max Liberman Max Moiseev Max Moiseev Max Moiseev Michael Ilseman Michael Ilseman Mishal Shah Mishal Shah Nikola Lajic Nikola Lajic Owen Voorhees Owen Voorhees Pavel Yaskevich Pavel Yaskevich Saleem Abdulrasool Saleem Abdulrasool Saleem Abdulrasool Sergio Campamá Sergio Campamá Slava Pestov Slava Pestov Thomas Roughton Thomas Roughton Tim Condon <0xTim@users.noreply.github.com> <0xTim@users.noreply.github.com> Tim Condon <0xTim@users.noreply.github.com> Tim Gymnich Tim Gymnich Tom Doron Valeriy Van Valeriy Van finagolfin finagolfin ================================================ FILE: .pep8 ================================================ [flake8] filename = *.py,bootstrap max-line-length = 80 ================================================ FILE: .swift-version ================================================ 6.2.3 ================================================ FILE: .swiftformat ================================================ ## File options --swiftversion 5.9 --exclude .build ## Formatting options # Configure the placement of an extension's access control keyword. --extensionacl on-declarations # #if indenting --ifdef no-indent # Wrap lines that exceed the specified maximum width. --maxwidth 120 # Reposition `let` or `var` bindings within pattern. --patternlet inline # Insert explicit `self` where applicable. --self insert # Mark unused function arguments with `_`. --stripunusedargs unnamed-only # Remove trailing space at end of a line. --trimwhitespace always # Wrap `@attributes` onto a separate line. --funcattributes prev-line --typeattributes prev-line # Use `Void` for type declarations and `()` for values. --voidtype void # Align wrapped function arguments or collection elements. --wraparguments before-first ## Rules # Prefer `&&` over `,` comma in `if`, `guard` or `while` conditions. # Preserve `nil` default value (Optional `var`s are `nil` by default). --disable andOperator,redundantNilInit ================================================ FILE: Benchmarks/Benchmarks/PackageGraphBenchmarks/PackageGraphBenchmarks.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// @_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) import Basics import Benchmark import Foundation import PackageModel @_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) import func PackageGraph.loadModulesGraph import Workspace let benchmarks = { let defaultMetrics: [BenchmarkMetric] if let envVar = ProcessInfo.processInfo.environment["SWIFTPM_BENCHMARK_ALL_METRICS"], envVar.lowercased() == "true" || envVar == "1" { defaultMetrics = .all } else { defaultMetrics = [ .mallocCountTotal, .syscalls, ] } let modulesGraphDepth: Int if let envVar = ProcessInfo.processInfo.environment["SWIFTPM_BENCHMARK_MODULES_GRAPH_DEPTH"], let parsedValue = Int(envVar) { modulesGraphDepth = parsedValue } else { modulesGraphDepth = 150 } let modulesGraphWidth: Int if let envVar = ProcessInfo.processInfo.environment["SWIFTPM_BENCHMARK_MODULES_GRAPH_WIDTH"], let parsedValue = Int(envVar) { modulesGraphWidth = parsedValue } else { modulesGraphWidth = 150 } let packagesGraphDepth: Int if let envVar = ProcessInfo.processInfo.environment["SWIFTPM_BENCHMARK_PACKAGES_GRAPH_DEPTH"], let parsedValue = Int(envVar) { packagesGraphDepth = parsedValue } else { packagesGraphDepth = 10 } // Benchmarks computation of a resolved graph of modules for a package using `Workspace` as an entry point. It runs PubGrub to get // resolved concrete versions of dependencies, assigning all modules and products to each other as corresponding dependencies // with their build triples, but with the build plan not yet constructed. In this benchmark specifically we're loading `Package.swift` // for SwiftPM itself. Benchmark( "SwiftPMWorkspaceModulesGraph", configuration: .init( metrics: defaultMetrics, maxDuration: .seconds(10), thresholds: [ .mallocCountTotal: .init(absolute: [.p90: 12000]), .syscalls: .init(absolute: [.p90: 1600]), ] ) ) { benchmark in let path = try AbsolutePath(validating: #file).parentDirectory.parentDirectory.parentDirectory let workspace = try Workspace(fileSystem: localFileSystem, location: .init(forRootPackage: path, fileSystem: localFileSystem)) for _ in benchmark.scaledIterations { try workspace.loadPackageGraph(rootPath: path, observabilityScope: ObservabilitySystem.NOOP) } } // Benchmarks computation of a resolved graph of modules for a trivial synthesized package using `loadModulesGraph` // as an entry point, which almost immediately delegates to `ModulesGraph.load` under the hood. Benchmark( "SyntheticModulesGraph", configuration: .init( metrics: defaultMetrics, maxDuration: .seconds(10), thresholds: [ .mallocCountTotal: .init(absolute: [.p90: 17000]), .syscalls: .init(absolute: [.p90: 5]), ] ) ) { benchmark in try syntheticModulesGraph( benchmark, modulesGraphDepth: modulesGraphDepth, modulesGraphWidth: modulesGraphWidth ) } // Benchmarks computation of a resolved graph of modules for a synthesized package that includes macros, // using `loadModulesGraph` as an entry point, which almost immediately delegates to `ModulesGraph.load` under // the hood. Benchmark( "SyntheticModulesGraphWithMacros", configuration: .init( metrics: defaultMetrics, maxDuration: .seconds(10), thresholds: [ .mallocCountTotal: .init(absolute: [.p90: 8000]), .syscalls: .init(absolute: [.p90: 5]), ] ) ) { benchmark in try syntheticModulesGraph( benchmark, modulesGraphDepth: modulesGraphDepth, modulesGraphWidth: modulesGraphWidth, includeMacros: true ) } } func syntheticModulesGraph( _ benchmark: Benchmark, modulesGraphDepth: Int, modulesGraphWidth: Int, includeMacros: Bool = false ) throws { // If macros are included, modules are split in three parts: // 1. top-level modules // 2. macros // 3. dependencies of macros let macrosDenominator = includeMacros ? 3 : 1 let libraryModules: [TargetDescription] = try (0..<(modulesGraphWidth / macrosDenominator)).map { i -> TargetDescription in let dependencies = (0.. [TargetDescription.Dependency] in if includeMacros { [.target(name: "Module\(i)"), .target(name: "Macros\(i)")] } else { [.target(name: "Module\(i)")] } } return try TargetDescription(name: "Module\(i)", dependencies: dependencies) } let macrosModules: [TargetDescription] let macrosDependenciesModules: [TargetDescription] if includeMacros { macrosModules = try (0..`, or there is more than one target, the existing expectation for sources apply. * [#6540] Build tool plugins can be used with C-family targets * [#6663] Add `visionOS` as a platform alongside `iOS` and other platforms Swift 5.8 ----------- * [SE-0362] SwiftPM targets can now specify the upcoming language features they require. `Package.swift` manifest syntax has been expanded with an API to include setting `enableUpcomingFeature` and `enableExperimentalFeature` flags at the target level, as specified by [SE-0362]. * [SE-0378] SwiftPM now supports token authentication when interacting with a package registry. The `swift package-registry` command has two new subcommands `login` and `logout` as defined in SE-0378 for adding/removing registry credentials. * [#5810] SwiftPM now allows exposing an executable product that consists solely of a binary target that is backed by an artifact bundle. This allow vending binary executables as their own separate package, independently of the plugins that are using them. * [#5819] Improved handling of offline behavior when a cached version of a dependency exists on disk. SwiftPM will check for network availability status to determine if it should attempt to update a checked version of a dependency, and when offline will use the cached version without an update. * [#5874] In packages using tools version 5.8 or later, Foundation is no longer implicitly imported into package manifests. If Foundation APIs are used, the module needs to be imported explicitly. * [#5892] Added new `--emit-extension-block-symbols` and `--omit-extension-block-symbols` via `swift package dump-symbol-graph`. `--emit-extension-block-symbols` dumps symbol graph files that are extension block symbol format. The default behavior does not change. The `--omit-extension-block-symbols` flag will be used to explicitly disable the feature once the default behavior has been changed to `--emit-extension-block-symbols` in the future. * [#5949] New `--pkg-config-path` option on `build`, `test`, and `run` commands has been introduced as an alternative to passing `PKG_CONFIG_PATH` environment variable. It allows specifying alternative path to search for `.pc` files used by `pkg-config`. Use the option multiple times to specify more than one path. Swift 5.7 ----------- * [SE-0292] SwiftPM can now resolve dependencies from a server compliant with the package registry server API defined in SE-0292. * [SE-0339] Module aliases can now be defined in the package manifest to disambiguate between modules with the same name originating from different packages. * [#4119] Add a `--disable-testable-imports` flag to `swift test` with which tests are built without the testability feature (`import @testable` disabled). * [#4131] Update to manifest API to make it impossible to create an invalid build settings condition. * [#4135] Enable linker dead stripping for all platforms. This can be disabled with `--disable-dead-strip` * [#4168] Update to manifest API to make it impossible to create an invalid target dependency condition. Swift 5.6 ----------- * [SE-0303] Package plugins of the type `buildTool` can now be declared in packages that specify a tools version of 5.6 or later, and can be invoked using the `swift build` command. * [SE-0332] Package plugins of the type `command` can now be declared in packages that specify a tools version of 5.6 or later, and can be invoked using the `swift package` subcommand. * [#3649] Semantic version dependencies can now be resolved against Git tag names that contain only major and minor version identifiers. A tag with the form `X.Y` will be treated as `X.Y.0`. This improves compatibility with existing repositories. * [#3486] Both parsing and comparison of semantic versions now strictly follow the [Semantic Versioning 2.0.0 specification](https://semver.org). The parsing logic now treats the first "-" in a version string as the delimiter between the version core and the pre-release identifiers, _only_ if there is no preceding "+". Otherwise, it's treated as part of a build metadata identifier. The comparison logic now ignores build metadata identifiers, and treats 2 semantic versions as equal if and only if they're equal in their major, minor, patch versions and pre-release identifiers. * [#3641] Soft deprecate `.package(name:, url:)` dependency syntax in favor of `.package(url:)`, given that an explicit `name` attribute is no longer needed for target dependencies lookup. * [#3641] Adding a dependency requirement can now be done with the convenience initializer `.package(url: String, exact: Version)`. * [#3641] Dependency requirement enum calling convention is deprecated in favour of labeled argument: * `.package(url: String, .branch(String))` -> `.package(url: String, branch: String)` * `.package(url: String, .revision(String))` -> `.package(url: String, revision: String)` * `.package(url: String, .exact(Version))` -> `.package(url: String, exact: Version)` * [#3717] Introduce a second version of `Package.resolved` file format which more accurately captures package identity. * [#3890] To increase the security of packages, SwiftPM performs trust on first use (TOFU) validation. The fingerprint of a package is now being recorded when the package is first downloaded from a Git repository or package registry. Subsequent downloads must have fingerpints matching previous recorded values, otherwise it would result in build warnings or failures depending on settings. * [#3670], [#3901], [#3942] Location of configuration files (including mirror file) have changed to accomodate new features that require more robust configuration directories structure, such as SE-0292: * `/.swiftpm/config` (mirrors file) was moved to `/.swiftpm/configuration/mirrors.json`. SwiftPM 5.6 will automatically copy the file from the old location to the new one and emit a warning to prompt the user to delete the file from the old location. * `~/.swiftpm/config/collections.json` (collections file) was moved to `~/.swiftpm/configuration/collections.json`. SwiftPM 5.6 will automatically copy the file from the old location to the new one and emit a warning to prompt the user to delete the file from the old location. Swift 5.5 ----------- * [#3410] In a package that specifies a minimum tools version of 5.5, `@main` can now be used in a single-source file executable as long as the name of the source file isn't `main.swift`. To work around special compiler semantics with single-file modules, SwiftPM now passes `-parse-as-library` when compiling an executable module that contains a single Swift source file whose name is not `main.swift`. * [#3310] Adding a dependency requirement can now be done with the convenience initializer `.package(url: String, revision: String)`. * [#3292] Adding a dependency requirement can now be done with the convenience initializer `.package(url: String, branch: String)`. * [#3280] A more intuitive `.product(name:, package:)` target dependency syntax is now accepted, where `package` is the package identifier as defined by the package URL. * [#3316] Test targets can now link against executable targets as if they were libraries, so that they can test any data structures or algorithms in them. All the code in the executable except for the main entry point itself is available to the unit test. Separate executables are still linked, and can be tested as a subprocess in the same way as before. This feature is available to tests defined in packages that have a tools version of `5.5` or newer. Swift 5.4 ----------- * [#2937] * Improvements `Package` manifests can now have any combination of leading whitespace characters. This allows more flexibility in formatting the manifests. [SR-13566] The Swift tools version specification in each manifest file now accepts any combination of _horizontal_ whitespace characters surrounding `swift-tools-version`, if and only if the specified version ≥ `5.4`. For example, `//swift-tools-version: 5.4` and `// swift-tools-version: 5.4` are valid. All [Unicode line terminators](https://www.unicode.org/reports/tr14/) are now recognized in `Package` manifests. This ensures correctness in parsing manifests that are edited and/or built on many non-Unix-like platforms that use ASCII or Unicode encodings. * API Removal `ToolsVersionLoader.Error.malformedToolsVersion(specifier: String, currentToolsVersion: ToolsVersion)` is replaced by `ToolsVersionLoader.Error.malformedToolsVersionSpecification(_ malformation: ToolsVersionSpecificationMalformation)`. `ToolsVersionLoader.split(_ bytes: ByteString) -> (versionSpecifier: String?, rest: [UInt8])` and `ToolsVersionLoader.regex` are together replaced by `ToolsVersionLoader.split(_ manifest: String) -> ManifestComponents`. * Source Breakages for Swift Packages The package manager now throws an error if a manifest file contains invalid UTF-8 byte sequences. Swift 4.2 --------- * [SE-0209] The `swiftLanguageVersions` property no longer takes its Swift language versions via a freeform Integer array; instead it should be passed as a new `SwiftVersion` enum array. * [SE-0208] The `Package` manifest now accepts a new type of target, `systemLibrary`. This deprecates "system-module packages" which are now to be included in the packages that require system-installed dependencies. * [SE-0201] Packages can now specify a dependency as `package(path: String)` to point to a path on the local filesystem which hosts a package. This will enable interconnected projects to be edited in parallel. * [#1604] The `generate-xcodeproj` has a new `--watch` option to automatically regenerate the Xcode project if changes are detected. This uses the [`watchman`](https://facebook.github.io/watchman/docs/install.html) tool to detect filesystem changes. * Scheme generation has been improved: * One scheme containing all regular and test targets of the root package. * One scheme per executable target containing the test targets whose dependencies intersect with the dependencies of the exectuable target. * [SR-6978] Packages which mix versions of the form `vX.X.X` with `Y.Y.Y` will now be parsed and ordered numerically. * [#1489] A simpler progress bar is now generated for "dumb" terminals. Swift 4.1 --------- * [#1485] Support has been added to automatically generate the `LinuxMain` files for testing on Linux systems. On a macOS system, run `swift test --generate-linuxmain`. * [SR-5918] `Package` manifests that include multiple products with the same name will now throw an error. Swift 4.0 --------- * The generated Xcode project creates a dummy target which provides autocompletion for the manifest files. The name of the dummy target is in format: `PackageDescription`. * `--specifier` option for `swift test` is now deprecated. Use `--filter` instead which supports regex. Swift 3.0 --------- * [SE-0135] The package manager now supports writing Swift 3.0 specific tags and manifests, in order to support future evolution of the formats used in both cases while still allowing the Swift 3.0 package manager to continue to function. * [SE-0129] Test modules now *must* be named with a `Tests` suffix (e.g., `Foo/Tests/BarTests/BarTests.swift`). This name also defines the name of the Swift module, replacing the old `BarTestSuite` module name. * It is no longer necessary to run `swift build` before running `swift test` (it will always regenerates the build manifest when necessary). In addition, it now accepts (and requires) the same `-Xcc`, etc. options as are used with `swift build`. * The `Package` initializer now requires the `name:` parameter. [SE-0129]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0129-package-manager-test-naming-conventions.md [SE-0135]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0135-package-manager-support-for-differentiating-packages-by-swift-version.md [SE-0201]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0201-package-manager-local-dependencies.md [SE-0208]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0208-package-manager-system-library-targets.md [SE-0209]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0209-package-manager-swift-lang-version-update.md [SE-0272]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0272-swiftpm-binary-dependencies.md [SE-0292]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md [SE-0303]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md [SE-0332]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0332-swiftpm-command-plugins.md [SE-0339]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0339-module-aliasing-for-disambiguation.md [SE-0362]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md [SE-0378]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0378-package-registry-auth.md [SE-0386]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0386-package-access-modifier.md [SE-0387]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0387-cross-compilation-destinations.md [SE-0391]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md [SE-0387 proposal text]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0387-cross-compilation-destinations.md#swift-sdk-installation-and-configuration [SE-0458]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md [SR-5918]: https://bugs.swift.org/browse/SR-5918 [SR-6978]: https://bugs.swift.org/browse/SR-6978 [SR-13566]: https://bugs.swift.org/browse/SR-13566 [#1485]: https://github.com/swiftlang/swift-package-manager/pull/1485 [#1489]: https://github.com/swiftlang/swift-package-manager/pull/1489 [#1604]: https://github.com/swiftlang/swift-package-manager/pull/1604 [#2937]: https://github.com/swiftlang/swift-package-manager/pull/2937 [#3280]: https://github.com/swiftlang/swift-package-manager/pull/3280 [#3292]: https://github.com/swiftlang/swift-package-manager/pull/3292 [#3310]: https://github.com/swiftlang/swift-package-manager/pull/3310 [#3316]: https://github.com/swiftlang/swift-package-manager/pull/3316 [#3410]: https://github.com/swiftlang/swift-package-manager/pull/3410 [#3486]: https://github.com/swiftlang/swift-package-manager/pull/3486 [#3641]: https://github.com/swiftlang/swift-package-manager/pull/3641 [#3649]: https://github.com/swiftlang/swift-package-manager/pull/3649 [#3670]: https://github.com/swiftlang/swift-package-manager/pull/3670 [#3717]: https://github.com/swiftlang/swift-package-manager/pull/3717 [#3890]: https://github.com/swiftlang/swift-package-manager/pull/3890 [#3901]: https://github.com/swiftlang/swift-package-manager/pull/3901 [#3942]: https://github.com/swiftlang/swift-package-manager/pull/3942 [#4119]: https://github.com/swiftlang/swift-package-manager/pull/4119 [#4131]: https://github.com/swiftlang/swift-package-manager/pull/4131 [#4135]: https://github.com/swiftlang/swift-package-manager/pull/4135 [#4168]: https://github.com/swiftlang/swift-package-manager/pull/4168 [#5728]: https://github.com/swiftlang/swift-package-manager/pull/5728 [#5810]: https://github.com/swiftlang/swift-package-manager/pull/5810 [#5819]: https://github.com/swiftlang/swift-package-manager/pull/5819 [#5874]: https://github.com/swiftlang/swift-package-manager/pull/5874 [#5949]: https://github.com/swiftlang/swift-package-manager/pull/5949 [#5892]: https://github.com/swiftlang/swift-package-manager/pull/5892 [#5966]: https://github.com/swiftlang/swift-package-manager/pull/5966 [#6060]: https://github.com/swiftlang/swift-package-manager/pull/6060 [#6067]: https://github.com/swiftlang/swift-package-manager/pull/6067 [#6111]: https://github.com/swiftlang/swift-package-manager/pull/6111 [#6114]: https://github.com/swiftlang/swift-package-manager/pull/6114 [#6144]: https://github.com/swiftlang/swift-package-manager/pull/6144 [#6294]: https://github.com/swiftlang/swift-package-manager/pull/6294 [#6185]: https://github.com/swiftlang/swift-package-manager/pull/6185 [#6200]: https://github.com/swiftlang/swift-package-manager/pull/6200 [#6276]: https://github.com/swiftlang/swift-package-manager/pull/6276 [#6540]: https://github.com/swiftlang/swift-package-manager/pull/6540 [#6663]: https://github.com/swiftlang/swift-package-manager/pull/6663 [#7010]: https://github.com/swiftlang/swift-package-manager/pull/7010 [#7101]: https://github.com/swiftlang/swift-package-manager/pull/7101 [#7118]: https://github.com/swiftlang/swift-package-manager/pull/7118 [#7201]: https://github.com/swiftlang/swift-package-manager/pull/7201 [#7202]: https://github.com/swiftlang/swift-package-manager/pull/7202 [#7507]: https://github.com/swiftlang/swift-package-manager/pull/7507 [#7530]: https://github.com/swiftlang/swift-package-manager/pull/7530 [#7535]: https://github.com/swiftlang/swift-package-manager/pull/7535 [#7722]: https://github.com/swiftlang/swift-package-manager/pull/7722 [#7741]: https://github.com/swiftlang/swift-package-manager/pull/7741 [#7813]: https://github.com/swiftlang/swift-package-manager/pull/7813 [#8301]: https://github.com/swiftlang/swift-package-manager/pull/8301 [#8314]: https://github.com/swiftlang/swift-package-manager/pull/8314 ================================================ FILE: CMakeLists.txt ================================================ # This source file is part of the Swift open source project # # Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for Swift project authors if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) endif() cmake_minimum_required(VERSION 3.24) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) project(SwiftPM LANGUAGES C Swift) option(BUILD_SHARED_LIBS "Build shared libraries by default" YES) option(FIND_PM_DEPS "Search for all external Package Manager dependencies" YES) option(SwiftPM_ENABLE_RUNTIME "Build the runtime" YES) set(CMAKE_Swift_LANGUAGE_VERSION 5) set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) set(CMAKE_POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}) if(FIND_PM_DEPS) find_package(SwiftSystem CONFIG REQUIRED) find_package(TSC CONFIG REQUIRED) find_package(LLBuild CONFIG) if(NOT LLBuild_FOUND) find_package(LLBuild REQUIRED) endif() find_package(ArgumentParser CONFIG REQUIRED) find_package(SwiftDriver CONFIG REQUIRED) find_package(SwiftCollections CONFIG REQUIRED) find_package(SwiftASN1 CONFIG REQUIRED) find_package(SwiftCertificates CONFIG REQUIRED) find_package(SwiftCrypto CONFIG REQUIRED) find_package(SwiftToolsProtocols CONFIG REQUIRED) find_package(SwiftBuild CONFIG REQUIRED) endif() find_package(dispatch QUIET) find_package(Foundation QUIET) find_package(SQLite3 REQUIRED) # Enable `package` modifier for the whole package. add_compile_options("$<$:SHELL:-package-name swift_package_manager>") if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD) link_directories(/usr/local/lib) endif() add_subdirectory(BuildSupport/SwiftSyntax) add_subdirectory(Sources) add_subdirectory(cmake/modules) ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Swift Package Manager There are several types of contributions one can make. Bug fixes, documentation and enhancements that do not materially change the user facing semantics of Swift Package Manager should be submitted directly as PR. Larger changes that do materially change the semantics of Swift Package Manager (e.g. changes to the manifest format or behavior) are required to go through [Swift Evolution Process](https://github.com/swiftlang/swift-evolution/blob/main/process.md). To see how previous evolution decisions for SwiftPM have been made and have some direction for the development of future features please check out the [Community Proposals](https://forums.swift.org/tag/packagemanager). For more information about making contributions to the Swift project in general see [Swift Contribution Guide](https://swift.org/contributing/). ## Reporting issues Issues are tracked using [SwiftPM GitHub Issue Tracker](https://github.com/swiftlang/swift-package-manager/issues). Fill the following fields: * `Title`: A one line summary of the problem you're facing. * `Description`: The complete description of the problem. Be specific. * `Expected behavior`: How you expect SwiftPM to behave. * `Actual behavior` : What actually happens. * `Steps to reproduce`: Be specific, provide steps to reproduce the bug. * `Swift Package Manager version/commit hash` : With which version are you testing. * `Actual behavior` : What actually happens. * `Swift & OS version` : (output of `swift --version && uname -a`). Please include a minimal example package which can reproduce the issue. The sample package can be attached with the report or you can include the URL of the package hosted on places like GitHub. Also, include the verbose logs by adding `--verbose` or `-v` after a subcommand. For example: $ swift build --verbose $ swift package update --verbose If the bug is with a generated Xcode project, include how the project was generated and the Xcode build log. ## Setting up the development environment First, clone a copy of SwiftPM code from https://github.com/swiftlang/swift-package-manager. If you are preparing to make a contribution you should fork the repository first and clone the fork which will make opening Pull Requests easier. See "Creating Pull Requests" section below. SwiftPM is typically built with a pre-existing version of SwiftPM present on the system, but there are multiple ways to setup your development environment: ### Using Xcode (Easiest) 1. Install Xcode from [https://developer.apple.com/xcode](https://developer.apple.com/xcode) (including betas!). 2. Verify the expected version of Xcode was installed. 3. Open SwiftPM's `Package.swift` manifest with Xcode. 4. Use Xcode to inspect, edit, and build the code. 5. Select the `SwiftPM-Package` scheme to run the tests from Xcode. Note that the `SwiftPM-Package` should be built prior to running any other schemes. This is so the `PackageDescription` module can be built and cached for use. ### Using the Command Line If you are using macOS and have Xcode installed, you can use Swift from the command line immediately. If you are not using macOS or do not have Xcode installed, you need to download and install a toolchain. #### Installing a toolchain 1. Download a toolchain from https://swift.org/download/ 2. Install it and verify the expected version of the toolchain was installed: **macOS** ```bash $> export TOOLCHAINS=swift $> xcrun --find swift /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swift $> swift package --version Swift Package Manager - Swift 5.3.0 $> swift --version Apple Swift version 5.3 ``` **Linux** ```bash $> export PATH=/path/to/swift-toolchain/usr/bin:"${PATH}" $> which swift /path/to/swift-toolchain/usr/bin/swift $> swift package --version Swift Package Manager - Swift 5.3.0 $> swift --version Apple Swift version 5.3 ``` Alternatively, there are tools like [swiftly](https://github.com/swiftlang/swiftly) that can install and manage toolchains automatically. This repository has a file called `.swift-version` that will keep swiftly at the current recommended version of the toolchain for best results. The `swiftly install` command ensures that SwiftPM's in-use toolchain is installed on your system and ready for you to do your development work with the usual swift commands. ```bash swiftly install swift build swift test ``` ## Developing in the Linux devcontainer SwiftPM includes a devcontainer configuration that allows you to develop in a containerized environment with VS Code. This approach provides a consistent development environment with all necessary dependencies pre-installed, regardless of your host operating system. ### Prerequisites 1. Install [Visual Studio Code](https://code.visualstudio.com/) 2. Install the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) for VS Code 3. Install [Docker](https://www.docker.com/products/docker-desktop/) on your system ### Opening the Project in a Container 1. Clone the SwiftPM repository (if you haven't already) 2. Open the SwiftPM folder in VS Code 3. VS Code will detect the devcontainer configuration and prompt you to "Reopen in Container". Click this button to start building and opening the container - Alternatively, you can press `F1`, type "Dev Containers: Reopen in Container", and press Enter 4. Wait for the container to build and initialize (this may take a few minutes the first time) ### What's Included in the Dev Container The SwiftPM devcontainer is based on the `swiftlang/swift:nightly-main` Docker image and includes: - Swift nightly build from the main branch - Git - Common development utilities - VS Code Swift extension for syntax highlighting and language support - Debugging support with LLDB ### Building and Testing in the Container Once you've opened the project in VS Code, choose `> Dev Containers: Build and Reopen in Container` from the command pallete. Once the container finishes building it will open and you can develop as if you are on Linux using VS Code. All the commands described in the "Local Development" section below will work in the container environment. ## Local Development With a Swift toolchain installed and the SwiftPM code cloned, you are ready to make changes and test them locally. ### Building ```bash $> swift build ``` A successful build will create a `.build/` directory with the following approximate structure: ``` artifacts checkouts debug repositories x86_64-apple-macosx ``` Binary artifacts are located in `x86_64-apple-macosx/` when building on macOS, or the equivalent on other architectures and operating systems. These binaries can be used to test the code modification. For example, to test the `swift package init` and `swift build` commands from the new SwiftPM artifacts in `.build/`: ```bash $> cd /tmp && mkdir hello && cd hello $> /path/to/swiftpm/.build/x86_64-apple-macosx/debug/swift-package init $> /path/to/swiftpm/.build/x86_64-apple-macosx/debug/swift-build ``` ### Testing ```bash $> swift test ``` to run a single test: ```bash $> swift test --filter PackageGraphTests.DependencyResolverTests/testBasics ``` Or another example, to run tests for the test targets BuildTests and WorkspaceTests, but skip some test cases: ```bash $> swift test --filter BuildTests --skip BuildPlanTests --filter WorkspaceTests --skip InitTests ``` To run the performance tests, enable them with an ENV variable: ```bash $> export TSC_ENABLE_PERF_TESTS=1 $> swift test -c release --filter PerformanceTests ``` ### The bootstrap script The bootstrap script is designed for building SwiftPM on systems that do not have Xcode or a toolchain installed. It is used on bare systems to bootstrap the Swift toolchain (including SwiftPM), and as such not typically used outside the Swift team. The bootstrap script requires having [CMake](https://cmake.org/) and [Ninja](https://ninja-build.org/) installed. Please refer to the [_Get Started_ guide](https://github.com/apple/swift/blob/main/docs/HowToGuides/GettingStarted.md#installing-dependencies) on the Swift project repository for installation instructions. Clone the following repositories beside the SwiftPM directory: 1. [swift-argument-parser] and check out tag with the [latest version](https://github.com/apple/swift-argument-parser/tags). For example, if the latest tag is 0.4.3: ```sh $> git clone https://github.com/apple/swift-argument-parser --branch 0.4.3 ``` 2. [swift-llbuild] as llbuild ```sh $> git clone https://github.com/apple/swift-llbuild llbuild ``` > Note: Make sure the directory for llbuild is called "llbuild" and not "swift-llbuild". 3. [swift-tools-support-core] ```sh $> git clone https://github.com/apple/swift-tools-support-core ``` 4. [swift-driver] ```sh $> git clone https://github.com/apple/swift-driver ``` 5. [swift-system] and check out tag with the [latest version](https://github.com/apple/swift-system/tags). For example, if the latest tag is 1.0.0: ```sh $> git clone https://github.com/apple/swift-system --branch 1.0.0 ``` 6. [swift-collections] and check out tag with the [latest version](https://github.com/apple/swift-collections/tags). For example, if the latest tag is 1.0.1: ```sh $> git clone https://github.com/apple/swift-collections --branch 1.0.1 ``` 7. [swift-crypto] and check out tag with the [latest version](https://github.com/apple/swift-crypto/tags). For example, if the latest tag is 2.3.0: ```sh $> git clone https://github.com/apple/swift-crypto --branch 2.3.0 ``` 8. [swift-asn1] ```sh $> git clone https://github.com/apple/swift-asn1 ``` 9. [swift-certificates] ```sh $> git clone https://github.com/apple/swift-certificates ``` 10. [swift-syntax] ```sh $> git clone https://github.com/swiftlang/swift-syntax ``` 11. [swift-toolchain-sqlite] ```sh $> git clone https://github.com/swiftlang/swift-toolchain-sqlite ``` [swift-argument-parser]: https://github.com/apple/swift-argument-parser [swift-collections]: https://github.com/apple/swift-collections [swift-driver]: https://github.com/apple/swift-driver [swift-llbuild]: https://github.com/apple/swift-llbuild [swift-system]: https://github.com/apple/swift-system [swift-tools-support-core]: https://github.com/apple/swift-tools-support-core [swift-crypto]: https://github.com/apple/swift-crypto [swift-asn1]: https://github.com/apple/swift-asn1 [swift-certificates]: https://github.com/apple/swift-certificates [swift-toolchain-sqlite]: https://github.com/swiftlang/swift-toolchain-sqlite [swift-syntax]: https://github.com/swiftlang/swift-syntax #### Building ```bash $> Utilities/bootstrap build ``` See "Using the Command Line / Building" section above for more information on how to test the new artifacts. #### Testing ```bash $> Utilities/bootstrap test ``` ## Working with Docker to build and test for Linux When developing on macOS and need to test on Linux, install [Docker](https://www.docker.com/products/docker-desktop) and [Docker compose](https://docs.docker.com/compose/install/) and use the following docker compose commands: Prepare the underlying image with the selected Ubuntu and Swift versions: ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ build ``` Start an interactive shell session: ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ run --rm shell ``` Build SwiftPM (using the pre-installed SwiftPM version). ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ run --rm build ``` Test SwiftPM (using the pre-installed SwiftPM version). ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ run --rm test ``` Build SwiftPM using the bootstrap script: ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ run --rm bootstrap-build ``` Test SwiftPM using the bootstrap script: ```bash docker-compose \ -f Utilities/docker/docker-compose.yaml \ -f Utilities/docker/docker-compose...yaml \ run --rm bootstrap-test ``` Note there are several Linux and Swift versions options to choose from, e.g.: `docker-compose.1804.53.yaml` => Ubuntu 18.04, Swift 5.3 `docker-compose.2004.54.yaml` => Ubuntu 20.04, Swift 5.4 `docker-compose.2004.main.yaml` => Ubuntu 20.04, Swift nightly ## Creating Pull Requests 1. Fork: https://github.com/swiftlang/swift-package-manager 2. Clone a working copy of your fork 3. Create a new branch 4. Make your code changes 5. If a particular version of the Swift toolchain is needed then update the `.swift-version` file to that version (or use `swiftly use` to update it). 6. Try to keep your changes (when possible) below 200 lines of code. 7. We use [SwiftFormat](https://www.github.com/nicklockwood/SwiftFormat) to enforce code style. Please install and run SwiftFormat before submitting your PR, ideally isolating formatting changes only to code changed for the original goal of the PR. This will keep the PR diff smaller. 8. Commit (include the Radar link or GitHub issue id in the commit message if possible and a description your changes). Try to have only 1 commit in your PR (but, of course, if you add changes that can be helpful to be kept aside from the previous commit, make a new commit for them). 9. Push the commit / branch to your fork 10. Make a PR from your fork / branch to `apple: main` 11. While creating your PR, make sure to follow the PR Template providing information about the motivation and highlighting the changes. 12. Reviewers are going to be automatically added to your PR 13. Pull requests will be merged by the maintainers after it passes CI testing and receives approval from one or more reviewers. Merge timing may be impacted by release schedule considerations. By submitting a pull request, you represent that you have the right to license your contribution to Apple and the community, and agree by submitting the patch that your contributions are licensed under the [Swift license](https://swift.org/LICENSE.txt). After a change is known not to cause regressions in the `main` branch, it may be considered for cherry-picking to the latest release branch depending on the release schedule. Cherry-picks require [a specific template to be followed](https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md) in PR description that consolidates information about the change necessary for inclusion in the release branch and provides risk evaluation for nominating the change. ## Continuous Integration SwiftPM uses [swift-ci](https://ci.swift.org) infrastructure for its continuous integration testing. The bots can be triggered on pull-requests if you have commit access. Otherwise, ask one of the code owners to trigger them for you. This is **required** before a pull-request can be merged. To run just the self-hosted test suite (faster turnaround times so it can be used to get quick feedback) use: ``` @swift-ci please test self hosted ``` To run the windows self-hosted suite, use: ``` @swift-ci please test self hosted windows ``` To run the swift toolchain test suite including SwiftPM use: ``` @swift-ci please test ``` To run the swift toolchain test suite against a specific platform use one of the following: ``` @swift-ci please test macos @swift-ci please test linux @swift-ci please test windows ``` To run package compatibility test suite (validates we do not break 3rd party packages) use: ``` @swift-ci please test package compatibility ``` ## Generating Documentation SwiftPM uses [DocC](https://github.com/apple/swift-docc) to generate some of its documentation (currently only the `PackageDescription` module). Documentation can be built using Xcode's GUI (Product → Build Documentation or `⌃⇧⌘D`) or manually: 1. Build and dump the symbol graph metadata used to generate the documentation: ``` swift package dump-symbol-graph ``` 2. Generate the documentation and start a local preview server to review your changes: ``` xcrun docc preview Sources/PackageDescription/PackageDescription.docc --additional-symbol-graph-dir .build/*/symbolgraph/ ``` Note that this may generate documentation for multiple modules — the preview link for PackageDescription will typically be: http://localhost:8000/documentation/packagedescription ## Advanced ### Using Custom Swift Compilers SwiftPM needs the Swift compiler to parse `Package.swift` manifest files and to compile Swift source files. You can use the `SWIFT_EXEC` and `SWIFT_EXEC_MANIFEST` environment variables to control which compiler to use for these operations. `SWIFT_EXEC_MANIFEST`: This variable controls which compiler to use for parsing `Package.swift` manifest files. The lookup order for the manifest compiler is: `SWIFT_EXEC_MANIFEST`, `swiftc` adjacent to the `swiftpm` binaries, then `SWIFT_EXEC` `SWIFT_EXEC`: This variable controls which compiler to use for compiling Swift sources. The lookup order for the sources' compiler is: `SWIFT_EXEC`, then `swiftc` adjacent to `swiftpm` binaries. This is also useful for Swift compiler developers when they want to use a debug compiler with SwiftPM. ```bash $> SWIFT_EXEC=/path/to/my/built/swiftc swift build ``` ### Overriding the Path to the Runtime Libraries SwiftPM computes the path of its runtime libraries relative to where it is installed. This path can be overridden by setting the environment variable `SWIFTPM_CUSTOM_LIBS_DIR` to a directory containing the libraries, or a colon-separated list of absolute search paths. SwiftPM will choose the first path which exists on disk. If none of the paths are present on disk, it will fall back to built-in computation. ### Making changes in TSC targets SwiftPM uses [Tools Support Core](https://github.com/apple/swift-tools-support-core) (aka TSC) for many of its general purpose utilities. Changes in SwiftPM often require changes in TSC first. To coordinate changes, open a PR against TSC first, then a second one against SwiftPM pulling the correct TSC version. ## Community and Support If you want to connect with the Swift community you can: * Use Swift Forums: [https://forums.swift.org/c/development/SwiftPM](https://forums.swift.org/c/development/SwiftPM) * Contact the CODEOWNERS: https://github.com/swiftlang/swift-package-manager/blob/main/CODEOWNERS ## Additional resources * `Swift.org` Contributing page [https://swift.org/contributing/](https://swift.org/contributing/) * License [https://swift.org/LICENSE.txt](https://swift.org/LICENSE.txt) * Code of Conduct [https://swift.org/community/#code-of-conduct](https://swift.org/community/#code-of-conduct) ## Troubleshooting * If during `swift build` you encounter this error: ```bash /../apple-repos/swift-package-manager/.build/checkouts/swift-driver/Sources/SwiftDriver/Explicit Module Builds/InterModuleDependencyGraph.swift:102:3: error: unknown attribute '_spi' @_spi(Testing) public var isFramework: Bool ^ ``` Make sure you are using SwiftPM 5.3 ```bash $> swift package --version Swift Package Manager - Swift 5.3.0 ``` * If during `swift build` you encounter this error: ```bash /../swift-package-manager/Sources/PackageLoading/Target+PkgConfig.swift:84:36: error: type 'PkgConfigError' has no member 'prohibitedFlags' error = PkgConfigError.prohibitedFlags(filtered.unallowed.joined(separator: ", ")) ~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ ``` Make sure to update your TSC (Tools Support Core): ```bash $> swift package update ``` Alternatively, if you are using Xcode, you can update to the latest version of all packages: **Xcode App** > *File* > *Swift Packages* > *Update to Latest Package Versions* ================================================ FILE: CONTRIBUTORS.txt ================================================ For the purpose of tracking copyright, this is the list of individuals and organizations who have contributed to Swift Package Manager. For employees of an organization/company where the copyright of work done by employees of that company is held by the company itself, only the company needs to be listed here. ## COPYRIGHT HOLDERS - Apple Inc. (all contributors with '@apple.com') ### Contributors - 3405691582 - A Koufatzis - AG - Aaron Crespo - Abdulhakim Ajetunmobi - Adam Cox - Adam Thayer - Adam Yanalunas - Ahmad Yasser <42544598+ahmdyasser@users.noreply.github.com> - Alastair Houghton - Alejandro Alonso - Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com> - Aleksey Mashanov - Aleph Retamal - Alex Blewitt - Alex Hoppen - Alex Lorenz - Alex Migicovsky - Alexander Sandberg - Alexey Ivashko - Alexis Laferrière - Anders Bertelrud - Andreas Koslowski - Andrew Carter - Andrew Clark - Angelo Villegas - Anh Pham - Ankit Aggarwal - Anton - Anton Pogonets - Antonio Mayorga - Argyrios Kyrtzidis - Ariel Elkin <1756909+arielelkin@users.noreply.github.com> - Aris Sarris <78614622+a-sarris@users.noreply.github.com> - Arjun Nayini - Arnold Schwaighofer - Artem Chikin - Artemiy Sobolev - Arthur Ariel Sabintsev - Atul Sowani - Aura Lily Vulcano - Austin - BJ Homer - Bastian Rinsche - Ben Barham - Ben Chatelain - Ben Cohen - Ben Kennedy - Ben Langmuir - Ben Rimmington - Ben Waldie - BenedictSt <52418145+BenedictSt@users.noreply.github.com> - Benedikt Terhechte - Benjamin Herzog - Benjamin Scholtysik - Bhargav - Bhargav Gurlanka - Bob Flanagan <89808793+bflanagan-apple@users.noreply.github.com> - Bob Wilson - Boris Bielik - Boris Buegling - BossJue <240778488@qq.com> - Bouke Haarsma - Braden Scothern - Brandon Titus - Brent Royal-Gordon - Brian Croom - Brian Gesiak - Brian Pratt - Calvin Hill - Chris Lattner - Chris Willmore - Chris Zielinski - Christian Rishøj - Christopher Goulet - Clay Ellis - Colin Cornaby - Connor Wakamo - Conrad Kramer - Cory Benfield - Dadoum <24679280+Dadoum@users.noreply.github.com> - Damiaan Dufaux - Dan Liew - Dan Mendoza - Dan Zheng - Daniel Duan - Daniel Dunbar - Daniel Firsht - Daniel Rodríguez Troitiño - Danny Mösch - Dario Rexin - Dave Abrahams - Dave Weston - David Bryson - David Farler - David Hart - David M. Bryson - David Nadoba - David Ungar - Denis Morozov - Derik Ramirez - Diggory Laycock - Dima Hutsuliak - Ding Ye - Dmitri Gribenko - Dmitriy Borovikov - Dmytro Mishchenko - Doug Gregor - Drew Crawford - Ed Arenberg - Edan Lichtenstein - Edward Huynh - Edward Valentini - Egor Zhdan - Egor Zhdan - Eli Geller - Ellie Shin - Eric Dudiak - Eric Jensen - Eric Miotto <1094986+edymtt@users.noreply.github.com> - Erik Eckstein - Erwin Mazariegos - Etan1 - Euan Harris - Eugene Tulushev - Evan Wilde - Example Example - Fabian Cañas - Federico Bucchi - Federico Zanetello - Florian Friedrich - Florian Reinhart - Franz Busch - Gaushik M.R - Gavin Eadie - George - George Barnett - Glenn 'devalias' Grant - Grzegorz Miłoś - Guillermo Ignacio Enriquez Gutierrez - Gwen Mittertreiner - Harlan Haskins - Hayden McCabe - Helge Hess - Honza Dvorsky - Husein Kareem - Ian Partridge - Ilya Kulakov - Ismael Vilas Boas - Itai Ferber - Iulian Onofrei <5748627+revolter@users.noreply.github.com> - IxhenHasaniQM <94111216+IxhenHasaniQM@users.noreply.github.com> - J. Cheyo Jimenez - J.D. Healy - JP Simard - JPMartha - Jacob Bandes-Storch - Jacopo Andrea Giola - Jader Feijo - Jake Heiser - Jake Petroules - Jane Manchun Wong - Jason Choi - Jason R Tibbetts <708510+jrtibbetts@users.noreply.github.com> - Jason Wray - Jeff Kelley - Jeff Lett <2142301+jeffctown@users.noreply.github.com> - Jeremiah Njoroge - Jeremy David Giesbrecht - Jhonny Bill - Jimmy Arts - Jobins John - Joe Groff - Joe Heck - Joe Smith - Joe Susnick - Johannes Plunien - Johannes Weiss - John Holdsworth - John McCall - Jonas Schwartz - Jonathan Grynspan - Jordan Rose - Jose Marcelino - Joseph Heck - Josh Parnham - Joshua Emmons - Joshua Peek - Julian Grosshauser - Justas Brazauskas - Justin Jia - Justin Oroz - Justus Kandzi - Kaan Dedeoglu - Karl <5254025+karwa@users.noreply.github.com> - Karoy Lorentey - Kazumasa Wakamori - Keith Smiley - Kenta Kubo <601636+kkk669@users.noreply.github.com> - Kilian Koeltzsch - Kit Langton - Kohki Miki - Kostiantyn Koval - Kyle <43724855+Kyle-Ye@users.noreply.github.com> - Kyle - Kyle Jessup - Kyle Rokita - Lei Zhang - Lev Walkin - Lily Vulcano - Ling Wang - Liu Liu - Lukas Stabe - Luke Lau - MIZUNO Hiroki - Marcin Iwanicki - Marcin Krzyzanowski - Marco Eidinger - Marin Todorov - Mark Brownsword - Mark Lacey - Martin Waitz - Matt Diephouse - Matt Seaman - Matthew Seaman - Matthias Bartelmeß - Mattt Thompson - Max Desiatov - Max Desiatov - Max Howell - Max Liberman - Max Moiseev - Max Obermeier - Michael Gottesman - Michael Henson - Michael Ilseman - Michael McGuire - Michael Munday - Michael Vendivel - Miguel A. Perez Ojito <54909066+miggs597@users.noreply.github.com> - Miguel Salinas - Mike Ash - Mike Ferris - Mishal Awadah - Mishal Shah - Morten Bjerg Gregersen - Muhammed Yavuz Nuzumlali - Nate Cook - Nathan Hawes - Nathan Lanza - Natik Gadzhi - Neil Jones - Nicholas Maccharoli - Nick Cooke <36927374+ncooke3@users.noreply.github.com> - Nikola Lajic - Noah Gilmore - NobodyNada - Norio Nomura - Noé Froidevaux - Oliver Chick - Oliver Epper <45991777+oliverepper@users.noreply.github.com> - Orta - Ostap Taran - Owen Voorhees - P W - Patrick Balestra - Patrick Metcalfe - Paul Nettle - Paulo Faria - Pavel Yaskevich - Pedro José Pereira Vieito - Peteous - Peter Adams - Peter Matta - Philippe Hausler - Prachi - Pritesh Nandgaonkar - Quinn McHenry - Rahul Malik - Randy Becker <81446220+randy-becker@users.noreply.github.com> - Rauhul Varma - Renzo Crisóstomo - Rich Ellis - Rick Ballard - Rintaro Ishizaki - Ritwik Gupta - Robert Widmann - Romain Pouclet - Roman Levenstein - Ron Baker - Ron Olson - Runar - Runar Hummelsund - Ryan Lovelett - Ryan Wilson - Ryosuke Hayashi - Saleem Abdulrasool - Saleem Abdulrasool - Samuel Giddins - Sebastian Grail - Sergio Campamá - Sheikh Bayazid <44797746+sheikhbayazid@users.noreply.github.com> - Slava Pestov - Stan Stadelman - Stephen Brown - Stephen Celis - Steve Barron - Steve Moser - Steven Sherry - Stuart Montgomery - Sven A. Schmidt - Swiftfuchs - TaborKelly - Ted Kremenek - Thi - Thiago Holanda - Thomas Grapperon <35562418+tgrapperon@users.noreply.github.com> - Thomas Roughton - Thomas Van Lenten - Tiago Martinho - Tianyu Wang - Tim Condon <0xTim@users.noreply.github.com> - Tim Gymnich - Tobias Landsberg - Tokuriku - Tom Doron - Tomasz Bąk - Tomoya Kose - Toni Suter - Tony Arnold - Tony Parker - TornjV - Trevör Anne Denise - Tyler Stromberg - Török Zsolt - Vadim Eisenberg - Vadim Smal - Valeriy Van - Vasilica Costescu - Vatsal Manot - Viktor Szilárd Simkó - Vincent Esche - Vivian Kong - Vladislav Alekseev - WFT - Wang Binbin - William Dillon - William Entriken - Wojtek Czekalski - Wowbagger & his liquid lunch <55120045+WowbaggersLiquidLunch@users.noreply.github.com> - Xavier Matos - Xiaodi Wu <13952+xwu@users.noreply.github.com> - Xiaodi Wu - Xing He <17washabi@gmail.com> - YOCKOW - YOUNG MO SONG <77970826+mooyoung2309@users.noreply.github.com> - YR Chen - Yan Li - Yannick Heinrich - Yim Lee - Yonas Kolb - Yoshimasa Niwa - Yu Ao - Yu Su - YuAo - Yuta Koshizawa - Yuta Saito - Zsolt Kiraly - adamnemecek - aemino - akashhansda <99724223+akashhansda@users.noreply.github.com> - aniket sharma - badim - buttaface - dudiak - eeckstein - elsh - emlai - freak4pc - futbalguy - futurejones - gibachan - giginet - givip - goloveychuk - hotchemi - jhonnybillm - jp_pancake - k-kohey - linqingmo - naru - nate-chandler <46721658+nate-chandler@users.noreply.github.com> - nathan spindel - nonsensery - onevcat - pcbeard - prachipai - samding01 - sarveshtamba - seabaylea - sora0077 - swift-ci - swiftix - t_hayashi - thecb4 - twobitunicorn - uhooi - yonihemi - Łukasz Mróz - Šimon Javora - ✪ vi4m Marcin Kliks - 冀卓疌 <55120045+WowbaggersLiquidLunch@users.noreply.github.com> **Updating this list** Please do not edit this file manually. It is generated using `./Utilities/generate_contributors_list.sh`. If a name is misspelled or appearing multiple times: add an entry in `./.mailmap` ================================================ FILE: Documentation/Design/EvolutionIdeas.md ================================================ # Swift Package Manager Ideas This is a list of some evolution ideas for the package manager. Once the details of an idea are fleshed out and there is a full proposal, it can be scheduled for the Swift Evolution process. It is important to note that not every idea on this list is guaranteed to become an official feature, and it all depends on where the design discussion leads us. Also, this is not meant to be an exhaustive feature list, if you have an idea for a feature that you think will be a valuable addition to the package manager, feel free to start a discussion about it. If you're interested in participating in a particular evolution idea, please familiarize yourself with the existing discussion on that topic and start participating in the discussion thread of that idea. If a thread doesn't exist for that idea, please start one with a [draft proposal](https://github.com/swiftlang/swift-evolution/blob/main/proposal-templates/0000-swiftpm-template.md) that can be used as a starting point. **Important Note**: This list is not in any particular order. I plan to keep this post updated, but please let me know if you see something out-of-date. ## Mirror and Fork Support You may want an easy way to mirror or fork specific packages in your package graph. This could be useful if you want to make a private customization to a package that you depend on, or even if you just want to override the origin repository of your packages so that you can fetch from a private mirror and not depend on the original repository always being there. Thread: https://forums.swift.org/t/dependency-mirroring-and-forking/13902 Bug: [SR-679](https://bugs.swift.org/browse/SR-679) ## Build Settings Some packages require specific language or linker flags that SwiftPM doesn’t currently support, and some packages may desire other configurable properties as well. We want to have a real, robust "build settings" model for adding these kinds of properties, potentially including conditional settings and fine-grained control over what parts of the package use which property values. Thread: N/A Bug: [SR-3948](https://bugs.swift.org/browse/SR-3948) ## Conditional Dependencies Packages may want to use dependencies that they only use while testing the package. Such dependencies shouldn't take part in dependency resolution process when a package is being used as a dependency. This is also called test-only or development dependencies in other package managers. It is sometimes also required to declare platform-specific dependencies which should only be fetched when a package is being built for a certain platform. This is currently possible using `#if os` checks, but it leads to two problems: 1) it forces a non-declarative syntax in the manifest file, and 2) it causes issues in maintaining the `Package.resolved` file as the dependency is added or removed depending on the platform. Thread: N/A Bug: [SR-883](https://bugs.swift.org/browse/SR-883) ## Resource Support The Swift Package Manager needs a story for how packages should specify their resources to include with products. Thread: N/A Bug: [SR-2866](https://bugs.swift.org/browse/SR-2866) ## Extensible Build Tools Many users want to incorporate a variety of build-time tools into their packages, whether to support a custom language or preprocessor, or to add their own documentation generator or linter. SwiftPM could add extensibility to support tools packages which could bring these steps to the build process. We expect this behavior to greatly enhance our capacity for building complex software packages. One important thing for us to be careful about here is to make sure that all parts of the build process still clearly declare their inputs and outputs to SwiftPM, so that it can make sure that they behave correctly and perform well for incremental and parallel builds. Thread: https://forums.swift.org/t/package-manager-extensible-build-tools/10900 Bug: N/A ## User-defined Template Support It would be nice if users can hook into the init command to add custom templates that they frequently use. Thread: N/A Bug: [SR-7837](https://bugs.swift.org/browse/SR-7837) ## Documentation Generation Support We can leverage SourceKit to extract documentation information from Swift packages that can be further transformed into a developer consumable format like a static HTML website. Thread: N/A Bug: N/A ## Tagging and Publishing Support Today you publish new versions of your package by tagging manually with Git, and you use Git directly to view your published tags. SwiftPM could help automate this process, performing any validation, housekeeping, or auxiliary tasks that might make sense as part of a streamlined and safe publication workflow. Thread: N/A Bug: N/A ## Install/Deploy Command When you’re deploying the product of your package, whether to a server or your local system, it could be helpful for SwiftPM to provide support for automating that process. You may want to configure layout and library linkage aspects of your products for your specific deployment environment, record version information about what your products were built from, and otherwise leverage the context that SwiftPM has about your packages for a seamless deployment experience. Thread: N/A Bug: N/A ## Performance Testing Support Currently, SwiftPM has no support for running performance tests. We need to provide a way to specify performance tests for a package and to run them from the SwiftPM command-line tools. [Here](https://github.com/aciidb0mb3r/swift-evolution/blob/pref-proposal/proposals/xxxx-package-manager-performance-testing.md) is a very old draft proposal that I haven't gotten around to posting for discussion yet. Thread: N/A Bug: [SR-1354](https://bugs.swift.org/browse/SR-1354) ## Support for External Testing Frameworks Currently, SwiftPM only supports writing tests with help of the XCTest testing framework. The community should be able to use any testing framework of their choice to test with SwiftPM. This feature will most likely depend on the proposed extensible build tools feature described [here](https://forums.swift.org/t/package-manager-extensible-build-tools/10900). Thread: N/A Bug: N/A ## Package Index SwiftPM plans to have a real index for Swift packages some day. In addition to defining a namespace for package names and providing easier package discovery, it could even support metrics for quality, such as automated test coverage statistics, or ways to evaluate the trustworthiness of packages that you’re considering using. This will be a large project. Thread: N/A Bug: N/A ## Multi-Package Repository Support Currently the package manager requires that each package live at the root of a Git repository. This means that you can't store multiple packages in the same repository, or develop packages which locate each other in a filesystem-relative manner without relying on Git. We need a proposal for how we would like to support this. Thread: N/A Bug: [SR-3951](https://bugs.swift.org/browse/SR-3951) ## Cross-platform Sandboxing Sandboxing is one way to help prevent `Package.swift` manifest evaluation and builds from escaping out into your system, either accidentally or deliberately. SwiftPM uses macOS's sandboxing technology already, but it would be great to bring this safety to other platforms. Thread: N/A Bug: N/A ## Automatic Semantic Versioning Automatically detecting what semantic version it looks like you should be publishing your changes with could be very helpful for package authors. SwiftPM could do this by analyzing the source code's API to see what has changed and whether the API is backwards-compatible, at least at compile time. Thread: N/A Bug: N/A ## Machine-Editable Package.swift We need an easy way to edit the Package.swift manifest from automated tools, for cases where you don't want users to have to update the Swift code directly. We think that it's possible to provide an API to allow this, probably using [`SwiftSyntax`](https://github.com/swiftlang/swift-syntax). Thread: N/A Bug: N/A ================================================ FILE: Documentation/Design/README.md ================================================ # Swift Package Manager Design Docs Swift Package Manager design is done in open source, and governed by Swift Evolution process. As such, you can find up-to-date Swift Package Manager design docs [in the Swift Evolution repository](https://github.com/swiftlang/swift-evolution/tree/main/proposals). This directory contains documentation on the engineering design decisions and internals of the Swift Package Manager, outside the evolution process. ================================================ FILE: Documentation/Design/SwiftBasedManifestFormat.md ================================================ # Swift-based Manifest Format > **PLEASE NOTE** This document represents the initial proposal for Swift Package Manager, and is provided for historical purposes only. It does not represent the current state or future direction of the project. For current documentation, see the main Swift Package Manager [documentation](../README.md). ## Purpose We need to have some facility for describing additional package metadata, outside of the content in the sources files. This document describes a proposal for using a Swift-based format for this manifest data. ## Motivation The package manager strives to support a "convention based" project structure which is derived from the project files and source code. This approach allows users to primarily focus on authoring their actual software and expect that the tools will assemble it into a product by following sensible defaults. However, packages also have information which cannot naturally be inferred from the project structure. To that end, we need to support some kind of manifest which contains the additional project information. At a high level, the primary purpose of this manifest is to: * Complement the convention based system. The manifest complements the convention based system, by being the one definitive place to add any project metadata that would otherwise require the project to use a custom configuration. The goal is that 80%+ of projects should be able to use only a manifest and the convention based layout. By allowing the manifest to extend and override a few key, carefully picked details of the convention based system, then we allow many more projects to use the system without needing to define complex conventions. * Provide package information in a standard format. There are certain pieces of information which are important enough and common enough that we would like all projects to include, or any projects which do include them to do so in a standardized manner. For example, the license declaration of a project should follow a very standard definition. * Serve as an indicator of a package manager project. Although it is simple, having the manifest exist with a known name at the root of a package serves as an indicator to developers and tools of the type of project and how they are expected to interact with it. * Provide support for programmatic analysis and editing of project structure. The manifest should be machine readable and writeable format. We envision a variety of tools that may want to inspect the contents of packages (for example, to build information for an index) or make automatic edits to the project structure. For example, when introducing a new library dependency via adding an import statement, we would like it if a tool could, after a user prompt, automatically update the manifest to specify the new dependency. ## Proposal We propose to use the Swift language itself to write the manifest. An example of a proposed manifest for a small cross-platform project with several libraries might look something like this: ```swift // This imports the API for declaring packages. import PackageDescription // This declares the package. let package = Package( // The name of the package (defaults to source root directory name). name: "Foo", // The list of targets in the package. targets: [ // Declares the main application. Target( name: "Foo", // Declare the type of application. type: .Tool, // Declare that this target is a published product of the package // (as opposed to an internal library or tool). published: true), // Add information on a support library "CoreFoo" (as found by the // convention based system in CoreFoo/**/*.swift). Target( name: "CoreFoo", depends: [ // The library always depends on the "Utils" target. "Utils", // This library depends on "AccessibilityUtils" on Linux. .Conditional(name: "AccessibilityUtils", platforms: [.Linux]) ]), // NOTE: There is a "Utils" target inferred by the convention based // system, but we don't need to modify it at all because the defaults // were fine. // Declare that the "AccessibilityUtils" target is Linux-specific. Target(name: "AccessibilityUtils", platforms: [.Linux]) ]) ``` *NOTE: this example is for expository purposes, the exact APIs are subject to change.* By writing the manifest in Swift, we ensure a consistent development experience across not only authoring their source code, but also their project metadata. This means developers will have a consistent environment with all of the development conveniences they expect: syntax coloring, code completion, API documentation, and formatting tools. This also ensures that new developers to Swift can focus on learning the language and its tools, not another custom package description format. The package description itself is a declarative definition of information which *augments* the convention based system. The actual package definition that will be used for a project consists of the convention based package definition with the package description applied to override or customize default behaviors. For example, this target description: ```swift Target(name: "AccessibilityUtils", platforms: [.Linux]) ``` *does not* add a new target. Rather, it modifies the existing target `AccessibilityUtils` to specify what platforms it is available for. ## Customization We intend for the declaration package definition to cover 80%+ of the use cases for modifying the convention based system. Nevertheless, there are some kinds of legitimate project structures which are difficult or cumbersome to encode in a purely declarative model. For example, designing a general purpose mechanism to cover all the ways in which users may wish to divide their source code is difficult. Instead, we allow users to interact with the `Package` object using its native Swift APIs. The package declaration in a file may be followed by additional code which configures the package using a natural, imperative, Swifty API. For example, this is an example of a project which uses a custom convention for selecting which files build with unchecked optimizations: ```swift import PackageDescription let package = Package(name: "FTW") // MARK: Custom Configuration // Build all *_unchecked.swift files using "-Ounchecked" for Release mode. for target in package.targets { for source in target.sources { if source.path.hasSuffix("_unchecked.swift") { source.customFlags += [.Conditional("-Ounchecked", mode: .Release) } } } ``` It is important to note that even when using this feature, package manifest still **must be** declarative. That is, the only output of a manifest is a complete description of the package, which is then operated on by the package manager and build tools. For example, a manifest **must not** attempt to do anything to directly interact with the build output. All such interactions must go through a documented, public API vended by the package manager libraries and surfaced via the package manager tools. ## Editor Support The package definition format being written in Swift is problematic for tools that wish to perform automatic updates to the file (for example, in response to a user action, or to bind to a user interface), or for situations where dealing with executable code is problematic. To that end, the declarative package specification portion of the file is "Swift" in the same sense that "JSON is Javascript". The syntax itself is valid, executable, Swift but the tools that process it will only accept a restricted, declarative, subset of Swift which can be statically evaluated, and which can be unambiguously, automatically rewritten by editing tools. We do not intend to define a "standard" syntax for "Swift Object Notation", but we intend to accept a natural restriction of the language which only accepts literal expressions. We do intend to allow the restricted subset to take full advantage of Swift's rich type inference and literal convertible design to allow for a succinct, readable, and yet expressive syntax. The customization section above will *not* be written in this syntax. Instead, the customization section will be clearly demarcated in the file. The leading file section up to the first '// MARK:' will be processed as part of the restricted declarative specification. All subsequent code **must be** honored by tools which only need to consume the output of the specification, and **should be** displayed by tools which present an editor view of the manifest, but **should not** be automatically modified. The semantics of the APIs will be specifically designed to accommodate the expected use case of editor support for the primary data with custom project-specific logic for special cases. All tools which process the package manifest **must** validate that the declaration portion of the specification fits into the restricted language subset, to ensure a consistent user experience. ## Implementation We need to have efficient, programmatic access to the data from the manifest for use in the package manager and associated tools. Additionally, we may wish to use this data in contexts where the executable-code nature of the manifest format is problematic. On the other hand, we also want the file format to properly match the Swift language. To satisfy these two goals, we intend to extract the package metadata from the manifest file by using the Swift parser **and** type checker to parse the leading package declaration portion of the file (not including any customizations made subsequent to the package definition). Once type checked, we will then validate the AST produced for the package description using custom logic which validates that the AST can (a) be parsed into validate model objects without needing to execute code, and (b) is written following the strict format such that it can be automatically modified by editing tools. Tools that do not need to be as strict with the manifest format will be able to load it by using Swift directly to execute the file and then interact with the package definition API to extract the constructed model. ## Discussion We decided to use a Swift-based format for the manifest because we believe it gives developers the best experience for working with and describing their project. The primary alternative we considered was to use a declarative format encoded in a common data format like JSON. Although that would simplify implementation of the tooling around the manifest, it has the downside that users must then learn this additional language, and the development of high quality tools for that (documentation, syntax coloring, parsing diagnostics) isn't aligned with our goal of building great tools for Swift. In contrast, using the Swift language means that we can leverage all of the work on Swift to make those tools great. The decision to use a restricted subset of Swift for the primary package definition is because we believe it is important that common tasks which require the manifest be able to be automated or surfaced via a user interface. We decided to allow additional customization of the package via imperative code because we do not anticipate that the convention based system will be able to cover all possible uses cases. When users need to accommodate special cases, we want them to be able to do so using the most natural and expression medium, by writing Swift code. By explicitly designing in a customization system, we believe we will be able to deliver a higher quality set of core conventions -- there is an escape hatch for the special cases that allows us to focus on only delivering conventions (and core APIs) for the things that truly merit it. A common problem with systems that permit arbitrary customization (especially via a programmatic interface) is that they become difficult to maintain and evolve, since it is hard to predict how developers have taken advantage of the interface. We deal with this by requiring that the manifest only interact with the package and tools through a strict, well defined API. That is, even though we allow developers to write arbitrary code to construct their package, we do not allow arbitrary interactions with the build process. Viewed a different way, the output of *all* manifests **must be** able to be treated as a single declaration specification -- even if part of that specification was programmatically generated. ================================================ FILE: Documentation/PackageRegistry/PackageRegistryUsage.md ================================================ # Package Registry Usage ## Table of Contents * [Getting Started](#getting-started) + [Configuring a registry](#configuring-a-registry) + [Adding a registry package dependency](#adding-a-registry-package-dependency) + [Registry authentication](#registry-authentication) * [Dependency Resolution Using Registry](#dependency-resolution-using-registry) + [Using registry for source control dependencies](#using-registry-for-source-control-dependencies) * [Dependency Download From Registry](#dependency-download-from-registry) + [Checksum TOFU](#checksum-tofu) + [Validating signed packages](#validating-signed-packages) - [Trusted vs. untrusted certificate](#trusted-vs-untrusted-certificate) - [Certificate policies](#certificate-policies) - [Publisher TOFU](#publisher-tofu) * [Publishing to Registry](#publishing-to-registry) + [Package release metadata](#package-release-metadata) + [Package signing](#package-signing) - [Signature formats](#signature-formats) - [Signed contents](#signed-contents) * [Source archive](#source-archive) * [Package release metadata](#package-release-metadata-1) * [Package manifest(s)](#package-manifest-s-) * [SwiftPM Registry Configuration](#swiftpm-registry-configuration) + [Registry-to-scope mappings](#registry-to-scope-mappings) - [`swift package-registry set` subcommand](#-swift-package-registry-set--subcommand) + [Security configuration](#security-configuration) ## Getting Started SwiftPM supports downloading dependencies from any package registry that implements [SE-0292](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md) and the corresponding [service specification](Registry.md). In a registry, packages are identified by [package identifier](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md#package-identity) in the form of `scope.package-name`. ### Configuring a registry A registry can be configured in SwiftPM at two levels: - Project: the registry will be used for packages within the project. Settings are stored in `.swiftpm/configuration/registries.json`. - User: the registry will be used for all projects for the user. Settings are stored in `~/.swiftpm/configuration/registries.json`. One could use the [`swift package-registry set` subcommand](#swift-package-registry-set-subcommand) to assign a registry URL: ```bash $ swift package-registry set https://packages.example.com ``` The above sets registry to `https://packages.example.com` at project level. Pass the `--global` option to set registry at user level: ```bash $ swift package-registry set --global https://packages.example.com ``` The resulting `registries.json` would look something like: ```json { "registries" : { "[default]" : { "url": "https://packages.example.com" } }, "version" : 1 } ``` The JSON key `[default]` means that the registry at `https://packages.example.com` is "unscoped" and will be applied when there is no registry association found for a given scope. In this example, `https://packages.example.com` will be applied to all scopes. ### Adding a registry package dependency A registry package dependency is declared in `Package.swift` using the package identifier. For example: ```swift dependencies: [ .package(id: "mona.LinkedList", .upToNextMajor(from: "1.0.0")), ], ``` SwiftPM will query the registry mapped to a package's scope to resolve and download the appropriate release version. ### Registry authentication If a registry requires authentication, it can be set up by using the [`swift package-registry login` subcommand](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0378-package-registry-auth.md#new-login-subcommand) introduced by SE-0378: ```bash $ swift package-registry login OVERVIEW: Log in to a registry USAGE: swift package-registry login [] [--username ] [--password ] [--token ] [--no-confirm] ARGUMENTS: The registry URL OPTIONS: --username Username --password Password --token Access token --no-confirm Allow writing to netrc file without confirmation ``` Currently, basic and token authentication are supported. Provide the credentials either by setting the corresponding options (i.e., one of username/password or access token) or when prompted: ```bash $ swift package-registry login https://packages.example.com ``` SwiftPM will save the credentials to the operating system's credential store (e.g., Keychain in macOS) or netrc file (which by default is located at `~/.netrc`) and apply them automatically when making registry API requests. ## Dependency Resolution Using Registry Resolving a registry dependency involves these steps: 1. Fetch a package's available versions by calling the [list package releases](Registry.md#41-list-package-releases) API. 2. Compute the dependency graph by [fetching manifest(s) for a package release](Registry.md#43-fetch-manifest-for-a-package-release). 3. Pinpoint the package version to use. ### Using registry for source control dependencies Here is an example of a source control dependency: ```swift dependencies: [ .package(url: "https://github.com/mona/LinkedList", .upToNextMajor(from: "1.0.0")), ], ``` Registry can be used for source control dependencies as well. This is particularly useful when there is a "mixed" graph (i.e., a dependency graph that has both source control and registry dependencies). SwiftPM considers packages with different origins to be different, so if a package is referenced as both a registry (e.g., `mona.LinkedList`) and source control (e.g., `https://github.com/mona/LinkedList`) dependency, they are considered different even though they are the same package, and would result in symbol clashes. SwiftPM can deduplicate packages by performing a [lookup on the source control URL](Registry.md#endpoint-5) (e.g., `https://github.com/mona/LinkedList`) to see if it is associated with any package identifier (e.g., `mona.LinkedList`). One can control if/how SwiftPM should use registry in conjunction with source control dependencies by setting one of these flags: - `--disable-scm-to-registry-transformation` (default): SwiftPM will not transform source control dependency to registry dependency. Source control dependency will be downloaded from its corresponding URL, while registry dependency will be resolved and downloaded using the configured registry (if any). - `--use-registry-identity-for-scm`: SwiftPM will look up source control dependencies in the registry and use their registry identity whenever possible to help deduplicate packages across the two origins. In other words, suppose `mona.LinkedList` is the package identifier for `https://github.com/mona/LinkedList`, then SwiftPM will treat both references in the dependency graph as the same package. - `--replace-scm-with-registry`: SwiftPM will look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible. In other words, SwiftPM will attempt to download a source control dependency from the registry first, and fall back to cloning the source repository iff the dependency is not found in the registry. ## Dependency Download From Registry After a registry dependency is resolved, SwiftPM can [download source archive](Registry.md#endpoint-4) of the computed package version from the registry. ### Checksum TOFU SwiftPM performs checksum TOFU ([trust-on-first-use](https://en.wikipedia.org/wiki/Trust_on_first_use)) on the downloaded source archive. If the archive is downloaded for the first time, SwiftPM [fetches metadata of the package release](Registry.md#endpoint-2) to obtain the expected checksum. Otherwise, SwiftPM compares the checksum with that in local storage (`~/.swiftpm/security/fingerprints/`) saved from previous download. If checksum of the downloaded archive doesn't match the expected or previous value, SwiftPM will fail the build. This can be tuned down from error to warning by setting the build option `--resolver-fingerprint-checking` to `warn` (default is `strict`). Checksum TOFU is also done for manifests downloaded from registry. ### Validating signed packages [SE-0391](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-signing) adds package signing support to SwiftPM. SwiftPM determines if a downloaded archive is signed by checking for presence of the `X-Swift-Package-Signature-Format` and `X-Swift-Package-Signature` headers in the HTTP response. SwiftPM then performs a series of validations based on user's [security configuration](#security-configuration). - If the archive is unsigned, SwiftPM will error/prompt/warn/allow based on the `signing.onUnsigned` configuration. - If the archive is signed, SwiftPM will validate the signature and the signing certificate chain. (see the following sections for details) #### Trusted vs. untrusted certificate A certificate is trusted if it is chained to any root in SwiftPM's trust store, which consists of: - SwiftPM's default trust store, if `signing.includeDefaultTrustedRootCertificates` is `true`. - Custom root(s) in the configured trusted roots directory at `signing.trustedRootCertificatesPath`. Certificates must be DER-encoded. Otherwise, a certificate is untrusted and handled according to the `signing.onUntrustedCertificate` configuration. If user opts to continue with the untrusted certificate, SwiftPM will proceed with the archive as if it were an unsigned package. #### Certificate policies SwiftPM requires all certificates used for package signing to have the "code signing" extended key usage extension. They must also satisfy the core policies from [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280), as implemented by [swift-certificates](https://github.com/apple/swift-certificates). User can configure certificate expiry and revocation check through the `signing.validationChecks.certificateExpiration` and `signing.validationChecks.certificateRevocation` configuration, respectively. Note that revocation check implicitly requires expiry check. An invalid signing certificate would result in SwiftPM rejecting the archive. #### Publisher TOFU Some certificates allow SwiftPM to extract additional information about the signing identity. For packages signed with these certificates, SwiftPM will perform publisher TOFU to ensure the signer remains the same across all versions of the package. The `--resolver-signing-entity-checking` option controls whether publisher mismatch should result in a warning (`warn`) or error (`strict`). Data used by publisher TOFU is saved to `~/.swiftpm/security/signing-entities/`. ## Publishing to Registry [`swift package-registry publish`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#new-package-registry-publish-subcommand) is an all-in-one command for publishing a package release to registry: ```bash OVERVIEW: Publish to a registry USAGE: swift package-registry publish [--url ] [--scratch-directory ] [--metadata-path ] [--signing-identity ] [--private-key-path ] [--cert-chain-paths ...] [--dry-run] ARGUMENTS: The package identifier. The package release version being created. OPTIONS: --url, --registry-url The registry URL. --scratch-directory The path of the directory where working file(s) will be written. --metadata-path The path to the package metadata JSON file if it is not 'package-metadata.json' in the package directory. --signing-identity The label of the signing identity to be retrieved from the system's identity store if supported. --private-key-path The path to the certificate's PKCS#8 private key (DER-encoded). --cert-chain-paths Path(s) to the signing certificate (DER-encoded) and optionally the rest of the certificate chain. Certificates should be ordered with the leaf first and the root last. --dry-run Dry run only; prepare the archive and sign it but do not publish to the registry. ``` The command creates source archive for the package release, optionally signs the package release, and [publishes the package release](Registry.md#endpoint-6) to the registry. If authentication is required for package publication, package author should [configure registry login](#registry-authentication) before running `publish`. ### Package release metadata Package author can specify a custom location of the package release metadata file by setting the `--metadata-path` option of the `publish` subcommand. Otherwise, by default SwiftPM looks for a file named `package-metadata.json` in the package directory. Contents of the metadata file must conform to the [JSON schema](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-release-metadata-standards) defined in SE-0391. Also refer to registry documentation for any additional requirements. ### Package signing A registry may support or require signing. To sign a package release, package author will need to set either the `signing-identity` (for reading from operating system's identity store such as Keychain in macOS), or `private-key-path` and `cert-chain-paths` (for reading from files) options of the `publish` subcommand such that SwiftPM can locate the signing key and certificate. If the certificate chain's root and intermediates are known by SwiftPM, then package author would only need to provide the leaf signing certificate in `cert-chain-paths`. Otherwise, the entire certificate chain should be provided as `cert-chain-paths` so that all of the certificates will be included in the signature and make it possible for SwiftPM to reconstruct the certificate chain for validation later. This is applicable to `signing-identity` as well (i.e., `signing-identity` can be used in combination with `cert-chain-paths` to provide the entire certificate chain). If the root of the signing certificate is not in SwiftPM's default trust store, package author is responsible for telling package users to include the root certificate in their local [trust roots](#trusted-vs-untrusted-certificate) directory, or else [signature validation](#validating-signed-packages) may fail upon download because the signing certificate is not trusted. Refer to registry documentation for its certificate policy. #### Signature formats | Signature Format | Specification | | ---------------- | ------------- | | `cms-1.0.0` | [SE-391](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md#package-signature-format-cms-100) | Since there is only one supported signature format, all signatures produced by SwiftPM are in `cms-1.0.0`. #### Signed contents ##### Source archive The signature is detached and sent as part of the HTTP request to the publish API. It is included in the source archive download response as HTTP headers, and is part of the package release metadata. ##### Package release metadata The signature is detached and sent as part of the HTTP request to the publish API. The current API specification does not include an endpoint for fetching this metadata in its original form. ##### Package manifest(s) `Package.swift` and version-specific manifests are individually signed. The signature is embedded in the corresponding manifest file. The source archive is generated and signed **after** manifest signing. ```swift // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "library", products: [ .library(name: "library", targets: ["library"]) ], targets: [ .target(name: "library") ] ) // signature: cms-1.0.0;l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== ``` When a manifest is fetched from the registry, SwiftPM checks if the containing source archive is signed by fetching the package release metadata. It is a failure if the source archive is signed but the manifest is not. SwiftPM will extract and parse signature from the manifest then validate it similar to what is done for [source archive signature](#validating-signed-packages). SwiftPM performs publisher TOFU to ensure it remains consistent for the package. This implies the signer of manifests and source archive must be the same. To reduce the amount of logging and thus noise, diagnostics related to manifest signature validation are set to DEBUG level. Only when user chooses the `prompt` option for unsigned packages or packages signed with an untrusted certificate would SwiftPM behave like source archive validation. ## SwiftPM Registry Configuration ### Registry-to-scope mappings When resolving or downloading registry packages, SwiftPM looks at the registry-to-scope mappings in project and user-level configuration to determine which registry is assigned for a package's scope. For example, given the following configuration files: ```json // User-level configuration (~/.swiftpm/configuration/registries.json) { "registries": { "[default]": { "url": "https://global.example.com" }, "foo": { "url": "https://global.example.com" }, }, "version": 1 } // Local configuration (.swiftpm/configuration/registries.json) { "registries": { "foo": { "url": "https://local.example.com" } }, "version": 1 } ``` - For package `foo.LinkedList`, the registry at `https://local.example.com` is used. (Local configuration has higher precedence than user-level configuration.) - For package `bar.LinkedList`, the registry at `https://global.example.com` is used. (No mapping for scope `bar` is found, so `[default]` is used.) #### `swift package-registry set` subcommand ```bash $ swift package-registry set OVERVIEW: Set a custom registry USAGE: swift package-registry set [--global] [--scope ] ARGUMENTS: The registry URL OPTIONS: --global Apply settings to all projects for this user --scope Associate the registry with a given scope ``` This subcommand is used to assign registry at project or user-level: ```bash # project-level $ swift package-registry set https://packages.example.com # user-level $ swift package-registry set --global https://global.example.com ``` For a specific scope: ```bash # project-level $ swift package-registry set --scope foo https://local.example.com # user-level $ swift package-registry set --scope foo --global https://global.example.com ``` To remove a registry assignment, use the `swift package-registry unset` subcommand. ### Security configuration Registry security configuration are specified in the user-level `registries.json` (`~/.swiftpm/configuration/registries.json`): ```json { "security": { "default": { "signing": { "onUnsigned": "prompt", // One of: "error", "prompt", "warn", "silentAllow" "onUntrustedCertificate": "prompt", // One of: "error", "prompt", "warn", "silentAllow" "trustedRootCertificatesPath": "~/.swiftpm/security/trusted-root-certs/", "includeDefaultTrustedRootCertificates": true, "validationChecks": { "certificateExpiration": "disabled", // One of: "enabled", "disabled" "certificateRevocation": "disabled" // One of: "strict", "allowSoftFail", "disabled" } } }, "registryOverrides": { // The example shows all configuration overridable at registry level "packages.example.com": { "signing": { "onUnsigned": "warn", "onUntrustedCertificate": "warn", "trustedRootCertificatesPath": , "includeDefaultTrustedRootCertificates": , "validationChecks": { "certificateExpiration": "enabled", "certificateRevocation": "allowSoftFail" } } } }, "scopeOverrides": { // The example shows all configuration overridable at scope level "mona": { "signing": { "trustedRootCertificatesPath": , "includeDefaultTrustedRootCertificates": } } }, "packageOverrides": { // The example shows all configuration overridable at package level "mona.LinkedList": { "signing": { "trustedRootCertificatesPath": , "includeDefaultTrustedRootCertificates": } } } }, ... } ``` There are multiple levels of overrides. Configuration for a package is computed using values from the following (in descending precedence): 1. `packageOverrides` (if any) 1. `scopeOverrides` (if any) 1. `registryOverrides` (if any) 1. `default` The `default` JSON object in the example above contains all configurable security options and their default value when there is no override. - `signing.onUnsigned`: Indicates how SwiftPM will handle an unsigned package. | Option | Description | | ------------- | --------------------------------------------------------- | | `error` | SwiftPM will reject the package and fail the build. | | `prompt` | SwiftPM will prompt user to see if the unsigned package should be allowed.
  • If no, SwiftPM will reject the package and fail the build.
  • If yes and the package has never been downloaded, its checksum will be stored for [checksum TOFU](#checksum-tofu). Otherwise, if the package has been downloaded before, its checksum must match the previous value or else SwiftPM will reject the package and fail the build.
SwiftPM will record user's response to prevent repetitive prompting. | | `warn` | SwiftPM will not prompt user but will emit a warning before proceeding. | | `silentAllow` | SwiftPM will allow the unsigned package without prompting user or emitting warning. | - `signing.onUntrustedCertificate`: Indicates how SwiftPM will handle a package signed with an [untrusted certificate](#trusted-vs-untrusted-certificate). | Option | Description | | ------------- | --------------------------------------------------------- | | `error` | SwiftPM will reject the package and fail the build. | | `prompt` | SwiftPM will prompt user to see if the package signed with an untrusted certificate should be allowed.
  • If no, SwiftPM will reject the package and fail the build.
  • If yes, SwiftPM will proceed with the package as if it were an unsigned package.
SwiftPM will record user's response to prevent repetitive prompting. | | `warn` | SwiftPM will not prompt user but will emit a warning before proceeding. | | `silentAllow` | SwiftPM will allow the package signed with an untrusted certificate without prompting user or emitting warning. | - `signing.trustedRootCertificatesPath`: Absolute path to the directory containing custom trusted roots. SwiftPM will include these roots in its [trust store](#trusted-vs-untrusted-certificate), and certificates used for package signing must chain to roots found in this store. This configuration allows override at the package, scope, and registry levels. - `signing.includeDefaultTrustedRootCertificates`: Indicates if SwiftPM should include default trusted roots in its [trust store](#trusted-vs-untrusted-certificate). This configuration allows override at the package, scope, and registry levels. - `signing.validationChecks`: Validation check settings for the package signature. | Validation | Description | | ------------------------ | --------------------------------------------------------------- | | `certificateExpiration` |
  • `enabled`: SwiftPM will check that the current timestamp when downloading falls within the signing certificate's validity period. If it doesn't, SwiftPM will reject the package and fail the build.
  • `disabled`: SwiftPM will not perform this check.
| | `certificateRevocation` | With the exception of `disabled`, SwiftPM will check revocation status of the signing certificate. Currently, SwiftPM only supports revocation check done through [OCSP](https://www.rfc-editor.org/rfc/rfc6960).
  • `strict`: Revocation check must complete successfully and the certificate must be in good status. SwiftPM will reject the package and fail the build if the revocation status is revoked or unknown (including revocation check not supported or failed).
  • `allowSoftFail`: SwiftPM will reject the package and fail the build iff the certificate has been revoked. SwiftPM will allow the certificate's revocation status to be unknown (including revocation check not supported or failed).
  • `disabled`: SwiftPM will not perform this check.
| ================================================ FILE: Documentation/PackageRegistry/Registry.md ================================================ # Swift Package Registry Service Specification - [1. Notations](#1-notations) - [2. Definitions](#2-definitions) - [3. Conventions](#3-conventions) - [3.1. Application layer protocols](#31-application-layer-protocols) - [3.2. Authentication](#32-authentication) - [3.3. Error handling](#33-error-handling) - [3.4. Rate limiting](#34-rate-limiting) - [3.5. API versioning](#35-api-versioning) - [3.6. Package identification](#36-package-identification) - [3.6.1 Package scope](#361-package-scope) - [3.6.2. Package name](#362-package-name) - [4. Endpoints](#4-endpoints) - [4.1. List package releases](#41-list-package-releases) - [4.2. Fetch information about a package release](#42-fetch-information-about-a-package-release) - [4.2.1. Package release resources](#421-package-release-resources) - [4.2.2. Package release metadata standards](#422-package-release-metadata-standards) - [4.3. Fetch manifest for a package release](#43-fetch-manifest-for-a-package-release) - [4.3.1. swift-version query parameter](#431-swift-version-query-parameter) - [4.4. Download source archive](#44-download-source-archive) - [4.4.1. Integrity verification](#441-integrity-verification) - [4.4.2. Download locations](#442-download-locations) - [4.4.3. Signature validation](#443-signature-validation) - [4.5. Lookup package identifiers registered for a URL](#45-lookup-package-identifiers-registered-for-a-url) - [4.5.1 URL to package identifier mappings](#451-url-to-package-identifier-mappings) - [4.6. Create a package release](#46-create-a-package-release) - [4.6.1. Source archive](#461-source-archive) - [4.6.2. Package release metadata](#462-package-release-metadata) - [4.6.3. Synchronous and asynchronous publication](#463-synchronous-and-asynchronous-publication) - [4.6.3.1. Synchronous publication](#4631-synchronous-publication) - [4.6.3.2. Asynchronous publication](#4632-asynchronous-publication) - [5. Normative References](#5-normative-references) - [6. Informative References](#6-informative-references) - [Appendix A - OpenAPI Document](#appendix-a---openapi-document) - [Appendix B - Package Release Metadata JSON Schema](#appendix-b---package-release-metadata-json-schema) ## 1. Notations The following terminology and conventions are used in this document. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119]. This specification uses the Augmented Backus-Naur Form (ABNF) notation as described in [RFC 5234] and Unicode regular expression syntax as described in [Unicode Technical Standard #18][UAX18]. API endpoints that accept parameters in their path are expressed by Uniform Resource Identifier (URI) templates, as described in [RFC 6570]. ## 2. Definitions The following terms, as used in this document, have the meanings indicated. - _Package_: A named collection of Swift source code that is organized into one or more modules according to a `Package.swift` manifest file. - _Scope_: A logical grouping of related packages assigned by a package registry. - _Release_: The state of a package after applying a particular set of changes that is uniquely identified by an assigned version number. - _Version Number_: An identifier for a package release in accordance with the [Semantic Versioning Specification (SemVer)][SemVer]. - _Precedence_: The ordering of version numbers relative to each other as defined by the [Semantic Versioning Specification (SemVer)][SemVer]. ## 3. Conventions This document uses the following conventions in its description of client-server interactions. ### 3.1. Application layer protocols A client and server MUST communicate over a secured connection using Transport Layer Security (TLS) with the `https` URI scheme. The use of HTTP 1.1 in examples is non-normative. A client and server MAY communicate according to this specification using any version of the HTTP protocol. ### 3.2. Authentication A server MAY require authentication for client requests to access information about packages and package releases. A server SHOULD respond with a status code of `401` (Unauthorized) if a client sends a request to an endpoint that requires authentication without providing credentials. A server MAY respond with a status code of `404` (Not Found) or `403` (Forbidden) when a client provides valid credentials but isn't authorized to access the requested resource. A server MAY use any authentication model of its choosing. However, the use of a scoped, revocable authorization framework like [OAuth 2.0][RFC 6749] is RECOMMENDED. ### 3.3. Error handling A server MUST communicate any errors to the client using "problem details" objects, as described by [RFC 7807]. For example, a client sends a request for a nonexistent release of a package and receives the following response: ```http HTTP/1.1 404 Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "release not found" } ``` ### 3.4. Rate limiting A server MAY limit the number of requests made by a client by responding with a status code of `429` (Too Many Requests). ```http HTTP/1.1 429 Content-Version: 1 Content-Type: application/problem+json Content-Language: en Retry-After: 60 { "detail": "try again in 60 seconds" } ``` A client SHOULD follow the guidance of any `Retry-After` header values provided in responses to prevent overwhelming a server with retry requests. It is RECOMMENDED for clients to introduce random jitter in their retry logic to avoid a [thundering herd effect]. ### 3.5. API versioning Package registry APIs are versioned. API version numbers are designated by decimal integers. The accepted version of this proposal constitutes the initial version, `1`. Subsequent revisions SHOULD be numbered sequentially (`2`, `3`, and so on). API version numbers SHOULD follow Semantic Versioning conventions for major releases. Non-breaking changes, such as adding new endpoints, adding new optional parameters to existing endpoints, or adding new information to existing endpoints in a backward-compatible way, SHOULD NOT require a new version. Breaking changes, such as removing or changing an existing endpoint in a backward-incompatible way, MUST correspond to a new version. A client SHOULD set the `Accept` header field to specify the API version of a request. ```http GET /mona/LinkedList/list HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+json ``` Valid `Accept` header field values are described by the following rules: ```abnf version = "1" ; The API version mediatype = "json" / ; JSON (default media type) "zip" / ; Zip archives, used for package releases "swift" ; Swift file, used for package manifest accept = "application/vnd.swift.registry" [".v" version] ["+" mediatype] ``` A server MUST set the `Content-Type` header field with the corresponding content type of the response. A server MUST set the `Content-Version` header field with the API version number of the response, unless explicitly stated otherwise. ```http HTTP/1.1 200 OK Content-Type: application/json Content-Version: 1 ``` If a client sends a request without an `Accept` header, a server MAY either respond with a status code of `400 Bad Request` or process the request using an API version that it chooses, making sure to set the `Content-Type` and `Content-Version` headers accordingly. If a client sends a request with an `Accept` header that specifies an unknown or invalid API version, a server SHOULD respond with a status code of `400` (Bad Request). ```http HTTP/1.1 400 Bad Request Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "invalid API version" } ``` If a client sends a request with an `Accept` header that specifies a valid but unsupported API version, a server SHOULD respond with a status code of `415` (Unsupported Media Type). ```http HTTP/1.1 415 Unsupported Media Type Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "unsupported API version" } ``` ### 3.6. Package identification A package may declare external packages as dependencies in its manifest. Each package dependency may specify a requirement on which versions are allowed. An external package dependency may itself have one or more external package dependencies, known as transitive dependencies. When multiple packages have dependencies in common, Swift Package Manager determines which version of that package should be used (if any exist that satisfy all specified requirements) in a process called package resolution. Each external package is uniquely identified by a scoped identifier in the form `scope.package-name`. #### 3.6.1 Package scope A *scope* provides a namespace for related packages within a package registry. A package scope consists of alphanumeric characters and hyphens. Hyphens may not occur at the beginning or end, nor consecutively within a scope. The maximum length of a package scope is 39 characters. A valid package scope matches the following regular expression pattern: ```regexp \A[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}\z ``` Package scopes are case-insensitive (for example, `mona` ≍ `MONA`). #### 3.6.2. Package name A package's *name* uniquely identifies a package in a scope. A package name consists of alphanumeric characters, underscores, and hyphens. Hyphens and underscores may not occur at the beginning or end, nor consecutively within a name. The maximum length of a package name is 100 characters. A valid package name matches the following regular expression pattern: ```regexp \A[a-zA-Z0-9](?:[a-zA-Z0-9]|[-_](?=[a-zA-Z0-9])){0,99}\z ``` Package names are case-insensitive (for example, `LinkedList` ≍ `LINKEDLIST`). ## 4. Endpoints A server MUST respond to the following endpoints: | Link | Method | Path | Description | | -------------------- | ------ | --------------------------------------------------------- | ------------------------------------------------- | | [\[1\]](#endpoint-1) | `GET` | `/{scope}/{name}` | List package releases | | [\[2\]](#endpoint-2) | `GET` | `/{scope}/{name}/{version}` | Fetch metadata for a package release | | [\[3\]](#endpoint-3) | `GET` | `/{scope}/{name}/{version}/Package.swift{?swift-version}` | Fetch manifest for a package release | | [\[4\]](#endpoint-4) | `GET` | `/{scope}/{name}/{version}.zip` | Download source archive for a package release | | [\[5\]](#endpoint-5) | `GET` | `/identifiers{?url}` | Lookup package identifiers registered for a URL | | [\[6\]](#endpoint-6) | `PUT` | `/{scope}/{name}/{version}` | Create a package release | A server SHOULD also respond to `HEAD` requests for each of the specified endpoints. A client MAY send an `OPTIONS` request with an asterisk (`*`) to determine the permitted communication options for the server. A server MAY respond with a `Link` header containing an entry for the `service-doc` relation type with a link to this document, and an entry for the `service-desc` relation type with a link to the OpenAPI specification. * * * ### 4.1. List package releases A client MAY send a `GET` request for a URI matching the expression `/{scope}/{name}` to retrieve a list of the available releases for a particular package. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+json` and MAY append the `.json` extension to the requested URI. ```http GET /mona/LinkedList HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+json ``` If a package is found at the requested location, a server SHOULD respond with a status code of `200` (OK) and the `Content-Type` header `application/json`. Otherwise, a server SHOULD respond with a status code of `404` (Not Found). A server SHOULD respond with a JSON document containing the releases for the requested package. ```http HTTP/1.1 200 OK Content-Type: application/json Content-Version: 1 Content-Length: 508 Link: ; rel="canonical", ; rel="alternate", ; rel="latest-version", ; rel="payment" { "releases": { "1.1.1": { "url": "https://packages.example.com/mona/LinkedList/1.1.1" }, "1.1.0": { "url": "https://packages.example.com/mona/LinkedList/1.1.0", "problem": { "status": 410, "title": "Gone", "detail": "this release was removed from the registry" } }, "1.0.0": { "url": "https://packages.example.com/mona/LinkedList/1.0.0" } } } ``` The response body MUST contain a JSON object nested at a top-level `releases` key, whose keys are version numbers for releases and whose values are objects containing the following fields: | Key | Type | Description | Requirement Level | | --------- | ------ | ------------------------------------- | ----------------- | | `url` | String | The location of the release resource. | OPTIONAL | | `problem` | Object | A [problem details][RFC 7807] object. | OPTIONAL | A server MAY specify a URL for a release using the `url` key. A client SHOULD locate a release using the value of the `url` key, if one is provided. Otherwise, the client SHOULD locate a release by expanding the URI Template `/{scope}/{name}/{version}` on the originating host. A server SHOULD communicate the unavailability of a package release using a ["problem details"][RFC 7807] object. A client SHOULD consider any releases with an associated `problem` to be unavailable for the purposes of package resolution. A server SHOULD respond with a link to the highest precedence published release of the package if one exists, using a `Link` header field with a `latest-version` relation. A server SHOULD list releases in order of precedence, starting with the highest precedence version. However, a client SHOULD NOT assume any specific ordering of versions in a response. A server MAY include a `Link` entry with the `canonical` relation type that locates the source repository of the package. A server MAY include one or more `Link` entries with the `alternate` relation type for other source repository locations. A server MAY paginate results by responding with a `Link` header field that includes any of the following relations: | Name | Description | | ------- | --------------------------------------- | | `next` | The immediate next page of results. | | `last` | The last page of results. | | `first` | The first page of results. | | `prev` | The immediate previous page of results. | For example, the `Link` header field in a response for the third page of paginated results: ```http Link: ; rel="latest-version", ; rel="first", ; rel="previous", ; rel="next", ; rel="last" ``` A server MAY respond with additional `Link` entries, such as one with a `payment` relation for sponsoring a package maintainer. ### 4.2. Fetch information about a package release A client MAY send a `GET` request for a URI matching the expression `/{scope}/{name}/{version}` to retrieve information about a release. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+json`, and MAY append the `.json` extension to the requested URI. ```http GET /mona/LinkedList/1.1.1 HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+json ``` If a release is found at the requested location, a server SHOULD respond with a status code of `200` (OK) and the `Content-Type` header `application/json`. Otherwise, a server SHOULD respond with a status code of `404` (Not Found). ```http HTTP/1.1 200 OK Content-Version: 1 Content-Type: application/json Content-Length: 720 Link: ; rel="latest-version", ; rel="predecessor-version" { "id": "mona.LinkedList", "version": "1.1.1", "resources": [ { "name": "source-archive", "type": "application/zip", "checksum": "a2ac54cf25fbc1ad0028f03f0aa4b96833b83bb05a14e510892bb27dea4dc812", "signing": { "signatureBase64Encoded": "l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw==", "signatureFormat": "cms-1.0.0" } } ], "metadata": { ... }, "publishedAt": "2023-02-16T04:00:00.000Z" } ``` The response body SHOULD contain a JSON object containing the following fields: | Key | Type | Description | Required | | ------------- | ------ | ----------------------------------------- | :------: | | `id` | String | The namespaced package identifier. | ✓ | | `version` | String | The package release version number. | ✓ | | `resources` | Array | The resources available for the release. | ✓ | | `metadata` | Object | Additional information about the release. | ✓ | | `publishedAt` | String | The [ISO 8601]-formatted datetime string of when the package release was published, as recorded by the registry. See related [`originalPublicationTime`](#appendix-b---package-release-metadata-json-schema) in `metadata`. | | A server SHOULD respond with a `Link` header containing the following entries: | Relation | Description | | --------------------- | ------------------------------------------------------------------------------------ | | `latest-version` | The highest precedence published release of the package | | `successor-version` | The next published release of the package ordered by precedence, if one exists | | `predecessor-version` | The previously published release of the package ordered by precedence, if one exists | A link with the `latest-version` relation MAY correspond to the requested release. #### 4.2.1. Package release resources Each element in the `resources` array is a JSON object with the following keys: | Key | Type | Description | | ---------- | ------- | -------------------------------------------------------------------------- | | `name` | String | The name of the resource. | | `type` | String | The content type of the resource. | | `checksum` | String | A hexadecimal representation of the SHA256 digest for the resource. | | `signing` | Object | Information about the signature. Required only if the resource is signed. | The `signing` JSON object contains these keys: | Key | Type | Description | | ------------------------ | ------- | ------------------------------------------------- | | `signatureBase64Encoded` | String | The resource's signature, base64 encoded. | | `signatureFormat` | String | The signature format. (e.g., `cms-1.0.0`) | A resource object SHOULD have one of the following combinations of `name` and `type` values: | Name | Content Type | Description | | ------------------ | ----------------- | ---------------------------------- | | `source-archive` | `application/zip` | An archive of package sources. | A release MUST NOT have more than a single resource object with a given combination of `name` and `type` values. #### 4.2.2. Package release metadata standards [Appendix B](#appendix-b---package-release-metadata-json-schema) defines the JSON schema for package release metadata that gets submitted as part of the ["create a package release"](#endpoint-6) request. A server MAY allow and/or populate additional metadata by expanding the schema. The `metadata` key in the ["fetch information about a package release "](#endpoint-2) API response will hold the user-provided as well as the server populated metadata. ### 4.3. Fetch manifest for a package release A client MAY send a `GET` request for a URI matching the expression `/{scope}/{name}/{version}/Package.swift` to retrieve the package manifest for a release. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+swift`. ```http GET /mona/LinkedList/1.1.1/Package.swift HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+swift ``` If a release is found at the requested location, a server SHOULD respond with a status code of `200` (OK) and the `Content-Type` header `text/x-swift`. Otherwise, a server SHOULD respond with a status code of `404` (Not Found). ```http HTTP/1.1 200 OK Cache-Control: public, immutable Content-Type: text/x-swift Content-Disposition: attachment; filename="Package.swift" Content-Length: 361 Content-Version: 1 Link: ; rel="alternate"; filename="Package@swift-4.swift"; swift-tools-version="4.0", ; rel="alternate"; filename="Package@swift-4.2.swift"; swift-tools-version="4.2" // swift-tools-version:5.0 import PackageDescription let package = Package( name: "LinkedList", products: [ .library(name: "LinkedList", targets: ["LinkedList"]) ], targets: [ .target(name: "LinkedList"), .testTarget(name: "LinkedListTests", dependencies: ["LinkedList"]), ], swiftLanguageVersions: [.v4, .v5] ) ``` A server SHOULD respond with a `Content-Length` header set to the size of the manifest in bytes. A server SHOULD respond with a `Content-Disposition` header set to `attachment` with a `filename` parameter equal to the name of the manifest file (for example, "Package.swift"). A server MAY omit the `Content-Version` header since the response content (i.e., the manifest) SHOULD NOT change across different API versions. It is RECOMMENDED for clients and servers to support caching as described by [RFC 7234]. A server MUST include a `Link` header field with a value for each version-specific package manifest file in the release's source archive, whose filename matches the following regular expression pattern: ```regexp \APackage@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift\z ``` Each link value SHOULD have the `alternate` relation type, a `filename` attribute set to the version-specific package manifest filename (for example, `Package@swift-4.swift`), and a `swift-tools-version` attribute set to the [Swift tools version] specified by the package manifest file (for example, `4.0` for a manifest beginning with the comment `// swift-tools-version:4.0`). #### 4.3.1. swift-version query parameter A client MAY specify a `swift-version` query parameter to request a manifest for a particular version of Swift. ```http GET /mona/LinkedList/1.1.1/Package.swift?swift-version=4.2 HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+swift ``` If the package includes a file named `Package@swift-{swift-version}.swift`, the server SHOULD respond with a status code of `200` (OK) and the content of that file in the response body. ```http HTTP/1.1 200 OK Cache-Control: public, immutable Content-Type: text/x-swift Content-Disposition: attachment; filename="Package@swift-4.2.swift" Content-Length: 361 Content-Version: 1 // swift-tools-version:4.2 import PackageDescription let package = Package( name: "LinkedList", products: [ .library(name: "LinkedList", targets: ["LinkedList"]) ], targets: [ .target(name: "LinkedList"), .testTarget(name: "LinkedListTests", dependencies: ["LinkedList"]), ], swiftLanguageVersions: [.v3, .v4] ) ``` Otherwise, the server SHOULD respond with a status code of `303` (See Other) and redirect to the unqualified `Package.swift` resource. ```http HTTP/1.1 303 See Other Content-Version: 1 Location: https://packages.example.com/mona/LinkedList/1.1.1/Package.swift ``` ### 4.4. Download source archive A client MAY send a `GET` request for a URI matching the expression `/{scope}/{name}/{version}.zip` to retrieve a release's source archive. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+zip` and MUST append the `.zip` extension to the requested path. ```http GET /mona/LinkedList/1.1.1.zip HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+zip ``` If a release is found at the requested location, a server SHOULD respond with a status code of `200` (OK) and the `Content-Type` header `application/zip`. Otherwise, a server SHOULD respond with a status code of `404` (Not Found). ```http HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: public, immutable Content-Type: application/zip Content-Disposition: attachment; filename="LinkedList-1.1.1.zip" Content-Length: 2048 Content-Version: 1 Digest: sha-256=oqxUzyX7wa0AKPA/CqS5aDO4O7BaFOUQiSuyfepNyBI= Link: ; rel=duplicate; geo=jp; pri=10; type="application/zip" X-Swift-Package-Signature-Format: cms-1.0.0 X-Swift-Package-Signature: l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== ``` A server MUST respond with a `Content-Length` header set to the size of the archive in bytes. A client SHOULD terminate any requests whose response exceeds the expected content length. A server MAY respond with a `Digest` header containing a cryptographic digest of the source archive. A server SHOULD respond with a `Content-Disposition` header set to `attachment` with a `filename` parameter equal to the name of the package followed by a hyphen (`-`), the version number, and file extension (for example, "LinkedList-1.1.1.zip"). A server MAY omit the `Content-Version` header since the response content (i.e., the source archive) SHOULD NOT change across different API versions. It is RECOMMENDED for clients and servers to support range requests as described by [RFC 7233] and caching as described by [RFC 7234]. If a release is signed, a server MUST include `X-Swift-Package-Signature-Format` and `X-Swift-Package-Signature` headers in the response. #### 4.4.1. Integrity verification A client MUST verify the integrity of a downloaded source archive using the `checksum` value for the associated `source-archive` resource in the response to `GET /{scope}/{name}/{version}`, as described in [4.2.1](#421-package-release-resources). A client SHOULD also verify the integrity using any values provided in the `Digest` header of the source archive response (for using the command `shasum -b -a 256 LinkedList-1.1.1.zip | cut -f1 | xxd -r -p | base64`). #### 4.4.2. Download locations A server MAY specify mirrors or multiple download locations using `Link` header fields with a `duplicate` relation, as described by [RFC 6249]. A client MAY use this information to determine its preferred strategy for downloading. A server MAY respond with a status code of `303` (See Other) to redirect the client to download the source archive from another host. The client MUST NOT follow redirects that downgrade to an insecure connection. The client SHOULD limit the number of redirects to prevent a redirect loop. For example, a server redirects the client to download from a content delivery network (CDN) using a signed URL: ```http HTTP/1.1 303 See Other Location: https://example.cdn.com/LinkedList-1.1.1.zip?key=XXXXXXXXXXXXXXXXX ``` ```http GET /LinkedList-1.1.1.zip?key=XXXXXXXXXXXXXXXXX HTTP/1.1 Host: example.cdn.com Accept: application/vnd.swift.registry.v1+zip ``` ```http HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: public, immutable Content-Type: application/zip Content-Disposition: attachment; filename="LinkedList-1.1.1.zip" Content-Length: 2048 Content-Version: 1 Digest: sha-256=a2ac54cf25fbc1ad0028f03f0aa4b96833b83bb05a14e510892bb27dea4dc812 ``` #### 4.4.3. Signature validation A client MUST validate the signature of a signed archive according to the signature format and configuration. Signing information can alternatively be found in the associated `source-archive` resource in the response to `GET /{scope}/{name}/{version}`, as described in [4.2.1](#421-package-release-resources). ### 4.5. Lookup package identifiers registered for a URL A client MAY send a `GET` request for a URI matching the expression `/identifiers?url={url}` to retrieve package identifiers associated with a particular URL. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+json`. ```http GET /identifiers?url=https://github.com/mona/LinkedList HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1 ``` A client MUST provide a URL for the `url` query parameter. When no `url` parameter is specified, a server SHOULD respond with a status code of `400` (Bad Request). If one or more package identifiers are associated with the specified URL, a server SHOULD respond with a status code of `200` (OK) and the `Content-Type` header `application/json`. Otherwise, a server SHOULD respond with a status code of `404` (Not Found). A server SHOULD respond with a JSON document containing the package identifiers for the specified URL. ```http HTTP/1.1 200 OK Content-Type: application/json Content-Version: 1 { "identifiers": [ "mona.LinkedList" ] } ``` The response body MUST contain an array of package identifier strings nested at a top-level `identifiers` key. It is RECOMMENDED for clients and servers to support caching as described by [RFC 7234]. #### 4.5.1 URL to package identifier mappings As part of the [package release metadata](#422-package-release-metadata-standards) JSON object, the `repositoryURLs` array can be used to specify URLs associated with a package identifier. This is one way through which a server can obtain URL to package identifier mappings for this API. A server MAY choose other mechanism(s) for package authors to specify these mappings. A server SHOULD validate the package author's ownership claim on the corresponding repository. ### 4.6. Create a package release A client MAY send a `PUT` request for a URI matching the expression `/{scope}/{name}/{version}` to publish a release of a package. A client MUST provide a body encoded as multipart form data with the following sections: | Key | Content-Type | Description | Requirement Level | | -------------------------- | -------------------------- | ----------------------------------------- | ----------------- | | `source-archive` | `application/zip` | The source archive of the package. | REQUIRED | | `source-archive-signature` | `application/octet-stream` | The signature of the source archive. | OPTIONAL | | `metadata` | `application/json` | Additional information about the release. | OPTIONAL | | `metadata-signature` | `application/octet-stream` | The signature of the metadata. | OPTIONAL | A client MUST set a `Content-Type` header with the value `multipart/form-data`. `boundary` can be any string. A client MAY use any valid value (e.g., `binary`) for the `Content-Transfer-Encoding` header. A client SHOULD set the `Content-Length` header with the total size of the body in bytes. A client SHOULD set the `Accept` header with the value `application/vnd.swift.registry.v1+json`. A client MUST set a `X-Swift-Package-Signature-Format` header with the signature format if the source archive is signed. ```http PUT /mona/LinkedList/1.1.1 HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1+json Content-Type: multipart/form-data;boundary="boundary" Content-Length: 336 Expect: 100-continue X-Swift-Package-Signature-Format: cms-1.0.0 --boundary Content-Disposition: form-data; name="source-archive" Content-Type: application/zip Content-Length: 32 Content-Transfer-Encoding: base64 gHUFBgAAAAAAAAAAAAAAAAAAAAAAAA== --boundary Content-Disposition: form-data; name="source-archive-signature" Content-Type: application/octet-stream Content-Length: 88 Content-Transfer-Encoding: base64 l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== --boundary Content-Disposition: form-data; name="metadata" Content-Type: application/json Content-Transfer-Encoding: quoted-printable Content-Length: 3 { "repositoryURLs": [] } --boundary Content-Disposition: form-data; name="metadata-signature" Content-Type: application/octet-stream Content-Length: 88 Content-Transfer-Encoding: base64 M6TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw== ``` A server SHOULD require a client to perform authentication for any requests to create a package release. Use of multi-factor authentication is RECOMMENDED. A client MAY publish releases in any order. For example, if a package has existing `1.0.0` and `2.0.0` releases, a client MAY publish a new `1.0.1` or `1.1.0` release. Once a release has been published, any resources associated with that release, including its source archive, MUST NOT change. If a release already exists for a package at the specified version, the server SHOULD respond with a status code of `409` (Conflict). ```http HTTP/1.1 409 Conflict Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "a release with version 1.0.0 already exists" } ``` It is RECOMMENDED that a server institute policies for publishing new releases of a package after a scope is transferred to a new owner. For example, the next release of an existing package is published with a new major version, or only after a period of 45 days after transfer. If the client provides an `Expect` header, a server SHOULD check that the request can succeed before responding with a status code of `100 (Continue)`. A server that doesn't support expectations SHOULD respond with a status code of `417 (Expectation Failed)`. In response, a client MAY remove the `Expect` header and retry the request. ```http HTTP/1.1 417 (Expectation Failed) Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "expectations aren't supported" } ``` Support for this endpoint is OPTIONAL. A server SHOULD indicate that publishing isn't supported by responding with a status code of `405` (Method Not Allowed). ```http HTTP/1.1 405 (Method Not Allowed) Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "publishing isn't supported" } ``` A server MAY respond either synchronously or asynchronously. For more information, see [4.6.4](#464-synchronous-and-asynchronous-publication). #### 4.6.1. Source archive A client MUST include a multipart section named `source-archive` containing the source archive for a release. A client SHOULD set a `Content-Type` header with the value `application/zip` and a `Content-Length` header with the size of the Zip archive in bytes. ```http --boundary Content-Disposition: form-data; name="source-archive" Content-Type: application/zip Content-Length: 32 Content-Transfer-Encoding: base64 gHUFBgAAAAAAAAAAAAAAAAAAAAAAAA== ``` A client SHOULD use the `swift package archive-source` tool to create a source archive for the release. A server MAY analyze a package to assess its viability, perform security testing, or otherwise evaluate software quality. A server MAY refuse to publish a package release for any reason by responding with a status code of `422` (Unprocessable Entity). ```http HTTP/1.1 422 Unprocessable Entity Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "package doesn't contain a valid manifest (Package.swift) file" } ``` A server SHOULD use the `swift package compute-checksum` tool to compute the checksum that's provided in response to a client's subsequent request to [download the source archive](#endpoint-4) for the release. #### 4.6.2. Package release metadata A client MAY include a multipart section named `metadata` containing additional information about the release. A client SHOULD set a `Content-Type` header with the value `application/json` and a `Content-Length` header with the size of the JSON document in bytes. The package release metadata MUST be based on the [JSON schema](#appendix-b---package-release-metadata-json-schema), as discussed in [4.2.2](#422-package-release-metadata-standards). ```http --boundary Content-Disposition: form-data; name="metadata" Content-Type: application/json Content-Length: 226 Content-Transfer-Encoding: quoted-printable { "description": "One thing links to another.", "repositoryURLs": ["https://github.com/mona/LinkedList"], "licenseURL": "https://www.apache.org/licenses/LICENSE-2.0", "author": { "name": "Mona Lisa Octocat" } } ``` A server MAY allow and/or populate additional metadata for a release. A server MAY make any properties in the [JSON schema](#appendix-b---package-release-metadata-json-schema) and additional metadata it defines required. If a client provides an invalid JSON document, the server SHOULD respond with a status code of `422` (Unprocessable Entity) or `413` (Payload Too Large) and MAY communicate validation error details in the response body. ```http HTTP/1.1 422 Unprocessable Entity Content-Version: 1 Content-Type: application/problem+json Content-Language: en { "detail": "invalid JSON provided for release metadata" } ``` #### 4.6.3. Synchronous and asynchronous publication A server MAY respond to a request to publish a new package release either synchronously or asynchronously. A client MAY indicate their preference for asynchronous processing with a `Prefer` header field containing the token `respond-async` and an optional `wait` preference, as described by [RFC 7240]. ```http PUT /mona/LinkedList/1.1.1 HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1 Prefer: respond-async, wait=300 ``` ##### 4.6.3.1. Synchronous publication If processing is done synchronously, the server MUST respond with a status code of `201` (Created) to indicate that the package release was published. This response SHOULD also contain a `Location` header with a URL to the new release. ```http HTTP/1.1 201 Created Content-Version: 1 Location: https://packages.example.com/github.com/mona/LinkedList/1.1.1 ``` A client MAY set a timeout to guarantee a timely response to each request. ##### 4.6.3.2. Asynchronous publication If processing is done asynchronously, the server MUST respond with a status code of `202` (Accepted) to acknowledge that the request is being processed. This response MUST contain a `Location` header with a URL that the client can poll for progress updates and SHOULD contain a `Retry-After` header with an estimate of when processing is expected to finish. A server MAY locate the status resource endpoint at a URI of its choosing. However, the use of a non-sequential, randomly-generated identifier is RECOMMENDED. ```http HTTP/1.1 202 Accepted Content-Version: 1 Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC Retry-After: 120 ``` A client MAY send a `GET` request to the location provided by the server in response to a publish request to see the current status of that process. ```http GET /submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC HTTP/1.1 Host: packages.example.com Accept: application/vnd.swift.registry.v1 ``` If the asynchronous publish request is still processing, the server SHOULD respond with a status code of `202` (Accepted) and a `Retry-After` header with an estimate of when processing should finish. A server MAY include additional details in the response body. ```http HTTP/1.1 202 Accepted Content-Version: 1 Content-Type: application/json Retry-After: 120 { "status": "Processing (2/3 steps complete)", "steps": { {"name": "Validate metadata", "status": "complete"}, {"name": "Verify package manifest", "status": "complete"}, {"name": "Scan for vulnerabilities", "status": "pending"} } } ``` If the asynchronous publish request is finished processing successfully, the server SHOULD respond with a status code of `301` (Moved Permanently) and a `Location` header with a URL to the package release. ```http HTTP/1.1 301 Moved Permanently Content-Version: 1 Location: https://packages.example.com/mona/LinkedList/1.1.1 ``` If the asynchronous publish request failed, the server SHOULD respond with an appropriate client error status code (`4xx`). ```http HTTP/1.1 400 Bad Request Content-Version: 1 Content-Type: application/problem+json Content-Language: en Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC { "detail": "invalid package" } ``` A client MAY send a `DELETE` request to the location provided by the server in response to a publish request to cancel that process. If a request to publish a new package release were to fail, a server MUST communicate that failure in the same way if sending an immediate response as it would if responding to a client polling for status. If a client makes a request to publish a package release to a server that is asynchronously processing a request to publish that release, the server MUST respond with a status code of `409` (Conflict) ```http HTTP/1.1 409 Conflict Content-Version: 1 Content-Type: application/problem+json Content-Language: en Location: https://packages.example.com/submissions/90D8CC77-A576-47AE-A531-D6402C4E33BC { "detail": "already processing a request to publish this package version" } ``` If a client makes a request to publish a package release to a server that finished processing a failed request to publish that release, the server SHOULD try publishing that release again. A server MAY refuse to fulfill a subsequent request to publish a package release by responding with a status code of `409` (Conflict). ## 5. Normative References * [RFC 2119]: Key words for use in RFCs to Indicate Requirement Levels * [RFC 3230]: Instance Digests in HTTP * [RFC 3986]: Uniform Resource Identifier (URI): Generic Syntax * [RFC 3987]: Internationalized Resource Identifiers (IRIs) * [RFC 5234]: Augmented BNF for Syntax Specifications: ABNF * [RFC 5843]: Additional Hash Algorithms for HTTP Instance Digests * [RFC 6249]: Metalink/HTTP: Mirrors and Hashes * [RFC 6570]: URI Template * [RFC 7159]: The JavaScript Object Notation (JSON) Data Interchange Format * [RFC 7230]: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing * [RFC 7231]: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content * [RFC 7233]: Hypertext Transfer Protocol (HTTP/1.1): Range Requests * [RFC 7234]: Hypertext Transfer Protocol (HTTP/1.1): Caching * [RFC 7240]: Prefer Header for HTTP * [RFC 7578]: Returning Values from Forms: multipart/form-data * [RFC 7807]: Problem Details for HTTP APIs * [RFC 8288]: Web Linking * [SemVer]: Semantic Versioning ## 6. Informative References * [BCP 13] Media Type Specifications and Registration Procedures * [RFC 6749]: The OAuth 2.0 Authorization Framework * [RFC 8446]: The Transport Layer Security (TLS) Protocol Version 1.3 * [RFC 8631]: Link Relation Types for Web Services * [JSON-LD]: A JSON-based Serialization for Linked Data * [Schema.org]: A shared vocabulary for structured data. * [OAS]: OpenAPI Specification ## Appendix A - OpenAPI Document The following [OpenAPI (v3) specification][OAS] is non-normative, and is provided for the convenience of developers interested in building their own package registry. See [registry.openapi.yaml](./registry.openapi.yaml). ## Appendix B - Package Release Metadata JSON Schema The `metadata` section of the [create package release request](#46-create-a-package-release) must be a JSON object of type [`PackageRelease`](#packagerelease-type), as defined in the JSON schema below.
Expand to view JSON schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md", "title": "Package Release Metadata", "description": "Metadata of a package release.", "type": "object", "properties": { "author": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the author." }, "email": { "type": "string", "format": "email", "description": "Email address of the author." }, "description": { "type": "string", "description": "A description of the author." }, "organization": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the organization." }, "email": { "type": "string", "format": "email", "description": "Email address of the organization." }, "description": { "type": "string", "description": "A description of the organization." }, "url": { "type": "string", "format": "uri", "description": "URL of the organization." }, }, "required": ["name"] }, "url": { "type": "string", "format": "uri", "description": "URL of the author." }, }, "required": ["name"] }, "description": { "type": "string", "description": "A description of the package release." }, "licenseURL": { "type": "string", "format": "uri", "description": "URL of the package release's license document." }, "originalPublicationTime": { "type": "string", "format": "date-time", "description": "Original publication time of the package release in ISO 8601 format." }, "readmeURL": { "type": "string", "format": "uri", "description": "URL of the README specifically for the package release or broadly for the package." }, "repositoryURLs": { "type": "array", "description": "Code repository URL(s) of the package release.", "items": { "type": "string", "description": "Code repository URL." } } } } ```
##### `PackageRelease` type | Property | Type | Description | Required | | ------------------------- | :-----------------: | ------------------------------------------------ | :------: | | `author` | [Author](#author-type) | Author of the package release. | | | `description` | String | A description of the package release. | | | `licenseURL` | String | URL of the package release's license document. | | | `originalPublicationTime` | String | Original publication time of the package release in [ISO 8601] format. This can be set if the package release was previously published elsewhere.
A registry should record the publication time independently and include it as `publishedAt` in the [package release metadata response](#42-fetch-information-about-a-package-release).
In case both `originalPublicationTime` and `publishedAt` are set, `originalPublicationTime` should be used. | | | `readmeURL` | String | URL of the README specifically for the package release or broadly for the package. | | | `repositoryURLs` | Array | Code repository URL(s) of the package. It is recommended to include all URL variations (e.g., SSH, HTTPS) for the same repository. This can be an empty array if the package does not have source control representation.
Setting this property is one way through which a registry can obtain repository URL to package identifier mappings for the ["lookup package identifiers registered for a URL" API](Registry.md#45-lookup-package-identifiers-registered-for-a-url). A registry may choose other mechanism(s) for package authors to specify such mappings. | | ##### `Author` type | Property | Type | Description | Required | | ----------------- | :-----------------: | ------------------------------------------------ | :------: | | `name` | String | Name of the author. | ✓ | | `email` | String | Email address of the author. | | | `description` | String | A description of the author. | | | `organization` | [Organization](#organization-type) | Organization that the author belongs to. | | | `url` | String | URL of the author. | | ##### `Organization` type | Property | Type | Description | Required | | ----------------- | :-----------------: | ------------------------------------------------ | :------: | | `name` | String | Name of the organization. | ✓ | | `email` | String | Email address of the organization. | | | `description` | String | A description of the organization. | | | `url` | String | URL of the organization. | | [UAX18]: https://unicode.org/reports/tr18/ [BCP 13]: https://tools.ietf.org/html/rfc6838 "Media Type Specifications and Registration Procedures" [RFC 2119]: https://tools.ietf.org/html/rfc2119 "Key words for use in RFCs to Indicate Requirement Levels" [RFC 3230]: https://tools.ietf.org/html/rfc5843 "Instance Digests in HTTP" [RFC 3986]: https://tools.ietf.org/html/rfc3986 "Uniform Resource Identifier (URI): Generic Syntax" [RFC 3987]: https://tools.ietf.org/html/rfc3987 "Internationalized Resource Identifiers (IRIs)" [RFC 5234]: https://tools.ietf.org/html/rfc5234 "Augmented BNF for Syntax Specifications: ABNF" [RFC 5843]: https://tools.ietf.org/html/rfc5843 "Additional Hash Algorithms for HTTP Instance Digests" [RFC 6249]: https://tools.ietf.org/html/rfc6249 "Metalink/HTTP: Mirrors and Hashes" [RFC 6570]: https://tools.ietf.org/html/rfc6570 "URI Template" [RFC 6749]: https://tools.ietf.org/html/rfc6749 "The OAuth 2.0 Authorization Framework" [RFC 7159]: https://tools.ietf.org/html/rfc7159 "The JavaScript Object Notation (JSON) Data Interchange Format" [RFC 7230]: https://tools.ietf.org/html/rfc7230 "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing" [RFC 7231]: https://tools.ietf.org/html/rfc7231 "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" [RFC 7233]: https://tools.ietf.org/html/rfc7233 "Hypertext Transfer Protocol (HTTP/1.1): Range Requests" [RFC 7234]: https://tools.ietf.org/html/rfc7234 "Hypertext Transfer Protocol (HTTP/1.1): Caching" [RFC 7240]: https://tools.ietf.org/html/rfc7240 "Prefer Header for HTTP" [RFC 7578]: https://tools.ietf.org/html/rfc7578 "Returning Values from Forms: multipart/form-data" [RFC 7807]: https://tools.ietf.org/html/rfc7807 "Problem Details for HTTP APIs" [RFC 8288]: https://tools.ietf.org/html/rfc8288 "Web Linking" [RFC 8446]: https://tools.ietf.org/html/rfc8446 "The Transport Layer Security (TLS) Protocol Version 1.3" [RFC 8631]: https://tools.ietf.org/html/rfc8631 "Link Relation Types for Web Services" [IANA Link Relations]: https://www.iana.org/assignments/link-relations/link-relations.xhtml [JSON-LD]: https://w3c.github.io/json-ld-syntax/ "JSON-LD 1.1: A JSON-based Serialization for Linked Data" [SemVer]: https://semver.org/ "Semantic Versioning" [Schema.org]: https://schema.org/ [SoftwareSourceCode]: https://schema.org/SoftwareSourceCode [DUST]: https://doi.org/10.1145/1462148.1462151 "Bar-Yossef, Ziv, et al. Do Not Crawl in the DUST: Different URLs with Similar Text. Association for Computing Machinery, 17 Jan. 2009. January 2009" [OAS]: https://swagger.io/specification/ "OpenAPI Specification" [GitHub / Swift Package Management Service]: https://forums.swift.org/t/github-swift-package-management-service/30406 [RubyGems]: https://rubygems.org "RubyGems: The Ruby community’s gem hosting service" [PyPI]: https://pypi.org "PyPI: The Python Package Index" [npm]: https://www.npmjs.com "The npm Registry" [crates.io]: https://crates.io "crates.io: The Rust community’s crate registry" [CocoaPods]: https://cocoapods.org "A dependency manager for Swift and Objective-C Cocoa projects" [thundering herd effect]: https://en.wikipedia.org/wiki/Thundering_herd_problem "Thundering herd problem" [offline cache]: https://yarnpkg.com/features/offline-cache "Offline Cache | Yarn - Package Manager" [XCFramework]: https://developer.apple.com/videos/play/wwdc2019/416/ "WWDC 2019 Session 416: Binary Frameworks in Swift" [SE-0272]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0272-swiftpm-binary-dependencies.md "Package Manager Binary Dependencies" [Swift tools version]: https://github.com/swiftlang/swift-package-manager/blob/9b9bed7eaf0f38eeccd0d8ca06ae08f6689d1c3f/Documentation/Usage.md#swift-tools-version-specification "Swift Tools Version Specification" [ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html "ISO 8601 Date and Time Format" ================================================ FILE: Documentation/PackageRegistry/registry.openapi.yaml ================================================ openapi: 3.0.3 info: title: Swift Package Registry API description: API for managing Swift package releases and interacting with the package registry. version: 1.0.0 tags: - name: Releases - name: Packages - name: Authentication paths: '/{scope}/{name}': parameters: - $ref: '#/components/parameters/Scope' - $ref: '#/components/parameters/PackageName' get: tags: - Releases summary: List package releases operationId: listPackageReleases responses: '200': description: Retrieve a list of all available releases for a given package headers: Link: $ref: '#/components/headers/PackageLinks' Content-Version: $ref: '#/components/headers/ContentVersion' content: 'application/json': schema: $ref: '#/components/schemas/Releases' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '415': $ref: '#/components/responses/UnsupportedMediaType' '429': $ref: '#/components/responses/TooManyRequests' '/{scope}/{name}/{version}': parameters: - $ref: '#/components/parameters/Scope' - $ref: '#/components/parameters/PackageName' - $ref: '#/components/parameters/Version' get: tags: - Releases summary: Fetch metadata for a package release operationId: fetchReleaseMetadata responses: '200': description: Retrieve detailed metadata for a specific package release headers: Link: $ref: '#/components/headers/PackageLinks' Content-Version: $ref: '#/components/headers/ContentVersion' content: 'application/json': schema: $ref: '#/components/schemas/ReleaseMetadata' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '415': $ref: '#/components/responses/UnsupportedMediaType' '429': $ref: '#/components/responses/TooManyRequests' put: tags: - Releases summary: Create a package release operationId: createPackageRelease parameters: - in: header name: X-Swift-Package-Signature-Format description: The signature format if the source archive is signed. schema: type: string example: 'cms-1.0.0' - in: header name: Prefer description: |- Communicates the preference for sync vs async processing. Use "respond-async" to get async processing, for example "respond-async, wait=300" to wait up to 300 seconds. Omit this header to prefer sync processing. schema: type: string requestBody: description: A multipart payload. required: true content: multipart/form-data: schema: type: object properties: source-archive: type: string format: binary description: The binary source archive of the package to be published example: 'Binary data for Linked List package release' source-archive-signature: type: string format: binary description: The signature for the source archive. metadata: $ref: '#/components/schemas/PackageMetadata' metadata-signature: type: string format: base64 description: The signature for the metadata. required: - source-archive encoding: source-archive: contentType: application/zip source-archive-signature: contentType: application/octet-stream metadata: contentType: application/json metadata-signature: contentType: application/octet-stream responses: '201': description: The package release has been successfully published headers: Content-Version: $ref: '#/components/headers/ContentVersion' Location: description: The URL to the created release. schema: type: string format: uri example: 'https://packages.example.com/github.com/mona/LinkedList/1.1.1' content: 'application/json': schema: $ref: '#/components/schemas/PublishResponse' '202': description: The request to publish the package has been accepted and is being processed headers: 'Retry-After': $ref: '#/components/headers/RetryAfter' Location: description: |- The URL to poll for status of the publication process. Poll that URL using a `GET` request, and if the response is 202, extract the Retry-After header to get a new estimate of when the processing will be finished. When the response is 301, the processing is finished and the Location header points to the new release. If the response is 4xx, the processing failed and you can stop polling. The response contains the failure details. Send `DELETE` to the URL to cancel the processing. schema: type: string format: uri description: URL to poll for status of the publication process '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '405': description: Method not allowed - publishing is not supported on this server. content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' '409': description: Conflict - an existing release already exists, or the release is still processing. headers: Location: description: The location of the release that's still processing, see the 202 response for details. schema: type: string format: uri content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' '413': description: Content too large. content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' '415': $ref: '#/components/responses/UnsupportedMediaType' '422': description: Unprocessable entity - refused to publish the release. content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' '429': $ref: '#/components/responses/TooManyRequests' '/{scope}/{name}/{version}/Package.swift': parameters: - $ref: '#/components/parameters/Scope' - $ref: '#/components/parameters/PackageName' - $ref: '#/components/parameters/Version' get: tags: - Packages summary: Fetch manifest for a package release operationId: fetchManifestForPackageRelease parameters: - $ref: '#/components/parameters/SwiftVersion' responses: '200': description: Retrieve the manifest file for the specified package release headers: Link: required: true schema: type: string description: |- One value for each version-specific package manifest file in the release's source archive, whose filename matches the following regular expression pattern: `\APackage@swift-(\d+)(?:\.(\d+))?(?:\.(\d+))?.swift\z` Each link value should have the alternate relation type, a filename attribute set to the version-specific package manifest filename (for example, Package@swift-4.swift), and a swift-tools-version attribute set to the Swift tools version specified by the package manifest file (for example, 4.0 for a manifest beginning with the comment // swift-tools-version:4.0). content: text/x-swift: schema: type: string '303': description: Redirect to the unqualified Package.swift resource. headers: Location: required: true schema: type: string format: uri example: 'https://packages.example.com/mona/LinkedList/1.1.1/Package.swift' Content-Version: $ref: '#/components/headers/ContentVersion' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '415': $ref: '#/components/responses/UnsupportedMediaType' '429': $ref: '#/components/responses/TooManyRequests' '/{scope}/{name}/{version}.zip': parameters: - $ref: '#/components/parameters/Scope' - $ref: '#/components/parameters/PackageName' - $ref: '#/components/parameters/Version' get: tags: - Packages summary: Download source archive for a package release operationId: downloadSourceArchive responses: '200': description: Download the source archive for the specified package release headers: Digest: description: A digest containing a cryptographic digest of the source archive. schema: type: string example: 'sha-256=oqxUzyX7wa0AKPA/CqS5aDO4O7BaFOUQiSuyfepNyBI=' Content-Disposition: description: |- A header set to attachment with a filename parameter equal to the name of the package followed by a hyphen (-), the version number, and file extension (for example, "LinkedList-1.1.1.zip") schema: type: string example: 'attachment; filename="LinkedList-1.1.1.zip"' X-Swift-Package-Signature-Format: description: The format of the package signature, used for integrity verification schema: type: string example: 'cms-1.0.0' X-Swift-Package-Signature: description: Signature of the downloaded package, used for integrity verification schema: type: string format: base64 example: 'l1TdTeIuGdNsO1FQ0ptD64F5nSSOsQ5WzhM6/7KsHRuLHfTsggnyIWr0DxMcBj5F40zfplwntXAgS0ynlqvlFw==' Link: description: A header containing mirrors or multiple download locations. schema: type: string description: A Link header with a `duplicate` relation, as described by RFC 6249. example: '; rel=duplicate; geo=jp; pri=10; type="application/zip"' content: application/zip: schema: type: string format: binary '303': description: See other - download from the URL in the Location header. headers: Location: description: The location from which to download the resource. required: true schema: type: string example: 'https://example.cdn.com/LinkedList-1.1.1.zip?key=XXXXXXXXXXXXXXXXX' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '415': $ref: '#/components/responses/UnsupportedMediaType' '429': $ref: '#/components/responses/TooManyRequests' '/identifiers': parameters: - $ref: '#/components/parameters/Url' get: tags: - Packages summary: Lookup package identifiers registered for a URL operationId: lookupPackageIdentifiersByURL responses: '200': description: Retrieve a list of package identifiers registered for a specific URL headers: Content-Version: $ref: '#/components/headers/ContentVersion' content: 'application/json': schema: $ref: '#/components/schemas/Identifiers' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '415': $ref: '#/components/responses/UnsupportedMediaType' '429': $ref: '#/components/responses/TooManyRequests' '/login': post: tags: - Authentication summary: Log in to the package registry operationId: loginToRegistry description: |- Log in using either basic or token authentication. Use the `Authorization` header to provide credentials. Also use this endpoint to verify authentication credentials before saving them to the local secrets store. responses: '200': description: User successfully logged in to the package registry '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' '501': description: Registry does not support authentication. components: parameters: SwiftVersion: name: swift-version in: query required: false description: The Swift version for which to fetch the manifest schema: type: string example: '4.2' Scope: name: scope in: path required: true description: |- The scope of the package (for example, the organization or user). Package scopes are case-insensitive. schema: type: string pattern: '[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}' example: 'mona' PackageName: name: name in: path required: true description: |- The name of the package. Package names are case-insensitive. schema: type: string pattern: '[a-zA-Z0-9](?:[a-zA-Z0-9]|[-_](?=[a-zA-Z0-9])){0,99}' example: 'LinkedList' Version: name: version in: path required: true description: The semantic version of the package release. schema: type: string example: '1.2.3' Url: name: url in: query required: true description: The URL for which to look up registered package identifiers schema: type: string example: 'https://example.com/mona/LinkedList' responses: Unauthorized: description: Authentication failed due to invalid credentials provided content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' BadRequest: description: Bad Request - The request was invalid or cannot be otherwise served content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' NotFound: description: Not Found - The specified resource could not be found content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' UnsupportedMediaType: description: Unsupported Media Type - Accept header specifies a valid but unsupported API version. content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' TooManyRequests: description: Too Many Requests - Rate limit exceeded headers: 'Retry-After': $ref: '#/components/headers/RetryAfter' content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetails' headers: PackageLinks: schema: type: string description: |- A set of related links. An example: ; rel="canonical", ; rel="alternate", ; rel="latest-version", ; rel="payment", ; rel="first", ; rel="previous", ; rel="next", ; rel="last" Another example: ; rel="latest-version", ; rel="predecessor-version" Also see: - https://www.rfc-editor.org/rfc/rfc6596.html - https://html.spec.whatwg.org/multipage/links.html#link-type-alternate - https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#4-endpoints RetryAfter: schema: type: string description: |- Retry-After header, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After. Examples: Retry-After: Wed, 21 Oct 2015 07:28:00 GMT Retry-After: 120 example: '120' ContentVersion: description: The content version. required: true schema: type: integer enum: - 1 schemas: PackageOrganization: type: object properties: description: description: A description of the organization. type: string email: description: Email address of the organization. format: email type: string name: description: Name of the organization. type: string url: description: URL of the organization. format: uri type: string required: - name PackageAuthor: type: object properties: description: description: A description of the author. type: string email: description: Email address of the author. format: email type: string name: description: Name of the author. type: string organization: $ref: '#/components/schemas/PackageOrganization' url: description: URL of the author. format: uri type: string required: - name PackageMetadata: type: object description: Metadata of a package release. properties: author: $ref: '#/components/schemas/PackageAuthor' description: type: string description: A description of the package release. licenseURL: type: string format: uri description: URL of the package release's license document. originalPublicationTime: type: string format: date-time description: Original publication time of the package release in ISO 8601 format. readmeURL: type: string format: uri description: URL of the README specifically for the package release or broadly for the package. repositoryURLs: type: array items: description: Code repository URL. type: string format: uri description: Code repository URL(s) of the package release. PublishResponse: type: object properties: message: type: string example: 'Package release successfully published' url: type: string format: uri description: The URL of the newly published package release example: 'https://packages.example.com/mona/LinkedList/1.1.0' ProblemDetails: type: object description: A problem detail object conforming to RFC7807 properties: type: type: string format: uri description: |- A URI reference that identifies the problem type. This specification encourages that, when dereferenced, it provides human-readable documentation for the problem type. example: 'https://example.com/problem/invalid-request-parameters' title: type: string description: |- A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. example: 'Invalid request parameters' status: type: integer description: |- The HTTP status code generated by the origin server for this occurrence of the problem. example: 400 detail: type: string description: A human-readable explanation specific to this occurrence of the problem. example: 'The "name" field is required.' instance: type: string format: uri description: A URI reference that identifies the specific occurrence of the problem. example: '/requests/12345' additionalProperties: true ListedRelease: type: object properties: url: type: string format: uri example: 'https://packages.example.com/mona/LinkedList/1.1.0' problem: $ref: '#/components/schemas/ProblemDetails' Releases: type: object properties: releases: type: object additionalProperties: $ref: '#/components/schemas/ListedRelease' required: - releases ReleaseSignature: type: object properties: signatureBase64Encoded: type: string format: base64 description: The resource's signature, base64 encoded. example: 'dGVzdFNpZ25hdHVyZQ==' signatureFormat: type: string description: The signature format. example: 'cms-1.0.0' required: - signatureBase64Encoded - signatureFormat ReleaseResource: type: object properties: name: type: string description: The name of the resource. example: 'source-archive' type: type: string description: The content type of the resource. example: 'application/zip' checksum: type: string description: A hexadecimal representation of the SHA256 digest for the resource. example: 'efaa6545cd99dd1e124b5269ea0586994b6d97a0443021d2966e1df6dec9c4a1' signing: $ref: '#/components/schemas/ReleaseSignature' required: - name - type - checksum ReleaseMetadata: type: object properties: id: $ref: '#/components/schemas/Identifier' version: type: string description: The package release version number. example: '1.2.3' resources: type: array items: $ref: '#/components/schemas/ReleaseResource' description: The resources available for the release. metadata: $ref: '#/components/schemas/PackageMetadata' publishedAt: type: string format: date-time description: |- The ISO 8601-formatted datetime string of when the package release was published, as recorded by the registry. See related `originalPublicationTime` in metadata. required: - id - version - resources - metadata Identifier: type: string example: 'mona.LinkedList' Identifiers: type: object properties: identifiers: type: array items: $ref: '#/components/schemas/Identifier' required: - identifiers ================================================ FILE: Documentation/README.md ================================================ # Swift Package Manager The documentation previously included here has primarily been migrated into DocC format, and is available for viewing online at Swift.org [Package Manager Docs](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs). The sources for the documentation content are in the [Sources/PackageManagerDocs](Sources/PackageManagerDocs) directory. For documentation on developing the Swift Package Manager itself, see the [contribution guide](CONTRIBUTING.md). This directory continues to retain legacy [design notes](Design), [release notes](ReleaseNotes), details about the [Package Registry API](PackageRegistry), and [libSwiftPM](libSwiftPM). ================================================ FILE: Documentation/ReleaseNotes/5.3.md ================================================ # SwiftPM 5.3 Release Notes SwiftPM brings several new features in version 5.3, all of which are opt-in based on the tools-version. ### Conditional dependencies You can now declare conditions for a Swift package’s target dependencies, such as limiting the dependencies by platform. This gives you more flexibility to describe complex target dependencies that support multiple platforms. (40237402) ```swift // swift-tools-version:5.3 import PackageDescription let package = Package( name: "SamplePackage", dependencies: [ .package(url: "https://github.com/pureswift/bluetooth", .branch("main")), .package(url: "https://github.com/pureswift/bluetoothlinux", .branch("main")), ], targets: [ .target( name: "SampleExecutable", dependencies: [ .product(name: "Bluetooth", condition: .when(platforms: [.macOS])), .product(name: "BluetoothLinux", condition: .when(platforms: [.linux])), ] ), ] ) ``` ### Resources Swift packages can now contain resources such as images, asset catalogs, storyboards, and other files. When Xcode builds an app that depends on a package, it adds the package’s code and resources to the app bundle for use at runtime. For more information see [Bundling Resources with a Swift Package](https://developer.apple.com/documentation/swift_packages/bundling_resources_with_a_swift_package). (54361843) Any resource in the package can now contain localized content. In addition to localized content in asset catalogs, Xcode supports separate localization files in .lproj folders. For more information see [Localizing Package Resources](https://developer.apple.com/documentation/swift_packages/localizing_package_resources). (56925255) **Important**: The addition of resource support also changed the inclusion behavior for non-source files in packages. Updating a package tools-version to 5.3, means one has to explicitly declare whether to exclude or process any file whose type is unknown to SwiftPM. This can be done at the file or directory level. ### Binary dependencies Swift packages can now vend prebuilt libraries distributed as XCFrameworks, allowing dependencies on libraries that can’t be distributed as source code. When Xcode builds an app that uses such a package, it embeds the libraries into the app bundle. For more information see [Distributing Binary Frameworks as Swift Packages](https://developer.apple.com/documentation/swift_packages/distributing_binary_frameworks_as_swift_packages). (56592977) ================================================ FILE: Documentation/ReleaseNotes/5.4.md ================================================ # SwiftPM 5.4 Release Notes SwiftPM 5.4 includes several improvements, all of which are opt-in based on specifying a tools version of 5.4. ### Executable targets Swift packages that specify a 5.4 tools version can now explicitly declare targets as executable, which allows the use of the `@main` keyword in package code. This is done by declaring the target using `executableTarget()` in the package manifest, telling SwiftPM that the target should be considered to be executable regardless of whether it contains a file with a base name of `main`. The compiler still applies its usual rules when compiling an executable module, so a single target cannot, for example, have a file named `main.swift` and another file that uses `@main`. ### Automatic test discovery Automatic test discovery is now the default on all platforms, removing the need in `LinuxMain.swift`, which has been deprecated. This file is still honored if it is present. ### More flexible tools version formatting `Package` manifests can now have any combination of leading whitespace characters before the tools version comment. This allows more flexibility in formatting manifests. Specifically, the Swift tools version specification in each manifest file now accepts any combination of _horizontal_ whitespace characters surrounding `swift-tools-version`, if and only if the specified version ≥ `5.4`. For example, `//swift-tools-version: 5.4` and `// swift-tools-version: 5.4` are valid. All [Unicode line terminators](https://www.unicode.org/reports/tr14/) are now recognised in `Package` manifests. This ensures correctness in parsing manifests that are edited and/or built on many non-Unix-like platforms that use ASCII or Unicode encodings. ### Package dependency caching Swift Package Manager now caches package dependency repositories on a per-user basis, which reduces the amount of network traffic and increases performance of dependency resolution for subsequent uses of the same package. The default location of the cache differs depending on the platform, but can be controlled using the new `--cache-path` option. SwiftPM also creates a symbolic link at `~/.swiftpm` referencing the default cache location. Compiled package manifests are also now cached on a per-user basis. This can be overridden using the new `--manifest-cache` option. ================================================ FILE: Documentation/ReleaseNotes/5.5.md ================================================ # SwiftPM 5.5 Release Notes ### Package Collections You can now use package collections to discover, manage, and publish curated lists of packages. Package collections are authored as static JSON documents and can be published to the web or distributed to local file systems. SwiftPM and Xcode locally share the same package collections, so either interface can manage your added collections. To try the official Apple Swift Packages collection, run: ``` swift package-collection add https://developer.apple.com/swift/packages/collections/apple.json ``` Then, to see which packages are included in that collection and can now be imported in your code, run: ``` swift package-collection describe https://developer.apple.com/swift/packages/collections/apple.json ``` For more information about usage and how to publish your own package collections, see the [Package Collections documentation](../PackageCollections.md). ### Executable target testing Test targets can now link against executable targets as if they were libraries, so that they can test any data structures or algorithms in them. All the code in the executable except for the main entry point itself is available to the unit test. Separate executables are still linked, and can be tested as a subprocess in the same way as before. This feature is available to tests defined in packages that have a tools version of `5.5` or newer. (#3316) ### Manifest API improvements Two new dependency convenience initializers are now available (#3292, #3310): ``` .package(url: String, revision: String) .package(url: String, branch: String) ``` Target-based dependency resolution has also been improved. A more intuitive `.product(name:, package:)` syntax is now accepted, where `package` is the package name as defined by the package URL. (#3280) ### Other improvements `@main` can now be used in a single-source file executable as long as the name of the source file isn't `main.swift`. To work around special compiler semantics with single-file modules, SwiftPM now passes `-parse-as-library` when compiling an executable module that contains a single Swift source file whose name is not `main.swift`. This feature is available in packages that have a tools version of `5.5` or newer. (#3410) An issue where resolution of packages with binary dependencies failed to extract the binary archive was fixed. (#3507) ================================================ FILE: Documentation/ReleaseNotes/5.6.md ================================================ # SwiftPM 5.6 Release Notes ### Package Plugins [SE-0303](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md) Introduces the ability to define build tool plugins in SwiftPM, allowing custom tools to be automatically invoked during a build. Build tool plugins are focused on code generation during the build of a package, for such purposes as generating Swift source files from .proto files or from other inputs, in order to allow build tools to be incorporated into the build graph and to run automatically in a safe manner. [SE-0332](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0332-swiftpm-command-plugins.md) Extends SwiftPM plugin support first introduced with SE-0303 to allow the definition of custom command plugins — plugins that users can invoke directly from the SwiftPM CLI, or from an IDE that supports Swift Packages, in order to perform custom actions on their packages. A command plugin specifies the semantic intent of the command — this might be one of the predefined intents such “documentation generation” or “source code formatting”, or it might be a custom intent with a specialized verb that can be passed to the swift package command. ### Manifest API Improvements Semantic version dependencies can now be resolved against Git tag names that contain only major and minor version identifiers. A tag with the form `X.Y` will be treated as `X.Y.0`. This improves compatibility with existing repositories. Both parsing and comparison of semantic versions now strictly follow the Semantic Versioning 2.0.0 specification (https://semver.org/). The parsing logic now treats the first "-" in a version string as the delimiter between the version core and the pre-release identifiers, only if there is no preceding "+". Otherwise, it's treated as part of a build metadata identifier. The comparison logic now ignores build metadata identifiers, and treats 2 semantic versions as equal if and only if they're equal in their major, minor, patch versions and pre-release identifiers. `.package(name:, url:)` dependency syntax is deprecated in favor of `.package(url:)`, given that an explicit name attribute is no longer needed for target dependencies lookup. Adding a dependency requirement can now be done with the convenience initializer .package(url: String, exact: Version). Dependency requirement enum calling convention is deprecated in favour of labeled argument: * `.package(url: String, .branch(String)) -> .package(url: String, branch: String)` * `.package(url: String, .revision(String)) -> .package(url: String, revision: String)` * `.package(url: String, .exact(Version)) -> .package(url: String, exact: Version)` ### Other Improvements Location of configuration files (including mirror file) have changed to accommodate new features that require more robust configuration directories structure, such as SE-0292: * `/.swiftpm/config` (mirrors file) was moved to `/.swiftpm/configuration/mirrors.json`. SwiftPM 5.6 will automatically copy the file from the old location to the new one and emit a warning to prompt the user to delete the file from the old location. * `~/.swiftpm/config/collections.json` (collections file) was moved to `~/.swiftpm/configuration/collections.json`. SwiftPM 5.6 will automatically copy the file from the old location to the new one and emit a warning to prompt the user to delete the file from the old location. To increase the security of packages, SwiftPM performs trust on first use (TOFU) validation. The fingerprint of a package is now being recorded when the package is first downloaded from a Git repository or package registry. Subsequent downloads must have fingerprints matching previous recorded values, otherwise it would result in build warnings or failures depending on settings. Introduce a second version of `Package.resolved` file format which more accurately captures package identity. ================================================ FILE: Documentation/ReleaseNotes/5.7.md ================================================ # SwiftPM 5.7 Release Notes ### Package Plugins [SE-0303: Build tool plugins](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md) and [SE-0332: Command Plugins](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0332-swiftpm-command-plugins.md) which were first introduced in Swift 5.6 have been further refined, with support for generating resources and improved diagnostics. To learn more, refer to the [Getting Started with Plugins](../Plugins.md) guide. ### Package Registry Support SwiftPM now supports package registry related capabilities introduced by [SE-0292](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md) and the corresponding [service specification](../Registry.md). With the exception of package publishing, SwiftPM can resolve and download dependencies from any compliant registry using the defined APIs. To get started, users will need to specify their package registry by running the `swift package-registry set` subcommand or editing the `registries.json` configuration file. `swift package` tool's `--use-registry-identity-for-scm` and `--replace-scm-with-registry` options might also be of interest. ### Module Aliasing For Disambiguation Modules with the same name from different packages can now be disambiguated by module aliasing [SE-0339](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0339-module-aliasing-for-disambiguation.md). When adding a product dependency for a target in a package manifest, use a new parameter `moduleAliases` to provide a new unique name for a conflicting module. * [#4119] Add a `--disable-testable-imports` flag to `swift test` with which tests are built without the testability feature (`import @testable` disabled). ================================================ FILE: Documentation/ReleaseNotes/5.8.md ================================================ # SwiftPM 5.8 Release Notes ## Package manifest changes SwiftPM targets can now specify the upcoming language features they require. `Package.swift` manifest syntax has been expanded with an API to include setting `enableUpcomingFeature` and `enableExperimentalFeature` flags at the target level, as specified by [SE-0362](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md). SwiftPM now allows exposing an executable product that consists solely of a binary target that is backed by an artifact bundle. This allows vending binary executables as their own separate package, independently of plugins that are using them. In packages using tools version 5.8 or later, `Foundation` is no longer implicitly imported into package manifests. If `Foundation` APIs are used, the module needs to be imported explicitly. ## Package Registry Support SwiftPM now supports token authentication when interacting with a package registry. The `swift package-registry` command has two new subcommands `login` and `logout` as defined in [SE-0378](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0378-package-registry-auth.md) for adding/removing registry credentials. ## Other improvements Improved handling of offline behavior when a compatible cached version of a dependency exists on disk in either the per-package or shared cache. SwiftPM will check for network availability status to determine if it should attempt to update a checked version of a dependency, and when offline will use the cached version without an update. New `--pkg-config-path` option on `build`, `test`, and `run` commands has been introduced as an alternative to passing `PKG_CONFIG_PATH` environment variable. It allows specifying alternative path to search for `.pc` files used by `pkg-config`. Use the option multiple times to specify more than one path. Added new `--emit-extension-block-symbols` and `--omit-extension-block-symbols` via `swift package dump-symbol-graph`. `--emit-extension-block-symbols` dumps symbol graph files that are extension block symbol format. The default behavior does not change. The `--omit-extension-block-symbols` flag will be used to explicitly disable the feature once the default behavior has been changed to `--emit-extension-block-symbols` in the future. ================================================ FILE: Documentation/ReleaseNotes/5.9.md ================================================ # SwiftPM 5.9 Release Notes ## Cross compilation SwiftPM now supports cross compilation based on the Swift SDK bundle format. While the feature is still considered experimental, we invite users to try it out and provide feedback. ## Package registry SwiftPM can now publish to a registry following the specification defined in SE-0391, as well as support signed packages, which may be required by a registry. Trust-on-first-use (TOFU) validation checks can now use signing identities in addition to fingerprints, and are enforced for source archives as well as package manifests. ## Embedded resources Basic support for a new `.embedInCode` resource rule which allows embedding the contents of the resource into the executable code by generating a byte array ``` struct PackageResources { static let best_txt: [UInt8] = [104,101,108,108,111,32,119,111,114,108,100,10] } ``` ## Other improvements The `CompilerPluginSupport` module enables defining macro targets. Macro targets allow authoring and distributing custom Swift macros as APIs in a library. Packages can use the new `package` access modifier, allowing access of symbols in another target / module within the same package without making them public. SwiftPM automatically sets the new compiler configuration to ensure this feature works out-of-the-box for packages. The `allowNetworkConnections(scope:reason:)` setting gives a command plugin permissions to access the network. Permissions can be scoped to Unix domain sockets as well as local or remote IP connections, with an option to limit by port. For non-interactive use cases, the `--allow-network-connections` command-line flag allows network connections for a particular scope. When a package contains a single target, sources may be distributed anywhere within the `./Sources` directory. If sources are placed in a subdirectory under `./Sources/`, or there is more than one target, the existing expectation for sources apply Build tool plugins can be used with C-family targets ================================================ FILE: Documentation/ReleaseNotes/6.3.md ================================================ # SwiftPM 6.3 Release Notes ## SwiftBuild: Preview of Next-Generation Build System SwiftBuild is being developed to replace the current native build system and brings several key improvements. Packages that build successfully with the existing native (default) build system should build with SwiftBuild without requiring changes to your `Package.swift` or source code. For more information, including known limitations and platform-specific issues, see the [SwiftBuild Preview documentation](https://github.com/swiftlang/swift-package-manager/blob/main/Sources/PackageManagerDocs/Documentation.docc/SwiftBuildPreview.md). ### Trying SwiftBuild You can preview the build system using the `--build-system` flag: ``` # Use SwiftBuild for building swift build --build-system swiftbuild # Use SwiftBuild for testing swift test --build-system swiftbuild # Use SwiftBuild for running executables swift run --build-system swiftbuild MyExecutable ``` The native build system remains the default and continues to be fully supported. We encourage developers to try SwiftBuild and [provide feedback](https://github.com/swiftlang/swift-package-manager/issues) on their experience. ## Improved Build Plugin Support for C Interoperability SwiftPM now properly supports generation of C source files from plugin tools into C module targets. In addition, it supports generation of module maps, header files, and API notes. This is an experimental feature. To enable it, add a tag to the swift tools version in the package manifest (Package.swift) of the target that uses the generator plugin as follows: ``` swift // swift-tools-version: 6.3;(experimentalCGen) ``` There are some limitations to this experimental mode. There can be only one generated module map for a given target. Header files to which this module map refers must be in the same directory as the module map. This is also true for any API notes files generated for modules in the module map. If a module map is generated, you can not provide one in the public headers path for the target. To assist in finding generated public header files, the build system adds the `include` directory from the plugin output directory to the include path for the module and all modules that transitively depend on it. The name of this directory is currently fixed. This functionality is available in **both** the native build system and SwiftBuild. ## Improved Prebuilt Swift Syntax for Macros Support Better support has been added to use prebuilts of the swift-syntax package in libraries that are only used by macros. This allows for code sharing between macro targets. SwiftPM now detects when such a library may be used by non macro targets and disables use of prebuilts when this is detected. It is disabled because mixing of swift-syntax prebuilts and swift-syntax built from source at link time has caused a number of issues. ## Symbol Graph Generation: Control Over Inherited Documentation Command plugins that generate symbol graphs can now control whether inherited documentation is included, providing better flexibility for different documentation styles. ## Package Traits: Improved Discoverability A new `swift package show-traits` command makes it easier to discover the traits supported by a package. ================================================ FILE: Documentation/libSwiftPM.md ================================================ # libSwiftPM - SwiftPM as a Library **NOTE: The libSwiftPM API is currently _unstable_ and may change at any time.** SwiftPM has a library based architecture and the top-level library product is called `libSwiftPM`. Other packages can add SwiftPM as a package dependency and create powerful custom build tools on top of `libSwiftPM`. A subset of `libSwiftPM` that includes only the data model (without SwiftPM's build system) is available as `libSwiftPMDataModel`. Any one client should depend on one or the other, but not both. The SwiftPM repository contains an [example](https://github.com/swiftlang/swift-package-manager/tree/main/Examples/package-info) that demonstrates the use of `libSwiftPM` in a Swift package. Use the following commands to run the example package: ```sh $ git clone https://github.com/swiftlang/swift-package-manager $ cd swift-package-manager/Examples/package-info $ swift run ``` ================================================ FILE: Examples/package-info/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "package-info", platforms: [ .macOS(.v13), .iOS(.v13) ], dependencies: [ // This just points to the SwiftPM at the root of this repository. .package(name: "swift-package-manager", path: "../../"), // You will want to depend on a stable semantic version instead: // .package(url: "https://github.com/swiftlang/swift-package-manager", .exact("0.4.0")) ], targets: [ .executableTarget( name: "package-info", dependencies: [ .product(name: "SwiftPM", package: "swift-package-manager") ] ), ] ) ================================================ FILE: Examples/package-info/README.md ================================================ # package-info Sample package built on top of libSwiftPM. ================================================ FILE: Examples/package-info/Sources/package-info/example.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 - 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Basics import TSCBasic import Workspace @main @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) struct Example { static func main() async throws { // PREREQUISITES // ============ // We need a package to work with. // This computes the path of this package root based on the file location let packagePath = try Basics.AbsolutePath(validating: #file).parentDirectory.parentDirectory.parentDirectory // LOADING // ======= // There are several levels of information available. // Each takes longer to load than the level above it, but provides more detail. let observability = ObservabilitySystem({ print("\($0): \($1)") }, outputStream: stdoutStream, logLevel: .debug) let workspace = try Workspace(forRootPackage: packagePath) let manifest = try await workspace.loadRootManifest(at: packagePath, observabilityScope: observability.topScope) let package = try await workspace.loadRootPackage(at: packagePath, observabilityScope: observability.topScope) let graph = try await workspace.loadPackageGraph(rootPath: packagePath, observabilityScope: observability.topScope) // EXAMPLES // ======== // Manifest let products = manifest.products.map({ $0.name }).joined(separator: ", ") print("Products:", products) let targets = manifest.targets.map({ $0.name }).joined(separator: ", ") print("Targets:", targets) // Package let executables = package.modules.filter({ $0.type == .executable }).map({ $0.name }) print("Executable targets:", executables) // PackageGraph let numberOfFiles = graph.reachableModules.reduce(0, { $0 + $1.sources.paths.count }) print("Total number of source files (including dependencies):", numberOfFiles) } } ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "Package1", targets: [ .executableTarget( name: "Example", dependencies: [ "Simple", "Wrapper" ] ), .target( name: "Wrapper", dependencies: [ "Simple" ] ), .binaryTarget( name: "Simple", path: "Simple.artifactbundle" ), ] ) ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/Makefile ================================================ SRC_FILES := $(wildcard *.c) # Define architectures and platforms ARCHS := x86_64 arm64 PLATFORMS := macos linux # Define output directories BUILD_DIR := build DIST_DIR := dist # Platform-specific settings MACOS_SDK := $(shell xcrun --sdk macosx --show-sdk-path 2>/dev/null || echo "") MACOS_MIN_VERSION := 10.15 # Compiler flags COMMON_FLAGS := -O2 # Platform and architecture specific flags MACOS_X86_64_FLAGS := -target x86_64-apple-macos$(MACOS_MIN_VERSION) -isysroot $(MACOS_SDK) MACOS_ARM64_FLAGS := -target arm64-apple-macos$(MACOS_MIN_VERSION) -isysroot $(MACOS_SDK) LINUX_X86_64_FLAGS := -target x86_64-unknown-linux-gnu LINUX_ARM64_FLAGS := -target aarch64-unknown-linux-gnu .PHONY: all clean macos linux universal all: macos linux # Create necessary directories $(BUILD_DIR): mkdir -p $(BUILD_DIR)/macos/x86_64 mkdir -p $(BUILD_DIR)/macos/arm64 mkdir -p $(BUILD_DIR)/linux/x86_64 mkdir -p $(BUILD_DIR)/linux/arm64 $(DIST_DIR): mkdir -p $(DIST_DIR)/macos mkdir -p $(DIST_DIR)/linux # macOS x86_64 build $(BUILD_DIR)/macos/x86_64/%.o: %.c | $(BUILD_DIR) clang $(COMMON_FLAGS) $(MACOS_X86_64_FLAGS) -c -o $@ $< # macOS arm64 build $(BUILD_DIR)/macos/arm64/%.o: %.c | $(BUILD_DIR) clang $(COMMON_FLAGS) $(MACOS_ARM64_FLAGS) -c -o $@ $< # Linux x86_64 build $(BUILD_DIR)/linux/x86_64/%.o: %.c | $(BUILD_DIR) clang $(COMMON_FLAGS) $(LINUX_X86_64_FLAGS) -c -o $@ $< # Linux arm64 build $(BUILD_DIR)/linux/arm64/%.o: %.c | $(BUILD_DIR) clang $(COMMON_FLAGS) $(LINUX_ARM64_FLAGS) -c -o $@ $< # Define object files for each platform and architecture MACOS_X86_64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/macos/x86_64/%.o,$(SRC_FILES)) MACOS_ARM64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/macos/arm64/%.o,$(SRC_FILES)) LINUX_X86_64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/linux/x86_64/%.o,$(SRC_FILES)) LINUX_ARM64_OBJ_FILES := $(patsubst %.c,$(BUILD_DIR)/linux/arm64/%.o,$(SRC_FILES)) # Create individual architecture libraries $(DIST_DIR)/macos/libSimple_x86_64.a: $(MACOS_X86_64_OBJ_FILES) | $(DIST_DIR) llvm-ar rc $@ $^ $(DIST_DIR)/macos/libSimple_arm64.a: $(MACOS_ARM64_OBJ_FILES) | $(DIST_DIR) llvm-ar rc $@ $^ $(DIST_DIR)/linux/libSimple_x86_64.a: $(LINUX_X86_64_OBJ_FILES) | $(DIST_DIR) llvm-ar rc $@ $^ $(DIST_DIR)/linux/libSimple_arm64.a: $(LINUX_ARM64_OBJ_FILES) | $(DIST_DIR) llvm-ar rc $@ $^ # Create universal binary for macOS $(DIST_DIR)/macos/libSimple.a: $(DIST_DIR)/macos/libSimple_x86_64.a $(DIST_DIR)/macos/libSimple_arm64.a lipo -create -output $@ $^ # For Linux, we'll provide separate libraries since lipo is macOS-specific linux: $(DIST_DIR)/linux/libSimple_x86_64.a $(DIST_DIR)/linux/libSimple_arm64.a @echo "Linux libraries built in $(DIST_DIR)/linux/" @echo "Note: For Linux, use the architecture-specific libraries as needed." macos: $(DIST_DIR)/macos/libSimple.a @echo "macOS universal library built at $(DIST_DIR)/macos/libSimple.a" clean: rm -rf $(BUILD_DIR) $(DIST_DIR) ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "Simple", products: [ .library(name: "Simple", type: .static, targets: ["Simple"]), ], targets: [ .target( name: "Simple", path: "." ), ] ) ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/build.sh ================================================ #!/bin/bash # currently only used for Windows rm -fr .build swift build --arch arm64 -c release swift build --arch x86_64 -c release cd dist rm -fr windows mkdir windows cd windows cp ../../.build/arm64-unknown-windows-msvc/release/libSimple.a Simple_arm64.lib cp ../../.build/x86_64-unknown-windows-msvc/release/libSimple.a Simple_x86_64.lib ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/include/simple.h ================================================ int foo(void); ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/include/simple.modulemap ================================================ module Simple { header "simple.h" export * } ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/info.json ================================================ { "schemaVersion": "1.0", "artifacts": { "simple": { "type": "staticLibrary", "version": "1.0.0", "variants": [ { "path": "dist/macOS/libSimple.a", "supportedTriples": ["arm64-apple-macosx", "x86_64-apple-macosx"], "staticLibraryMetadata": { "headerPaths": ["include"], "moduleMapPath": "include/simple.modulemap" } }, { "path": "dist/linux/libSimple_arm64.a", "supportedTriples": ["aarch64-unknown-linux-gnu"], "staticLibraryMetadata": { "headerPaths": ["include"], "moduleMapPath": "include/simple.modulemap" } }, { "path": "dist/linux/libSimple_x86_64.a", "supportedTriples": ["x86_64-unknown-linux-gnu"], "staticLibraryMetadata": { "headerPaths": ["include"], "moduleMapPath": "include/simple.modulemap" } }, { "path": "dist/windows/Simple_arm64.lib", "supportedTriples": ["aarch64-unknown-windows-msvc"], "staticLibraryMetadata": { "headerPaths": ["include"], "moduleMapPath": "include/simple.modulemap" } }, { "path": "dist/windows/Simple_x86_64.lib", "supportedTriples": ["x86_64-unknown-windows-msvc"], "staticLibraryMetadata": { "headerPaths": ["include"], "moduleMapPath": "include/simple.modulemap" } }, ] } } } ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Simple.artifactbundle/simple.c ================================================ int foo(void) { return 42; } ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Sources/Example/Example.swift ================================================ import Simple import Wrapper @main struct Example { static func main() { print(foo()) print(bar()) } } ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Sources/Wrapper/include/wrapper.h ================================================ int bar(void); ================================================ FILE: Fixtures/BinaryLibraries/Static/Package1/Sources/Wrapper/wrapper.c ================================================ #include "simple.h" int bar(void) { return foo(); } ================================================ FILE: Fixtures/BinaryTargets/Inputs/DynamicLibrary/DynamicLibrary.m ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ #import "DynamicLibrary.h" @implementation DynamicLibrary @end ================================================ FILE: Fixtures/BinaryTargets/Inputs/DynamicLibrary/include/DynamicLibrary.h ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ #import @interface DynamicLibrary : NSObject @end ================================================ FILE: Fixtures/BinaryTargets/Inputs/StaticLibrary/StaticLibrary.m ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ #import "StaticLibrary.h" @implementation StaticLibrary @end ================================================ FILE: Fixtures/BinaryTargets/Inputs/StaticLibrary/include/StaticLibrary.h ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ #import @interface StaticLibrary : NSObject @end ================================================ FILE: Fixtures/BinaryTargets/Inputs/SwiftFramework/SwiftFramework/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2020 David Hart. All rights reserved. ================================================ FILE: Fixtures/BinaryTargets/Inputs/SwiftFramework/SwiftFramework/SwiftFramework.h ================================================ // // SwiftFramework.h // SwiftFramework // // Created by David Hart on 17.02.20. // Copyright © 2020 David Hart. All rights reserved. // #import //! Project version number for SwiftFramework. FOUNDATION_EXPORT double SwiftFrameworkVersionNumber; //! Project version string for SwiftFramework. FOUNDATION_EXPORT const unsigned char SwiftFrameworkVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: Fixtures/BinaryTargets/Inputs/SwiftFramework/SwiftFramework/SwiftFramework.swift ================================================ // // SwiftFramework.swift // SwiftFramework // // Created by David Hart on 17.02.20. // Copyright © 2020 David Hart. All rights reserved. // import Foundation public struct SwiftFramework { public init() {} } ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "TestBinary", dependencies: [ ], targets: [ .target(name: "exe", dependencies: ["Library"]), .target(name: "Library", dependencies: ["SwiftFramework"]), .target(name: "cexe", dependencies: ["CLibrary"]), .target(name: "CLibrary", dependencies: ["StaticLibrary", "DynamicLibrary"]), .binaryTarget(name: "SwiftFramework", path: "SwiftFramework.xcframework"), .binaryTarget(name: "StaticLibrary", path: "StaticLibrary.xcframework"), .binaryTarget(name: "DynamicLibrary", path: "DynamicLibrary.xcframework"), ] ) ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Sources/CLibrary/CLibrary.m ================================================ #import "CLibrary.h" @implementation CLibrary - (instancetype)init { self = [super init]; _staticLibrary = [StaticLibrary new]; _dynamicLibrary = [DynamicLibrary new]; return self; } @end ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Sources/CLibrary/include/CLibrary.h ================================================ #import #import @interface CLibrary: NSObject @property (nonatomic, readonly) StaticLibrary* staticLibrary; @property (nonatomic, readonly) DynamicLibrary* dynamicLibrary; @end ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Sources/Library/Library.swift ================================================ import SwiftFramework public struct Library { public let framework = SwiftFramework() public init() { } } ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Sources/cexe/main.m ================================================ #import int main(int argc, const char* argv[]) { printf("%s", [CLibrary new].description.UTF8String); } ================================================ FILE: Fixtures/BinaryTargets/TestBinary/Sources/exe/main.swift ================================================ import SwiftFramework import Library print(SwiftFramework()) print(Library()) ================================================ FILE: Fixtures/CFamilyTargets/CDynamicLookup/Foo.c ================================================ #include "Foo.h" int foo() { bar(); int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/CDynamicLookup/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CDynamicLookup", targets: [ .target(name: "CDynamicLookup", path: "./"), ] ) ================================================ FILE: Fixtures/CFamilyTargets/CDynamicLookup/include/Foo.h ================================================ void bar(); int foo(); ================================================ FILE: Fixtures/CFamilyTargets/CLibraryNoIncludeDir/Cfactorial/Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Cfactorial", products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Cfactorial", targets: ["Cfactorial"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Cfactorial", dependencies: [], path: "Sources/factorial"), ] ) ================================================ FILE: Fixtures/CFamilyTargets/CLibraryNoIncludeDir/Cfactorial/Sources/factorial/factorial.c ================================================ //#include "include/factorial.h" #include "factorial.h" long factorial(int n) { if (n == 0 || n == 1) return 1; return n * factorial(n-1); } ================================================ FILE: Fixtures/CFamilyTargets/CLibraryNoIncludeDir/Cfactorial/Sources/factorial/factorial.h ================================================ #ifndef factorial_h #define factorial_h #include long factorial(int n); #endif /* factorial_h */ ================================================ FILE: Fixtures/CFamilyTargets/CLibraryNoIncludeDir/Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Client", dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), .package(path: "Cfactorial") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .executableTarget( name: "Client", dependencies: ["Cfactorial"]), ] ) ================================================ FILE: Fixtures/CFamilyTargets/CLibraryNoIncludeDir/Sources/Client/main.swift ================================================ import Cfactorial print(factorial(5)) print("Hello, world!") ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj xcuserdata/ DerivedData/ .swiftpm/config/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let package = Package( name: "CLibraryParentSearchPath", products: [ .library( name: "HeaderInclude", targets: ["HeaderInclude"]), ], targets: [ .target( name: "CHeaderInclude", cSettings: [ /* This package tests path normalization; incorrect path normalization on certain OSes (especially Windows) can lead to relative paths like these not being correctly passed to the C compiler. */ .headerSearchPath("../Constants") ] ), .target( name: "HeaderInclude", dependencies: [ "CHeaderInclude" ] ) ] ) ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/Sources/CHeaderInclude/answers.c ================================================ #include "answers.h" #include "Constants.h" int getAnswer(void) { return kTheAnswer; } ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/Sources/CHeaderInclude/include/answers.h ================================================ #ifndef answers_h #define answers_h extern int getAnswer(void); #endif /* answers_h */ ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/Sources/Constants/Constants.h ================================================ #ifndef Constants_h #define Constants_h static const int kTheAnswer = 42; #endif /* Constants_h */ ================================================ FILE: Fixtures/CFamilyTargets/CLibraryParentSearchPath/Sources/HeaderInclude/FinalForm.swift ================================================ import CHeaderInclude enum Answer { var value: Int { Int(getAnswer()) } } ================================================ FILE: Fixtures/CFamilyTargets/CLibrarySources/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CLibrarySources", targets: [ .target(name: "CLibrarySources", path: "Sources"), ] ) ================================================ FILE: Fixtures/CFamilyTargets/CLibrarySources/Sources/Foo.c ================================================ #include "Foo.h" int foo() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/CLibrarySources/Sources/include/Foo.h ================================================ int foo(); ================================================ FILE: Fixtures/CFamilyTargets/CLibrarySources/Tests/CLibrarySourcesTests/foo.swift ================================================ ================================================ FILE: Fixtures/CFamilyTargets/CLibrarySources/Tests/LinuxMain.swift ================================================ ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CLibraryWithSpaces", targets: [ .target(name: "Bar", dependencies: ["Foo"]), .target(name: "Baz", dependencies: ["Foo", "Bar"]), .target(name: "Foo", dependencies: []), .target(name: "Bar with spaces", dependencies: []), ] ) ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Bar/Bar.c ================================================ #include "Bar/Bar.h" #include "Foo/Foo.h" int bar() { int a = foo(); int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Bar/include/Bar/Bar.h ================================================ int bar(); ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Bar with spaces/Bar.c ================================================ int bar() { return 5; } ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Bar with spaces/include/Bar/Bar.h ================================================ int bar(); ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Baz/main.swift ================================================ import Foo import Bar let _ = foo() let _ = bar() ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Foo/Foo.c ================================================ #include "Foo/Foo.h" int foo() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/CLibraryWithSpaces/Sources/Foo/include/Foo/Foo.h ================================================ int foo(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ModuleMapGenerationCases", targets: [ .target( name: "Baz", dependencies: ["CustomModuleMap", "FlatInclude", "NonModuleDirectoryInclude", "UmbrellaHeader", "UmbrellaDirectoryInclude", "UmbrellaHeaderFlat"]), .target( name: "CustomModuleMap", dependencies: []), .target( name: "FlatInclude", dependencies: []), .target( name: "NoIncludeDir", dependencies: []), .target( name: "NonModuleDirectoryInclude", dependencies: []), .target( name: "UmbrellaDirectoryInclude", dependencies: []), .target( name: "UmbrellaHeader", dependencies: []), .target( name: "UmbrellaHeaderFlat", dependencies: []), ] ) ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/Baz/main.swift ================================================ import CustomModuleMap import UmbrellaDirectoryInclude import FlatInclude import UmbrellaHeader import UmbrellaHeaderFlat let _ = foo() let _ = bar() let _ = jaz() let _ = umbrellaHeaderFlat() let _ = qux() ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/CustomModuleMap/CustomModuleMap.c ================================================ #include "CustomModuleMap.h" int qux() { int a = 6; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/CustomModuleMap/include/CustomModuleMap.h ================================================ int qux(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/CustomModuleMap/include/module.modulemap ================================================ module CustomModuleMap { header "CustomModuleMap.h" export * } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/FlatInclude/FlatInclude.c ================================================ #include "FlatIncludeHeader.h" int bar() { int a = 6; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/FlatInclude/include/FlatIncludeHeader.h ================================================ int bar(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/NoIncludeDir/Jaz.c ================================================ int noDir() { int a = 6; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/NonModuleDirectoryInclude/Maz.c ================================================ #include "NonModuleDirectoryInclude/Maz.h" int maz() { int a = 6; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/NonModuleDirectoryInclude/include/NonModuleDirectoryInclude/Maz.h ================================================ int jaz(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaDirectoryInclude/Jaz.c ================================================ #include "Paz.h" int jaz() { int a = 6; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaDirectoryInclude/include/Paz.h ================================================ int jaz(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaHeader/UmbrellaHeader.c ================================================ #include "UmbrellaHeader/UmbrellaHeader.h" int foo() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaHeader/include/UmbrellaHeader/UmbrellaHeader.h ================================================ int foo(); ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaHeaderFlat/UmbrellaHeader.c ================================================ #include "UmbrellaHeaderFlat.h" int umbrellaHeaderFlat() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/CFamilyTargets/ModuleMapGenerationCases/Sources/UmbrellaHeaderFlat/include/UmbrellaHeaderFlat.h ================================================ int umbrellaHeaderFlat(); ================================================ FILE: Fixtures/CFamilyTargets/ObjCmacOSPackage/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ObjCmacOSPackage", targets: [ .target(name: "ObjCmacOSPackage", path: "Sources"), .testTarget(name: "ObjCmacOSPackageTests", dependencies: ["ObjCmacOSPackage"]), ] ) ================================================ FILE: Fixtures/CFamilyTargets/ObjCmacOSPackage/Sources/HelloWorldExample.m ================================================ #import #import "HelloWorldExample.h" @implementation HelloWorld - (NSString *)hello:(NSString *)name { if(!name) { name = @"World"; } return [NSString stringWithFormat:@"Hello, %@!", name]; } @end ================================================ FILE: Fixtures/CFamilyTargets/ObjCmacOSPackage/Sources/include/HelloWorldExample.h ================================================ #import @interface HelloWorld : NSObject - (NSString *)hello:(NSString *)name; @end ================================================ FILE: Fixtures/CFamilyTargets/ObjCmacOSPackage/Tests/ObjCmacOSPackageTests/HelloWorldTest.m ================================================ #import # import "HelloWorldExample.h" @interface HelloWorldTest : XCTestCase @end @implementation HelloWorldTest - (HelloWorld *)helloWorld { return [[HelloWorld alloc] init]; } - (void)testNoName { NSString *input = nil; NSString *expected = @"Hello, World!"; NSString *result = [[self helloWorld] hello:input]; XCTAssertEqualObjects(expected, result); } - (void)testSampleName { NSString *input = @"Alice"; NSString *expected = @"Hello, Alice!"; NSString *result = [[self helloWorld] hello:input]; XCTAssertEqualObjects(expected, result); } - (void)testOtherSampleName { NSString *input = @"Bob"; NSString *expected = @"Hello, Bob!"; NSString *result = [[self helloWorld] hello:input]; XCTAssertEqualObjects(expected, result); } @end ================================================ FILE: Fixtures/CFamilyTargets/SwiftCMixed/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "SwiftCMixed", targets: [ .target(name: "SeaExec", dependencies: ["SeaLib"]), .target(name: "CExec", dependencies: ["SeaLib"]), .target(name: "SeaLib", dependencies: []), ] ) ================================================ FILE: Fixtures/CFamilyTargets/SwiftCMixed/Sources/CExec/main.c ================================================ #include "Foo.h" #include int main() { printf("%d", foo(5)); return 0; } ================================================ FILE: Fixtures/CFamilyTargets/SwiftCMixed/Sources/SeaExec/main.swift ================================================ import SeaLib let a = foo(5) print("a = \(a)") ================================================ FILE: Fixtures/CFamilyTargets/SwiftCMixed/Sources/SeaLib/Foo.c ================================================ int foo(int a) { return a; } ================================================ FILE: Fixtures/CFamilyTargets/SwiftCMixed/Sources/SeaLib/include/Foo.h ================================================ int foo(int a); ================================================ FILE: Fixtures/Collections/GitHub/contributors.json ================================================ [ { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false, "contributions": 32 } ] ================================================ FILE: Fixtures/Collections/GitHub/languages.json ================================================ { "Swift": 3836385, "Shell": 96027, "C": 87433, } ================================================ FILE: Fixtures/Collections/GitHub/license.json ================================================ { "name": "LICENSE", "path": "LICENSE", "sha": "401c59dcc4570b954dd6d345e76199e1f4e76266", "size": 1077, "url": "https://api.github.com/repos/benbalter/gman/contents/LICENSE?ref=main", "html_url": "https://github.com/benbalter/gman/blob/main/LICENSE", "git_url": "https://api.github.com/repos/benbalter/gman/git/blobs/401c59dcc4570b954dd6d345e76199e1f4e76266", "download_url": "https://raw.githubusercontent.com/benbalter/gman/main/LICENSE?lab=true", "type": "file", "content": "VGhlIE1JVCBMaWNlbnNlIChNSVQpCgpDb3B5cmlnaHQgKGMpIDIwMTMgQmVu\nIEJhbHRlcgoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBv\nZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZgp0\naGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmls\nZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbgp0aGUgU29mdHdhcmUg\nd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRh\ndGlvbiB0aGUgcmlnaHRzIHRvCnVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwg\ncHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwg\nY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z\nIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywK\nc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJv\ndmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGlj\nZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwKY29waWVzIG9yIHN1YnN0YW50\naWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJ\nUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBL\nSU5ELCBFWFBSRVNTIE9SCklNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJ\nTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBG\nSVRORVNTCkZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklO\nR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUgpDT1BZ\nUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdF\nUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIKSU4gQU4gQUNUSU9OIE9G\nIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBP\nVVQgT0YgT1IgSU4KQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBU\nSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K\n", "encoding": "base64", "_links": { "self": "https://api.github.com/repos/benbalter/gman/contents/LICENSE?ref=main", "git": "https://api.github.com/repos/benbalter/gman/git/blobs/401c59dcc4570b954dd6d345e76199e1f4e76266", "html": "https://github.com/benbalter/gman/blob/main/LICENSE" }, "license": { "key": "mit", "name": "MIT License", "spdx_id": "MIT", "url": "https://api.github.com/licenses/mit", "node_id": "MDc6TGljZW5zZW1pdA==" } } ================================================ FILE: Fixtures/Collections/GitHub/metadata.json ================================================ { "id": 1296269, "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", "name": "Hello-World", "full_name": "octocat/Hello-World", "owner": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "private": false, "html_url": "https://github.com/octocat/Hello-World", "description": "This your first repo!", "fork": false, "url": "https://api.github.com/repos/octocat/Hello-World", "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", "events_url": "https://api.github.com/repos/octocat/Hello-World/events", "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", "git_url": "git:github.com/octocat/Hello-World.git", "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", "ssh_url": "git@github.com:octocat/Hello-World.git", "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", "clone_url": "https://github.com/octocat/Hello-World.git", "mirror_url": "git:git.example.com/octocat/Hello-World", "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", "svn_url": "https://svn.github.com/octocat/Hello-World", "homepage": "https://github.com", "language": null, "forks_count": 9, "forks": 9, "stargazers_count": 80, "watchers_count": 80, "watchers": 80, "size": 108, "default_branch": "main", "open_issues_count": 0, "open_issues": 0, "is_template": true, "topics": [ "octocat", "atom", "electron", "api" ], "has_issues": true, "has_projects": true, "has_wiki": true, "has_pages": false, "has_downloads": true, "archived": false, "disabled": false, "visibility": "public", "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:14:43Z", "permissions": { "pull": true, "push": false, "admin": false }, "allow_rebase_merge": true, "template_repository": null, "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", "allow_squash_merge": true, "delete_branch_on_merge": true, "allow_merge_commit": true, "subscribers_count": 42, "network_count": 0, "license": { "key": "mit", "name": "MIT License", "spdx_id": "MIT", "url": "https://api.github.com/licenses/mit", "node_id": "MDc6TGljZW5zZW1pdA==" }, "organization": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "Organization", "site_admin": false }, "parent": { "id": 1296269, "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", "name": "Hello-World", "full_name": "octocat/Hello-World", "owner": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "private": false, "html_url": "https://github.com/octocat/Hello-World", "description": "This your first repo!", "fork": false, "url": "https://api.github.com/repos/octocat/Hello-World", "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", "events_url": "https://api.github.com/repos/octocat/Hello-World/events", "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", "git_url": "git:github.com/octocat/Hello-World.git", "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", "ssh_url": "git@github.com:octocat/Hello-World.git", "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", "clone_url": "https://github.com/octocat/Hello-World.git", "mirror_url": "git:git.example.com/octocat/Hello-World", "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", "svn_url": "https://svn.github.com/octocat/Hello-World", "homepage": "https://github.com", "language": null, "forks_count": 9, "stargazers_count": 80, "watchers_count": 80, "size": 108, "default_branch": "main", "open_issues_count": 0, "is_template": true, "topics": [ "octocat", "atom", "electron", "api" ], "has_issues": true, "has_projects": true, "has_wiki": true, "has_pages": false, "has_downloads": true, "archived": false, "disabled": false, "visibility": "public", "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:14:43Z", "permissions": { "admin": false, "push": false, "pull": true }, "allow_rebase_merge": true, "template_repository": null, "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", "allow_squash_merge": true, "delete_branch_on_merge": true, "allow_merge_commit": true, "subscribers_count": 42, "network_count": 0, "license": { "key": "mit", "name": "MIT License", "url": "https://api.github.com/licenses/mit", "spdx_id": "MIT", "node_id": "MDc6TGljZW5zZW1pdA==", "html_url": "https://api.github.com/licenses/mit" }, "forks": 1, "open_issues": 1, "watchers": 1 }, "source": { "id": 1296269, "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", "name": "Hello-World", "full_name": "octocat/Hello-World", "owner": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "private": false, "html_url": "https://github.com/octocat/Hello-World", "description": "This your first repo!", "fork": false, "url": "https://api.github.com/repos/octocat/Hello-World", "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}", "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}", "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}", "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}", "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}", "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}", "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}", "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}", "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}", "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors", "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments", "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads", "events_url": "https://api.github.com/repos/octocat/Hello-World/events", "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks", "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}", "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}", "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}", "git_url": "git:github.com/octocat/Hello-World.git", "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}", "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}", "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}", "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}", "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}", "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges", "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}", "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}", "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}", "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}", "ssh_url": "git@github.com:octocat/Hello-World.git", "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers", "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}", "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers", "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription", "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags", "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams", "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}", "clone_url": "https://github.com/octocat/Hello-World.git", "mirror_url": "git:git.example.com/octocat/Hello-World", "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks", "svn_url": "https://svn.github.com/octocat/Hello-World", "homepage": "https://github.com", "language": null, "forks_count": 9, "stargazers_count": 80, "watchers_count": 80, "size": 108, "default_branch": "main", "open_issues_count": 0, "is_template": true, "topics": [ "octocat", "atom", "electron", "api" ], "has_issues": true, "has_projects": true, "has_wiki": true, "has_pages": false, "has_downloads": true, "archived": false, "disabled": false, "visibility": "public", "pushed_at": "2011-01-26T19:06:43Z", "created_at": "2011-01-26T19:01:12Z", "updated_at": "2011-01-26T19:14:43Z", "permissions": { "admin": false, "push": false, "pull": true }, "allow_rebase_merge": true, "template_repository": null, "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O", "allow_squash_merge": true, "delete_branch_on_merge": true, "allow_merge_commit": true, "subscribers_count": 42, "network_count": 0, "license": { "key": "mit", "name": "MIT License", "url": "https://api.github.com/licenses/mit", "spdx_id": "MIT", "node_id": "MDc6TGljZW5zZW1pdA==", "html_url": "https://api.github.com/licenses/mit" }, "forks": 1, "open_issues": 1, "watchers": 1 } } ================================================ FILE: Fixtures/Collections/GitHub/readme.json ================================================ { "type": "file", "encoding": "base64", "size": 5362, "name": "README.md", "path": "README.md", "content": "encoded content ...", "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", "url": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md", "git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", "html_url": "https://github.com/octokit/octokit.rb/blob/main/README.md", "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/main/README.md", "_links": { "git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1", "self": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md", "html": "https://github.com/octokit/octokit.rb/blob/main/README.md" } } ================================================ FILE: Fixtures/Collections/GitHub/releases.json ================================================ [ { "url": "https://api.github.com/repos/octocat/Hello-World/releases/1", "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0", "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets", "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}", "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0", "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0", "id": 1, "node_id": "MDc6UmVsZWFzZTE=", "tag_name": "v2.0.0", "target_commitish": "main", "name": "2.0.0", "body": "Description of the release", "draft": false, "prerelease": false, "created_at": "2013-02-27T19:35:32Z", "published_at": "2013-02-27T19:35:32Z", "author": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "assets": [ { "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1", "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip", "id": 1, "node_id": "MDEyOlJlbGVhc2VBc3NldDE=", "name": "example.zip", "label": "short description", "state": "uploaded", "content_type": "application/zip", "size": 1024, "download_count": 42, "created_at": "2013-02-27T19:35:32Z", "updated_at": "2013-02-27T19:35:32Z", "uploader": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false } } ] }, { "url": "https://api.github.com/repos/octocat/Hello-World/releases/1", "html_url": "https://github.com/octocat/Hello-World/releases/v1.0.0", "assets_url": "https://api.github.com/repos/octocat/Hello-World/releases/1/assets", "upload_url": "https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}", "tarball_url": "https://api.github.com/repos/octocat/Hello-World/tarball/v1.0.0", "zipball_url": "https://api.github.com/repos/octocat/Hello-World/zipball/v1.0.0", "id": 1, "node_id": "MDc6UmVsZWFzZTE=", "tag_name": "1.0.0", "target_commitish": "main", "name": "1.0.0", "body": "Description of the release", "draft": false, "prerelease": false, "created_at": "2013-02-27T19:35:32Z", "published_at": "2013-02-27T19:35:32Z", "author": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false }, "assets": [ { "url": "https://api.github.com/repos/octocat/Hello-World/releases/assets/1", "browser_download_url": "https://github.com/octocat/Hello-World/releases/download/v1.0.0/example.zip", "id": 1, "node_id": "MDEyOlJlbGVhc2VBc3NldDE=", "name": "example.zip", "label": "short description", "state": "uploaded", "content_type": "application/zip", "size": 1024, "download_count": 42, "created_at": "2013-02-27T19:35:32Z", "updated_at": "2013-02-27T19:35:32Z", "uploader": { "login": "octocat", "id": 1, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "", "url": "https://api.github.com/users/octocat", "html_url": "https://github.com/octocat", "followers_url": "https://api.github.com/users/octocat/followers", "following_url": "https://api.github.com/users/octocat/following{/other_user}", "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", "organizations_url": "https://api.github.com/users/octocat/orgs", "repos_url": "https://api.github.com/users/octocat/repos", "events_url": "https://api.github.com/users/octocat/events{/privacy}", "received_events_url": "https://api.github.com/users/octocat/received_events", "type": "User", "site_admin": false } } ] } ] ================================================ FILE: Fixtures/Collections/JSON/good.json ================================================ { "name": "Sample Package Collection", "overview": "This is a sample package collection listing made-up packages.", "keywords": ["sample package collection"], "formatVersion": "1.0", "revision": 3, "generatedAt": "2020-10-22T06:03:52Z", "generatedBy": { "name": "Jane Doe" }, "packages": [ { "url": "https://www.example.com/repos/RepoOne.git", "identity": "repos.one", "summary": "Package One", "keywords": ["sample package"], "readmeURL": "https://www.example.com/repos/RepoOne/README", "license": { "name": "Apache-2.0", "url": "https://www.example.com/repos/RepoOne/LICENSE" }, "versions": [ { "version": "0.1.0", "summary": "Fixed a few bugs", "manifests": { "5.1": { "toolsVersion": "5.1", "packageName": "PackageOne", "targets": [ { "name": "Foo", "moduleName": "Foo" } ], "products": [ { "name": "Foo", "type": { "library": ["automatic"] }, "targets": ["Foo"] } ], "minimumPlatformVersions": [ { "name": "macOS", "version": "10.15" } ] } }, "defaultToolsVersion": "5.1", "verifiedCompatibility": [ { "platform": { "name": "macOS" }, "swiftVersion": "5.1" }, { "platform": { "name": "iOS" }, "swiftVersion": "5.1" }, { "platform": { "name": "Linux" }, "swiftVersion": "5.1" } ], "license": { "name": "Apache-2.0", "url": "https://www.example.com/repos/RepoOne/LICENSE" }, "author": { "name": "J. Appleseed" }, "signer": { "type": "ADP", "commonName": "J. Appleseed", "organizationalUnitName": "A1", "organizationName": "Appleseed Inc." }, "createdAt": "2020-10-21T09:25:36Z" } ] }, { "url": "https://www.example.com/repos/RepoTwo.git", "summary": "Package Two", "readmeURL": "https://www.example.com/repos/RepoTwo/README", "versions": [ { "version": "2.1.0", "manifests": { "5.2": { "toolsVersion": "5.2", "packageName": "PackageTwo", "targets": [ { "name": "Bar", "moduleName": "Bar" } ], "products": [ { "name": "Bar", "type": { "library": ["automatic"] }, "targets": ["Bar"] } ] } }, "defaultToolsVersion": "5.2" }, { "version": "v1.8.3", "manifests": { "5.0": { "toolsVersion": "5.0", "packageName": "PackageTwo", "targets": [ { "name": "Bar", "moduleName": "Bar" } ], "products": [ { "name": "Bar", "type": { "library": ["automatic"] }, "targets": ["Bar"] } ] } }, "defaultToolsVersion": "5.0" } ] } ] } ================================================ FILE: Fixtures/Collections/JSON/good_signed.json ================================================ { "name": "Sample Package Collection", "overview": "This is a sample package collection listing made-up packages.", "keywords": ["sample package collection"], "formatVersion": "1.0", "revision": 3, "generatedAt": "2020-10-22T06:03:52Z", "generatedBy": { "name": "Jane Doe" }, "packages": [ { "url": "https://www.example.com/repos/RepoOne.git", "identity": "repos.one", "summary": "Package One", "keywords": ["sample package"], "readmeURL": "https://www.example.com/repos/RepoOne/README", "license": { "name": "Apache-2.0", "url": "https://www.example.com/repos/RepoOne/LICENSE" }, "versions": [ { "version": "0.1.0", "summary": "Fixed a few bugs", "manifests": { "5.1": { "toolsVersion": "5.1", "packageName": "PackageOne", "targets": [ { "name": "Foo", "moduleName": "Foo" } ], "products": [ { "name": "Foo", "type": { "library": ["automatic"] }, "targets": ["Foo"] } ], "minimumPlatformVersions": [ { "name": "macOS", "version": "10.15" } ] } }, "defaultToolsVersion": "5.1", "verifiedCompatibility": [ { "platform": { "name": "macOS" }, "swiftVersion": "5.1" }, { "platform": { "name": "iOS" }, "swiftVersion": "5.1" }, { "platform": { "name": "Linux" }, "swiftVersion": "5.1" } ], "license": { "name": "Apache-2.0", "url": "https://www.example.com/repos/RepoOne/LICENSE" }, "author": { "name": "J. Appleseed" }, "signer": { "type": "ADP", "commonName": "J. Appleseed", "organizationalUnitName": "A1", "organizationName": "Appleseed Inc." }, "createdAt": "2020-10-21T09:25:36Z" } ] }, { "url": "https://www.example.com/repos/RepoTwo.git", "summary": "Package Two", "readmeURL": "https://www.example.com/repos/RepoTwo/README", "versions": [ { "version": "2.1.0", "manifests": { "5.2": { "toolsVersion": "5.2", "packageName": "PackageTwo", "targets": [ { "name": "Bar", "moduleName": "Bar" } ], "products": [ { "name": "Bar", "type": { "library": ["automatic"] }, "targets": ["Bar"] } ] } }, "defaultToolsVersion": "5.2" }, { "version": "v1.8.3", "manifests": { "5.0": { "toolsVersion": "5.0", "packageName": "PackageTwo", "targets": [ { "name": "Bar", "moduleName": "Bar" } ], "products": [ { "name": "Bar", "type": { "library": ["automatic"] }, "targets": ["Bar"] } ] } }, "defaultToolsVersion": "5.0" } ] } ], "signature": { "signature": "", "certificate": { "subject": { "commonName": "Sample Subject" }, "issuer": { "commonName": "Sample Issuer" } } } } ================================================ FILE: Fixtures/Collections/Signing/Test_ec_key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIFyZDwhGj2Q6ZchEt6DIQSptRk9yKPo60JH5x4u3p4YmoAoGCCqGSM49 AwEHoUQDQgAEHg58TCXScU6zXSYygCNW0tBZeYFRWf3XAjaDJUkeEFUvKxiIcP8S sLfb8P9mukwJsj2CwfatwneFIUQGJ4P+SQ== -----END EC PRIVATE KEY----- ================================================ FILE: Fixtures/Collections/Signing/Test_rsa_key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAk1a/7/deGbDnbe9K8/LzN7fkx4D0kzCHIBlCuSylKOJKiPQ5 MHH13IXAKJYbudkufYdbACTo/4xjgvWLWI/C/ycbNfEGTPd0r6ahS9LRljgGaCVr eK4Jqg4VHIuC5B2fTQ5Tuv4k16JhKXuD/hCZ1my96Xwt2HPniRu9cIJFxlAz/1Fj botlL6EbUzzZ7msNLdXEm7QWUIuCN48z1FKk/uapAewzjq1r3X4+pWmEJSi+2tyS 5K03bmH+SE63fBui6o4dzeCrOblGQxqyqnR0mHOKe5rHU8Y5LVmkam/wyiRGTrmT OywsDhRtTyI0EZEp194C7QdLxiksGnl0wt/ArQIDAQABAoIBAG/1AD4QwrFU6lZv +Y1rNANHuhEa3T2nJ1Ztu3TIBuwNH8P3iClWvxMFkyGEBqdu71O1caGnamEcxVTy ziLKgsqtZZDUiAweEM2UGYZrOJUkF0I2BPcbj/5nWwVowVojZDQCSf+SNF6iZaBG 2eJJrQvxb1Gm6ZNLZ0mZCZcfdnOcwOwubGYGjoJV7qXRhs4kCfZMmA7g8MkQ0FBu 3fLmD2MMjWqJA2kgnYVf27BfoZrEJBfWSAQ5SKOeSnH7UqTF+L/HTrXJJnpjIY5i Xr/+lJ7BiOHHouP8dwbggjCmkrcGwcwE7PULyhycty5DOnSpGT2ktElyeqivxPVl Nqm3U+ECgYEAw8bsQrYrZoSGsmUBFQ29z+S402TJyTOF14PinkfEyF2Gmel0024A 1pY7eTrmlHJMBooy4IgdkLjKnaFMd98H+jcOpfX7dXXE+cCLAs9CA3HCeP5hsOl/ PduswEahqne58v/FcGDdc66Jf6bCb3sOcIku4vxKiInbbtv8hjvpCcUCgYEAwKlp KQZ072QP4cNil+ITZjlf5xhihHUudL6BLfiR3BxQhtDqk/23rbEB69yl5JkSoYA8 4T86Gdhnfe6lKHmWbgBN54tcoaesH8yKfTFvZZfbhENfV0gxXXpxdvjM1/1peRVK 0CJsDAEvyREKhD4nuWv50vqMBK+HjD9gYANNEckCgYBbCMKPernPn8wqY8EPEyax 5r7yvSj/P8/6mL7lrqWYLbULGH1UWxBUt+LLylGxsTwcxmJF+cUVqHe+uGQgUTsa ZEORdEILKkn/gEKjedBOXbV6IX83jju2fdFkTvOZmraCgeBDEyemRQB2tQowYF4k ggWlUn8t4jyA3hYcLPt9qQKBgQCDIsyxX/O3/iPRR2yUdQ0/R04/vhlQj3JPhFvp LogZiixFl24TzV54m0Lzh/xi3M4Rn3fQ2XhynxnSXd2M7zW1Kf/c2r7ySW6fNloN XNi2Decc377Fah4vwmf40uCbI6HnCNcjVEq24Rflg/Pkj2n6i8RAFsm3ZsKcc4bl 01liAQKBgBTPtA4M3/TpKDwuPedsmzumSe1Rmn4QSAd0ssrQ9XoPHYw2RkBSpCQg 1HYM/lD21uBr66nAtqpByiNILTQm1LiitBSnC9jOjpoM+ECqMyYPwfU9AD7weYlX qjLG9mzvjAEa7bzjweN77Mox4LDf6rEiAcs9ObceElEwN8W1g+63 -----END RSA PRIVATE KEY----- ================================================ FILE: Fixtures/Coverage/Simple/Package.swift ================================================ // swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Simple", products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "Simple", targets: ["Simple"] ), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( name: "Simple" ), .testTarget( name: "SimpleTests", dependencies: ["Simple"] ), ] ) ================================================ FILE: Fixtures/Coverage/Simple/Sources/Simple/Simple.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book public func greet(name: String = "world") -> String { return "Hello, \(name)!" } public func libA() -> String { return "libA" } ================================================ FILE: Fixtures/Coverage/Simple/Tests/SimpleTests/SimpleTests.swift ================================================ import Testing import XCTest @testable import Simple @Test( arguments: [ "Bob", "Alice", "", ] ) func testGreet( name: String ) async throws { let actual = greet(name: name) #expect(actual == "Hello, \(name)!") } final class SimpleTests: XCTestCase { func testExample() throws { XCTAssertEqual(libA(), "libA", "Actual is not as expected") } } ================================================ FILE: Fixtures/DependencyResolution/External/Branch/Bar/Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Bar", products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Bar", targets: ["Bar"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), .package(url: "../Foo", branch: "main") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Bar", dependencies: ["Foo"]), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Branch/Bar/Sources/Bar/Bar.swift ================================================ import Foo struct Bar { var text = "Hello, World!" } ================================================ FILE: Fixtures/DependencyResolution/External/Branch/Foo/Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Foo", products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Foo", targets: ["Foo"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "Foo", dependencies: []), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Branch/Foo/Sources/Foo/Foo.swift ================================================ struct Foo { var text = "Hello, World!" } ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", dependencies: [ .package(url: "../Foo", from: "1.0.0"), ], targets: [ .target(name: "SeaLover", dependencies: ["Foo"]), .target(name: "SwiftExec", dependencies: ["Foo"]), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Bar/Sources/SeaLover/Sea.c ================================================ #include void cool() { foo(); } ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Bar/Sources/SeaLover/include/Sea.h ================================================ ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Bar/Sources/SwiftExec/main.swift ================================================ import Foo foo() ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Foo/Foo.c ================================================ void foo() { } ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/CUsingCDep/Foo/include/Foo/Foo.h ================================================ void foo(); ================================================ FILE: Fixtures/DependencyResolution/External/Complex/FisherYates/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "FisherYates", products: [ .library(name: "FisherYates", targets: ["FisherYates"]), ], targets: [ .target(name: "FisherYates", path: "src"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Complex/FisherYates/src/Fisher-Yates_Shuffle.swift ================================================ public extension Collection { func shuffle() -> [Iterator.Element] { var array = Array(self) array.shuffleInPlace() return array } } public extension MutableCollection { /// Shuffles the contents of this collection. mutating func shuffleInPlace() { let c = count guard c > 1 else { return } for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) { var g = SystemRandomNumberGenerator() let d = Int.random(in: 1...unshuffledCount, using: &g) let i = index(firstUnshuffled, offsetBy: d) swapAt(firstUnshuffled, i) } } } public let shuffle = false ================================================ FILE: Fixtures/DependencyResolution/External/Complex/PlayingCard/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "PlayingCard", products: [ .library(name: "PlayingCard", targets: ["PlayingCard"]), ], targets: [ .target(name: "PlayingCard", path: "src"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Complex/PlayingCard/src/PlayingCard.swift ================================================ public struct PlayingCard: Equatable { let rank: Rank let suit: Suit public init(rank: Rank, suit: Suit) { self.rank = rank self.suit = suit } } // MARK: - Comparable extension PlayingCard: Comparable {} public func <(lhs: PlayingCard, rhs: PlayingCard) -> Bool { return lhs.suit < rhs.suit || (lhs.suit == rhs.suit && lhs.rank < rhs.rank) } // MARK: - CustomStringConvertible extension PlayingCard : CustomStringConvertible { public var description: String { return "\(suit)\(rank)" } } ================================================ FILE: Fixtures/DependencyResolution/External/Complex/PlayingCard/src/Rank.swift ================================================ public enum Rank : Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King } // MARK: - Comparable extension Rank : Comparable {} public func <(lhs: Rank, rhs: Rank) -> Bool { switch (lhs, rhs) { case (_, _) where lhs == rhs: return false case (.Ace, _): return false default: return lhs.rawValue < rhs.rawValue } } // MARK: - CustomStringConvertible extension Rank : CustomStringConvertible { public var description: String { switch self { case .Ace: return "A" case .Jack: return "J" case .Queen: return "Q" case .King: return "K" default: return "\(rawValue)" } } } ================================================ FILE: Fixtures/DependencyResolution/External/Complex/PlayingCard/src/Suit.swift ================================================ public enum Suit: String { case Spades, Hearts, Diamonds, Clubs } // MARK: - Comparable extension Suit: Comparable {} public func <(lhs: Suit, rhs: Suit) -> Bool { switch (lhs, rhs) { case (_, _) where lhs == rhs: return false case (.Spades, _), (.Hearts, .Diamonds), (.Hearts, .Clubs), (.Diamonds, .Clubs): return false default: return true } } // MARK: - CustomStringConvertible extension Suit : CustomStringConvertible { public var description: String { switch self { case .Spades: return "♠︎" case .Hearts: return "♡" case .Diamonds: return "♢" case .Clubs: return "♣︎" } } } ================================================ FILE: Fixtures/DependencyResolution/External/Complex/app/Package.swift ================================================ // swift-tools-version:5.0 import PackageDescription let package = Package( name: "Dealer", platforms: [ .macOS(.v10_12), .iOS(.v10), .tvOS(.v11), .watchOS(.v5) ], dependencies: [ .package(url: "../deck-of-playing-cards", from: "1.0.0"), ], targets: [ .target( name: "Dealer", dependencies: ["DeckOfPlayingCards"], path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Complex/app/main.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import FisherYates import PlayingCard import DeckOfPlayingCards let numberOfCards = 10 var deck = Deck.standard52CardDeck() if FisherYates.shuffle { deck.shuffle() } for _ in 0.. Deck { let suits: [Suit] = [.Spades, .Hearts, .Diamonds, .Clubs] let ranks: [Rank] = [.Ace, .Two, .Three, .Four, .Five, .Six, .Seven, .Eight, .Nine, .Ten, .Jack, .Queen, .King] var cards: [PlayingCard] = [] for suit in suits { for rank in ranks { cards.append(PlayingCard(rank: rank, suit: suit)) } } return Deck(cards) } public init(_ cards: [PlayingCard]) { self.cards = cards } public mutating func shuffle() { cards.shuffleInPlace() } public mutating func deal() -> PlayingCard? { guard !cards.isEmpty else { return nil } return cards.removeLast() } } // MARK: - ExpressibleByArrayLiteral extension Deck : ExpressibleByArrayLiteral { public init(arrayLiteral elements: PlayingCard...) { self.init(elements) } } ================================================ FILE: Fixtures/DependencyResolution/External/Complex/deck-of-playing-cards-local/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "DeckOfPlayingCards", products: [ .library(name: "DeckOfPlayingCards", targets: ["DeckOfPlayingCards"]), ], dependencies: [ .package(path: "../PlayingCard"), .package(path: "../FisherYates") ], targets: [ .target( name: "DeckOfPlayingCards", dependencies: ["PlayingCard", "FisherYates"], path: "src"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Complex/deck-of-playing-cards-local/src/Deck.swift ================================================ ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/App/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "App", dependencies: [ .package(url: "../Foo", .branch("main")), .package(url: "../Bar", .branch("main")), ], targets: [ .target(name: "App", dependencies: [ .product(name: "Foo", package: "Foo"), .product(name: "Bar", package: "Bar"), ], path: "./") ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/App/main.swift ================================================ import Foo import Bar public func main() { } ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/Bar/Bar.swift ================================================ public func hello() { } ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "Bar", targets: ["Bar"]), ], targets: [ .target(name: "Bar", path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/BarMirror/Bar.swift ================================================ public func hello() { } ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/BarMirror/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "Bar", targets: ["Bar"]), ], targets: [ .target(name: "Bar", path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/Foo/Foo.swift ================================================ public func hello() { } ================================================ FILE: Fixtures/DependencyResolution/External/Mirror/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/PackageLookupCaseInsensitive/dep/Package.swift ================================================ // swift-tools-version:5.0 import PackageDescription let package = Package( name: "Dep", products: [ .library(name: "Dep", targets: ["Dep"]), ], targets: [ .target(name: "Dep", dependencies: []), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/PackageLookupCaseInsensitive/dep/Sources/Dep/dep.swift ================================================ public struct dep { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/DependencyResolution/External/PackageLookupCaseInsensitive/pkg/Package.swift ================================================ // swift-tools-version:5.4 import PackageDescription let package = Package( name: "pkg", products: [ .library(name: "pkg", targets: ["pkg"]), ], dependencies: [ .package(path: "../dep"), ], targets: [ .target( name: "pkg", dependencies: [.product(name: "Dep", package: "Dep")]), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/PackageLookupCaseInsensitive/pkg/Sources/pkg/pkg.swift ================================================ public struct pkg { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/DependencyResolution/External/Simple/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", dependencies: [ .package(url: "../Foo", from: "1.0.0"), ], targets: [ .target(name: "Bar", dependencies: ["Foo"], path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/Simple/Bar/main.swift ================================================ import Foo foo() ================================================ FILE: Fixtures/DependencyResolution/External/Simple/Foo/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/DependencyResolution/External/Simple/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/DependencyResolution/External/XCFramework/Bar.xcframework/Info.plist ================================================ AvailableLibraries LibraryIdentifier macos-x86_64 LibraryPath Framework.framework SupportedArchitectures x86_64 SupportedPlatform macos CFBundlePackageType XFWK XCFrameworkFormatVersion 1.0 ================================================ FILE: Fixtures/DependencyResolution/External/XCFramework/Foo/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/DependencyResolution/External/XCFramework/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo", "Bar"]), ], targets: [ .target(name: "Foo", path: "./Foo"), .binaryTarget(name: "Bar", path: "./Bar.xcframework") ] ) ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", targets: [ .target(name: "Bar", dependencies: ["Baz", "Cat"]), .target(name: "Baz", dependencies: []), .target(name: "Cat", dependencies: ["Sound"]), .target(name: "Foo", dependencies: ["Bar"]), .target(name: "Sound", dependencies: []), ] ) ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Bar/Bar.swift ================================================ import Baz import Cat public class Bar { public init() {} public let baz = Baz() public let cat = Cat() } ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Baz/Baz.swift ================================================ public class Baz { public let value = "Baz" public init() {} } ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Cat/Cat.swift ================================================ import Sound public class Cat { public let sound = Sound() public init() {} } ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Foo/Foo.swift ================================================ import Bar func foo() -> String { let bar = Bar() return bar.cat.sound.description + " " + bar.baz.value } ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Foo/main.swift ================================================ print(foo()) // TODO copy this fixture and make one that should not compile due to the dependency not being specified ================================================ FILE: Fixtures/DependencyResolution/Internal/Complex/Sources/Sound/Sound.swift ================================================ public class Sound: CustomStringConvertible { public init() {} public var description: String { return "meiow" } } ================================================ FILE: Fixtures/DependencyResolution/Internal/InternalExecutableAsDependency/Bar/Bar.swift ================================================ public struct Bar { public init() {} public let value = "Bar" } ================================================ FILE: Fixtures/DependencyResolution/Internal/InternalExecutableAsDependency/Bar/main.swift ================================================ ================================================ FILE: Fixtures/DependencyResolution/Internal/InternalExecutableAsDependency/Foo/Foo.swift ================================================ class Foo { let value = "Foo" } ================================================ FILE: Fixtures/DependencyResolution/Internal/InternalExecutableAsDependency/Foo/main.swift ================================================ import Bar print(Foo().value) print(Bar().value) ================================================ FILE: Fixtures/DependencyResolution/Internal/InternalExecutableAsDependency/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Foo", dependencies: ["Bar"], path: "Foo"), .target(name: "Bar", path: "Bar"), ] ) ================================================ FILE: Fixtures/DependencyResolution/Internal/Simple/Bar/Bar.swift ================================================ public struct Bar { public init() {} public let value = "Bar" } ================================================ FILE: Fixtures/DependencyResolution/Internal/Simple/Foo/Foo.swift ================================================ class Foo { let value = "Foo" } ================================================ FILE: Fixtures/DependencyResolution/Internal/Simple/Foo/main.swift ================================================ import Bar print(Foo().value) print(Bar().value) ================================================ FILE: Fixtures/DependencyResolution/Internal/Simple/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Foo", dependencies: ["Bar"], path: "Foo"), .target(name: "Bar", path: "Bar"), ] ) ================================================ FILE: Fixtures/Macros/MacroPackage/Package.swift ================================================ // swift-tools-version: 999.0 import PackageDescription import CompilerPluginSupport let settings: [SwiftSetting] = [ .enableExperimentalFeature("Macros"), .unsafeFlags(["-Xfrontend", "-dump-macro-expansions"]) ] let package = Package( name: "MacroPackage", platforms: [ .macOS(.v10_15), ], targets: [ .macro(name: "MacroImpl"), .target(name: "MacroDef", dependencies: ["MacroImpl"], swiftSettings: settings), .executableTarget(name: "MacroClient", dependencies: ["MacroDef"], swiftSettings: settings), ] ) ================================================ FILE: Fixtures/Macros/MacroPackage/Sources/MacroClient/client.swift ================================================ import MacroDef struct Font: ExpressibleByFontLiteral { init(fontLiteralName: String, size: Int, weight: MacroDef.FontWeight) { } } let _: Font = #fontLiteral(name: "Comic Sans", size: 14, weight: .thin) ================================================ FILE: Fixtures/Macros/MacroPackage/Sources/MacroDef/definition.swift ================================================ public enum FontWeight { case thin case normal case medium case semiBold case bold } public protocol ExpressibleByFontLiteral { init(fontLiteralName: String, size: Int, weight: FontWeight) } /// Font literal similar to, e.g., #colorLiteral. @freestanding(expression) public macro fontLiteral(name: String, size: Int, weight: FontWeight) -> T = #externalMacro(module: "MacroImpl", type: "FontLiteralMacro") where T: ExpressibleByFontLiteral ================================================ FILE: Fixtures/Macros/MacroPackage/Sources/MacroImpl/macro.swift ================================================ import SwiftSyntax import SwiftSyntaxBuilder import SwiftSyntaxMacros /// Implementation of the `#fontLiteral` macro, which is similar in spirit /// to the built-in expressions `#colorLiteral`, `#imageLiteral`, etc., but in /// a small macro. public struct FontLiteralMacro: ExpressionMacro { public static func expansion( of macro: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext ) -> ExprSyntax { let argList = replaceFirstLabel( of: macro.argumentList, with: "fontLiteralName" ) let initSyntax: ExprSyntax = ".init(\(argList))" if let leadingTrivia = macro.leadingTrivia { return initSyntax.with(\.leadingTrivia, leadingTrivia) } return initSyntax } } /// Replace the label of the first element in the tuple with the given /// new label. private func replaceFirstLabel( of tuple: TupleExprElementListSyntax, with newLabel: String ) -> TupleExprElementListSyntax { guard let firstElement = tuple.first else { return tuple } return tuple.replacing( childAt: 0, with: firstElement.with(\.label, .identifier(newLabel)) ) } ================================================ FILE: Fixtures/Macros/MinimalMacroPackage/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription import CompilerPluginSupport let package = Package( name: "MinimalMacroPackage", platforms: [ .macOS(.v13), ], targets: [ .macro(name: "MacroImpl"), .target(name: "MacroDef", dependencies: ["MacroImpl"]), .executableTarget(name: "MacroClient", dependencies: ["MacroDef"]), ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Macros/MinimalMacroPackage/Sources/MacroClient/main.swift ================================================ import MacroDef let result = #stringify(42) print("Macro result: \(result)") ================================================ FILE: Fixtures/Macros/MinimalMacroPackage/Sources/MacroDef/MacroDef.swift ================================================ @freestanding(expression) public macro stringify(_ value: T) -> String = #externalMacro(module: "MacroImpl", type: "StringifyMacro") ================================================ FILE: Fixtures/Macros/MinimalMacroPackage/Sources/MacroImpl/StringifyMacro.swift ================================================ import Foundation @main struct MacroPlugin { static func main() throws { while true { guard let headerData = try read(count: 8), headerData.count == 8 else { break } let length = headerData.withUnsafeBytes { buffer in buffer.load(as: UInt64.self) } let payloadLength = UInt64(littleEndian: length) if payloadLength == 0 { break } guard let payloadData = try read(count: Int(payloadLength)), payloadData.count == Int(payloadLength) else { break } guard let json = try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any] else { continue } if json.keys.contains("getCapability") { let response: [String: Any] = [ "getCapabilityResult": [ "capability": [ "protocolVersion": 2 ] ] ] if let responseData = try? JSONSerialization.data(withJSONObject: response) { try writeMessage(responseData, to: FileHandle.standardOutput) } } else if json.keys.contains("expandFreestandingMacro") { let response: [String: Any] = [ "expandMacroResult": [ "expandedSource": "\"expanded\"", "diagnostics": [] ] ] if let responseData = try? JSONSerialization.data(withJSONObject: response) { try writeMessage(responseData, to: FileHandle.standardOutput) } } } } } private func read(count: Int) throws -> Data? { var accumulated = Data() while accumulated.count < count { let remaining = count - accumulated.count guard let chunk = try FileHandle.standardInput.read(upToCount: remaining), !chunk.isEmpty else { return accumulated.isEmpty ? nil : accumulated } accumulated.append(chunk) } return accumulated } private func writeMessage(_ data: Data, to handle: FileHandle) throws { var length = UInt64(data.count).littleEndian let headerData = withUnsafeBytes(of: &length) { buffer in Data(buffer) } try handle.write(contentsOf: headerData) try handle.write(contentsOf: data) } ================================================ FILE: Fixtures/Metal/SimpleLibrary/Package.swift ================================================ // swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "MyRenderer", products: [ .library( name: "MyRenderer", targets: ["MyRenderer"]), ], targets: [ .target( name: "MyRenderer", dependencies: ["MySharedTypes"]), .target(name: "MySharedTypes") ] ) ================================================ FILE: Fixtures/Metal/SimpleLibrary/Sources/MyRenderer/Renderer.swift ================================================ import MySharedTypes let vertex = AAPLVertex(position: .init(250, -250), color: .init(1, 0, 0, 1)) ================================================ FILE: Fixtures/Metal/SimpleLibrary/Sources/MyRenderer/Shaders.metal ================================================ // A relative path to SharedTypes.h. #import "../MySharedTypes/include/SharedTypes.h" #include using namespace metal; vertex float4 simpleVertexShader(const device AAPLVertex *vertices [[buffer(0)]], uint vertexID [[vertex_id]]) { AAPLVertex in = vertices[vertexID]; return float4(in.position.x, in.position.y, 0.0, 1.0); } ================================================ FILE: Fixtures/Metal/SimpleLibrary/Sources/MySharedTypes/include/SharedTypes.h ================================================ #ifndef SharedTypes_h #define SharedTypes_h #import typedef struct { vector_float2 position; vector_float4 color; } AAPLVertex; #endif /* SharedTypes_h */ ================================================ FILE: Fixtures/Metal/SimpleLibrary/Tests/MyRendererTests/MyRendererTests.swift ================================================ import Testing @testable import MyRenderer @Test func example() async throws { // Write your test here and use APIs like `#expect(...)` to check expected conditions. } ================================================ FILE: Fixtures/Miscellaneous/-DSWIFT_PACKAGE/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ExtraCommandLineFlags", targets: [ .target(name: "CLib"), .target(name: "SwiftExec", dependencies: ["CLib"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/-DSWIFT_PACKAGE/Sources/CLib/foo.c ================================================ #include "CLib.h" void foo(void) { } ================================================ FILE: Fixtures/Miscellaneous/-DSWIFT_PACKAGE/Sources/CLib/include/CLib.h ================================================ // This is to check a -Xcc arg. #if !defined(EXTRA_C_DEFINE) || EXTRA_C_DEFINE != 2 #error "unexpected compiler flags" #endif void foo(void); ================================================ FILE: Fixtures/Miscellaneous/-DSWIFT_PACKAGE/Sources/SwiftExec/main.swift ================================================ import CLib // This is expected to be set with -Xswiftc. #if !EXTRA_SWIFTC_DEFINE doesNotCompile() #endif foo() class Bar { var bar: Int = 0 #if SWIFT_PACKAGE #else var bar: String = "" #endif } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "Baz", targets: ["Baz"]), .library(name: "Qux", targets: ["Qux"]), ], targets: [ .target(name: "Baz"), .target(name: "Qux") ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/Bar/Sources/Baz/Baz.swift ================================================ public func bar() -> Int { 42 } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/Bar/Sources/Qux/Qux.swift ================================================ public class Qux { public let x = 1 } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/BrokenPkg/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "BrokenPkg", products: [ .library(name: "BrokenPkg", targets: ["BrokenPkg", "Swift2"]), ], targets: [ .target(name: "BrokenPkg", publicHeadersPath: "bestHeaders", cSettings: [ .define("FLAG"), ]), .target(name: "Swift2", dependencies: ["BrokenPkg"], cSettings: [ .define("FLAG"), ]), ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/BrokenPkg/Sources/BrokenPkg/bestHeaders/header.h ================================================ #ifndef FLAG #error "fail" #endif ================================================ FILE: Fixtures/Miscellaneous/APIDiff/BrokenPkg/Sources/BrokenPkg/code.m ================================================ #import "header.h" ================================================ FILE: Fixtures/Miscellaneous/APIDiff/BrokenPkg/Sources/Swift2/file.swift ================================================ import BrokenPkg ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Package.swift ================================================ // swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Sample", products: [ .library( name: "Sample", targets: ["Sample"] ), ], targets: [ .target( name: "CSample", sources: ["./vendorsrc/src"], cSettings: [ .headerSearchPath("./vendorsrc/include"), ] ), .target( name: "Sample", dependencies: ["CSample"] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Sources/CSample/include/CSample.h ================================================ #include "config.h" #include "../vendorsrc/include/vendor.h" ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Sources/CSample/include/config.h ================================================ #define HAVE_VENDOR_CONFIG ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Sources/CSample/vendorsrc/include/vendor.h ================================================ #include "config.h" ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Sources/CSample/vendorsrc/src/vendor.c ================================================ #include "vendor.h" int vendor__func(int n) { return 0; } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CIncludePath/Sources/Sample/Sample.swift ================================================ import CSample ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CTargetDep/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CLibrarySources", products: [ .library(name: "Lib", targets: ["Bar"]) ], targets: [ .target(name: "Foo"), .target(name: "Bar", dependencies: ["Foo"]) ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CTargetDep/Sources/Bar/Bar.swift ================================================ import Foo public func bar() -> Int { foo() return 42 } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CTargetDep/Sources/Foo/Foo.c ================================================ #include "Foo.h" int foo() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/CTargetDep/Sources/Foo/include/Foo.h ================================================ int foo(); ================================================ FILE: Fixtures/Miscellaneous/APIDiff/Foo/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "NonAPILibraryTargets", products: [ .library(name: "One", targets: ["Foo"]), .library(name: "Two", targets: ["Bar", "Baz"]), .executable(name: "Exec", targets: ["Exec", "Qux"]) ], targets: [ .target(name: "Foo"), .target(name: "Bar", dependencies: ["Baz"]), .target(name: "Baz"), .target(name: "Qux"), .target(name: "Exec", dependencies: ["Qux"]) ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Sources/Bar/Bar.swift ================================================ import Baz public func bar() -> Int { 42 } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Sources/Baz/Baz.swift ================================================ public enum Baz { case a, c } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Sources/Exec/main.swift ================================================ import Qux print("Hello, world!") ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Sources/Foo/Foo.swift ================================================ public struct Foo { func doThing() {} } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/NonAPILibraryTargets/Sources/Qux/Qux.swift ================================================ public class Qux { public let x = 1 } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/WithPlugin/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "package-with-plugin", products: [.library(name: "PackageLib", targets: ["TargetLib"])], targets: [ .target(name: "TargetLib"), .executableTarget(name: "BuildTool", dependencies: ["TargetLib"]), .plugin( name: "BuildPlugin", capability: .command(intent: .custom(verb: "do-it-now", description: "")), dependencies: ["BuildTool"] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/APIDiff/WithPlugin/Plugins/BuildPlugin/BuildToolPlugin.swift ================================================ import Foundation import PackagePlugin @main final class BuildToolPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { _ = try context.tool(named: "BuildTool") } } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/WithPlugin/Sources/BuildTool/BuildTool.swift ================================================ import TargetLib @main public struct BuildTool { static func main() { TargetLibStruct.do_it() } } ================================================ FILE: Fixtures/Miscellaneous/APIDiff/WithPlugin/Sources/TargetLib/TargetLib.swift ================================================ public enum TargetLibStruct { public static func do_it() { print("Hello!") } } ================================================ FILE: Fixtures/Miscellaneous/AtMainSupport/Package.swift ================================================ // swift-tools-version:5.5 import PackageDescription let package = Package( name: "AtMainSupport", products: [ .executable(name: "ClangExecSingleFile", targets: ["ClangExecSingleFile"]), .executable(name: "SwiftExecSingleFile", targets: ["SwiftExecSingleFile"]), .executable(name: "SwiftExecMultiFile", targets: ["SwiftExecMultiFile"]), ], targets: [ .executableTarget(name: "ClangExecSingleFile", linkerSettings: [ .linkedLibrary("swiftCore", .when(platforms: [.windows])), // for swift_addNewDSOImage ]), .executableTarget(name: "SwiftExecSingleFile"), .executableTarget(name: "SwiftExecMultiFile"), ] ) ================================================ FILE: Fixtures/Miscellaneous/AtMainSupport/Sources/ClangExecSingleFile/NotMain.c ================================================ #include int main() { printf("Hello, C."); } ================================================ FILE: Fixtures/Miscellaneous/AtMainSupport/Sources/SwiftExecMultiFile/NotMain.swift ================================================ @main struct MyProgram { static func main() { print("Hello, Swift.") } } ================================================ FILE: Fixtures/Miscellaneous/AtMainSupport/Sources/SwiftExecMultiFile/OtherFile.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/AtMainSupport/Sources/SwiftExecSingleFile/NotMain.swift ================================================ @main struct MyProgram { static func main() { print("Hello, Swift.") } } ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_7/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "CXX17WithFModules", targets: [ .target( name: "lodepng", path: "lodepng", sources: ["lodepng.cpp"], publicHeadersPath: "include"), .target(name: "CXX17WithFModules", dependencies: ["lodepng"], path: "./", sources: ["src/user_objects.cc"], publicHeadersPath: "include"), ], cxxLanguageStandard: .cxx17 ) ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_7/include/user_objects.h ================================================ // Copyright 2021 DeepMind Technologies Limited // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef MUJOCO_SRC_USER_USER_OBJECTS_H_ #define MUJOCO_SRC_USER_USER_OBJECTS_H_ #include #include #include "lodepng.h" // forward declarations of all mjC/X classes class mjCError; class mjCAlternative; class mjCBase; class mjCBody; class mjCJoint; class mjCGeom; class mjCSite; class mjCCamera; class mjCLight; class mjCMesh; class mjCSkin; class mjCTexture; class mjCMaterial; class mjCPair; class mjCBodyPair; class mjCEquality; class mjCTendon; class mjCWrap; class mjCActuator; class mjCSensor; class mjCNumeric; class mjCText; class mjCTuple; class mjCDef; class mjCMesh; // defined in user_mesh class mjCModel; // defined in user_model class mjXWriter; // defined in xml_native class mjXURDF; // defined in xml_urdf //------------------------- helper classes and constants ------------------------------------------- // builtin type for procedural textures typedef enum _mjtBuiltin { mjBUILTIN_NONE = 0, // no builtin mjBUILTIN_GRADIENT, // circular gradient: rgb1->rgb2->rgb3 mjBUILTIN_CHECKER, // checker pattern: rgb1, rgb2 mjBUILTIN_FLAT // 2d: rgb1; cube: rgb1-up, rgb2-side, rgb3-down } mjtBuiltin; // mark type for procedural textures typedef enum _mjtMark { mjMARK_NONE = 0, // no mark mjMARK_EDGE, // paint edges mjMARK_CROSS, // paint cross mjMARK_RANDOM // paint random dots } mjtMark; // error information class mjCError { public: mjCError(const mjCBase* obj = 0, const char* msg = 0, const char* str = 0, int pos1 = 0, int pos2 = 0); char message[500]; // error message bool warning; // is this a warning instead of error }; // alternative specifications of frame orientation class mjCAlternative { public: mjCAlternative(); // constructor const char* Set(double* quat, double* inertia, // set frame quat and diag. inertia bool degree, // angle format: degree/radian const char* sequence); // euler sequence format: "xyz" double axisangle[4]; // rotation axis and angle double xyaxes[6]; // x and y axes double zaxis[3]; // z axis (use minimal rotation) double euler[3]; // euler rotations double fullinertia[6]; // non-axis-aligned inertia matrix }; //------------------------- class mjCBase ---------------------------------------------------------- // Generic functionality for all derived classes class mjCBase { friend class mjCDef; public: std::string name; // object name std::string classname; // defaults class name int id; // object id int xmlpos[2]; // row and column in xml file mjCDef* def; // defaults class used to init this object protected: mjCBase(); // constructor mjCModel* model; // pointer to model that created object }; //------------------------- class mjCBody ----------------------------------------------- // Describes a rigid body class mjCBody : public mjCBase { friend class mjCJoint; friend class mjCGeom; friend class mjCSite; friend class mjCCamera; friend class mjCLight; friend class mjCEquality; friend class mjCPair; friend class mjCModel; friend class mjXReader; friend class mjXWriter; friend class mjXURDF; public: // API for adding objects to body mjCBody* AddBody(mjCDef* = 0); mjCJoint* AddJoint(mjCDef* = 0, bool isfree = false); mjCGeom* AddGeom(mjCDef* = 0); mjCSite* AddSite(mjCDef* = 0); mjCCamera* AddCamera(mjCDef* = 0); mjCLight* AddLight(mjCDef* = 0); // setup child local frame, take into account change void MakeLocal(double* locpos, double* locquat, const double* pos, const double* quat); // set explicit_inertial to true void MakeInertialExplicit(); // variables set by user or 'Compile' bool mocap; // is this a mocap body double pos[3]; // frame position double quat[4]; // frame orientation double ipos[3]; // inertial frame position double iquat[4]; // inertial frame orientation double mass; // mass double inertia[3]; // diagonal inertia (in i-frame) std::vector userdata; // user data mjCAlternative alt; // alternative orientation specification mjCAlternative ialt; // alternative for inertial frame // variables computed by 'Compile' and 'AddXXX' private: mjCBody(mjCModel*); // constructor ~mjCBody(); // destructor void Compile(void); // compiler void GeomFrame(void); // get inertial info from geoms double locpos[3]; // position relative to parent double locquat[4]; // orientation relative to parent double locipos[3]; // inertial position frame, rel. to local frame double lociquat[4]; // inertial frame orientation int parentid; // parent index in global array int weldid; // top index of body we are welded to int dofnum; // number of motion dofs for body int mocapid; // mocap id, -1: not mocap bool explicit_inertial; // whether to save the body with an explicit inertial clause int lastdof; // id of last dof (used by compiler) // objects allocated by Add functions std::vector bodies; // child bodies std::vector geoms; // geoms attached to this body std::vector joints; // joints allowing motion relative to parent std::vector sites; // sites attached to this body std::vector cameras; // cameras attached to this body std::vector lights; // lights attached to this body }; #endif // MUJOCO_SRC_USER_USER_OBJECTS_H_ ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_7/lodepng/include/lodepng.h ================================================ /* LodePNG version 20220109 Copyright (c) 2005-2022 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef LODEPNG_H #define LODEPNG_H #include /*for size_t*/ extern const char* LODEPNG_VERSION_STRING; /* The following #defines are used to create code sections. They can be disabled to disable code sections, which can give faster compile time and smaller binary. The "NO_COMPILE" defines are designed to be used to pass as defines to the compiler command to disable them without modifying this header, e.g. -DLODEPNG_NO_COMPILE_ZLIB for gcc. In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to allow implementing a custom lodepng_crc32. */ /*deflate & zlib. If disabled, you must specify alternative zlib functions in the custom_zlib field of the compress and decompress settings*/ #ifndef LODEPNG_NO_COMPILE_ZLIB #define LODEPNG_COMPILE_ZLIB #endif /*png encoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_PNG #define LODEPNG_COMPILE_PNG #endif /*deflate&zlib decoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_DECODER #define LODEPNG_COMPILE_DECODER #endif /*deflate&zlib encoder and png encoder*/ #ifndef LODEPNG_NO_COMPILE_ENCODER #define LODEPNG_COMPILE_ENCODER #endif /*the optional built in harddisk file loading and saving functions*/ #ifndef LODEPNG_NO_COMPILE_DISK #define LODEPNG_COMPILE_DISK #endif /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS #define LODEPNG_COMPILE_ANCILLARY_CHUNKS #endif /*ability to convert error numerical codes to English text string*/ #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT #define LODEPNG_COMPILE_ERROR_TEXT #endif /*Compile the default allocators (C's free, malloc and realloc). If you disable this, you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your source files with custom allocators.*/ #ifndef LODEPNG_NO_COMPILE_ALLOCATORS #define LODEPNG_COMPILE_ALLOCATORS #endif /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP #define LODEPNG_COMPILE_CPP #endif #endif #ifdef LODEPNG_COMPILE_CPP #include #include #endif /*LODEPNG_COMPILE_CPP*/ #ifdef LODEPNG_COMPILE_PNG /*The PNG color types (also used for raw image).*/ typedef enum LodePNGColorType { LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ LCT_RGB = 2, /*RGB: 8,16 bit*/ LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid byte value from 0 to 255 that could be present in an invalid PNG file header. Do not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use the valid color type names above, or numeric values like 1 or 7 when checking for particular disallowed color type byte values, or cast to integer to print it.*/ LCT_MAX_OCTET_VALUE = 255 } LodePNGColorType; #ifdef LODEPNG_COMPILE_DECODER /* Converts PNG data in memory to raw pixel data. out: Output parameter. Pointer to buffer that will contain the raw pixel data. After decoding, its size is w * h * (bytes per pixel) bytes larger than initially. Bytes per pixel depends on colortype and bitdepth. Must be freed after usage with free(*out). Note: for 16-bit per channel colors, uses big endian format like PNG does. w: Output parameter. Pointer to width of pixel data. h: Output parameter. Pointer to height of pixel data. in: Memory buffer with the PNG file. insize: size of the in buffer. colortype: the desired color type for the raw output image. See explanation on PNG color types. bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_DISK /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Converts raw pixel data into a PNG image in memory. The colortype and bitdepth of the output PNG image cannot be chosen, they are automatically determined by the colortype, bitdepth and content of the input pixel data. Note: for 16-bit per channel colors, needs big endian format like PNG does. out: Output parameter. Pointer to buffer that will contain the PNG image data. Must be freed after usage with free(*out). outsize: Output parameter. Pointer to the size in bytes of the out buffer. image: The raw pixel data to encode. The size of this buffer should be w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. w: width of the raw pixel data in pixels. h: height of the raw pixel data in pixels. colortype: the color type of the raw input image. See explanation on PNG color types. bitdepth: the bit depth of the raw input image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DISK /* Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER /*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::vector& in, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /*Same as lodepng_encode_memory, but encodes to an std::vector. colortype is that of the raw input data. The output PNG color type will be auto chosen.*/ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_ENCODER */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /*Returns an English description of the numerical error code.*/ const char* lodepng_error_text(unsigned code); #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ #ifdef LODEPNG_COMPILE_DECODER /*Settings for zlib decompression*/ typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, return an error, output a data size > max_output_size and all the data up to that point. This is not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. Set to 0 to impose no limit (the default).*/ size_t max_output_size; /*use custom zlib decoder instead of built in one (default: null). Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); /*use custom deflate decoder instead of built in one (default: null) if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGDecompressSettings lodepng_default_decompress_settings; void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Settings for zlib compression. Tweaking these settings tweaks the balance between speed and compression ratio. */ typedef struct LodePNGCompressSettings LodePNGCompressSettings; struct LodePNGCompressSettings /*deflate = compress*/ { /*LZ77 related settings*/ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ /*use custom zlib encoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); /*use custom deflate encoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_deflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGCompressSettings lodepng_default_compress_settings; void lodepng_compress_settings_init(LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_PNG /* Color mode of an image. Contains all information required to decode the pixel bits to RGBA colors. This information is the same as used in the PNG file format, and is used both for PNG and raw image data in LodePNG. */ typedef struct LodePNGColorMode { /*header (IHDR)*/ LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ /* palette (PLTE and tRNS) Dynamically allocated with the colors of the palette, including alpha. This field may not be allocated directly, use lodepng_color_mode_init first, then lodepng_palette_add per color to correctly initialize it (to ensure size of exactly 1024 bytes). The alpha channels must be set as well, set them to 255 for opaque images. When decoding, by default you can ignore this palette, since LodePNG already fills the palette colors in the pixels of the raw RGBA output. The palette is only supported for color type 3. */ unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ /* transparent color key (tRNS) This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. For grayscale PNGs, r, g and b will all 3 be set to the same. When decoding, by default you can ignore this information, since LodePNG sets pixels with this key to transparent already in the raw RGBA output. The color key is only supported for color types 0 and 2. */ unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ unsigned key_r; /*red/grayscale component of color key*/ unsigned key_g; /*green component of color key*/ unsigned key_b; /*blue component of color key*/ } LodePNGColorMode; /*init, cleanup and copy functions to use with this struct*/ void lodepng_color_mode_init(LodePNGColorMode* info); void lodepng_color_mode_cleanup(LodePNGColorMode* info); /*return value is error code (0 means no error)*/ unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); /* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); void lodepng_palette_clear(LodePNGColorMode* info); /*add 1 color to the palette*/ unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a); /*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ unsigned lodepng_get_bpp(const LodePNGColorMode* info); /*get the amount of color channels used, based on colortype in the struct. If a palette is used, it counts as 1 channel.*/ unsigned lodepng_get_channels(const LodePNGColorMode* info); /*is it a grayscale type? (only colortype 0 or 4)*/ unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); /*has it got an alpha channel? (only colortype 2 or 6)*/ unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); /*has it got a palette? (only colortype 3)*/ unsigned lodepng_is_palette_type(const LodePNGColorMode* info); /*only returns true if there is a palette and there is a value in the palette with alpha < 255. Loops through the palette to check this.*/ unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); /* Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). Returns false if the image can only have opaque pixels. In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, or if "key_defined" is true. */ unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); /*Returns the byte size of a raw image buffer with given width, height and color mode*/ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*The information of a Time chunk in PNG.*/ typedef struct LodePNGTime { unsigned year; /*2 bytes used (0-65535)*/ unsigned month; /*1-12*/ unsigned day; /*1-31*/ unsigned hour; /*0-23*/ unsigned minute; /*0-59*/ unsigned second; /*0-60 (to allow for leap seconds)*/ } LodePNGTime; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*Information about the PNG image, except pixels, width and height.*/ typedef struct LodePNGInfo { /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ unsigned compression_method;/*compression method of the original file. Always 0.*/ unsigned filter_method; /*filter method of the original file*/ unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /* Suggested background color chunk (bKGD) This uses the same color mode and bit depth as the PNG (except no alpha channel), with values truncated to the bit depth in the unsigned integer. For grayscale and palette PNGs, the value is stored in background_r. The values in background_g and background_b are then unused. So when decoding, you may get these in a different color mode than the one you requested for the raw pixels. When encoding with auto_convert, you must use the color model defined in info_png.color for these values. The encoder normally ignores info_png.color when auto_convert is on, but will use it to interpret these values (and convert copies of them to its chosen color model). When encoding, avoid setting this to an expensive color, such as a non-gray value when the image is gray, or the compression will be worse since it will be forced to write the PNG with a more expensive color mode (when auto_convert is on). The decoder does not use this background color to edit the color of pixels. This is a completely optional metadata feature. */ unsigned background_defined; /*is a suggested background color given?*/ unsigned background_r; /*red/gray/palette component of suggested background color*/ unsigned background_g; /*green component of suggested background color*/ unsigned background_b; /*blue component of suggested background color*/ /* Non-international text chunks (tEXt and zTXt) The char** arrays each contain num strings. The actual messages are in text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. All the string fields below including strings, keys, names and language tags are null terminated. The PNG specification uses null characters for the keys, names and tags, and forbids null characters to appear in the main text which is why we can use null termination everywhere here. A keyword is minimum 1 character and maximum 79 characters long (plus the additional null terminator). It's discouraged to use a single line length longer than 79 characters for texts. Don't allocate these text buffers yourself. Use the init/cleanup functions correctly and use lodepng_add_text and lodepng_clear_text. Standard text chunk keywords and strings are encoded using Latin-1. */ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ char** text_strings; /*the actual text*/ /* International text chunks (iTXt) Similar to the non-international text chunks, but with additional strings "langtags" and "transkeys", and the following text encodings are used: keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. keys must be 1-79 characters (plus the additional null terminator), the other strings are any length. */ size_t itext_num; /*the amount of international texts in this PNG*/ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ char** itext_strings; /*the actual international text - UTF-8 string*/ /*time chunk (tIME)*/ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ LodePNGTime time; /*phys chunk (pHYs)*/ unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ unsigned phys_x; /*pixels per unit in x direction*/ unsigned phys_y; /*pixels per unit in y direction*/ unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* Color profile related chunks: gAMA, cHRM, sRGB, iCPP LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please use these values with a color management library. See the PNG, ICC and sRGB specifications for more information about the meaning of these values. */ /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */ unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ unsigned gama_gamma; /* Gamma exponent times 100000 */ /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */ unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ unsigned chrm_white_x; /* White Point x times 100000 */ unsigned chrm_white_y; /* White Point y times 100000 */ unsigned chrm_red_x; /* Red x times 100000 */ unsigned chrm_red_y; /* Red y times 100000 */ unsigned chrm_green_x; /* Green x times 100000 */ unsigned chrm_green_y; /* Green y times 100000 */ unsigned chrm_blue_x; /* Blue x times 100000 */ unsigned chrm_blue_y; /* Blue y times 100000 */ /* sRGB chunk: optional. May not appear at the same time as iCCP. If gAMA is also present gAMA must contain value 45455. If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. */ unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ /* iCCP chunk: optional. May not appear at the same time as sRGB. LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color management and conversions. For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile. For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel data if the pixels could be encoded as grayscale but the ICC profile is RGB. To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so make sure you compute it carefully to avoid the above problems. */ unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ /* The ICC profile in iccp_profile_size bytes. Don't allocate this buffer yourself. Use the init/cleanup functions correctly and use lodepng_set_icc and lodepng_clear_icc. */ unsigned char* iccp_profile; unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ /* End of color profile related chunks */ /* unknown chunks: chunks not known by LodePNG, passed on byte for byte. There are 3 buffers, one for each position in the PNG where unknown chunks can appear. Each buffer contains all unknown chunks for that position consecutively. The 3 positions are: 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag above in here, since the encoder will blindly follow this and could then encode an invalid PNG file (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), or any non-standard PNG chunk. Do not allocate or traverse this data yourself. Use the chunk traversing functions declared later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. */ unsigned char* unknown_chunks_data[3]; size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGInfo; /*init, cleanup and copy functions to use with this struct*/ void lodepng_info_init(LodePNGInfo* info); void lodepng_info_cleanup(LodePNGInfo* info); /*return value is error code (0 means no error)*/ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ /*replaces if exists*/ unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* Converts raw buffer from one color type to another color type, based on LodePNGColorMode structs to describe the input and output color type. See the reference manual at the end of this header file to see which color conversions are supported. return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel of the output color type (lodepng_get_bpp). For < 8 bpp images, there should not be padding bits at the end of scanlines. For 16-bit per channel colors, uses big endian format like PNG does. Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* Settings for the decoder. This contains settings for the PNG and the Zlib decoder, but not the Info settings from the Info structs. */ typedef struct LodePNGDecoderSettings { LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ unsigned ignore_crc; /*ignore CRC checksums*/ unsigned ignore_critical; /*ignore unknown critical chunks*/ unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters in string keys, etc... */ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ unsigned remember_unknown_chunks; /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. By default it is a value that prevents unreasonably large strings from hogging memory. */ size_t max_text_size; /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any legitimate profile could be to hog memory. */ size_t max_icc_size; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ typedef enum LodePNGFilterStrategy { /*every filter at zero*/ LFS_ZERO = 0, /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ LFS_ONE = 1, LFS_TWO = 2, LFS_THREE = 3, LFS_FOUR = 4, /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ LFS_MINSUM, /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending on the image, this is better or worse than minsum.*/ LFS_ENTROPY, /* Brute-force-search PNG filters by compressing each filter for each scanline. Experimental, very slow, and only rarely gives better compression than MINSUM. */ LFS_BRUTE_FORCE, /*use predefined_filters buffer: you specify the filter type for each scanline*/ LFS_PREDEFINED } LodePNGFilterStrategy; /*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), which helps decide which color model to use for encoding. Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ typedef struct LodePNGColorStats { unsigned colored; /*not grayscale*/ unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ unsigned short key_g; unsigned short key_b; unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ size_t numpixels; /*user settings for computing/using the stats*/ unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ } LodePNGColorStats; void lodepng_color_stats_init(LodePNGColorStats* stats); /*Get a LodePNGColorStats of the image. The stats must already have been inited. Returns error code (e.g. alloc fail) or 0 if ok.*/ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to completely follow the official PNG heuristic, filter_palette_zero must be true and filter_strategy must be LFS_MINSUM*/ unsigned filter_palette_zero; /*Which filter strategy to use when not using zeroes due to filter_palette_zero. Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ LodePNGFilterStrategy filter_strategy; /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with the same length as the amount of scanlines in the image, and each value must <= 5. You have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ const unsigned char* predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ unsigned force_palette; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ unsigned add_id; /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ unsigned text_compression; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGEncoderSettings; void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) /*The settings, state and information for extended encoding and decoding.*/ typedef struct LodePNGState { #ifdef LODEPNG_COMPILE_DECODER LodePNGDecoderSettings decoder; /*the decoding settings*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER LodePNGEncoderSettings encoder; /*the encoding settings*/ #endif /*LODEPNG_COMPILE_ENCODER*/ LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; } LodePNGState; /*init, cleanup and copy functions to use with this struct*/ void lodepng_state_init(LodePNGState* state); void lodepng_state_cleanup(LodePNGState* state); void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_DECODER /* Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and getting much more information about the PNG image and color mode. */ unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); /* Read the PNG header, but not the actual data. This returns only the information that is in the IHDR chunk of the PNG, such as width, height and color type. The information is placed in the info_png field of the LodePNGState. */ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); #endif /*LODEPNG_COMPILE_DECODER*/ /* Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it read in the state. Returns error code on failure. Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const to find the desired chunk type, and if non null use lodepng_inspect_chunk (with chunk_pointer - start_of_file as pos). Supports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...). Ignores unsupported, unknown, non-metadata or IHDR chunks (without error). Requirements: &in[pos] must point to start of a chunk, must use regular lodepng_inspect first since format of most other chunks depends on IHDR, and if there is a PLTE chunk, that one must be inspected before tRNS or bKGD. */ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_ENCODER /*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state); #endif /*LODEPNG_COMPILE_ENCODER*/ /* The lodepng_chunk functions are normally not needed, except to traverse the unknown chunks stored in the LodePNGInfo struct, or add new ones to it. It also allows traversing the chunks of an encoded PNG file yourself. The chunk pointer always points to the beginning of the chunk itself, that is the first byte of the 4 length bytes. In the PNG file format, chunks have the following format: -4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) -4 bytes chunk type (ASCII a-z,A-Z only, see below) -length bytes of data (may be 0 bytes if length was 0) -4 bytes of CRC, computed on chunk name + data The first chunk starts at the 8th byte of the PNG file, the entire rest of the file exists out of concatenated chunks with the above format. PNG standard chunk ASCII naming conventions: -First byte: uppercase = critical, lowercase = ancillary -Second byte: uppercase = public, lowercase = private -Third byte: must be uppercase -Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy */ /* Gets the length of the data of the chunk. Total chunk length has 12 bytes more. There must be at least 4 bytes to read from. If the result value is too large, it may be corrupt data. */ unsigned lodepng_chunk_length(const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ void lodepng_chunk_type(char type[5], const unsigned char* chunk); /*check if the type is the given type*/ unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); /*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); /*0: public, 1: private (see PNG standard)*/ unsigned char lodepng_chunk_private(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); /*get pointer to the data of the chunk, where the input points to the header of the chunk*/ unsigned char* lodepng_chunk_data(unsigned char* chunk); const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ unsigned lodepng_chunk_check_crc(const unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ void lodepng_chunk_generate_crc(unsigned char* chunk); /* Iterate to next chunks, allows iterating through all chunks of the PNG file. Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, or the 8th byte of a PNG file which always has the first chunk), or alternatively may point to the first byte of the PNG file (which is not a chunk but the magic header, the function will then skip over it and return the first real chunk). Will output pointer to the start of the next chunk, or at or beyond end of the file if there is no more chunk after this or possibly if the chunk is corrupt. Start this process at the 8th byte of the PNG file. In a non-corrupt PNG file, the last chunk should have name "IEND". */ unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); /*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); /* Appends chunk to the data in out. The given chunk should already have its chunk header. The out variable and outsize are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); /* Appends new chunk to out. The chunk to append is given by giving its length, type and data separately. The type is a 4-letter string. The out variable and outsize are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, const char* type, const unsigned char* data); /*Calculate CRC32 of buffer*/ unsigned lodepng_crc32(const unsigned char* buf, size_t len); #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /* This zlib part can be used independently to zlib compress and decompress a buffer. It cannot be used to create gzip files however, and it only supports the part of zlib that is required for PNG, it does not support dictionaries. */ #ifdef LODEPNG_COMPILE_DECODER /*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); /* Decompresses Zlib data. Reallocates the out buffer and appends the data. The data must be according to the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Compresses data with Zlib. Reallocates the out buffer and appends the data. Zlib adds a small header and trailer around the deflate data. The data is output in the format of the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); /* Find length-limited Huffman code for given frequencies. This function is in the public interface only for tests, it's used internally by lodepng_deflate. */ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen); /*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into buffer. The function allocates the out buffer, and after usage you should free it. out: output parameter, contains pointer to loaded buffer. outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); /* Save a file from buffer to disk. Warning, if it exists, this function overwrites the file without warning! buffer: the buffer to write buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory */ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP /* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ namespace lodepng { #ifdef LODEPNG_COMPILE_PNG class State : public LodePNGState { public: State(); State(const State& other); ~State(); State& operator=(const State& other); }; #ifdef LODEPNG_COMPILE_DECODER /* Same as other lodepng::decode, but using a State for more settings and information. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize); unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const std::vector& in); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Same as other lodepng::encode, but using a State for more settings and information. */ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, State& state); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, State& state); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into an std::vector. return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory */ unsigned load_file(std::vector& buffer, const std::string& filename); /* Save the binary data in an std::vector to a file on disk. The file is overwritten without warning. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory */ unsigned save_file(const std::vector& buffer, const std::string& filename); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_PNG */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER /* Zlib-decompress an unsigned char buffer */ unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); /* Zlib-decompress an std::vector */ unsigned decompress(std::vector& out, const std::vector& in, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /* Zlib-compress an unsigned char buffer */ unsigned compress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); /* Zlib-compress an std::vector */ unsigned compress(std::vector& out, const std::vector& in, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ /* TODO: [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often [.] check compatibility with various compilers - done but needs to be redone for every newer version [X] converting color to 16-bit per channel types [X] support color profile chunk types (but never let them touch RGB values by default) [ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] partial decoding (stream processing) [X] let the "isFullyOpaque" function check color keys and transparent palettes too [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) [ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... [ ] error messages with line numbers (and version) [ ] errors in state instead of as return code? [ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes [ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... [ ] allow user to give data (void*) to custom allocator [X] provide alternatives for C library functions not present on some platforms (memcpy, ...) */ #endif /*LODEPNG_H inclusion guard*/ /* LodePNG Documentation --------------------- 0. table of contents -------------------- 1. about 1.1. supported features 1.2. features not supported 2. C and C++ version 3. security 4. decoding 5. encoding 6. color conversions 6.1. PNG color types 6.2. color conversions 6.3. padding bits 6.4. A note about 16-bits per channel and endianness 7. error values 8. chunks and PNG editing 9. compiler support 10. examples 10.1. decoder C++ example 10.2. decoder C example 11. state settings reference 12. changes 13. contact information 1. about -------- PNG is a file format to store raster images losslessly with good compression, supporting different color types and alpha channel. LodePNG is a PNG codec according to the Portable Network Graphics (PNG) Specification (Second Edition) - W3C Recommendation 10 November 2003. The specifications used are: *) Portable Network Graphics (PNG) Specification (Second Edition): http://www.w3.org/TR/2003/REC-PNG-20031110 *) RFC 1950 ZLIB Compressed Data Format version 3.3: http://www.gzip.org/zlib/rfc-zlib.html *) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: http://www.gzip.org/zlib/rfc-deflate.html The most recent version of LodePNG can currently be found at http://lodev.org/lodepng/ LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds extra functionality. LodePNG exists out of two files: -lodepng.h: the header file for both C and C++ -lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage If you want to start using LodePNG right away without reading this doc, get the examples from the LodePNG website to see how to use it in code, or check the smaller examples in chapter 13 here. LodePNG is simple but only supports the basic requirements. To achieve simplicity, the following design choices were made: There are no dependencies on any external library. There are functions to decode and encode a PNG with a single function call, and extended versions of these functions taking a LodePNGState struct allowing to specify or get more information. By default the colors of the raw image are always RGB or RGBA, no matter what color type the PNG file uses. To read and write files, there are simple functions to convert the files to/from buffers in memory. This all makes LodePNG suitable for loading textures in games, demos and small programs, ... It's less suitable for full fledged image editors, loading PNGs over network (it requires all the image data to be available before decoding can begin), life-critical systems, ... 1.1. supported features ----------------------- The following features are supported by the decoder: *) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, or the same color type as the PNG *) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image *) Adam7 interlace and deinterlace for any color type *) loading the image from harddisk or decoding it from a buffer from other sources than harddisk *) support for alpha channels, including RGBA color model, translucent palettes and color keying *) zlib decompression (inflate) *) zlib compression (deflate) *) CRC32 and ADLER32 checksums *) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. *) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. *) the following chunks are supported by both encoder and decoder: IHDR: header information PLTE: color palette IDAT: pixel data IEND: the final chunk tRNS: transparency for palettized images tEXt: textual information zTXt: compressed textual information iTXt: international textual information bKGD: suggested background color pHYs: physical dimensions tIME: modification time cHRM: RGB chromaticities gAMA: RGB gamma correction iCCP: ICC color profile sRGB: rendering intent 1.2. features not supported --------------------------- The following features are _not_ supported: *) some features needed to make a conformant PNG-Editor might be still missing. *) partial loading/stream processing. All data must be available and is processed in one call. *) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: sBIT hIST sPLT 2. C and C++ version -------------------- The C version uses buffers allocated with alloc that you need to free() yourself. You need to use init and cleanup functions for each struct whenever using a struct from the C version to avoid exploits and memory leaks. The C++ version has extra functions with std::vectors in the interface and the lodepng::State class which is a LodePNGState with constructor and destructor. These files work without modification for both C and C++ compilers because all the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers ignore it, and the C code is made to compile both with strict ISO C90 and C++. To use the C++ version, you need to rename the source file to lodepng.cpp (instead of lodepng.c), and compile it with a C++ compiler. To use the C version, you need to rename the source file to lodepng.c (instead of lodepng.cpp), and compile it with a C compiler. 3. Security ----------- Even if carefully designed, it's always possible that LodePNG contains possible exploits. If you discover one, please let me know, and it will be fixed. When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style structs when working with C++. The following conventions are used for all C-style structs: -if a struct has a corresponding init function, always call the init function when making a new one -if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks -if a struct has a corresponding copy function, use the copy function instead of "=". The destination must also be inited already. 4. Decoding ----------- Decoding converts a PNG compressed image to a raw pixel buffer. Most documentation on using the decoder is at its declarations in the header above. For C, simple decoding can be done with functions such as lodepng_decode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_decode. For C++, all decoding can be done with the various lodepng::decode functions, and lodepng::State can be used for advanced features. When using the LodePNGState, it uses the following fields for decoding: *) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here *) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get *) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use LodePNGInfo info_png -------------------- After decoding, this contains extra information of the PNG image, except the actual pixels, width and height because these are already gotten directly from the decoder functions. It contains for example the original color type of the PNG image, text comments, suggested background color, etc... More details about the LodePNGInfo struct are at its declaration documentation. LodePNGColorMode info_raw ------------------------- When decoding, here you can specify which color type you want the resulting raw image to be. If this is different from the colortype of the PNG, then the decoder will automatically convert the result. This conversion always works, except if you want it to convert a color PNG to grayscale or to a palette with missing colors. By default, 32-bit color is used for the result. LodePNGDecoderSettings decoder ------------------------------ The settings can be used to ignore the errors created by invalid CRC and Adler32 chunks, and to disable the decoding of tEXt chunks. There's also a setting color_convert, true by default. If false, no conversion is done, the resulting data will be as it was in the PNG (after decompression) and you'll have to puzzle the colors of the pixels together yourself using the color type information in the LodePNGInfo. 5. Encoding ----------- Encoding converts a raw pixel buffer to a PNG compressed image. Most documentation on using the encoder is at its declarations in the header above. For C, simple encoding can be done with functions such as lodepng_encode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_encode. For C++, all encoding can be done with the various lodepng::encode functions, and lodepng::State can be used for advanced features. Like the decoder, the encoder can also give errors. However it gives less errors since the encoder input is trusted, the decoder input (a PNG image that could be forged by anyone) is not trusted. When using the LodePNGState, it uses the following fields for encoding: *) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. *) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has *) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use LodePNGInfo info_png -------------------- When encoding, you use this the opposite way as when decoding: for encoding, you fill in the values you want the PNG to have before encoding. By default it's not needed to specify a color type for the PNG since it's automatically chosen, but it's possible to choose it yourself given the right settings. The encoder will not always exactly match the LodePNGInfo struct you give, it tries as close as possible. Some things are ignored by the encoder. The encoder uses, for example, the following settings from it when applicable: colortype and bitdepth, text chunks, time chunk, the color key, the palette, the background color, the interlace method, unknown chunks, ... When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. If the palette contains any colors for which the alpha channel is not 255 (so there are translucent colors in the palette), it'll add a tRNS chunk. LodePNGColorMode info_raw ------------------------- You specify the color type of the raw image that you give to the input here, including a possible transparent color key and palette you happen to be using in your raw image data. By default, 32-bit color is assumed, meaning your input has to be in RGBA format with 4 bytes (unsigned chars) per pixel. LodePNGEncoderSettings encoder ------------------------------ The following settings are supported (some are in sub-structs): *) auto_convert: when this option is enabled, the encoder will automatically choose the smallest possible color mode (including color key) that can encode the colors of all pixels without information loss. *) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 2 = dynamic huffman tree (best compression). Should be 2 for proper compression. *) use_lz77: whether or not to use LZ77 for compressed block types. Should be true for proper compression. *) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value 2048 by default, but can be set to 32768 for better, but slow, compression. *) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE chunk if force_palette is true. This can used as suggested palette to convert to by viewers that don't support more than 256 colors (if those still exist) *) add_id: add text chunk "Encoder: LodePNG " to the image. *) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. zTXt chunks use zlib compression on the text. This gives a smaller result on large texts but a larger result on small texts (such as a single program name). It's all tEXt or all zTXt though, there's no separate setting per text yet. 6. color conversions -------------------- An important thing to note about LodePNG, is that the color type of the PNG, and the color type of the raw image, are completely independent. By default, when you decode a PNG, you get the result as a raw image in the color type you want, no matter whether the PNG was encoded with a palette, grayscale or RGBA color. And if you encode an image, by default LodePNG will automatically choose the PNG color type that gives good compression based on the values of colors and amount of colors in the image. It can be configured to let you control it instead as well, though. To be able to do this, LodePNG does conversions from one color mode to another. It can convert from almost any color type to any other color type, except the following conversions: RGB to grayscale is not supported, and converting to a palette when the palette doesn't have a required color is not supported. This is not supported on purpose: this is information loss which requires a color reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray is easy, but there are multiple ways if you want to give some channels more weight). By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB color, no matter what color type the PNG has. And by default when encoding, LodePNG automatically picks the best color model for the output PNG, and expects the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control the color format of the images yourself, you can skip this chapter. 6.1. PNG color types -------------------- A PNG image can have many color types, ranging from 1-bit color to 64-bit color, as well as palettized color modes. After the zlib decompression and unfiltering in the PNG image is done, the raw pixel data will have that color type and thus a certain amount of bits per pixel. If you want the output raw image after decoding to have another color type, a conversion is done by LodePNG. The PNG specification gives the following color types: 0: grayscale, bit depths 1, 2, 4, 8, 16 2: RGB, bit depths 8 and 16 3: palette, bit depths 1, 2, 4 and 8 4: grayscale with alpha, bit depths 8 and 16 6: RGBA, bit depths 8 and 16 Bit depth is the amount of bits per pixel per color channel. So the total amount of bits per pixel is: amount of channels * bitdepth. 6.2. color conversions ---------------------- As explained in the sections about the encoder and decoder, you can specify color types and bit depths in info_png and info_raw to change the default behaviour. If, when decoding, you want the raw image to be something else than the default, you need to set the color type and bit depth you want in the LodePNGColorMode, or the parameters colortype and bitdepth of the simple decoding function. If, when encoding, you use another color type than the default in the raw input image, you need to specify its color type and bit depth in the LodePNGColorMode of the raw image, or use the parameters colortype and bitdepth of the simple encoding function. If, when encoding, you don't want LodePNG to choose the output PNG color type but control it yourself, you need to set auto_convert in the encoder settings to false, and specify the color type you want in the LodePNGInfo of the encoder (including palette: it can generate a palette if auto_convert is true, otherwise not). If the input and output color type differ (whether user chosen or auto chosen), LodePNG will do a color conversion, which follows the rules below, and may sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image -the encoder converts from raw image to PNG -the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image -the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG -when encoding, the color type in LodePNGInfo is ignored if auto_convert is enabled, it is automatically generated instead -when decoding, the color type in LodePNGInfo is set by the decoder to that of the original PNG image, but it can be ignored since the raw image has the color type you requested instead -if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion between the color types is done if the color types are supported. If it is not supported, an error is returned. If the types are the same, no conversion is done. -even though some conversions aren't supported, LodePNG supports loading PNGs from any colortype and saving PNGs to any colortype, sometimes it just requires preparing the raw image correctly before encoding. -both encoder and decoder use the same color converter. The function lodepng_convert does the color conversion. It is available in the interface but normally isn't needed since the encoder and decoder already call it. Non supported color conversions: -color to grayscale when non-gray pixels are present: no error is thrown, but the result will look ugly because only the red channel is taken (it assumes all three channels are the same in this case so ignores green and blue). The reason no error is given is to allow converting from three-channel grayscale images to one-channel even if there are numerical imprecisions. -anything to palette when the palette does not have an exact match for a from-color in it: in this case an error is thrown Supported color conversions: -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA -any gray or gray+alpha, to gray or gray+alpha -anything to a palette, as long as the palette has the requested colors in it -removing alpha channel -higher to smaller bitdepth, and vice versa If you want no color conversion to be done (e.g. for speed or control): -In the encoder, you can make it save a PNG with any color type by giving the raw color mode and LodePNGInfo the same color mode, and setting auto_convert to false. -In the decoder, you can make it store the pixel data in the same color type as the PNG has, by setting the color_convert setting to false. Settings in info_raw are then ignored. 6.3. padding bits ----------------- In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines have a bit amount that isn't a multiple of 8, then padding bits are used so that each scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. The raw input image you give to the encoder, and the raw output image you get from the decoder will NOT have these padding bits, e.g. in the case of a 1-bit image with a width of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, not the first bit of a new byte. 6.4. A note about 16-bits per channel and endianness ---------------------------------------------------- LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like for any other color format. The 16-bit values are stored in big endian (most significant byte first) in these arrays. This is the opposite order of the little endian used by x86 CPU's. LodePNG always uses big endian because the PNG file format does so internally. Conversions to other formats than PNG uses internally are not supported by LodePNG on purpose, there are myriads of formats, including endianness of 16-bit colors, the order in which you store R, G, B and A, and so on. Supporting and converting to/from all that is outside the scope of LodePNG. This may mean that, depending on your use case, you may want to convert the big endian output of LodePNG to little endian with a for loop. This is certainly not always needed, many applications and libraries support big endian 16-bit colors anyway, but it means you cannot simply cast the unsigned char* buffer to an unsigned short* buffer on x86 CPUs. 7. error values --------------- All functions in LodePNG that return an error code, return 0 if everything went OK, or a non-zero code if there was an error. The meaning of the LodePNG error values can be retrieved with the function lodepng_error_text: given the numerical error code, it returns a description of the error in English as a string. Check the implementation of lodepng_error_text to see the meaning of each code. It is not recommended to use the numerical values to programmatically make different decisions based on error types as the numbers are not guaranteed to stay backwards compatible. They are for human consumption only. Programmatically only 0 or non-0 matter. 8. chunks and PNG editing ------------------------- If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG editor that should follow the rules about handling of unknown chunks, or if your program is able to read other types of chunks than the ones handled by LodePNG, then that's possible with the chunk functions of LodePNG. A PNG chunk has the following layout: 4 bytes length 4 bytes type name length bytes data 4 bytes CRC 8.1. iterating through chunks ----------------------------- If you have a buffer containing the PNG image data, then the first chunk (the IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the signature of the PNG and are not part of a chunk. But if you start at byte 8 then you have a chunk, and can check the following things of it. NOTE: none of these functions check for memory buffer boundaries. To avoid exploits, always make sure the buffer contains all the data of the chunks. When using lodepng_chunk_next, make sure the returned value is within the allocated memory. unsigned lodepng_chunk_length(const unsigned char* chunk): Get the length of the chunk's data. The total chunk length is this length + 12. void lodepng_chunk_type(char type[5], const unsigned char* chunk): unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): Get the type of the chunk or compare if it's a certain type unsigned char lodepng_chunk_critical(const unsigned char* chunk): unsigned char lodepng_chunk_private(const unsigned char* chunk): unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). Check if the chunk is private (public chunks are part of the standard, private ones not). Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your program doesn't handle that type of unknown chunk. unsigned char* lodepng_chunk_data(unsigned char* chunk): const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): Get a pointer to the start of the data of the chunk. unsigned lodepng_chunk_check_crc(const unsigned char* chunk): void lodepng_chunk_generate_crc(unsigned char* chunk): Check if the crc is correct or generate a correct one. unsigned char* lodepng_chunk_next(unsigned char* chunk): const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these functions do no boundary checking of the allocated data whatsoever, so make sure there is enough data available in the buffer to be able to go to the next chunk. unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, const char* type, const unsigned char* data): These functions are used to create new chunks that are appended to the data in *out that has length *outsize. The append function appends an existing chunk to the new data. The create function creates a new chunk with the given parameters and appends it. Type is the 4-letter name of the chunk. 8.2. chunks in info_png ----------------------- The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 buffers (each with size) to contain 3 types of unknown chunks: the ones that come before the PLTE chunk, the ones that come between the PLTE and the IDAT chunks, and the ones that come after the IDAT chunks. It's necessary to make the distinction between these 3 cases because the PNG standard forces to keep the ordering of unknown chunks compared to the critical chunks, but does not force any other ordering rules. info_png.unknown_chunks_data[0] is the chunks before PLTE info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT info_png.unknown_chunks_data[2] is the chunks after IDAT The chunks in these 3 buffers can be iterated through and read by using the same way described in the previous subchapter. When using the decoder to decode a PNG, you can make it store all unknown chunks if you set the option settings.remember_unknown_chunks to 1. By default, this option is off (0). The encoder will always encode unknown chunks that are stored in the info_png. If you need it to add a particular chunk that isn't known by LodePNG, you can use lodepng_chunk_append or lodepng_chunk_create to the chunk data in info_png.unknown_chunks_data[x]. Chunks that are known by LodePNG should not be added in that way. E.g. to make LodePNG add a bKGD chunk, set background_defined to true and add the correct parameters there instead. 9. compiler support ------------------- No libraries other than the current standard C library are needed to compile LodePNG. For the C++ version, only the standard C++ library is needed on top. Add the files lodepng.c(pp) and lodepng.h to your project, include lodepng.h where needed, and your program can read/write PNG files. It is compatible with C90 and up, and C++03 and up. If performance is important, use optimization when compiling! For both the encoder and decoder, this makes a large difference. Make sure that LodePNG is compiled with the same compiler of the same version and with the same settings as the rest of the program, or the interfaces with std::vectors and std::strings in C++ can be incompatible. CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. *) gcc and g++ LodePNG is developed in gcc so this compiler is natively supported. It gives no warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ version 4.7.1 on Linux, 32-bit and 64-bit. *) Clang Fully supported and warning-free. *) Mingw The Mingw compiler (a port of gcc for Windows) should be fully supported by LodePNG. *) Visual Studio and Visual C++ Express Edition LodePNG should be warning-free with warning level W4. Two warnings were disabled with pragmas though: warning 4244 about implicit conversions, and warning 4996 where it wants to use a non-standard function fopen_s instead of the standard C fopen. Visual Studio may want "stdafx.h" files to be included in each source file and give an error "unexpected end of file while looking for precompiled header". This is not standard C++ and will not be added to the stock LodePNG. You can disable it for lodepng.cpp only by right clicking it, Properties, C/C++, Precompiled Headers, and set it to Not Using Precompiled Headers there. NOTE: Modern versions of VS should be fully supported, but old versions, e.g. VS6, are not guaranteed to work. *) Compilers on Macintosh LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for C and C++. *) Other Compilers If you encounter problems on any compilers, feel free to let me know and I may try to fix it if the compiler is modern and standards compliant. 10. examples ------------ This decoder example shows the most basic usage of LodePNG. More complex examples can be found on the LodePNG website. NOTE: these examples do not support wide-character filenames, you can use an external method to handle such files and encode or decode in-memory 10.1. decoder C++ example ------------------------- #include "lodepng.h" #include int main(int argc, char *argv[]) { const char* filename = argc > 1 ? argv[1] : "test.png"; //load and decode std::vector image; unsigned width, height; unsigned error = lodepng::decode(image, width, height, filename); //if there's an error, display it if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... } 10.2. decoder C example ----------------------- #include "lodepng.h" int main(int argc, char *argv[]) { unsigned error; unsigned char* image; size_t width, height; const char* filename = argc > 1 ? argv[1] : "test.png"; error = lodepng_decode32_file(&image, &width, &height, filename); if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); / * use image here * / free(image); return 0; } 11. state settings reference ---------------------------- A quick reference of some settings to set on the LodePNGState For decoding: state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums state.decoder.zlibsettings.custom_...: use custom inflate function state.decoder.ignore_crc: ignore CRC checksums state.decoder.ignore_critical: ignore unknown critical chunks state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors state.decoder.color_convert: convert internal PNG color to chosen one state.decoder.read_text_chunks: whether to read in text metadata chunks state.decoder.remember_unknown_chunks: whether to read in unknown chunks state.info_raw.colortype: desired color type for decoded image state.info_raw.bitdepth: desired bit depth for decoded image state.info_raw....: more color settings, see struct LodePNGColorMode state.info_png....: no settings for decoder but output, see struct LodePNGInfo For encoding: state.encoder.zlibsettings.btype: disable compression by setting it to 0 state.encoder.zlibsettings.use_lz77: use LZ77 in compression state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching state.encoder.zlibsettings.lazymatching: try one more LZ77 matching state.encoder.zlibsettings.custom_...: use custom deflate function state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png state.encoder.filter_palette_zero: PNG filter strategy for palette state.encoder.filter_strategy: PNG filter strategy to encode with state.encoder.force_palette: add palette even if not encoding to one state.encoder.add_id: add LodePNG identifier and version as a text chunk state.encoder.text_compression: use compressed text chunks for metadata state.info_raw.colortype: color type of raw input image you provide state.info_raw.bitdepth: bit depth of raw input image you provide state.info_raw: more color settings, see struct LodePNGColorMode state.info_png.color.colortype: desired color type if auto_convert is false state.info_png.color.bitdepth: desired bit depth if auto_convert is false state.info_png.color....: more color settings, see struct LodePNGColorMode state.info_png....: more PNG related settings, see struct LodePNGInfo 12. changes ----------- The version number of LodePNG is the date of the change given in the format yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. Not all changes are listed here, the commit history in github lists more: https://github.com/lvandeve/lodepng *) 09 jan 2022: minor decoder speed improvements. *) 27 jun 2021: added warnings that file reading/writing functions don't support wide-character filenames (support for this is not planned, opening files is not the core part of PNG decoding/decoding and is platform dependent). *) 17 okt 2020: prevent decoding too large text/icc chunks by default. *) 06 mar 2020: simplified some of the dynamic memory allocations. *) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct overflow checks. *) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables. *) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette if gray ICC profile) and non-ICC LodePNGColorProfile renamed to LodePNGColorStats. *) 30 dec 2018: code style changes only: removed newlines before opening braces. *) 10 sep 2018: added way to inspect metadata chunks without full decoding. *) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use palette index in case of palette. *) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This change is backwards compatible unless you relied on unknown_chunks for those. *) 11 jun 2018: less restrictive check for pixel size integer overflow *) 14 jan 2018: allow optionally ignoring a few more recoverable errors *) 17 sep 2017: fix memory leak for some encoder input error cases *) 27 nov 2016: grey+alpha auto color model detection bugfix *) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). *) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within the limits of pure C90). *) 08 dec 2015: Made load_file function return error if file can't be opened. *) 24 okt 2015: Bugfix with decoding to palette output. *) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. *) 24 aug 2014: Moved to github *) 23 aug 2014: Reduced needless memory usage of decoder. *) 28 jun 2014: Removed fix_png setting, always support palette OOB for simplicity. Made ColorProfile public. *) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. *) 22 dec 2013: Power of two windowsize required for optimization. *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). *) 11 mar 2013: (!) Bugfix with custom free. Changed from "my" to "lodepng_" prefix for the custom allocators and made it possible with a new #define to use custom ones in your project without needing to change lodepng's code. *) 28 jan 2013: Bugfix with color key. *) 27 okt 2012: Tweaks in text chunk keyword length error handling. *) 8 okt 2012: (!) Added new filter strategy (entropy) and new auto color mode. (no palette). Better deflate tree encoding. New compression tweak settings. Faster color conversions while decoding. Some internal cleanups. *) 23 sep 2012: Reduced warnings in Visual Studio a little bit. *) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions and made it work with function pointers instead. *) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc and free functions and toggle #defines from compiler flags. Small fixes. *) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible. *) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed redundant C++ codec classes. Reduced amount of structs. Everything changed, but it is cleaner now imho and functionality remains the same. Also fixed several bugs and shrunk the implementation code. Made new samples. *) 6 nov 2011: (!) By default, the encoder now automatically chooses the best PNG color model and bit depth, based on the amount and type of colors of the raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. *) 9 okt 2011: simpler hash chain implementation for the encoder. *) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. *) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. A bug with the PNG filtertype heuristic was fixed, so that it chooses much better ones (it's quite significant). A setting to do an experimental, slow, brute force search for PNG filter types is added. *) 17 aug 2011: (!) changed some C zlib related function names. *) 16 aug 2011: made the code less wide (max 120 characters per line). *) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. *) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. *) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman to optimize long sequences of zeros. *) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and LodePNG_InfoColor_canHaveAlpha functions for convenience. *) 7 nov 2010: added LodePNG_error_text function to get error code description. *) 30 okt 2010: made decoding slightly faster *) 26 okt 2010: (!) changed some C function and struct names (more consistent). Reorganized the documentation and the declaration order in the header. *) 08 aug 2010: only changed some comments and external samples. *) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. *) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. *) 02 sep 2008: fixed bug where it could create empty tree that linux apps could read by ignoring the problem but windows apps couldn't. *) 06 jun 2008: added more error checks for out of memory cases. *) 26 apr 2008: added a few more checks here and there to ensure more safety. *) 06 mar 2008: crash with encoding of strings fixed *) 02 feb 2008: support for international text chunks added (iTXt) *) 23 jan 2008: small cleanups, and #defines to divide code in sections *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added Also various fixes, such as in the deflate and the padding bits code. *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved filtering code of encoder. *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A C++ wrapper around this provides an interface almost identical to before. Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code are together in these files but it works both for C and C++ compilers. *) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks *) 30 aug 2007: bug fixed which makes this Borland C++ compatible *) 09 aug 2007: some VS2005 warnings removed again *) 21 jul 2007: deflate code placed in new namespace separate from zlib code *) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images *) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing invalid std::vector element [0] fixed, and level 3 and 4 warnings removed *) 02 jun 2007: made the encoder add a tag with version by default *) 27 may 2007: zlib and png code separated (but still in the same file), simple encoder/decoder functions added for more simple usage cases *) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), moved some examples from here to lodepng_examples.cpp *) 12 may 2007: palette decoding bug fixed *) 24 apr 2007: changed the license from BSD to the zlib license *) 11 mar 2007: very simple addition: ability to encode bKGD chunks. *) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding palettized PNG images. Plus little interface change with palette and texts. *) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. Fixed a bug where the end code of a block had length 0 in the Huffman tree. *) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented and supported by the encoder, resulting in smaller PNGs at the output. *) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. *) 24 jan 2007: gave encoder an error interface. Added color conversion from any greyscale type to 8-bit greyscale with or without alpha. *) 21 jan 2007: (!) Totally changed the interface. It allows more color types to convert to and is more uniform. See the manual for how it works now. *) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: encode/decode custom tEXt chunks, separate classes for zlib & deflate, and at last made the decoder give errors for incorrect Adler32 or Crc. *) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. *) 29 dec 2006: Added support for encoding images without alpha channel, and cleaned out code as well as making certain parts faster. *) 28 dec 2006: Added "Settings" to the encoder. *) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. Removed some code duplication in the decoder. Fixed little bug in an example. *) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. Fixed a bug of the decoder with 16-bit per color. *) 15 okt 2006: Changed documentation structure *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the given image buffer, however for now it's not compressed. *) 08 sep 2006: (!) Changed to interface with a Decoder class *) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different way. Renamed decodePNG to decodePNGGeneric. *) 29 jul 2006: (!) Changed the interface: image info is now returned as a struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. *) 28 jul 2006: Cleaned the code and added new error checks. Corrected terminology "deflate" into "inflate". *) 23 jun 2006: Added SDL example in the documentation in the header, this example allows easy debugging by displaying the PNG and its transparency. *) 22 jun 2006: (!) Changed way to obtain error value. Added loadFile function for convenience. Made decodePNG32 faster. *) 21 jun 2006: (!) Changed type of info vector to unsigned. Changed position of palette in info vector. Fixed an important bug that happened on PNGs with an uncompressed block. *) 16 jun 2006: Internally changed unsigned into unsigned where needed, and performed some optimizations. *) 07 jun 2006: (!) Renamed functions to decodePNG and placed them in LodePNG namespace. Changed the order of the parameters. Rewrote the documentation in the header. Renamed files to lodepng.cpp and lodepng.h *) 22 apr 2006: Optimized and improved some code *) 07 sep 2005: (!) Changed to std::vector interface *) 12 aug 2005: Initial release (C++, decoder only) 13. contact information ----------------------- Feel free to contact me with suggestions, problems, comments, ... concerning LodePNG. If you encounter a PNG image that doesn't work properly with this decoder, feel free to send it and I'll use it to find and fix the problem. My email address is (puzzle the account and domain together with an @ symbol): Domain: gmail dot com. Account: lode dot vandevenne. Copyright (c) 2005-2022 Lode Vandevenne */ ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_7/lodepng/lodepng.cpp ================================================ #include "lodepng.h" ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_7/src/user_objects.cc ================================================ #include "user_objects.h" ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_8/Package.swift ================================================ // swift-tools-version:5.8.0 import PackageDescription let package = Package( name: "CXX17WithFModules", targets: [ .target( name: "lodepng", path: "lodepng", sources: ["lodepng.cpp"], publicHeadersPath: "include"), .target(name: "CXX17WithFModules", dependencies: ["lodepng"], path: "./", sources: ["src/user_objects.cc"], publicHeadersPath: "include"), ], cxxLanguageStandard: .cxx17 ) ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_8/include/user_objects.h ================================================ // Copyright 2021 DeepMind Technologies Limited // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef MUJOCO_SRC_USER_USER_OBJECTS_H_ #define MUJOCO_SRC_USER_USER_OBJECTS_H_ #include #include #include "lodepng.h" // forward declarations of all mjC/X classes class mjCError; class mjCAlternative; class mjCBase; class mjCBody; class mjCJoint; class mjCGeom; class mjCSite; class mjCCamera; class mjCLight; class mjCMesh; class mjCSkin; class mjCTexture; class mjCMaterial; class mjCPair; class mjCBodyPair; class mjCEquality; class mjCTendon; class mjCWrap; class mjCActuator; class mjCSensor; class mjCNumeric; class mjCText; class mjCTuple; class mjCDef; class mjCMesh; // defined in user_mesh class mjCModel; // defined in user_model class mjXWriter; // defined in xml_native class mjXURDF; // defined in xml_urdf //------------------------- helper classes and constants ------------------------------------------- // builtin type for procedural textures typedef enum _mjtBuiltin { mjBUILTIN_NONE = 0, // no builtin mjBUILTIN_GRADIENT, // circular gradient: rgb1->rgb2->rgb3 mjBUILTIN_CHECKER, // checker pattern: rgb1, rgb2 mjBUILTIN_FLAT // 2d: rgb1; cube: rgb1-up, rgb2-side, rgb3-down } mjtBuiltin; // mark type for procedural textures typedef enum _mjtMark { mjMARK_NONE = 0, // no mark mjMARK_EDGE, // paint edges mjMARK_CROSS, // paint cross mjMARK_RANDOM // paint random dots } mjtMark; // error information class mjCError { public: mjCError(const mjCBase* obj = 0, const char* msg = 0, const char* str = 0, int pos1 = 0, int pos2 = 0); char message[500]; // error message bool warning; // is this a warning instead of error }; // alternative specifications of frame orientation class mjCAlternative { public: mjCAlternative(); // constructor const char* Set(double* quat, double* inertia, // set frame quat and diag. inertia bool degree, // angle format: degree/radian const char* sequence); // euler sequence format: "xyz" double axisangle[4]; // rotation axis and angle double xyaxes[6]; // x and y axes double zaxis[3]; // z axis (use minimal rotation) double euler[3]; // euler rotations double fullinertia[6]; // non-axis-aligned inertia matrix }; //------------------------- class mjCBase ---------------------------------------------------------- // Generic functionality for all derived classes class mjCBase { friend class mjCDef; public: std::string name; // object name std::string classname; // defaults class name int id; // object id int xmlpos[2]; // row and column in xml file mjCDef* def; // defaults class used to init this object protected: mjCBase(); // constructor mjCModel* model; // pointer to model that created object }; //------------------------- class mjCBody ----------------------------------------------- // Describes a rigid body class mjCBody : public mjCBase { friend class mjCJoint; friend class mjCGeom; friend class mjCSite; friend class mjCCamera; friend class mjCLight; friend class mjCEquality; friend class mjCPair; friend class mjCModel; friend class mjXReader; friend class mjXWriter; friend class mjXURDF; public: // API for adding objects to body mjCBody* AddBody(mjCDef* = 0); mjCJoint* AddJoint(mjCDef* = 0, bool isfree = false); mjCGeom* AddGeom(mjCDef* = 0); mjCSite* AddSite(mjCDef* = 0); mjCCamera* AddCamera(mjCDef* = 0); mjCLight* AddLight(mjCDef* = 0); // setup child local frame, take into account change void MakeLocal(double* locpos, double* locquat, const double* pos, const double* quat); // set explicit_inertial to true void MakeInertialExplicit(); // variables set by user or 'Compile' bool mocap; // is this a mocap body double pos[3]; // frame position double quat[4]; // frame orientation double ipos[3]; // inertial frame position double iquat[4]; // inertial frame orientation double mass; // mass double inertia[3]; // diagonal inertia (in i-frame) std::vector userdata; // user data mjCAlternative alt; // alternative orientation specification mjCAlternative ialt; // alternative for inertial frame // variables computed by 'Compile' and 'AddXXX' private: mjCBody(mjCModel*); // constructor ~mjCBody(); // destructor void Compile(void); // compiler void GeomFrame(void); // get inertial info from geoms double locpos[3]; // position relative to parent double locquat[4]; // orientation relative to parent double locipos[3]; // inertial position frame, rel. to local frame double lociquat[4]; // inertial frame orientation int parentid; // parent index in global array int weldid; // top index of body we are welded to int dofnum; // number of motion dofs for body int mocapid; // mocap id, -1: not mocap bool explicit_inertial; // whether to save the body with an explicit inertial clause int lastdof; // id of last dof (used by compiler) // objects allocated by Add functions std::vector bodies; // child bodies std::vector geoms; // geoms attached to this body std::vector joints; // joints allowing motion relative to parent std::vector sites; // sites attached to this body std::vector cameras; // cameras attached to this body std::vector lights; // lights attached to this body }; #endif // MUJOCO_SRC_USER_USER_OBJECTS_H_ ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_8/lodepng/include/lodepng.h ================================================ /* LodePNG version 20220109 Copyright (c) 2005-2022 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef LODEPNG_H #define LODEPNG_H #include /*for size_t*/ extern const char* LODEPNG_VERSION_STRING; /* The following #defines are used to create code sections. They can be disabled to disable code sections, which can give faster compile time and smaller binary. The "NO_COMPILE" defines are designed to be used to pass as defines to the compiler command to disable them without modifying this header, e.g. -DLODEPNG_NO_COMPILE_ZLIB for gcc. In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to allow implementing a custom lodepng_crc32. */ /*deflate & zlib. If disabled, you must specify alternative zlib functions in the custom_zlib field of the compress and decompress settings*/ #ifndef LODEPNG_NO_COMPILE_ZLIB #define LODEPNG_COMPILE_ZLIB #endif /*png encoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_PNG #define LODEPNG_COMPILE_PNG #endif /*deflate&zlib decoder and png decoder*/ #ifndef LODEPNG_NO_COMPILE_DECODER #define LODEPNG_COMPILE_DECODER #endif /*deflate&zlib encoder and png encoder*/ #ifndef LODEPNG_NO_COMPILE_ENCODER #define LODEPNG_COMPILE_ENCODER #endif /*the optional built in harddisk file loading and saving functions*/ #ifndef LODEPNG_NO_COMPILE_DISK #define LODEPNG_COMPILE_DISK #endif /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS #define LODEPNG_COMPILE_ANCILLARY_CHUNKS #endif /*ability to convert error numerical codes to English text string*/ #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT #define LODEPNG_COMPILE_ERROR_TEXT #endif /*Compile the default allocators (C's free, malloc and realloc). If you disable this, you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your source files with custom allocators.*/ #ifndef LODEPNG_NO_COMPILE_ALLOCATORS #define LODEPNG_COMPILE_ALLOCATORS #endif /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP #define LODEPNG_COMPILE_CPP #endif #endif #ifdef LODEPNG_COMPILE_CPP #include #include #endif /*LODEPNG_COMPILE_CPP*/ #ifdef LODEPNG_COMPILE_PNG /*The PNG color types (also used for raw image).*/ typedef enum LodePNGColorType { LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ LCT_RGB = 2, /*RGB: 8,16 bit*/ LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid byte value from 0 to 255 that could be present in an invalid PNG file header. Do not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use the valid color type names above, or numeric values like 1 or 7 when checking for particular disallowed color type byte values, or cast to integer to print it.*/ LCT_MAX_OCTET_VALUE = 255 } LodePNGColorType; #ifdef LODEPNG_COMPILE_DECODER /* Converts PNG data in memory to raw pixel data. out: Output parameter. Pointer to buffer that will contain the raw pixel data. After decoding, its size is w * h * (bytes per pixel) bytes larger than initially. Bytes per pixel depends on colortype and bitdepth. Must be freed after usage with free(*out). Note: for 16-bit per channel colors, uses big endian format like PNG does. w: Output parameter. Pointer to width of pixel data. h: Output parameter. Pointer to height of pixel data. in: Memory buffer with the PNG file. insize: size of the in buffer. colortype: the desired color type for the raw output image. See explanation on PNG color types. bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_DISK /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory.*/ unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Converts raw pixel data into a PNG image in memory. The colortype and bitdepth of the output PNG image cannot be chosen, they are automatically determined by the colortype, bitdepth and content of the input pixel data. Note: for 16-bit per channel colors, needs big endian format like PNG does. out: Output parameter. Pointer to buffer that will contain the PNG image data. Must be freed after usage with free(*out). outsize: Output parameter. Pointer to the size in bytes of the out buffer. image: The raw pixel data to encode. The size of this buffer should be w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. w: width of the raw pixel data in pixels. h: height of the raw pixel data in pixels. colortype: the color type of the raw input image. See explanation on PNG color types. bitdepth: the bit depth of the raw input image. See explanation on PNG color types. Return value: LodePNG error code (0 means no error). */ unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DISK /* Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory.*/ unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER /*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::vector& in, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /*Same as lodepng_encode_memory, but encodes to an std::vector. colortype is that of the raw input data. The output PNG color type will be auto chosen.*/ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned encode(const std::string& filename, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); unsigned encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_ENCODER */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ERROR_TEXT /*Returns an English description of the numerical error code.*/ const char* lodepng_error_text(unsigned code); #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ #ifdef LODEPNG_COMPILE_DECODER /*Settings for zlib decompression*/ typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, return an error, output a data size > max_output_size and all the data up to that point. This is not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. Set to 0 to impose no limit (the default).*/ size_t max_output_size; /*use custom zlib decoder instead of built in one (default: null). Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); /*use custom deflate decoder instead of built in one (default: null) if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). Should return 0 if success, any non-0 if error (numeric value not exposed).*/ unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGDecompressSettings lodepng_default_decompress_settings; void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Settings for zlib compression. Tweaking these settings tweaks the balance between speed and compression ratio. */ typedef struct LodePNGCompressSettings LodePNGCompressSettings; struct LodePNGCompressSettings /*deflate = compress*/ { /*LZ77 related settings*/ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ /*use custom zlib encoder instead of built in one (default: null)*/ unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); /*use custom deflate encoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ unsigned (*custom_deflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGCompressSettings*); const void* custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGCompressSettings lodepng_default_compress_settings; void lodepng_compress_settings_init(LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_PNG /* Color mode of an image. Contains all information required to decode the pixel bits to RGBA colors. This information is the same as used in the PNG file format, and is used both for PNG and raw image data in LodePNG. */ typedef struct LodePNGColorMode { /*header (IHDR)*/ LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ /* palette (PLTE and tRNS) Dynamically allocated with the colors of the palette, including alpha. This field may not be allocated directly, use lodepng_color_mode_init first, then lodepng_palette_add per color to correctly initialize it (to ensure size of exactly 1024 bytes). The alpha channels must be set as well, set them to 255 for opaque images. When decoding, by default you can ignore this palette, since LodePNG already fills the palette colors in the pixels of the raw RGBA output. The palette is only supported for color type 3. */ unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ /* transparent color key (tRNS) This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. For grayscale PNGs, r, g and b will all 3 be set to the same. When decoding, by default you can ignore this information, since LodePNG sets pixels with this key to transparent already in the raw RGBA output. The color key is only supported for color types 0 and 2. */ unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ unsigned key_r; /*red/grayscale component of color key*/ unsigned key_g; /*green component of color key*/ unsigned key_b; /*blue component of color key*/ } LodePNGColorMode; /*init, cleanup and copy functions to use with this struct*/ void lodepng_color_mode_init(LodePNGColorMode* info); void lodepng_color_mode_cleanup(LodePNGColorMode* info); /*return value is error code (0 means no error)*/ unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); /* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); void lodepng_palette_clear(LodePNGColorMode* info); /*add 1 color to the palette*/ unsigned lodepng_palette_add(LodePNGColorMode* info, unsigned char r, unsigned char g, unsigned char b, unsigned char a); /*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ unsigned lodepng_get_bpp(const LodePNGColorMode* info); /*get the amount of color channels used, based on colortype in the struct. If a palette is used, it counts as 1 channel.*/ unsigned lodepng_get_channels(const LodePNGColorMode* info); /*is it a grayscale type? (only colortype 0 or 4)*/ unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); /*has it got an alpha channel? (only colortype 2 or 6)*/ unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); /*has it got a palette? (only colortype 3)*/ unsigned lodepng_is_palette_type(const LodePNGColorMode* info); /*only returns true if there is a palette and there is a value in the palette with alpha < 255. Loops through the palette to check this.*/ unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); /* Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). Returns false if the image can only have opaque pixels. In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, or if "key_defined" is true. */ unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); /*Returns the byte size of a raw image buffer with given width, height and color mode*/ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*The information of a Time chunk in PNG.*/ typedef struct LodePNGTime { unsigned year; /*2 bytes used (0-65535)*/ unsigned month; /*1-12*/ unsigned day; /*1-31*/ unsigned hour; /*0-23*/ unsigned minute; /*0-59*/ unsigned second; /*0-60 (to allow for leap seconds)*/ } LodePNGTime; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*Information about the PNG image, except pixels, width and height.*/ typedef struct LodePNGInfo { /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ unsigned compression_method;/*compression method of the original file. Always 0.*/ unsigned filter_method; /*filter method of the original file*/ unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /* Suggested background color chunk (bKGD) This uses the same color mode and bit depth as the PNG (except no alpha channel), with values truncated to the bit depth in the unsigned integer. For grayscale and palette PNGs, the value is stored in background_r. The values in background_g and background_b are then unused. So when decoding, you may get these in a different color mode than the one you requested for the raw pixels. When encoding with auto_convert, you must use the color model defined in info_png.color for these values. The encoder normally ignores info_png.color when auto_convert is on, but will use it to interpret these values (and convert copies of them to its chosen color model). When encoding, avoid setting this to an expensive color, such as a non-gray value when the image is gray, or the compression will be worse since it will be forced to write the PNG with a more expensive color mode (when auto_convert is on). The decoder does not use this background color to edit the color of pixels. This is a completely optional metadata feature. */ unsigned background_defined; /*is a suggested background color given?*/ unsigned background_r; /*red/gray/palette component of suggested background color*/ unsigned background_g; /*green component of suggested background color*/ unsigned background_b; /*blue component of suggested background color*/ /* Non-international text chunks (tEXt and zTXt) The char** arrays each contain num strings. The actual messages are in text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. All the string fields below including strings, keys, names and language tags are null terminated. The PNG specification uses null characters for the keys, names and tags, and forbids null characters to appear in the main text which is why we can use null termination everywhere here. A keyword is minimum 1 character and maximum 79 characters long (plus the additional null terminator). It's discouraged to use a single line length longer than 79 characters for texts. Don't allocate these text buffers yourself. Use the init/cleanup functions correctly and use lodepng_add_text and lodepng_clear_text. Standard text chunk keywords and strings are encoded using Latin-1. */ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ char** text_strings; /*the actual text*/ /* International text chunks (iTXt) Similar to the non-international text chunks, but with additional strings "langtags" and "transkeys", and the following text encodings are used: keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. keys must be 1-79 characters (plus the additional null terminator), the other strings are any length. */ size_t itext_num; /*the amount of international texts in this PNG*/ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ char** itext_strings; /*the actual international text - UTF-8 string*/ /*time chunk (tIME)*/ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ LodePNGTime time; /*phys chunk (pHYs)*/ unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ unsigned phys_x; /*pixels per unit in x direction*/ unsigned phys_y; /*pixels per unit in y direction*/ unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* Color profile related chunks: gAMA, cHRM, sRGB, iCPP LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please use these values with a color management library. See the PNG, ICC and sRGB specifications for more information about the meaning of these values. */ /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */ unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ unsigned gama_gamma; /* Gamma exponent times 100000 */ /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */ unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ unsigned chrm_white_x; /* White Point x times 100000 */ unsigned chrm_white_y; /* White Point y times 100000 */ unsigned chrm_red_x; /* Red x times 100000 */ unsigned chrm_red_y; /* Red y times 100000 */ unsigned chrm_green_x; /* Green x times 100000 */ unsigned chrm_green_y; /* Green y times 100000 */ unsigned chrm_blue_x; /* Blue x times 100000 */ unsigned chrm_blue_y; /* Blue y times 100000 */ /* sRGB chunk: optional. May not appear at the same time as iCCP. If gAMA is also present gAMA must contain value 45455. If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. */ unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ /* iCCP chunk: optional. May not appear at the same time as sRGB. LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color management and conversions. For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile. For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel data if the pixels could be encoded as grayscale but the ICC profile is RGB. To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so make sure you compute it carefully to avoid the above problems. */ unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ /* The ICC profile in iccp_profile_size bytes. Don't allocate this buffer yourself. Use the init/cleanup functions correctly and use lodepng_set_icc and lodepng_clear_icc. */ unsigned char* iccp_profile; unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ /* End of color profile related chunks */ /* unknown chunks: chunks not known by LodePNG, passed on byte for byte. There are 3 buffers, one for each position in the PNG where unknown chunks can appear. Each buffer contains all unknown chunks for that position consecutively. The 3 positions are: 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag above in here, since the encoder will blindly follow this and could then encode an invalid PNG file (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), or any non-standard PNG chunk. Do not allocate or traverse this data yourself. Use the chunk traversing functions declared later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. */ unsigned char* unknown_chunks_data[3]; size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGInfo; /*init, cleanup and copy functions to use with this struct*/ void lodepng_info_init(LodePNGInfo* info); void lodepng_info_cleanup(LodePNGInfo* info); /*return value is error code (0 means no error)*/ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ /*replaces if exists*/ unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* Converts raw buffer from one color type to another color type, based on LodePNGColorMode structs to describe the input and output color type. See the reference manual at the end of this header file to see which color conversions are supported. return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel of the output color type (lodepng_get_bpp). For < 8 bpp images, there should not be padding bits at the end of scanlines. For 16-bit per channel colors, uses big endian format like PNG does. Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* Settings for the decoder. This contains settings for the PNG and the Zlib decoder, but not the Info settings from the Info structs. */ typedef struct LodePNGDecoderSettings { LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ unsigned ignore_crc; /*ignore CRC checksums*/ unsigned ignore_critical; /*ignore unknown critical chunks*/ unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters in string keys, etc... */ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ unsigned remember_unknown_chunks; /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. By default it is a value that prevents unreasonably large strings from hogging memory. */ size_t max_text_size; /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any legitimate profile could be to hog memory. */ size_t max_icc_size; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ typedef enum LodePNGFilterStrategy { /*every filter at zero*/ LFS_ZERO = 0, /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ LFS_ONE = 1, LFS_TWO = 2, LFS_THREE = 3, LFS_FOUR = 4, /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ LFS_MINSUM, /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending on the image, this is better or worse than minsum.*/ LFS_ENTROPY, /* Brute-force-search PNG filters by compressing each filter for each scanline. Experimental, very slow, and only rarely gives better compression than MINSUM. */ LFS_BRUTE_FORCE, /*use predefined_filters buffer: you specify the filter type for each scanline*/ LFS_PREDEFINED } LodePNGFilterStrategy; /*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), which helps decide which color model to use for encoding. Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ typedef struct LodePNGColorStats { unsigned colored; /*not grayscale*/ unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ unsigned short key_g; unsigned short key_b; unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ size_t numpixels; /*user settings for computing/using the stats*/ unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ } LodePNGColorStats; void lodepng_color_stats_init(LodePNGColorStats* stats); /*Get a LodePNGColorStats of the image. The stats must already have been inited. Returns error code (e.g. alloc fail) or 0 if ok.*/ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, const unsigned char* image, unsigned w, unsigned h, const LodePNGColorMode* mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to completely follow the official PNG heuristic, filter_palette_zero must be true and filter_strategy must be LFS_MINSUM*/ unsigned filter_palette_zero; /*Which filter strategy to use when not using zeroes due to filter_palette_zero. Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ LodePNGFilterStrategy filter_strategy; /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with the same length as the amount of scanlines in the image, and each value must <= 5. You have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ const unsigned char* predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ unsigned force_palette; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ unsigned add_id; /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ unsigned text_compression; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGEncoderSettings; void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) /*The settings, state and information for extended encoding and decoding.*/ typedef struct LodePNGState { #ifdef LODEPNG_COMPILE_DECODER LodePNGDecoderSettings decoder; /*the decoding settings*/ #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER LodePNGEncoderSettings encoder; /*the encoding settings*/ #endif /*LODEPNG_COMPILE_ENCODER*/ LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; } LodePNGState; /*init, cleanup and copy functions to use with this struct*/ void lodepng_state_init(LodePNGState* state); void lodepng_state_cleanup(LodePNGState* state); void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ #ifdef LODEPNG_COMPILE_DECODER /* Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and getting much more information about the PNG image and color mode. */ unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); /* Read the PNG header, but not the actual data. This returns only the information that is in the IHDR chunk of the PNG, such as width, height and color type. The information is placed in the info_png field of the LodePNGState. */ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize); #endif /*LODEPNG_COMPILE_DECODER*/ /* Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it read in the state. Returns error code on failure. Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const to find the desired chunk type, and if non null use lodepng_inspect_chunk (with chunk_pointer - start_of_file as pos). Supports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...). Ignores unsupported, unknown, non-metadata or IHDR chunks (without error). Requirements: &in[pos] must point to start of a chunk, must use regular lodepng_inspect first since format of most other chunks depends on IHDR, and if there is a PLTE chunk, that one must be inspected before tRNS or bKGD. */ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, const unsigned char* in, size_t insize); #ifdef LODEPNG_COMPILE_ENCODER /*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ unsigned lodepng_encode(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h, LodePNGState* state); #endif /*LODEPNG_COMPILE_ENCODER*/ /* The lodepng_chunk functions are normally not needed, except to traverse the unknown chunks stored in the LodePNGInfo struct, or add new ones to it. It also allows traversing the chunks of an encoded PNG file yourself. The chunk pointer always points to the beginning of the chunk itself, that is the first byte of the 4 length bytes. In the PNG file format, chunks have the following format: -4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) -4 bytes chunk type (ASCII a-z,A-Z only, see below) -length bytes of data (may be 0 bytes if length was 0) -4 bytes of CRC, computed on chunk name + data The first chunk starts at the 8th byte of the PNG file, the entire rest of the file exists out of concatenated chunks with the above format. PNG standard chunk ASCII naming conventions: -First byte: uppercase = critical, lowercase = ancillary -Second byte: uppercase = public, lowercase = private -Third byte: must be uppercase -Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy */ /* Gets the length of the data of the chunk. Total chunk length has 12 bytes more. There must be at least 4 bytes to read from. If the result value is too large, it may be corrupt data. */ unsigned lodepng_chunk_length(const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ void lodepng_chunk_type(char type[5], const unsigned char* chunk); /*check if the type is the given type*/ unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); /*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); /*0: public, 1: private (see PNG standard)*/ unsigned char lodepng_chunk_private(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); /*get pointer to the data of the chunk, where the input points to the header of the chunk*/ unsigned char* lodepng_chunk_data(unsigned char* chunk); const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ unsigned lodepng_chunk_check_crc(const unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ void lodepng_chunk_generate_crc(unsigned char* chunk); /* Iterate to next chunks, allows iterating through all chunks of the PNG file. Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, or the 8th byte of a PNG file which always has the first chunk), or alternatively may point to the first byte of the PNG file (which is not a chunk but the magic header, the function will then skip over it and return the first real chunk). Will output pointer to the start of the next chunk, or at or beyond end of the file if there is no more chunk after this or possibly if the chunk is corrupt. Start this process at the 8th byte of the PNG file. In a non-corrupt PNG file, the last chunk should have name "IEND". */ unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); /*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); /* Appends chunk to the data in out. The given chunk should already have its chunk header. The out variable and outsize are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); /* Appends new chunk to out. The chunk to append is given by giving its length, type and data separately. The type is a 4-letter string. The out variable and outsize are updated to reflect the new reallocated buffer. Returns error code (0 if it went ok) */ unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, const char* type, const unsigned char* data); /*Calculate CRC32 of buffer*/ unsigned lodepng_crc32(const unsigned char* buf, size_t len); #endif /*LODEPNG_COMPILE_PNG*/ #ifdef LODEPNG_COMPILE_ZLIB /* This zlib part can be used independently to zlib compress and decompress a buffer. It cannot be used to create gzip files however, and it only supports the part of zlib that is required for PNG, it does not support dictionaries. */ #ifdef LODEPNG_COMPILE_DECODER /*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ unsigned lodepng_inflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); /* Decompresses Zlib data. Reallocates the out buffer and appends the data. The data must be according to the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Compresses data with Zlib. Reallocates the out buffer and appends the data. Zlib adds a small header and trailer around the deflate data. The data is output in the format of the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); /* Find length-limited Huffman code for given frequencies. This function is in the public interface only for tests, it's used internally by lodepng_deflate. */ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen); /*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ unsigned lodepng_deflate(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into buffer. The function allocates the out buffer, and after usage you should free it. out: output parameter, contains pointer to loaded buffer. outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory. */ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); /* Save a file from buffer to disk. Warning, if it exists, this function overwrites the file without warning! buffer: the buffer to write buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory */ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP /* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ namespace lodepng { #ifdef LODEPNG_COMPILE_PNG class State : public LodePNGState { public: State(); State(const State& other); ~State(); State& operator=(const State& other); }; #ifdef LODEPNG_COMPILE_DECODER /* Same as other lodepng::decode, but using a State for more settings and information. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize); unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const std::vector& in); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER /* Same as other lodepng::encode, but using a State for more settings and information. */ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, State& state); unsigned encode(std::vector& out, const std::vector& in, unsigned w, unsigned h, State& state); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DISK /* Load a file from disk into an std::vector. return value: error code (0 means ok) NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and decode in-memory */ unsigned load_file(std::vector& buffer, const std::string& filename); /* Save the binary data in an std::vector to a file on disk. The file is overwritten without warning. NOTE: Wide-character filenames are not supported, you can use an external method to handle such files and encode in-memory */ unsigned save_file(const std::vector& buffer, const std::string& filename); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_PNG */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER /* Zlib-decompress an unsigned char buffer */ unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); /* Zlib-decompress an std::vector */ unsigned decompress(std::vector& out, const std::vector& in, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /* Zlib-compress an unsigned char buffer */ unsigned compress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); /* Zlib-compress an std::vector */ unsigned compress(std::vector& out, const std::vector& in, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ } /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ /* TODO: [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often [.] check compatibility with various compilers - done but needs to be redone for every newer version [X] converting color to 16-bit per channel types [X] support color profile chunk types (but never let them touch RGB values by default) [ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] partial decoding (stream processing) [X] let the "isFullyOpaque" function check color keys and transparent palettes too [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) [ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... [ ] error messages with line numbers (and version) [ ] errors in state instead of as return code? [ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes [ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... [ ] allow user to give data (void*) to custom allocator [X] provide alternatives for C library functions not present on some platforms (memcpy, ...) */ #endif /*LODEPNG_H inclusion guard*/ /* LodePNG Documentation --------------------- 0. table of contents -------------------- 1. about 1.1. supported features 1.2. features not supported 2. C and C++ version 3. security 4. decoding 5. encoding 6. color conversions 6.1. PNG color types 6.2. color conversions 6.3. padding bits 6.4. A note about 16-bits per channel and endianness 7. error values 8. chunks and PNG editing 9. compiler support 10. examples 10.1. decoder C++ example 10.2. decoder C example 11. state settings reference 12. changes 13. contact information 1. about -------- PNG is a file format to store raster images losslessly with good compression, supporting different color types and alpha channel. LodePNG is a PNG codec according to the Portable Network Graphics (PNG) Specification (Second Edition) - W3C Recommendation 10 November 2003. The specifications used are: *) Portable Network Graphics (PNG) Specification (Second Edition): http://www.w3.org/TR/2003/REC-PNG-20031110 *) RFC 1950 ZLIB Compressed Data Format version 3.3: http://www.gzip.org/zlib/rfc-zlib.html *) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: http://www.gzip.org/zlib/rfc-deflate.html The most recent version of LodePNG can currently be found at http://lodev.org/lodepng/ LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds extra functionality. LodePNG exists out of two files: -lodepng.h: the header file for both C and C++ -lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage If you want to start using LodePNG right away without reading this doc, get the examples from the LodePNG website to see how to use it in code, or check the smaller examples in chapter 13 here. LodePNG is simple but only supports the basic requirements. To achieve simplicity, the following design choices were made: There are no dependencies on any external library. There are functions to decode and encode a PNG with a single function call, and extended versions of these functions taking a LodePNGState struct allowing to specify or get more information. By default the colors of the raw image are always RGB or RGBA, no matter what color type the PNG file uses. To read and write files, there are simple functions to convert the files to/from buffers in memory. This all makes LodePNG suitable for loading textures in games, demos and small programs, ... It's less suitable for full fledged image editors, loading PNGs over network (it requires all the image data to be available before decoding can begin), life-critical systems, ... 1.1. supported features ----------------------- The following features are supported by the decoder: *) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, or the same color type as the PNG *) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image *) Adam7 interlace and deinterlace for any color type *) loading the image from harddisk or decoding it from a buffer from other sources than harddisk *) support for alpha channels, including RGBA color model, translucent palettes and color keying *) zlib decompression (inflate) *) zlib compression (deflate) *) CRC32 and ADLER32 checksums *) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. *) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. *) the following chunks are supported by both encoder and decoder: IHDR: header information PLTE: color palette IDAT: pixel data IEND: the final chunk tRNS: transparency for palettized images tEXt: textual information zTXt: compressed textual information iTXt: international textual information bKGD: suggested background color pHYs: physical dimensions tIME: modification time cHRM: RGB chromaticities gAMA: RGB gamma correction iCCP: ICC color profile sRGB: rendering intent 1.2. features not supported --------------------------- The following features are _not_ supported: *) some features needed to make a conformant PNG-Editor might be still missing. *) partial loading/stream processing. All data must be available and is processed in one call. *) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: sBIT hIST sPLT 2. C and C++ version -------------------- The C version uses buffers allocated with alloc that you need to free() yourself. You need to use init and cleanup functions for each struct whenever using a struct from the C version to avoid exploits and memory leaks. The C++ version has extra functions with std::vectors in the interface and the lodepng::State class which is a LodePNGState with constructor and destructor. These files work without modification for both C and C++ compilers because all the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers ignore it, and the C code is made to compile both with strict ISO C90 and C++. To use the C++ version, you need to rename the source file to lodepng.cpp (instead of lodepng.c), and compile it with a C++ compiler. To use the C version, you need to rename the source file to lodepng.c (instead of lodepng.cpp), and compile it with a C compiler. 3. Security ----------- Even if carefully designed, it's always possible that LodePNG contains possible exploits. If you discover one, please let me know, and it will be fixed. When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style structs when working with C++. The following conventions are used for all C-style structs: -if a struct has a corresponding init function, always call the init function when making a new one -if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks -if a struct has a corresponding copy function, use the copy function instead of "=". The destination must also be inited already. 4. Decoding ----------- Decoding converts a PNG compressed image to a raw pixel buffer. Most documentation on using the decoder is at its declarations in the header above. For C, simple decoding can be done with functions such as lodepng_decode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_decode. For C++, all decoding can be done with the various lodepng::decode functions, and lodepng::State can be used for advanced features. When using the LodePNGState, it uses the following fields for decoding: *) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here *) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get *) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use LodePNGInfo info_png -------------------- After decoding, this contains extra information of the PNG image, except the actual pixels, width and height because these are already gotten directly from the decoder functions. It contains for example the original color type of the PNG image, text comments, suggested background color, etc... More details about the LodePNGInfo struct are at its declaration documentation. LodePNGColorMode info_raw ------------------------- When decoding, here you can specify which color type you want the resulting raw image to be. If this is different from the colortype of the PNG, then the decoder will automatically convert the result. This conversion always works, except if you want it to convert a color PNG to grayscale or to a palette with missing colors. By default, 32-bit color is used for the result. LodePNGDecoderSettings decoder ------------------------------ The settings can be used to ignore the errors created by invalid CRC and Adler32 chunks, and to disable the decoding of tEXt chunks. There's also a setting color_convert, true by default. If false, no conversion is done, the resulting data will be as it was in the PNG (after decompression) and you'll have to puzzle the colors of the pixels together yourself using the color type information in the LodePNGInfo. 5. Encoding ----------- Encoding converts a raw pixel buffer to a PNG compressed image. Most documentation on using the encoder is at its declarations in the header above. For C, simple encoding can be done with functions such as lodepng_encode32, and more advanced decoding can be done with the struct LodePNGState and lodepng_encode. For C++, all encoding can be done with the various lodepng::encode functions, and lodepng::State can be used for advanced features. Like the decoder, the encoder can also give errors. However it gives less errors since the encoder input is trusted, the decoder input (a PNG image that could be forged by anyone) is not trusted. When using the LodePNGState, it uses the following fields for encoding: *) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. *) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has *) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use LodePNGInfo info_png -------------------- When encoding, you use this the opposite way as when decoding: for encoding, you fill in the values you want the PNG to have before encoding. By default it's not needed to specify a color type for the PNG since it's automatically chosen, but it's possible to choose it yourself given the right settings. The encoder will not always exactly match the LodePNGInfo struct you give, it tries as close as possible. Some things are ignored by the encoder. The encoder uses, for example, the following settings from it when applicable: colortype and bitdepth, text chunks, time chunk, the color key, the palette, the background color, the interlace method, unknown chunks, ... When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. If the palette contains any colors for which the alpha channel is not 255 (so there are translucent colors in the palette), it'll add a tRNS chunk. LodePNGColorMode info_raw ------------------------- You specify the color type of the raw image that you give to the input here, including a possible transparent color key and palette you happen to be using in your raw image data. By default, 32-bit color is assumed, meaning your input has to be in RGBA format with 4 bytes (unsigned chars) per pixel. LodePNGEncoderSettings encoder ------------------------------ The following settings are supported (some are in sub-structs): *) auto_convert: when this option is enabled, the encoder will automatically choose the smallest possible color mode (including color key) that can encode the colors of all pixels without information loss. *) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 2 = dynamic huffman tree (best compression). Should be 2 for proper compression. *) use_lz77: whether or not to use LZ77 for compressed block types. Should be true for proper compression. *) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value 2048 by default, but can be set to 32768 for better, but slow, compression. *) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE chunk if force_palette is true. This can used as suggested palette to convert to by viewers that don't support more than 256 colors (if those still exist) *) add_id: add text chunk "Encoder: LodePNG " to the image. *) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. zTXt chunks use zlib compression on the text. This gives a smaller result on large texts but a larger result on small texts (such as a single program name). It's all tEXt or all zTXt though, there's no separate setting per text yet. 6. color conversions -------------------- An important thing to note about LodePNG, is that the color type of the PNG, and the color type of the raw image, are completely independent. By default, when you decode a PNG, you get the result as a raw image in the color type you want, no matter whether the PNG was encoded with a palette, grayscale or RGBA color. And if you encode an image, by default LodePNG will automatically choose the PNG color type that gives good compression based on the values of colors and amount of colors in the image. It can be configured to let you control it instead as well, though. To be able to do this, LodePNG does conversions from one color mode to another. It can convert from almost any color type to any other color type, except the following conversions: RGB to grayscale is not supported, and converting to a palette when the palette doesn't have a required color is not supported. This is not supported on purpose: this is information loss which requires a color reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray is easy, but there are multiple ways if you want to give some channels more weight). By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB color, no matter what color type the PNG has. And by default when encoding, LodePNG automatically picks the best color model for the output PNG, and expects the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control the color format of the images yourself, you can skip this chapter. 6.1. PNG color types -------------------- A PNG image can have many color types, ranging from 1-bit color to 64-bit color, as well as palettized color modes. After the zlib decompression and unfiltering in the PNG image is done, the raw pixel data will have that color type and thus a certain amount of bits per pixel. If you want the output raw image after decoding to have another color type, a conversion is done by LodePNG. The PNG specification gives the following color types: 0: grayscale, bit depths 1, 2, 4, 8, 16 2: RGB, bit depths 8 and 16 3: palette, bit depths 1, 2, 4 and 8 4: grayscale with alpha, bit depths 8 and 16 6: RGBA, bit depths 8 and 16 Bit depth is the amount of bits per pixel per color channel. So the total amount of bits per pixel is: amount of channels * bitdepth. 6.2. color conversions ---------------------- As explained in the sections about the encoder and decoder, you can specify color types and bit depths in info_png and info_raw to change the default behaviour. If, when decoding, you want the raw image to be something else than the default, you need to set the color type and bit depth you want in the LodePNGColorMode, or the parameters colortype and bitdepth of the simple decoding function. If, when encoding, you use another color type than the default in the raw input image, you need to specify its color type and bit depth in the LodePNGColorMode of the raw image, or use the parameters colortype and bitdepth of the simple encoding function. If, when encoding, you don't want LodePNG to choose the output PNG color type but control it yourself, you need to set auto_convert in the encoder settings to false, and specify the color type you want in the LodePNGInfo of the encoder (including palette: it can generate a palette if auto_convert is true, otherwise not). If the input and output color type differ (whether user chosen or auto chosen), LodePNG will do a color conversion, which follows the rules below, and may sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image -the encoder converts from raw image to PNG -the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image -the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG -when encoding, the color type in LodePNGInfo is ignored if auto_convert is enabled, it is automatically generated instead -when decoding, the color type in LodePNGInfo is set by the decoder to that of the original PNG image, but it can be ignored since the raw image has the color type you requested instead -if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion between the color types is done if the color types are supported. If it is not supported, an error is returned. If the types are the same, no conversion is done. -even though some conversions aren't supported, LodePNG supports loading PNGs from any colortype and saving PNGs to any colortype, sometimes it just requires preparing the raw image correctly before encoding. -both encoder and decoder use the same color converter. The function lodepng_convert does the color conversion. It is available in the interface but normally isn't needed since the encoder and decoder already call it. Non supported color conversions: -color to grayscale when non-gray pixels are present: no error is thrown, but the result will look ugly because only the red channel is taken (it assumes all three channels are the same in this case so ignores green and blue). The reason no error is given is to allow converting from three-channel grayscale images to one-channel even if there are numerical imprecisions. -anything to palette when the palette does not have an exact match for a from-color in it: in this case an error is thrown Supported color conversions: -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA -any gray or gray+alpha, to gray or gray+alpha -anything to a palette, as long as the palette has the requested colors in it -removing alpha channel -higher to smaller bitdepth, and vice versa If you want no color conversion to be done (e.g. for speed or control): -In the encoder, you can make it save a PNG with any color type by giving the raw color mode and LodePNGInfo the same color mode, and setting auto_convert to false. -In the decoder, you can make it store the pixel data in the same color type as the PNG has, by setting the color_convert setting to false. Settings in info_raw are then ignored. 6.3. padding bits ----------------- In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines have a bit amount that isn't a multiple of 8, then padding bits are used so that each scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. The raw input image you give to the encoder, and the raw output image you get from the decoder will NOT have these padding bits, e.g. in the case of a 1-bit image with a width of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, not the first bit of a new byte. 6.4. A note about 16-bits per channel and endianness ---------------------------------------------------- LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like for any other color format. The 16-bit values are stored in big endian (most significant byte first) in these arrays. This is the opposite order of the little endian used by x86 CPU's. LodePNG always uses big endian because the PNG file format does so internally. Conversions to other formats than PNG uses internally are not supported by LodePNG on purpose, there are myriads of formats, including endianness of 16-bit colors, the order in which you store R, G, B and A, and so on. Supporting and converting to/from all that is outside the scope of LodePNG. This may mean that, depending on your use case, you may want to convert the big endian output of LodePNG to little endian with a for loop. This is certainly not always needed, many applications and libraries support big endian 16-bit colors anyway, but it means you cannot simply cast the unsigned char* buffer to an unsigned short* buffer on x86 CPUs. 7. error values --------------- All functions in LodePNG that return an error code, return 0 if everything went OK, or a non-zero code if there was an error. The meaning of the LodePNG error values can be retrieved with the function lodepng_error_text: given the numerical error code, it returns a description of the error in English as a string. Check the implementation of lodepng_error_text to see the meaning of each code. It is not recommended to use the numerical values to programmatically make different decisions based on error types as the numbers are not guaranteed to stay backwards compatible. They are for human consumption only. Programmatically only 0 or non-0 matter. 8. chunks and PNG editing ------------------------- If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG editor that should follow the rules about handling of unknown chunks, or if your program is able to read other types of chunks than the ones handled by LodePNG, then that's possible with the chunk functions of LodePNG. A PNG chunk has the following layout: 4 bytes length 4 bytes type name length bytes data 4 bytes CRC 8.1. iterating through chunks ----------------------------- If you have a buffer containing the PNG image data, then the first chunk (the IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the signature of the PNG and are not part of a chunk. But if you start at byte 8 then you have a chunk, and can check the following things of it. NOTE: none of these functions check for memory buffer boundaries. To avoid exploits, always make sure the buffer contains all the data of the chunks. When using lodepng_chunk_next, make sure the returned value is within the allocated memory. unsigned lodepng_chunk_length(const unsigned char* chunk): Get the length of the chunk's data. The total chunk length is this length + 12. void lodepng_chunk_type(char type[5], const unsigned char* chunk): unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): Get the type of the chunk or compare if it's a certain type unsigned char lodepng_chunk_critical(const unsigned char* chunk): unsigned char lodepng_chunk_private(const unsigned char* chunk): unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). Check if the chunk is private (public chunks are part of the standard, private ones not). Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your program doesn't handle that type of unknown chunk. unsigned char* lodepng_chunk_data(unsigned char* chunk): const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): Get a pointer to the start of the data of the chunk. unsigned lodepng_chunk_check_crc(const unsigned char* chunk): void lodepng_chunk_generate_crc(unsigned char* chunk): Check if the crc is correct or generate a correct one. unsigned char* lodepng_chunk_next(unsigned char* chunk): const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these functions do no boundary checking of the allocated data whatsoever, so make sure there is enough data available in the buffer to be able to go to the next chunk. unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, const char* type, const unsigned char* data): These functions are used to create new chunks that are appended to the data in *out that has length *outsize. The append function appends an existing chunk to the new data. The create function creates a new chunk with the given parameters and appends it. Type is the 4-letter name of the chunk. 8.2. chunks in info_png ----------------------- The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 buffers (each with size) to contain 3 types of unknown chunks: the ones that come before the PLTE chunk, the ones that come between the PLTE and the IDAT chunks, and the ones that come after the IDAT chunks. It's necessary to make the distinction between these 3 cases because the PNG standard forces to keep the ordering of unknown chunks compared to the critical chunks, but does not force any other ordering rules. info_png.unknown_chunks_data[0] is the chunks before PLTE info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT info_png.unknown_chunks_data[2] is the chunks after IDAT The chunks in these 3 buffers can be iterated through and read by using the same way described in the previous subchapter. When using the decoder to decode a PNG, you can make it store all unknown chunks if you set the option settings.remember_unknown_chunks to 1. By default, this option is off (0). The encoder will always encode unknown chunks that are stored in the info_png. If you need it to add a particular chunk that isn't known by LodePNG, you can use lodepng_chunk_append or lodepng_chunk_create to the chunk data in info_png.unknown_chunks_data[x]. Chunks that are known by LodePNG should not be added in that way. E.g. to make LodePNG add a bKGD chunk, set background_defined to true and add the correct parameters there instead. 9. compiler support ------------------- No libraries other than the current standard C library are needed to compile LodePNG. For the C++ version, only the standard C++ library is needed on top. Add the files lodepng.c(pp) and lodepng.h to your project, include lodepng.h where needed, and your program can read/write PNG files. It is compatible with C90 and up, and C++03 and up. If performance is important, use optimization when compiling! For both the encoder and decoder, this makes a large difference. Make sure that LodePNG is compiled with the same compiler of the same version and with the same settings as the rest of the program, or the interfaces with std::vectors and std::strings in C++ can be incompatible. CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. *) gcc and g++ LodePNG is developed in gcc so this compiler is natively supported. It gives no warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ version 4.7.1 on Linux, 32-bit and 64-bit. *) Clang Fully supported and warning-free. *) Mingw The Mingw compiler (a port of gcc for Windows) should be fully supported by LodePNG. *) Visual Studio and Visual C++ Express Edition LodePNG should be warning-free with warning level W4. Two warnings were disabled with pragmas though: warning 4244 about implicit conversions, and warning 4996 where it wants to use a non-standard function fopen_s instead of the standard C fopen. Visual Studio may want "stdafx.h" files to be included in each source file and give an error "unexpected end of file while looking for precompiled header". This is not standard C++ and will not be added to the stock LodePNG. You can disable it for lodepng.cpp only by right clicking it, Properties, C/C++, Precompiled Headers, and set it to Not Using Precompiled Headers there. NOTE: Modern versions of VS should be fully supported, but old versions, e.g. VS6, are not guaranteed to work. *) Compilers on Macintosh LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for C and C++. *) Other Compilers If you encounter problems on any compilers, feel free to let me know and I may try to fix it if the compiler is modern and standards compliant. 10. examples ------------ This decoder example shows the most basic usage of LodePNG. More complex examples can be found on the LodePNG website. NOTE: these examples do not support wide-character filenames, you can use an external method to handle such files and encode or decode in-memory 10.1. decoder C++ example ------------------------- #include "lodepng.h" #include int main(int argc, char *argv[]) { const char* filename = argc > 1 ? argv[1] : "test.png"; //load and decode std::vector image; unsigned width, height; unsigned error = lodepng::decode(image, width, height, filename); //if there's an error, display it if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... } 10.2. decoder C example ----------------------- #include "lodepng.h" int main(int argc, char *argv[]) { unsigned error; unsigned char* image; size_t width, height; const char* filename = argc > 1 ? argv[1] : "test.png"; error = lodepng_decode32_file(&image, &width, &height, filename); if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); / * use image here * / free(image); return 0; } 11. state settings reference ---------------------------- A quick reference of some settings to set on the LodePNGState For decoding: state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums state.decoder.zlibsettings.custom_...: use custom inflate function state.decoder.ignore_crc: ignore CRC checksums state.decoder.ignore_critical: ignore unknown critical chunks state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors state.decoder.color_convert: convert internal PNG color to chosen one state.decoder.read_text_chunks: whether to read in text metadata chunks state.decoder.remember_unknown_chunks: whether to read in unknown chunks state.info_raw.colortype: desired color type for decoded image state.info_raw.bitdepth: desired bit depth for decoded image state.info_raw....: more color settings, see struct LodePNGColorMode state.info_png....: no settings for decoder but output, see struct LodePNGInfo For encoding: state.encoder.zlibsettings.btype: disable compression by setting it to 0 state.encoder.zlibsettings.use_lz77: use LZ77 in compression state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching state.encoder.zlibsettings.lazymatching: try one more LZ77 matching state.encoder.zlibsettings.custom_...: use custom deflate function state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png state.encoder.filter_palette_zero: PNG filter strategy for palette state.encoder.filter_strategy: PNG filter strategy to encode with state.encoder.force_palette: add palette even if not encoding to one state.encoder.add_id: add LodePNG identifier and version as a text chunk state.encoder.text_compression: use compressed text chunks for metadata state.info_raw.colortype: color type of raw input image you provide state.info_raw.bitdepth: bit depth of raw input image you provide state.info_raw: more color settings, see struct LodePNGColorMode state.info_png.color.colortype: desired color type if auto_convert is false state.info_png.color.bitdepth: desired bit depth if auto_convert is false state.info_png.color....: more color settings, see struct LodePNGColorMode state.info_png....: more PNG related settings, see struct LodePNGInfo 12. changes ----------- The version number of LodePNG is the date of the change given in the format yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. Not all changes are listed here, the commit history in github lists more: https://github.com/lvandeve/lodepng *) 09 jan 2022: minor decoder speed improvements. *) 27 jun 2021: added warnings that file reading/writing functions don't support wide-character filenames (support for this is not planned, opening files is not the core part of PNG decoding/decoding and is platform dependent). *) 17 okt 2020: prevent decoding too large text/icc chunks by default. *) 06 mar 2020: simplified some of the dynamic memory allocations. *) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct overflow checks. *) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables. *) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette if gray ICC profile) and non-ICC LodePNGColorProfile renamed to LodePNGColorStats. *) 30 dec 2018: code style changes only: removed newlines before opening braces. *) 10 sep 2018: added way to inspect metadata chunks without full decoding. *) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use palette index in case of palette. *) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This change is backwards compatible unless you relied on unknown_chunks for those. *) 11 jun 2018: less restrictive check for pixel size integer overflow *) 14 jan 2018: allow optionally ignoring a few more recoverable errors *) 17 sep 2017: fix memory leak for some encoder input error cases *) 27 nov 2016: grey+alpha auto color model detection bugfix *) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). *) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within the limits of pure C90). *) 08 dec 2015: Made load_file function return error if file can't be opened. *) 24 okt 2015: Bugfix with decoding to palette output. *) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. *) 24 aug 2014: Moved to github *) 23 aug 2014: Reduced needless memory usage of decoder. *) 28 jun 2014: Removed fix_png setting, always support palette OOB for simplicity. Made ColorProfile public. *) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. *) 22 dec 2013: Power of two windowsize required for optimization. *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). *) 11 mar 2013: (!) Bugfix with custom free. Changed from "my" to "lodepng_" prefix for the custom allocators and made it possible with a new #define to use custom ones in your project without needing to change lodepng's code. *) 28 jan 2013: Bugfix with color key. *) 27 okt 2012: Tweaks in text chunk keyword length error handling. *) 8 okt 2012: (!) Added new filter strategy (entropy) and new auto color mode. (no palette). Better deflate tree encoding. New compression tweak settings. Faster color conversions while decoding. Some internal cleanups. *) 23 sep 2012: Reduced warnings in Visual Studio a little bit. *) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions and made it work with function pointers instead. *) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc and free functions and toggle #defines from compiler flags. Small fixes. *) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible. *) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed redundant C++ codec classes. Reduced amount of structs. Everything changed, but it is cleaner now imho and functionality remains the same. Also fixed several bugs and shrunk the implementation code. Made new samples. *) 6 nov 2011: (!) By default, the encoder now automatically chooses the best PNG color model and bit depth, based on the amount and type of colors of the raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. *) 9 okt 2011: simpler hash chain implementation for the encoder. *) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. *) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. A bug with the PNG filtertype heuristic was fixed, so that it chooses much better ones (it's quite significant). A setting to do an experimental, slow, brute force search for PNG filter types is added. *) 17 aug 2011: (!) changed some C zlib related function names. *) 16 aug 2011: made the code less wide (max 120 characters per line). *) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. *) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. *) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman to optimize long sequences of zeros. *) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and LodePNG_InfoColor_canHaveAlpha functions for convenience. *) 7 nov 2010: added LodePNG_error_text function to get error code description. *) 30 okt 2010: made decoding slightly faster *) 26 okt 2010: (!) changed some C function and struct names (more consistent). Reorganized the documentation and the declaration order in the header. *) 08 aug 2010: only changed some comments and external samples. *) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. *) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. *) 02 sep 2008: fixed bug where it could create empty tree that linux apps could read by ignoring the problem but windows apps couldn't. *) 06 jun 2008: added more error checks for out of memory cases. *) 26 apr 2008: added a few more checks here and there to ensure more safety. *) 06 mar 2008: crash with encoding of strings fixed *) 02 feb 2008: support for international text chunks added (iTXt) *) 23 jan 2008: small cleanups, and #defines to divide code in sections *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added Also various fixes, such as in the deflate and the padding bits code. *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved filtering code of encoder. *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A C++ wrapper around this provides an interface almost identical to before. Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code are together in these files but it works both for C and C++ compilers. *) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks *) 30 aug 2007: bug fixed which makes this Borland C++ compatible *) 09 aug 2007: some VS2005 warnings removed again *) 21 jul 2007: deflate code placed in new namespace separate from zlib code *) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images *) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing invalid std::vector element [0] fixed, and level 3 and 4 warnings removed *) 02 jun 2007: made the encoder add a tag with version by default *) 27 may 2007: zlib and png code separated (but still in the same file), simple encoder/decoder functions added for more simple usage cases *) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), moved some examples from here to lodepng_examples.cpp *) 12 may 2007: palette decoding bug fixed *) 24 apr 2007: changed the license from BSD to the zlib license *) 11 mar 2007: very simple addition: ability to encode bKGD chunks. *) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding palettized PNG images. Plus little interface change with palette and texts. *) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. Fixed a bug where the end code of a block had length 0 in the Huffman tree. *) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented and supported by the encoder, resulting in smaller PNGs at the output. *) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. *) 24 jan 2007: gave encoder an error interface. Added color conversion from any greyscale type to 8-bit greyscale with or without alpha. *) 21 jan 2007: (!) Totally changed the interface. It allows more color types to convert to and is more uniform. See the manual for how it works now. *) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: encode/decode custom tEXt chunks, separate classes for zlib & deflate, and at last made the decoder give errors for incorrect Adler32 or Crc. *) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. *) 29 dec 2006: Added support for encoding images without alpha channel, and cleaned out code as well as making certain parts faster. *) 28 dec 2006: Added "Settings" to the encoder. *) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. Removed some code duplication in the decoder. Fixed little bug in an example. *) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. Fixed a bug of the decoder with 16-bit per color. *) 15 okt 2006: Changed documentation structure *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the given image buffer, however for now it's not compressed. *) 08 sep 2006: (!) Changed to interface with a Decoder class *) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different way. Renamed decodePNG to decodePNGGeneric. *) 29 jul 2006: (!) Changed the interface: image info is now returned as a struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. *) 28 jul 2006: Cleaned the code and added new error checks. Corrected terminology "deflate" into "inflate". *) 23 jun 2006: Added SDL example in the documentation in the header, this example allows easy debugging by displaying the PNG and its transparency. *) 22 jun 2006: (!) Changed way to obtain error value. Added loadFile function for convenience. Made decodePNG32 faster. *) 21 jun 2006: (!) Changed type of info vector to unsigned. Changed position of palette in info vector. Fixed an important bug that happened on PNGs with an uncompressed block. *) 16 jun 2006: Internally changed unsigned into unsigned where needed, and performed some optimizations. *) 07 jun 2006: (!) Renamed functions to decodePNG and placed them in LodePNG namespace. Changed the order of the parameters. Rewrote the documentation in the header. Renamed files to lodepng.cpp and lodepng.h *) 22 apr 2006: Optimized and improved some code *) 07 sep 2005: (!) Changed to std::vector interface *) 12 aug 2005: Initial release (C++, decoder only) 13. contact information ----------------------- Feel free to contact me with suggestions, problems, comments, ... concerning LodePNG. If you encounter a PNG image that doesn't work properly with this decoder, feel free to send it and I'll use it to find and fix the problem. My email address is (puzzle the account and domain together with an @ symbol): Domain: gmail dot com. Account: lode dot vandevenne. Copyright (c) 2005-2022 Lode Vandevenne */ ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_8/lodepng/lodepng.cpp ================================================ #include "lodepng.h" ================================================ FILE: Fixtures/Miscellaneous/CXX17CompilerCrash/v5_8/src/user_objects.cc ================================================ #include "user_objects.h" ================================================ FILE: Fixtures/Miscellaneous/CaseCollision/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "CaseInsensitiveCollisions", products: [ .executable(name: "foo", targets: ["footool"]), ], targets: [ .executableTarget(name: "footool", dependencies: ["Foo"]), .target(name: "Foo"), ] ) ================================================ FILE: Fixtures/Miscellaneous/CaseCollision/Sources/Foo/Foo.swift ================================================ public func greeting() -> String { "Hello, world!" } ================================================ FILE: Fixtures/Miscellaneous/CaseCollision/Sources/footool/main.swift ================================================ import Foo print(greeting()) ================================================ FILE: Fixtures/Miscellaneous/CheckTestLibraryEnvironmentVariable/Package.swift ================================================ // swift-tools-version: 5.10 import PackageDescription let package = Package( name: "CheckTestLibraryEnvironmentVariable", targets: [ .testTarget(name: "CheckTestLibraryEnvironmentVariableTests"), ] ) ================================================ FILE: Fixtures/Miscellaneous/CheckTestLibraryEnvironmentVariable/Tests/CheckTestLibraryEnvironmentVariableTests/CheckTestLibraryEnvironmentVariableTests.swift ================================================ import XCTest final class CheckTestLibraryEnvironmentVariableTests: XCTestCase { func testEnvironmentVariables() throws { #if !os(macOS) try XCTSkipIf(true, "Test is macOS specific") #endif let testingEnabled = ProcessInfo.processInfo.environment["SWIFT_TESTING_ENABLED"] XCTAssertEqual(testingEnabled, "0") if ProcessInfo.processInfo.environment["CONTAINS_SWIFT_TESTING"] != nil { let frameworkPath = try XCTUnwrap(ProcessInfo.processInfo.environment["DYLD_FRAMEWORK_PATH"]) let libraryPath = try XCTUnwrap(ProcessInfo.processInfo.environment["DYLD_LIBRARY_PATH"]) XCTAssertTrue( frameworkPath.contains("testing") || libraryPath.contains("testing"), "Expected 'testing' in '\(frameworkPath)' or '\(libraryPath)'" ) } } } ================================================ FILE: Fixtures/Miscellaneous/CompileFails/Foo.swift ================================================ class Foo { var bar: Int = 0 compile_failure } ================================================ FILE: Fixtures/Miscellaneous/CompileFails/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CompileFails", targets: [ .target(name: "CompileFails", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/app/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "app", products: [ .executable(name: "app", targets: ["app"]) ], dependencies: [ .package(url: "../dep1", from: "1.0.0"), .package(url: "../dep2", from: "1.0.0"), ], targets: [ .executableTarget( name: "app", dependencies: [ .product(name: "dep1", package: "dep1"), .product(name: "dep2", package: "dep2") ], path: "./" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/app/app.swift ================================================ import dep1 import dep2 @main struct App { var deprecated: DeprecatedApp public static func main() { print("hello, world!") } } @available(*, deprecated) struct DeprecatedApp { } ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/dep1/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "dep1", products: [ .library(name: "dep1", targets: ["dep1"]) ], targets: [ .target(name: "dep1", path: "./") ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/dep1/code.swift ================================================ struct Dep1 { var deprecated: Deprecated1 } @available(*, deprecated) struct Deprecated1 { } ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/dep2/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "dep2", products: [ .library(name: "dep2", targets: ["dep2"]) ], targets: [ .target(name: "dep2", path: "./") ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings/dep2/code.swift ================================================ struct Dep2 { var deprecated: Deprecated2 } @available(*, deprecated) struct Deprecated2 { } ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/app/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "app", products: [ .executable(name: "app", targets: ["app"]) ], dependencies: [ .package(url: "../dep1", from: "1.0.0"), .package(url: "../dep2", from: "1.0.0"), ], targets: [ .executableTarget( name: "app", dependencies: [ .product(name: "dep1", package: "dep1"), .product(name: "dep2", package: "dep2") ], path: "./" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/app/app.swift ================================================ import dep1 import dep2 @main struct App { public static func main() { print("hello, world!") } } ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/dep1/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "dep1", products: [ .library(name: "dep1", targets: ["dep1"]) ], targets: [ .target(name: "dep1", path: "./") ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/dep1/code.swift ================================================ struct Dep1 { var deprecated: Deprecated1 } @available(*, deprecated) struct Deprecated1 { } ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/dep2/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "dep2", products: [ .library(name: "dep2", targets: ["dep2"]) ], targets: [ .target(name: "dep2", path: "./") ] ) ================================================ FILE: Fixtures/Miscellaneous/DependenciesWarnings2/dep2/code.swift ================================================ struct Dep2 { var deprecated: Deprecated2 } @available(*, deprecated) struct Deprecated2 { } ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/dep1/Foo.swift ================================================ public let foo = "Hello" ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/dep1/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "dep1", products: [ .library(name: "dep1", targets: ["dep1"]), ], targets: [ .target(name: "dep1", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/dep2/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "dep2", products: [ .executable(name: "dep2", targets: ["dep2"]), ], dependencies: [ .package(url: "../dep1", from: "1.0.0"), ], targets: [ .target(name: "dep2", dependencies:[ "dep1"], path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/dep2/main.swift ================================================ import dep1 print(foo) ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/root/Bar.swift ================================================ let bar = 1 ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/External/root/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "root", dependencies: [ .package(url: "../dep2", from: "1.0.0"), ], targets: [ .target(name: "root", dependencies: ["dep2"], path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/Internal/Bar/Bar.swift ================================================ public let bar = "Hello" ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/Internal/Foo/main.swift ================================================ import Bar print(bar) ================================================ FILE: Fixtures/Miscellaneous/DependencyEdges/Internal/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ExtraCommandLineFlags", targets: [ .target(name: "Bar", path: "Bar"), .target(name: "Foo", dependencies: ["Bar"], path: "Foo"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DifferentProductTargetName/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", products: [ .executable(name: "Foo", targets: ["Bar"]), ], targets: [ .target(name: "Bar", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DifferentProductTargetName/main.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/DistantFutureDeploymentTarget/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "DistantFutureDeploymentTarget", targets: [ .target(name: "DistantFutureDeploymentTarget", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DistantFutureDeploymentTarget/Sources/main.swift ================================================ /// This file exists to test the ability to override deployment targets via args passed to swiftc /// For this test to work, this file must have an API call which was introduced in a version /// higher than the default macOS deployment target that is checked in. @available(macOS 41.0, *) func foo() {} foo() ================================================ FILE: Fixtures/Miscellaneous/DoNotFilterLinkerDiagnostics/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "DoNotFilterLinkerDiagnostics", targets: [ .executableTarget( name: "DoNotFilterLinkerDiagnostics", linkerSettings: [ .unsafeFlags(["-Lfoobar"]), ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/DoNotFilterLinkerDiagnostics/Sources/DoNotFilterLinkerDiagnostics/main.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book print("Hello, world!") ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/PlayingCard/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "PlayingCard", products: [ .library(name: "PlayingCard", targets: ["PlayingCard"]), ], targets: [ .target(name: "PlayingCard", path: "src"), ] ) ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/PlayingCard/src/PlayingCard.swift ================================================ public struct PlayingCard: Equatable { let rank: Rank let suit: Suit public init(rank: Rank, suit: Suit) { self.rank = rank self.suit = suit } } // MARK: - Comparable extension PlayingCard: Comparable {} public func <(lhs: PlayingCard, rhs: PlayingCard) -> Bool { return lhs.suit < rhs.suit || (lhs.suit == rhs.suit && lhs.rank < rhs.rank) } // MARK: - CustomStringConvertible extension PlayingCard : CustomStringConvertible { public var description: String { return "\(suit)\(rank)" } } ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/PlayingCard/src/Rank.swift ================================================ public enum Rank : Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King } // MARK: - Comparable extension Rank : Comparable {} public func <(lhs: Rank, rhs: Rank) -> Bool { switch (lhs, rhs) { case (_, _) where lhs == rhs: return false case (.Ace, _): return false default: return lhs.rawValue < rhs.rawValue } } // MARK: - CustomStringConvertible extension Rank : CustomStringConvertible { public var description: String { switch self { case .Ace: return "A" case .Jack: return "J" case .Queen: return "Q" case .King: return "K" default: return "\(rawValue)" } } } ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/PlayingCard/src/Suit.swift ================================================ public enum Suit: String { case Spades, Hearts, Diamonds, Clubs } // MARK: - Comparable extension Suit: Comparable {} public func <(lhs: Suit, rhs: Suit) -> Bool { switch (lhs, rhs) { case (_, _) where lhs == rhs: return false case (.Spades, _), (.Hearts, .Diamonds), (.Hearts, .Clubs), (.Diamonds, .Clubs): return false default: return true } } // MARK: - CustomStringConvertible extension Suit : CustomStringConvertible { public var description: String { switch self { case .Spades: return "♠︎" case .Hearts: return "♡" case .Diamonds: return "♢" case .Clubs: return "♣︎" } } } ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/app/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "Dealer", defaultLocalization: "en", platforms: [ .macOS(.v10_13), .iOS(.v12), .tvOS(.v12), .watchOS(.v5) ], dependencies: [ .package(path: "../PlayingCard"), ], targets: [ .target( name: "Dealer", dependencies: ["PlayingCard"], path: "./" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/DumpPackage/app/main.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import PlayingCard let hand: [PlayingCard] = [ .init(rank: .Ace, suit: .Hearts), .init(rank: .King, suit: .Spades), ] for card in hand { print(card) } ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/exec/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "exec", dependencies: [ .package(path: "../secondDyna") ], targets: [ .executableTarget( name: "exec", dependencies: ["secondDyna"]), .testTarget( name: "DynaTests", dependencies: ["exec"]) ] ) ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/exec/README.md ================================================ # exec A description of this package. ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/exec/Sources/exec/main.swift ================================================ import secondDyna print(secondDyna.hello()) ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/exec/Tests/DynaTests/Tests.swift ================================================ error ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/firstDyna/Package.swift ================================================ // swift-tools-version:5.0 import PackageDescription let package = Package( name: "firstDyna", products: [ .library( name: "firstDyna", type: .dynamic, targets: ["firstDyna"]) ], targets: [ .target( name: "firstDyna", dependencies: ["Core"]), .target( name: "Core", dependencies: []) ] ) ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/firstDyna/README.md ================================================ # firstDyna A description of this package. ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/firstDyna/Sources/Core/Core.c ================================================ #include char* hello() { return "Hello"; } ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/firstDyna/Sources/Core/include/Core.h ================================================ char* hello(); ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/firstDyna/Sources/firstDyna/firstDyna.swift ================================================ import Core public func hello() -> String { return String(cString: Core.hello()) } ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/secondDyna/Package.swift ================================================ // swift-tools-version:5.0 import PackageDescription let package = Package( name: "secondDyna", products: [ .library( name: "secondDyna", type: .dynamic, targets: ["secondDyna"]) ], dependencies: [ .package(path: "../firstDyna") ], targets: [ .target( name: "secondDyna", dependencies: ["firstDyna"]) ] ) ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/secondDyna/README.md ================================================ # secondDyna A description of this package. ================================================ FILE: Fixtures/Miscellaneous/DynamicProduct/secondDyna/Sources/secondDyna/secondDyna.swift ================================================ import firstDyna public func hello() -> String { return firstDyna.hello() } ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "EchoExecutable", products: [ .executable(name: "secho", targets: ["secho"]) ], targets: [ .target(name: "secho", dependencies: []), .testTarget(name: "TestSuite") ]) ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/Sources/secho/main.swift ================================================ #if canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(Android) import Android #elseif canImport(Darwin.C) import Darwin.C #elseif canImport(ucrt) import ucrt let PATH_MAX = 260 typealias Int = Int32 #endif let cwd = getcwd(nil, Int(PATH_MAX)) defer { free(cwd) } let workingDirectory = String(validatingUTF8: cwd!)! let values = [workingDirectory] + Array(CommandLine.arguments.dropFirst()) print(values.map({ "\"\($0)\"" }).joined(separator: " ")) ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/Tests/TestSuite/Tests.swift ================================================ import XCTest final class TestCase: XCTestCase { func testFoo() { XCTAssertTrue(true) } } ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/echo.bat ================================================ echo sentinel echo %* ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/echo.sh ================================================ #!/bin/sh echo sentinel echo "$@" ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/toolset.json ================================================ { "debugger": { "path": "echo.sh" }, "testRunner": { "path": "echo.sh" }, "schemaVersion" : "1.0", "rootPath" : "." } ================================================ FILE: Fixtures/Miscellaneous/EchoExecutable/toolset.win32.json ================================================ { "debugger": { "path": "echo.bat" }, "testRunner": { "path": "echo.bat" }, "schemaVersion" : "1.0", "rootPath" : "." } ================================================ FILE: Fixtures/Miscellaneous/Edit/App/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "App", dependencies: [ .package(name: "Foo", url: "../Foo", .branch("main")), .package(name: "Bar", url: "../Bar", .branch("main")), ], targets: [ .target(name: "App", dependencies: [ .product(name: "Foo", package: "Foo"), .product(name: "Bar", package: "Bar"), ], path: "./src") ] ) ================================================ FILE: Fixtures/Miscellaneous/Edit/App/src/main.swift ================================================ import Foo import Bar public func main() { } ================================================ FILE: Fixtures/Miscellaneous/Edit/Bar/Bar.swift ================================================ public func hello() { } ================================================ FILE: Fixtures/Miscellaneous/Edit/Bar/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "Bar", targets: ["Bar"]), ], targets: [ .target(name: "Bar", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/Edit/Foo/Foo.swift ================================================ public func hello() { } ================================================ FILE: Fixtures/Miscellaneous/Edit/Foo/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/EmptyTestsPkg/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/EmptyTestsPkg/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "EmptyTestsPkg", targets: [ .target( name: "EmptyTestsPkg", dependencies: []), .testTarget( name: "EmptyTestsPkgTests", dependencies: ["EmptyTestsPkg"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/EmptyTestsPkg/Sources/EmptyTestsPkg/EmptyTestsPkg.swift ================================================ struct EmptyTests { var text = "Hello, World!" var bool = false } ================================================ FILE: Fixtures/Miscellaneous/EmptyTestsPkg/Tests/EmptyTestsPkgTests/EmptyTestsTests.swift ================================================ import XCTest @testable import EmptyTestsPkg ================================================ FILE: Fixtures/Miscellaneous/Errors/FatalErrorInSingleXCTest/TypeLibrary/.gitignore ================================================ .DS_Store /.build /Packages xcuserdata/ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc ================================================ FILE: Fixtures/Miscellaneous/Errors/FatalErrorInSingleXCTest/TypeLibrary/Package.swift ================================================ // swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "TypeLibrary", products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "TypeLibrary", targets: ["TypeLibrary"]), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( name: "TypeLibrary"), .testTarget( name: "TypeLibraryTests", dependencies: ["TypeLibrary"] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Errors/FatalErrorInSingleXCTest/TypeLibrary/Sources/TypeLibrary/TypeLibrary.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book ================================================ FILE: Fixtures/Miscellaneous/Errors/FatalErrorInSingleXCTest/TypeLibrary/Tests/TypeLibraryTests/TypeLibraryTests.swift ================================================ func testExample() throws { let x = 0 let y = 1 / x print(y) } ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooExec/FooExec.swift ================================================ import FooLib1 import FooLib2 public class FooExec { public var foo: FooLib1 public var bar: FooLib2 public init() { foo = FooLib1() bar = FooLib2() } } ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooExec/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "FooExec", products: [ .executable(name: "FooExec", targets: ["FooExec"]), ], dependencies: [ .package(url: "../FooLib1", from: "1.0.0"), .package(url: "../FooLib2", from: "1.0.0"), ], targets: [ .target(name: "FooExec", dependencies: ["FooLib1", "FooLib2"], path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooExec/main.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooLib1/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "FooLib1", products: [ .library(name: "FooLib1", targets: ["FooLib1"]), .executable(name: "cli", targets: ["cli"]), ], targets: [ .target(name: "FooLib1"), .target(name: "cli", dependencies: ["FooLib1"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooLib1/Sources/FooLib1/FooLib1.swift ================================================ public class FooLib1 { public var foo: Int public init() { foo = 0 } } ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooLib1/Sources/cli/main.swift ================================================ import FooLib1 print(FooLib1()) ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooLib2/FooLib2.swift ================================================ public class FooLib2 { public var foo: Int public init() { foo = 0 } } ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/FooLib2/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "FooLib2", products: [ .library(name: "FooLib2", targets: ["FooLib2"]), ], targets: [ .target(name: "FooLib2", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/app/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "28_exact_dependencies", dependencies: [ .package(url: "../FooExec", from: "1.0.0"), ], targets: [ .target(name: "28_exact_dependencies", dependencies: ["FooExec"], path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/ExactDependencies/app/main.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/ExeTest/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let package = Package( name: "ExeTest", targets: [ .executableTarget( name: "Exe", dependencies: [] ), .testTarget( name: "ExeTests", dependencies: ["Exe"] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/ExeTest/Sources/Exe/main.swift ================================================ public func GetGreeting() -> String { return "Hello" } print("\(GetGreeting()), world!") ================================================ FILE: Fixtures/Miscellaneous/ExeTest/Tests/ExeTests/ExeTests.swift ================================================ import XCTest import Exe final class ExeTestTests: XCTestCase { func testExample() throws { // This is an example of a test case that tries to imports an executable target. XCTAssertEqual(Exe.GetGreeting(), "Hello") } static var allTests = [ ("testExample", testExample), ] } ================================================ FILE: Fixtures/Miscellaneous/ExecutableTargetWithTwoProducts/Foo.swift ================================================ @main struct Entry { static func main() { // Ensure that Bar can be referenced as a member of the module named Foo, // even though the executable target Foo may have been merged into the Exe1 or Exe2 products. let x = Foo.Bar() } } struct Bar {} ================================================ FILE: Fixtures/Miscellaneous/ExecutableTargetWithTwoProducts/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "Foo", products: [ .executable(name: "Exe1", targets: ["Foo"]), .executable(name: "Exe2", targets: ["Foo"]), ], targets: [ .executableTarget(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/FlatPackage/MyExec.swift ================================================ @main public struct MyExec { public private(set) var text = "Hello, World!" public static func main() { print(MyExec().text) } } ================================================ FILE: Fixtures/Miscellaneous/FlatPackage/MyTest.swift ================================================ import XCTest @testable import MyExec final class MyTest: XCTestCase { func testExample() throws { XCTAssertEqual(MyExec().text, "Hello, World!") } } ================================================ FILE: Fixtures/Miscellaneous/FlatPackage/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let execSrcFiles = ["MyExec.swift"] let testSrcFiles = ["MyTest.swift"] let variousFiles = ["README.md"] let package = Package( name: "FlatPackage", dependencies: [ ], targets: [ .executableTarget( name: "MyExec", dependencies: [], path: ".", exclude: testSrcFiles + variousFiles, sources: execSrcFiles ), .testTarget( name: "MyTest", dependencies: ["MyExec"], path: ".", exclude: execSrcFiles + variousFiles, sources: testSrcFiles ), ] ) ================================================ FILE: Fixtures/Miscellaneous/FlatPackage/README.md ================================================ # FlatPackage A description of this package. ================================================ FILE: Fixtures/Miscellaneous/ImportOfMissingDependency/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription let package = Package( name: "VerificationTestPackage", products: [ .executable(name: "BExec", targets: ["B"]), ], dependencies: [ ], targets: [ .target( name: "A", dependencies: []), .target( name: "B", dependencies: []), ] ) ================================================ FILE: Fixtures/Miscellaneous/ImportOfMissingDependency/Sources/A/A.swift ================================================ import B public func bar(x: Int) -> Int { return 11 + foo(x: x) } ================================================ FILE: Fixtures/Miscellaneous/ImportOfMissingDependency/Sources/B/B.swift ================================================ public func foo(x: Int) -> Int { return 11 + x } ================================================ FILE: Fixtures/Miscellaneous/ImportOfMissingDependency/Sources/B/main.swift ================================================ print(baz(x: 11)) ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/.gitignore ================================================ .DS_Store /.build /Packages xcuserdata/ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "SwiftAndCTargets", targets: [ .target(name: "cLib"), .executableTarget(name: "exe", dependencies: ["cLib", "swiftLib"]), .target(name: "swiftLib"), ] ) ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/cLib.c ================================================ #include #include "include/cLib.h" void cPrint(int value) { printf("c value: %i\n", value); } ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/cLib/include/cLib.h ================================================ #pragma once extern void cPrint(int); ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/exe/main.swift ================================================ import swiftLib import cLib cPrint(1) swiftPrint(value: 2) ================================================ FILE: Fixtures/Miscellaneous/LTO/SwiftAndCTargets/Sources/swiftLib/swiftLib.swift ================================================ public func swiftPrint(value: Int) { print("swift value: \(value)") } ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolution/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription let package = Package( name: "LibraryEvolution", products: [ ], targets: [ .target(name: "A", dependencies: [], swiftSettings: [.unsafeFlags(["-enable-library-evolution"])]), .target(name: "B", dependencies: ["A"], swiftSettings: [.unsafeFlags(["-enable-library-evolution"])]), ]) ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolution/Sources/A/A.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolution/Sources/B/B.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "SwiftFramework", products: [ .library(name: "SwiftFramework", type: .dynamic, targets: ["SwiftFramework"]), ], targets: [ .target( name: "SwiftFramework", swiftSettings: [.unsafeFlags(["-enable-library-evolution"])] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/SwiftFramework/Sources/SwiftFramework/SwiftFramework.swift ================================================ public enum SwiftFrameworkWithEvolution { case v1 case v2 public static var latest:Self { .v2 } } ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package(name: "TestBinary", products: [ .executable(name: "TestBinary", targets: ["TestBinary"]), ], targets: [ .binaryTarget(name: "SwiftFramework", path: "SwiftFramework.xcframework"), .executableTarget(name: "TestBinary", dependencies: [ .target(name: "SwiftFramework"), ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/LibraryEvolutionLinuxXCF/TestBinary/Sources/TestBinary/Main.swift ================================================ import SwiftFramework print("Latest Framework with LibraryEvolution version: \(SwiftFrameworkWithEvolution.latest)") ================================================ FILE: Fixtures/Miscellaneous/LocalPackageAsURL/Bar/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription let package = Package( name: "Bar", dependencies: [ .package(url: "../Foo", from: "1.0.0"), ], targets: [ .target(name: "Bar", dependencies: ["Foo"], path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/LocalPackageAsURL/Bar/main.swift ================================================ import Foo foo() print("here") ================================================ FILE: Fixtures/Miscellaneous/LocalPackageAsURL/Foo/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/Miscellaneous/LocalPackageAsURL/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/MissingDependency/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", dependencies: [ .package(url: "../NonExistentPackage", from: "1.0.0"), ], targets: [ .target(name: "Bar", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/MissingDependency/Bar/main.swift ================================================ import Foo foo() ================================================ FILE: Fixtures/Miscellaneous/MultipleExecutables/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "EchoExecutable", products: [ .executable(name: "exec1", targets: ["exec1"]), .executable(name: "exec2", targets: ["exec2"]), .library(name: "lib1", targets: ["lib1"]), ], targets: [ .target(name: "exec1"), .target(name: "exec2"), .target(name: "lib1"), ] ) ================================================ FILE: Fixtures/Miscellaneous/MultipleExecutables/Sources/exec1/main.swift ================================================ print("1") ================================================ FILE: Fixtures/Miscellaneous/MultipleExecutables/Sources/exec2/main.swift ================================================ print("2") ================================================ FILE: Fixtures/Miscellaneous/MultipleExecutables/Sources/lib1/lib.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/bar/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "bar", products: [ .library(name: "bar", targets: ["bar"]), ], targets: [ .target(name: "bar", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/bar/Sources/bar.swift ================================================ public let theValue = 5 ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/baz/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/baz/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "baz", products: [ .library(name: "baz", targets: ["baz"]), ], targets: [ .target(name: "baz", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/baz/Sources/baz.swift ================================================ struct baz { var text = "Hello, World!" } ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/foo/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "foo", dependencies: [ .package(url: "../bar", from: "1.0.0"), .package(url: "../baz", from: "1.0.0"), ], targets: [ .target( name: "foo", dependencies: ["bar", "baz"], path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageEdit/foo/Sources/main.swift ================================================ import bar print(bar.theValue) ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/appPkg/Package.swift ================================================ // swift-tools-version:5.9 import PackageDescription let package = Package( name: "appPkg", dependencies: [ .package(url: "../fooPkg", from: "1.0.0"), .package(url: "../barPkg", from: "1.0.0") ], targets: [ .executableTarget(name: "exe", dependencies: ["App"]), .target(name: "App", dependencies: [ .product(name: "Foo", package: "fooPkg"), .product(name: "Bar", package: "barPkg"), ]) ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/appPkg/Sources/App/file.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/appPkg/Sources/exe/main.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/barPkg/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription let package = Package( name: "barPkg", products: [ .library(name: "Bar", targets: ["Bar"]), ], targets: [ .target(name: "Bar", dependencies: ["Baz"]), .target(name: "Baz"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/barPkg/Sources/Bar/file.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/barPkg/Sources/Baz/file.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/fooPkg/Package.swift ================================================ // swift-tools-version:5.9 import PackageDescription let package = Package( name: "fooPkg", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", dependencies: ["Zoo"]), .target(name: "Zoo"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/fooPkg/Sources/Foo/file.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageNameFlag/fooPkg/Sources/Zoo/file.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PackageWithMalformedLibraryProduct/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "PackageWithMalformedLibraryProduct", products: [ .library( name: "PackageWithMalformedLibraryProduct", targets: ["PackageWithMalformedLibraryProduct"]), ], targets: [ .executableTarget( name: "PackageWithMalformedLibraryProduct") ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageWithMalformedLibraryProduct/Sources/PackageWithMalformedLibraryProduct/main.swift ================================================ print("Hello World") ================================================ FILE: Fixtures/Miscellaneous/PackageWithNonc99NameModules/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "PackageWithNonc99NameModules", targets: [ .target(name: "A-B", dependencies: ["B-C"]), .target(name: "B-C", dependencies: []), .target(name: "C D", dependencies: []), ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageWithNonc99NameModules/Sources/A-B/ab.swift ================================================ import B_C func ab() { bc() } ================================================ FILE: Fixtures/Miscellaneous/PackageWithNonc99NameModules/Sources/B-C/bc.swift ================================================ public func bc() { } ================================================ FILE: Fixtures/Miscellaneous/PackageWithNonc99NameModules/Sources/C D/cd.swift ================================================ public func bc() { } ================================================ FILE: Fixtures/Miscellaneous/PackageWithResource/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "AwesomeResources", targets: [ .target(name: "AwesomeResources", resources: [.copy("hello.txt")]), .testTarget(name: "AwesomeResourcesTest", dependencies: ["AwesomeResources"], resources: [.copy("world.txt")]) ] ) ================================================ FILE: Fixtures/Miscellaneous/PackageWithResource/Sources/AwesomeResources/AwesomeResource.swift ================================================ import Foundation public struct AwesomeResource { public init() {} public let hello = try! String(contentsOf: Bundle.module.url(forResource: "hello", withExtension: "txt")!) } ================================================ FILE: Fixtures/Miscellaneous/PackageWithResource/Sources/AwesomeResources/hello.txt ================================================ hello ================================================ FILE: Fixtures/Miscellaneous/PackageWithResource/Tests/AwesomeResourcesTest/MyTests.swift ================================================ import XCTest import Foundation import AwesomeResources final class MyTests: XCTestCase { func testFoo() { XCTAssertTrue(AwesomeResource().hello == "hello") } func testBar() { let world = try! String(contentsOf: Bundle.module.url(forResource: "world", withExtension: "txt")!) XCTAssertTrue(world == "world") } } ================================================ FILE: Fixtures/Miscellaneous/PackageWithResource/Tests/AwesomeResourcesTest/world.txt ================================================ world ================================================ FILE: Fixtures/Miscellaneous/ParallelTestsPkg/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/ParallelTestsPkg/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ParallelTestsPkg", targets: [ .target( name: "ParallelTestsPkg", dependencies: []), .testTarget( name: "ParallelTestsPkgTests", dependencies: ["ParallelTestsPkg"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/ParallelTestsPkg/Sources/ParallelTestsPkg/ParallelTestsPkg.swift ================================================ struct ParallelTests { var text = "Hello, World!" var bool = false } ================================================ FILE: Fixtures/Miscellaneous/ParallelTestsPkg/Tests/ParallelTestsPkgTests/ParallelTestsFailureTests.swift ================================================ import XCTest @testable import ParallelTestsPkg class ParallelTestsFailureTests: XCTestCase { func testSureFailure() { XCTFail("Giving up is the only sure way to fail.") } } ================================================ FILE: Fixtures/Miscellaneous/ParallelTestsPkg/Tests/ParallelTestsPkgTests/ParallelTestsTests.swift ================================================ import XCTest @testable import ParallelTestsPkg class ParallelTestsTests: XCTestCase { func testExample1() { XCTAssertEqual(ParallelTests().text, "Hello, World!") } func testExample2() { XCTAssertEqual(ParallelTests().bool, false) } } ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "ParseAsLibrary", products: [], targets: [ .executableTarget(name: "ExecutableTargetOneFileNamedMainMainAttr"), .executableTarget(name: "ExecutableTargetOneFileNamedMainNoMainAttr"), .executableTarget(name: "ExecutableTargetOneFileNotNamedMainMainAttr"), .executableTarget(name: "ExecutableTargetOneFileNotNamedMainNoMainAttr"), .executableTarget(name: "ExecutableTargetTwoFiles"), ] ) ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetOneFileNamedMainMainAttr/main.swift ================================================ @main struct Entry { static func main() {} } ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetOneFileNamedMainNoMainAttr/main.swift ================================================ print(42) ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetOneFileNotNamedMainMainAttr/othername.swift ================================================ @main struct Entry { static func main() {} } ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetOneFileNotNamedMainNoMainAttr/othername.swift ================================================ print(42) ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetTwoFiles/one.swift ================================================ @main struct Entry { static func main() {} } ================================================ FILE: Fixtures/Miscellaneous/ParseAsLibrary/Sources/ExecutableTargetTwoFiles/two.swift ================================================ func foo() {} ================================================ FILE: Fixtures/Miscellaneous/ParseableInterfaces/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ParseableInterfaces", products: [ ], targets: [ .target(name: "A", dependencies: []), .target(name: "B", dependencies: ["A"]), ]) ================================================ FILE: Fixtures/Miscellaneous/ParseableInterfaces/Sources/A/A.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/ParseableInterfaces/Sources/B/B.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/CSystemModule/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CSystemModule", pkgConfig: "libSystemModule", providers: [ .brew(["SystemModule"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/CSystemModule/module.modulemap ================================================ module CSystemModule { header "shim.h" link "SystemModule" export * } ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/CSystemModule/shim.h ================================================ #include ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModule/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "SystemModule", products: [ .library(name: "SystemModule", targets: ["SystemModule"]), ], targets: [ .target(name: "SystemModule", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModule/Sources/SystemModule.c ================================================ int foo() { int a = 5; int b = a; a = b; return a; } ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModule/Sources/include/SystemModule.h ================================================ int foo(); ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModuleUser/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "SystemModuleUser", dependencies: [ .package(url: "../CSystemModule", from: "1.0.0"), ], targets: [ .target(name: "SystemModuleUser", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModuleUser/Sources/main.swift ================================================ import CSystemModule print("\(foo())") ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModuleUserClang/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "SystemModuleUserClang", dependencies: [ .package(url: "../CSystemModule", from: "1.0.0"), ], targets: [ .target(name: "SystemModuleUserClang", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/PkgConfig/SystemModuleUserClang/Sources/main.c ================================================ #include #include int main() { printf("%d", foo()); return 0; } ================================================ FILE: Fixtures/Miscellaneous/PluginGeneratedResources/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "PluginGeneratedResources", targets: [ .executableTarget(name: "PluginGeneratedResources", plugins: ["Generator"]), .plugin(name: "Generator", capability: .buildTool()), ] ) ================================================ FILE: Fixtures/Miscellaneous/PluginGeneratedResources/Plugins/Generator/plugin.swift ================================================ import PackagePlugin import Foundation #if os(Android) let touchExe = "/system/bin/touch" let touchArgs: [String] = [] #elseif os(Windows) let touchExe = "C:/Windows/System32/cmd.exe" let touchArgs = ["/c", "copy", "NUL"] #else let touchExe = "/usr/bin/touch" let touchArgs: [String] = [] #endif @main struct GeneratorPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { return [ .prebuildCommand( displayName: "Generating empty file", executable: .init(fileURLWithPath: touchExe), arguments: touchArgs + [String(cString: (context.pluginWorkDirectoryURL.appending(path: "best.txt") as NSURL).fileSystemRepresentation)], outputFilesDirectory: context.pluginWorkDirectoryURL ) ] } } ================================================ FILE: Fixtures/Miscellaneous/PluginGeneratedResources/Sources/PluginGeneratedResources/PluginGeneratedResources.swift ================================================ import Foundation @main public struct PluginGeneratedResources { public private(set) var text = "Hello, World!" public static func main() { let path = Bundle.module.path(forResource: "best", ofType: "txt") let exists = FileManager.default.fileExists(atPath: path!) assert(exists, "generated file is missing") print(PluginGeneratedResources().text) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Dependencies/A/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "A", products: [ .plugin( name: "A", targets: ["A"]), ], targets: [ .plugin( name: "A", capability: .command(intent: .custom( verb: "A", description: "prints hello" )) ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Dependencies/A/Plugins/A.swift ================================================ import PackagePlugin @main struct A: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { print("Hello A!") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Dependencies/B/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "B", products: [ .plugin( name: "B", targets: ["B"]), ], targets: [ .plugin( name: "B", capability: .command(intent: .custom( verb: "A", description: "prints hello" )) ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Dependencies/B/Plugins/B.swift ================================================ import PackagePlugin @main struct B: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { print("Hello B!") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "AmbiguousCommands", dependencies: [ .package(path: "Dependencies/A"), .package(path: "Dependencies/B"), ], targets: [ .executableTarget( name: "AmbiguousCommands"), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/AmbiguousCommands/Sources/main.swift ================================================ print("Hello, world!") ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Dependency/MyBinaryTargetExeArtifactBundle.artifactbundle/info.json ================================================ { "schemaVersion": "1.0", "artifacts": { "mytool": { "type": "executable", "version": "1.2.3", "variants": [ { "path": "mytool-macos/mytool", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, { "path": "mytool-linux/mytool", "supportedTriples": ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu"] } ] } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Dependency/MyBinaryTargetExeArtifactBundle.artifactbundle/mytool-linux/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-linux] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Dependency/MyBinaryTargetExeArtifactBundle.artifactbundle/mytool-macos/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-macosx] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyBinaryTargetExePlugin", products: [ .executable( name: "MyPluginExe", targets: ["MyPluginExe"] ), .plugin( name: "MyPlugin", targets: ["MyPlugin"] ), .executable( name: "MyBinaryTargetExe", targets: ["MyBinaryTargetExeArtifactBundle"] ), ], targets: [ .executableTarget( name: "MyPluginExe", dependencies: [], exclude: [], ), .plugin( name: "MyPlugin", capability: .buildTool(), dependencies: ["MyPluginExe", "MyBinaryTargetExeArtifactBundle"] ), .binaryTarget( name: "MyBinaryTargetExeArtifactBundle", path: "Dependency/MyBinaryTargetExeArtifactBundle.artifactbundle" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from MyPlugin!") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryTargetExePlugin/Sources/MyPluginExe/main.swift ================================================ print("It's Me MyPluginExe\n") ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Dependency/Binaries/MyVendedSourceGenBuildTool.artifactbundle/info.json ================================================ { "schemaVersion": "1.0", "artifacts": { "mytool": { "type": "executable", "version": "1.2.3", "variants": [ { "path": "mytool-macos/mytool", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, { "path": "mytool-linux/mytool", "supportedTriples": ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu"] } ] } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Dependency/Binaries/MyVendedSourceGenBuildTool.artifactbundle/mytool-linux/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-linux] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Dependency/Binaries/MyVendedSourceGenBuildTool.artifactbundle/mytool-macos/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-macosx] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Dependency/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyBinaryProduct", products: [ .executable( name: "MyVendedSourceGenBuildTool", targets: ["MyVendedSourceGenBuildTool"] ), ], targets: [ .binaryTarget( name: "MyVendedSourceGenBuildTool", path: "Binaries/MyVendedSourceGenBuildTool.artifactbundle" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MyBinaryToolPlugin", dependencies: [ .package(path: "Dependency"), ], targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ .product(name: "MyVendedSourceGenBuildTool", package: "Dependency"), ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } let inputFiles = target.sourceFiles.filter({ $0.url.pathExtension == "dat" }) return try inputFiles.map { let inputPath = $0.url let outputName = inputPath.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(inputPath.lastPathComponent)", executable: try context.tool(named: "mytool").url, arguments: [ "--verbose", inputPath.path, outputPath.path, ], inputFiles: [ inputPath, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/BinaryToolProductPlugin/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/BuildToolPluginCompilationError/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyPackage", targets: [ .target( name: "MyLibrary", plugins: [ "MyPlugin", ] ), .plugin( name: "MyPlugin", capability: .buildTool() ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/BuildToolPluginCompilationError/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyBuildToolPlugin: BuildToolPlugin { func createBuildCommands( context: PluginContext, target: Target ) throws -> [Command] { print("This is text from the plugin") throw "This is an error from the plugin" return [] } } extension String : Error {} ================================================ FILE: Fixtures/Miscellaneous/Plugins/BuildToolPluginCompilationError/Sources/MyLibrary/library.swift ================================================ public func Foo() { } ================================================ FILE: Fixtures/Miscellaneous/Plugins/ClientOfPluginWithInternalExecutable/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "ClientOfPluginWithInternalExecutable", dependencies: [ .package(path: "../PluginWithInternalExecutable") ], targets: [ .executableTarget( name: "RootTarget", plugins: [ .plugin(name: "PluginScriptProduct", package: "PluginWithInternalExecutable") ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/ClientOfPluginWithInternalExecutable/Sources/RootTarget/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginCompilationError/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyPackage", products: [ .library( name: "MyLibrary", targets: ["MyLibrary"] ), .executable( name: "MyExecutable", targets: ["MyExecutable"] ), ], targets: [ .target( name: "MyLibrary" ), .executableTarget( name: "MyExecutable", dependencies: ["MyLibrary"] ), .plugin( name: "MyBuildToolPlugin", capability: .buildTool() ), .plugin( name: "MyCommandPlugin", capability: .command( intent: .custom(verb: "my-build-tester", description: "Help description") ) ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginCompilationError/Plugins/MyBuildToolPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyBuildToolPlugin: BuildToolPlugin { func createBuildCommands( context: PluginContext, target: Target ) throws -> [Command] { return [] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginCompilationError/Plugins/MyCommandPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyCommandPlugin: CommandPlugin { func performCommand( context: PluginContext, arguments: [String] ) throws { this is an error } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginCompilationError/Sources/MyExecutable/main.swift ================================================ import MyLibrary print("\\(GetGreeting()), World!") ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginCompilationError/Sources/MyLibrary/library.swift ================================================ public func GetGreeting() -> String { return "Hello" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "CommandPluginDiagnostics", targets: [ .plugin( name: "diagnostics-stub", capability: .command(intent: .custom( verb: "print-diagnostics", description: "Writes diagnostic messages for testing" )) ), .plugin( name: "targetbuild-stub", capability: .command(intent: .custom( verb: "build-target", description: "Build a target for testing" )) ), .plugin( name: "plugin-dependencies-stub", capability: .command(intent: .custom( verb: "build-plugin-dependency", description: "Build a plugin dependency for testing" )), dependencies: [ .target(name: "plugintool") ] ), .plugin( name: "check-testability", capability: .command(intent: .custom( verb: "check-testability", description: "Check testability of a target" )) ), .executableTarget( name: "placeholder" ), .executableTarget( name: "plugintool" ), .target( name: "InternalModule" ), .testTarget( name: "InternalModuleTests", dependencies: [ .target(name: "InternalModule") ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Plugins/check-testability/main.swift ================================================ import Foundation import PackagePlugin @main struct CheckTestability: CommandPlugin { // This is a helper for testing target builds to ensure that they are testable. func performCommand(context: PluginContext, arguments: [String]) async throws { // Parse the arguments: guard arguments.count == 3 else { fatalError("Usage: ") } let rawSubsetName = arguments[0] var subset: PackageManager.BuildSubset switch rawSubsetName { // Special subset names case "all-with-tests": subset = .all(includingTests: true) // By default, treat the subset as a target name default: subset = .target(rawSubsetName) } guard let config = PackageManager.BuildConfiguration(rawValue: arguments[1]) else { fatalError("Invalid configuration: \(arguments[1])") } let shouldTestable = arguments[2] == "true" var parameters = PackageManager.BuildParameters() parameters.configuration = config parameters.logging = .verbose // Perform the build let result = try packageManager.build(subset, parameters: parameters) // Check if the build was successful guard result.succeeded else { fatalError("Build failed: \(result.logText)") } // Check if the build log contains "-enable-testing" flag let isTestable = result.logText.contains("-enable-testing") if isTestable != shouldTestable { fatalError("Testability mismatch: expected \(shouldTestable), but got \(isTestable):\n\(result.logText)") } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Plugins/diagnostics-stub/diagnostics_stub.swift ================================================ import Foundation import PackagePlugin @main struct diagnostics_stub: CommandPlugin { // This is a helper for testing plugin diagnostics. It sends different messages to SwiftPM depending on its arguments. func performCommand(context: PluginContext, arguments: [String]) async throws { // Build a target, possibly asking SwiftPM to echo the logs as they are produced. if arguments.contains("build") { // If echoLogs is true, SwiftPM will print build logs to stderr as they are produced. // SwiftPM does not add a prefix to these logs. let result = try packageManager.build( .product("placeholder"), parameters: .init(echoLogs: arguments.contains("echologs")) ) // To verify that logs are also returned correctly to the plugin, // print the accumulated log buffer lines with a prefix to // distinguish them from echoed logs. These logs are normal output // from the plugin and will be printed on stdout. if arguments.contains("printlogs") { for line in result.logText.components(separatedBy: "\n") { print("command plugin: packageManager.build logtext: \(line)") } } } // Anything a plugin writes to standard output appears on standard output. // Printing to stderr will also go to standard output because SwiftPM combines // stdout and stderr before launching the plugin. if arguments.contains("print") { print("command plugin: print") } // Diagnostics are collected by SwiftPM and printed to standard error, depending on the current log verbosity level. if arguments.contains("progress") { Diagnostics.progress("command plugin: Diagnostics.progress") // prefixed with [plugin_name] } if arguments.contains("remark") { Diagnostics.remark("command plugin: Diagnostics.remark") // prefixed with 'info:' when printed } if arguments.contains("warning") { Diagnostics.warning("command plugin: Diagnostics.warning") // prefixed with 'warning:' when printed } if arguments.contains("error") { Diagnostics.error("command plugin: Diagnostics.error") // prefixed with 'error:' when printed } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Plugins/plugin-dependencies-stub/main.swift ================================================ import PackagePlugin @main struct test: CommandPlugin { // This plugin exists to test that the executable it requires is built correctly when cross-compiling func performCommand(context: PluginContext, arguments: [String]) async throws { print("Hello from dependencies-stub") let _ = try packageManager.build( .product("placeholder"), parameters: .init(configuration: .debug, logging: .concise) ) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Plugins/targetbuild-stub/targetbuild_stub.swift ================================================ import Foundation import PackagePlugin @main struct targetbuild_stub: CommandPlugin { // This is a helper for testing target builds performed on behalf of plugins. // It sends asks SwiftPM to build a target with different options depending on its arguments. func performCommand(context: PluginContext, arguments: [String]) async throws { // Build a target var parameters = PackageManager.BuildParameters() if arguments.contains("build-debug") { parameters.configuration = .debug } else if arguments.contains("build-release") { parameters.configuration = .release } else if arguments.contains("build-inherit") { parameters.configuration = .inherit } // If no 'build-*' argument is present, the default (.debug) will be used. let _ = try packageManager.build( .product("placeholder"), parameters: parameters ) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Sources/InternalModule/InternalModule.swift ================================================ internal func internalFunction() { print("Internal function") } ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Sources/placeholder/main.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book print("Hello, world from executable target!") ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Sources/plugintool/main.swift ================================================ print("Hello from plugintool") ================================================ FILE: Fixtures/Miscellaneous/Plugins/CommandPluginTestStub/Tests/InternalModuleTests/InternalModuleTests.swift ================================================ @testable import InternalModule ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "ContrivedTestPlugin", targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", "MyAmbiguouslyNamedCommandPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // The command line tool that generates source files. .executableTarget( name: "MySourceGenBuildTool" ), // Plugin that emits commands with a generic name. .plugin( name: "MyAmbiguouslyNamedCommandPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // Sample system library target for testing. .systemLibrary( name: "libpcre", path: "Sources/libpcre", pkgConfig: "libpcre", providers: [ .apt(["libpcre-dev"]) ] ) ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Plugins/MyAmbiguouslyNamedCommandPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { guard let target = target as? SourceModuleTarget else { return [] } var commands: [Command] = [] for inputFile in target.sourceFiles.filter({ $0.url.pathExtension == "dat" }) { let inputPath = inputFile.url let outputName = "Ambiguous_" + inputPath.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) commands.append(.buildCommand( displayName: "This is a constant name", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ inputPath.path, outputPath.path, ], environment: [ "VARIABLE_NAME_PREFIX": "SECOND_PREFIX_" ], inputFiles: [ inputPath, ], outputFiles: [ outputPath ] )) } return commands } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { guard let target = target as? SourceModuleTarget else { return [] } let inputFiles = target.sourceFiles.filter({ $0.url.pathExtension == "dat" }) return try inputFiles.map { let inputPath = $0.url let outputName = inputPath.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(inputPath.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ inputPath.path, outputPath.path, ], environment: [ "VARIABLE_NAME_PREFIX": "PREFIX_" ], inputFiles: [ inputPath, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(PREFIX_foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Sources/MySourceGenBuildTool/main.swift ================================================ import Foundation // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file, with the value from an environment value prepended. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variablePrefix = ProcessInfo.processInfo.environment["VARIABLE_NAME_PREFIX"] ?? "" let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public var \(variablePrefix)\(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) extension String { public var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Sources/libpcre/module.modulemap ================================================ module readline [system] { header "sdk_libpcre.h" link "libpcre" export * } ================================================ FILE: Fixtures/Miscellaneous/Plugins/ContrivedTestPlugin/Sources/libpcre/sdk_libpcre.h ================================================ #include ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "DependentPlugins", platforms: [ .macOS(.v13) ], dependencies: [ ], targets: [ .executableTarget(name: "MyExecutable"), .executableTarget(name: "MyExecutable2"), .plugin( name: "MyPlugin", capability: .buildTool(), dependencies: [ "MyExecutable" ] ), .plugin( name: "MyPlugin2", capability: .buildTool(), dependencies: [ "MyExecutable2" ] ), .executableTarget( name: "MyClient", plugins: [ "MyPlugin", "MyPlugin2", ] ), ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { let outputFilePath = context.pluginWorkDirectoryURL.appendingPathComponent("MyGeneratedFile.swift") return [ .buildCommand( displayName: "Running MyExecutable", executable: try context.tool(named: "MyExecutable").url, arguments: ["--output-file-path", outputFilePath.path], outputFiles: [outputFilePath] ) ] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Plugins/MyPlugin2/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { guard let sourceTarget = target as? SourceModuleTarget else { throw "Target is not a source target, cannot get a file list" } guard let inputFilePath = sourceTarget.pluginGeneratedSources.first(where: { $0.lastPathComponent == "MyGeneratedFile.swift" }) else { throw "Cannot find MyGeneratedFile.swift, files: \(sourceTarget.pluginGeneratedSources), target: \(target)" } return [ .buildCommand( displayName: "Running MyExecutable2", executable: try context.tool(named: "MyExecutable2").url, arguments: ["--input-file-path", inputFilePath.path], inputFiles: [inputFilePath], ) ] } } extension String: Error, LocalizedError { public var errorDescription: String? { self } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Sources/MyClient/client.swift ================================================ @main struct Client { static func main() throws { print(MyGeneratedStruct.message) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Sources/MyExecutable/tool.swift ================================================ import Foundation @main struct Tool { static func main() async throws { print("warning: Whoops! Coming from the executable", to: &StdErr.shared) let path = CommandLine.arguments[2] print("Writing a file to \(path)") try #""" public struct MyGeneratedStruct { public static var message: String = "You got struct'd" } """#.write(to: URL(fileURLWithPath: path), atomically: true, encoding: .utf8) } } struct StdErr: TextOutputStream { static var shared: Self = .init() mutating func write(_ string: String) { string.withCString { ptr in _ = fputs(ptr, stderr) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/DependentPlugins/Sources/MyExecutable2/tool.swift ================================================ import Foundation @main struct Tool { static func main() async throws { let path = CommandLine.arguments[2] print("Printing file at \(path)") print(try String(contentsOfFile: path)) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "111920845-sample", platforms: [ .macOS(.v10_15), // example uses swift concurrency which is only available in 10.15 or newer ], products: [ .executable(name: "MyPluginExecutable", targets: ["MyPluginExecutable"]), .plugin(name: "MyPlugin", targets: ["MyPlugin"]), ], targets: [ .executableTarget(name: "MyPluginExecutable"), .plugin(name: "MyPlugin", capability: .buildTool, dependencies: ["MyPluginExecutable"]), .target(name: "MyLibrary", plugins: ["MyPlugin"]), .executableTarget(name: "MyExecutable", dependencies: ["MyLibrary"]), .testTarget(name: "MyExecutableTests", dependencies: ["MyExecutable"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Plugins/MyPlugin/MyPlugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { return [.buildCommand( displayName: "Running MyPluginExecutable", executable: try context.tool(named: "MyPluginExecutable").url, arguments: [], environment: [:], inputFiles: [], outputFiles: [] )] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Sources/MyExecutable/MyExecutable.swift ================================================ import MyLibrary @main struct MyExecutable { static func main() async throws { print("Hello from executable.") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Sources/MyLibrary/Empty.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Sources/MyPluginExecutable/MyPluginExecutable.swift ================================================ @main struct MyExecutable { static func main() async throws { print("Hello from plugin executable.") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/IncorrectDependencies/Tests/MyExecutableTests/MyExecutableTests.swift ================================================ import XCTest @testable import MyExecutable final class MyExecutableTests: XCTestCase { func test() throws { XCTAssertTrue(true) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/InvalidUseOfInternalPluginExecutable/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "InvalidUseOfInternalPluginExecutable", dependencies: [ .package(path: "../PluginWithInternalExecutable") ], targets: [ .executableTarget( name: "RootTarget", dependencies: [ .product(name: "PluginExecutable", package: "PluginWithInternalExecutable") ], plugins: [ .plugin(name: "PluginScriptProduct", package: "PluginWithInternalExecutable") ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/InvalidUseOfInternalPluginExecutable/Sources/RootTarget/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/LibraryWithLocalBuildToolPluginUsingRemoteTool/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MyLibrary", dependencies: [ .package(path: "../MySourceGenPlugin") ], targets: [ .plugin( name: "MyLocalSourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ .product(name: "MySourceGenBuildTool", package: "MySourceGenPlugin") ] ), .target( name: "MyLibrary", plugins: [ "MyLocalSourceGenBuildToolPlugin", ] ), .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"] ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/LibraryWithLocalBuildToolPluginUsingRemoteTool/Plugins/MyLocalSourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } return try target.sourceFiles.map{ $0.url }.compactMap { (url: URL) -> Command? in guard url.pathExtension == "dat" else { return nil } let outputName = url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(url.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ url.path, outputPath.path, ], inputFiles: [ url, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/LibraryWithLocalBuildToolPluginUsingRemoteTool/Sources/MyLibrary/library.swift ================================================ public func GetGeneratedString() -> String { return "Generated string: \(generated)" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/LibraryWithLocalBuildToolPluginUsingRemoteTool/Tests/MyLibraryTests/test.swift ================================================ import XCTest import MyLibrary final class MyLibraryTests: XCTestCase { func testLibrary() throws { XCTAssertEqual(GetGeneratedString(), "Generated string: 4920616d20466f6f210a") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MissingPlugin/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "MissingPlugin", targets: [ .target(name: "MissingPlugin", plugins: ["NonExistingPlugin"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MissingPlugin/Sources/MissingPlugin/MissingPlugin.swift ================================================ public struct MissingPlugin { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Binaries/MyVendedSourceGenBuildTool.artifactbundle/info.json ================================================ { "schemaVersion": "1.0", "artifacts": { "mytool": { "type": "executable", "version": "1.2.3", "variants": [ { "path": "mytool-macos/mytool", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] }, { "path": "mytool-linux/mytool", "supportedTriples": ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu"] }, { "path": "mytool-windows/mytool.bat", "supportedTriples": ["x86_64-unknown-windows-msvc", "aarch64-unknown-windows-msvc"] } ] } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Binaries/MyVendedSourceGenBuildTool.artifactbundle/mytool-linux/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-linux] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Binaries/MyVendedSourceGenBuildTool.artifactbundle/mytool-macos/mytool ================================================ #!/bin/bash print_usage() { echo "usage: ${0##*/} [--verbose] " } # Parse arguments until we find '--' or an argument that isn't an option. until [ $# -eq 0 ] do case "$1" in --verbose) verbose=1; shift;; --) shift; break;; -*) echo "unknown option: ${1}"; print_usage; exit 1; shift;; *) break;; esac done # Print usage and leave if we don't have exactly two arguments. if [ $# -ne 2 ]; then print_usage exit 1 fi # For our sample tool we just copy from one to the other. if [ $verbose != 0 ]; then echo "[${0##*/}-macosx] '$1' '$2'" fi cp "$1" "$2" ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Binaries/MyVendedSourceGenBuildTool.artifactbundle/mytool-windows/mytool.bat ================================================ @echo off set verbose=false IF NOT "%1"=="" ( IF "%1"=="--verbose" ( SET verbose=true SHIFT ) ) set input=%1 set output=%2 shift shift if "%verbose%" == "true" ( echo "[mytool-windows] '%input%' '%output%'" ) @echo on echo f | xcopy.exe /f "%input%" "%output%" ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "MyBinaryToolPlugin", targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MyVendedSourceGenBuildTool", ] ), // The vended executable that generates source files. .binaryTarget( name: "MyVendedSourceGenBuildTool", path: "Binaries/MyVendedSourceGenBuildTool.artifactbundle" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } let inputFiles = target.sourceFiles.filter({ $0.url.pathExtension == "dat" }) let workDir = context.pluginWorkDirectoryURL return try inputFiles.map { let inputFile = $0 let inputPath = $0.url let outputName = inputPath.deletingPathExtension().appendingPathExtension("swift") .lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(inputPath.lastPathComponent)", executable: try context.tool(named: "mytool").url, arguments: [ "--verbose", inputPath.path, outputPath.path, ], inputFiles: [ inputPath ], outputFiles: [ outputPath ] ) } + [ .prebuildCommand( displayName: "Generating files in \(workDir.path)", executable: try context.tool(named: "mytool").url, arguments: [ "--verbose", target.directoryURL.appendingPathComponent("bar.in").path, workDir.appendingPathComponent("bar.swift").path, ], outputFilesDirectory: workDir ) ] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Sources/MyLocalTool/bar.in ================================================ let bar = "I am Bar!" ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBinaryToolPlugin/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") print("Generated string Bar: '\(bar)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBuildToolPluginDependencies/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MyBuildToolPluginDependencies", targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // A command line tool that generates source files. .executableTarget( name: "MySourceGenBuildTool", dependencies: [ "MySourceGenBuildToolLib", ] ), // A library used by MySourceGenBuildTool (not the client). .target( name: "MySourceGenBuildToolLib" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBuildToolPluginDependencies/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { // Create build commands that don't invoke the MySourceGenBuildTool source generator // tool directly, but instead invoke a system tool that invokes it indirectly. We // want to test that we still end up with a dependency on not only that tool but also // on the library it depends on, even without including an explicit dependency on it. func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } let inputFiles = target.sourceFiles.filter({ $0.url.pathExtension == "dat" }) return try inputFiles.map { let inputPath = $0.url let outputName = inputPath.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(inputPath.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ inputPath.path, outputPath.path, ], inputFiles: [ inputPath, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBuildToolPluginDependencies/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBuildToolPluginDependencies/Sources/MySourceGenBuildTool/main.swift ================================================ import Foundation import MySourceGenBuildToolLib // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public let \(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MyBuildToolPluginDependencies/Sources/MySourceGenBuildToolLib/library.swift ================================================ import Foundation extension String { public var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenClient/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MySourceGenClient", dependencies: [ .package(path: "../MySourceGenPlugin") ], targets: [ // A tool that uses a plugin. .executableTarget( name: "MyTool", plugins: [ .plugin(name: "MySourceGenBuildToolPlugin", package: "MySourceGenPlugin") ] ), // A unit test that uses the plugin. .testTarget( name: "MyTests", plugins: [ .plugin(name: "MySourceGenBuildToolPlugin", package: "MySourceGenPlugin") ] ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenClient/Sources/MyTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenClient/Tests/MyTests/MyTests.swift ================================================ import XCTest import class Foundation.Bundle final class SwiftyProtobufTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } // Mac Catalyst won't have `Process`, but it is supported for executables. #if !targetEnvironment(macCatalyst) let fooBinary = productsDirectory.appendingPathComponent("MySourceGenTool") let process = Process() process.executableURL = fooBinary let pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, world!\n") #endif } /// Returns path to the built products directory. var productsDirectory: URL { #if os(macOS) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return bundle.bundleURL.deletingLastPathComponent() } fatalError("couldn't find the products directory") #else return Bundle.main.bundleURL #endif } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MySourceGenPlugin", products: [ // The product that vends MySourceGenBuildToolPlugin to client packages. .plugin( name: "MySourceGenBuildToolPlugin", targets: ["MySourceGenBuildToolPlugin"] ), // The product that vends the MySourceGenBuildTool executable to client packages. .executable( name: "MySourceGenBuildTool", targets: ["MySourceGenBuildTool"] ), // The product that vends MySourceGenPrebuildPlugin to client packages. .plugin( name: "MySourceGenPrebuildPlugin", targets: ["MySourceGenPrebuildPlugin"] ), ], targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // A local tool that uses a prebuild plugin. .executableTarget( name: "MyOtherLocalTool", plugins: [ "MySourceGenPrebuildPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // The plugin that generates prebuild commands (currently to invoke a system tool). .plugin( name: "MySourceGenPrebuildPlugin", capability: .buildTool() ), // The command line tool that generates source files. .executableTarget( name: "MySourceGenBuildTool", dependencies: [ "MySourceGenBuildToolLib", ] ), // A library used by MySourceGenBuildTool (not the client). .target( name: "MySourceGenBuildToolLib" ), // A runtime library that the client needs to link against. .target( name: "MySourceGenRuntimeLib" ), // Unit tests for the plugin. .testTarget( name: "MySourceGenPluginTests", dependencies: [ "MySourceGenRuntimeLib", ], plugins: [ "MySourceGenBuildToolPlugin", "MySourceGenPrebuildPlugin", ] ) ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { #if USE_CREATE let verb = "Creating" #else let verb = "Generating" #endif func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } return try target.sourceFiles.map { $0.url }.compactMap { (url: URL) -> Command? in guard url.pathExtension == "dat" else { return nil } let outputName = url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "\(verb) \(outputName) from \(url.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ url.path, outputPath.path ], inputFiles: [ url, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Plugins/MySourceGenPrebuildPlugin/plugin.swift ================================================ import PackagePlugin import Foundation #if os(Android) let touchExe = "/system/bin/touch" let touchArgs: [String] = [] #elseif os(Windows) let touchExe = "C:/Windows/System32/cmd.exe" let touchArgs = ["/c", "copy", "NUL"] #else let touchExe = "/usr/bin/touch" let touchArgs: [String] = [] #endif @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Prebuild Plugin!") guard let target = target as? SourceModuleTarget else { return [] } let outputPaths: [URL] = target.sourceFiles.filter{ $0.url.pathExtension == "dat" }.map { file in context.pluginWorkDirectoryURL.appendingPathComponent(file.url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent) } var commands: [Command] = [] let paths = outputPaths.map{ $0.path } #if os(Windows) let args = ["/c", "FOR %F IN (" + paths.joined(separator: " ") + ") DO TYPE NUL > %F"] #else let args = paths #endif if !outputPaths.isEmpty { commands.append(.prebuildCommand( displayName: "Running prebuild command for target \(target.name)", executable: .init(fileURLWithPath: touchExe), arguments: args, outputFilesDirectory: context.pluginWorkDirectoryURL )) } return commands } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Sources/MyOtherLocalTool/main.swift ================================================ // print("Generated string Bar: '\(bar)'") // print("Generated string Baz: '\(baz)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Sources/MySourceGenBuildTool/main.swift ================================================ import Foundation import MySourceGenBuildToolLib // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public let \(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Sources/MySourceGenBuildToolLib/library.swift ================================================ import Foundation extension String { public var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Sources/MySourceGenRuntimeLib/library.swift ================================================ public func GetLibraryName() -> String { return "MySourceGenRuntimeLib" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPlugin/Tests/MySourceGenPluginTests/MySourceGenPluginTests.swift ================================================ import XCTest import class Foundation.Bundle final class SwiftyProtobufTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } // Mac Catalyst won't have `Process`, but it is supported for executables. #if !targetEnvironment(macCatalyst) let fooBinary = productsDirectory.appendingPathComponent("MySourceGenTool") let process = Process() process.executableURL = fooBinary let pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, world!\n") #endif } /// Returns path to the built products directory. var productsDirectory: URL { #if os(macOS) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return bundle.bundleURL.deletingLastPathComponent() } fatalError("couldn't find the products directory") #else return Bundle.main.bundleURL #endif } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MySourceGenPluginNoPreBuildCommands", products: [ // The product that vends MySourceGenBuildToolPlugin to client packages. .plugin( name: "MySourceGenBuildToolPlugin", targets: ["MySourceGenBuildToolPlugin"] ), // The product that vends the MySourceGenBuildTool executable to client packages. .executable( name: "MySourceGenBuildTool", targets: ["MySourceGenBuildTool"] ), ], targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // A local tool that uses a prebuild plugin. .executableTarget( name: "MyOtherLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // The command line tool that generates source files. .executableTarget( name: "MySourceGenBuildTool", dependencies: [ "MySourceGenBuildToolLib", ] ), // A library used by MySourceGenBuildTool (not the client). .target( name: "MySourceGenBuildToolLib" ), // A runtime library that the client needs to link against. .target( name: "MySourceGenRuntimeLib" ), // Unit tests for the plugin. .testTarget( name: "MySourceGenPluginTests", dependencies: [ "MySourceGenRuntimeLib", ], plugins: [ "MySourceGenBuildToolPlugin", ] ) ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { #if USE_CREATE let verb = "Creating" #else let verb = "Generating" #endif func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } return try target.sourceFiles.map{ $0.url }.compactMap { (url: URL) -> Command? in guard url.pathExtension == "dat" else { return nil } let outputName = url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "\(verb) \(outputName) from \(url.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ url.path, outputPath.path, ], inputFiles: [ url, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Sources/MyOtherLocalTool/main.swift ================================================ // print("Generated string Bar: '\(bar)'") // print("Generated string Baz: '\(baz)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Sources/MySourceGenBuildTool/main.swift ================================================ import Foundation import MySourceGenBuildToolLib // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public var \(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Sources/MySourceGenBuildToolLib/library.swift ================================================ import Foundation extension String { public var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Sources/MySourceGenRuntimeLib/library.swift ================================================ public func GetLibraryName() -> String { return "MySourceGenRuntimeLib" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Tests/MySourceGenPluginNoPreBuildCommandsTests/MySourceGenPluginNoPreBuildCommandsTests.swift ================================================ import XCTest import class Foundation.Bundle // for rdar://113256834 final class SwiftyProtobufTests: XCTestCase { func testMyLocalTool() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } // Mac Catalyst won't have `Process`, but it is supported for executables. #if !targetEnvironment(macCatalyst) let fooBinary = productsDirectory.appendingPathComponent("MyLocalTool") let process = Process() process.executableURL = fooBinary let pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Generated string Foo: \'4920616d20466f6f210a\'\n") #endif } func testMyOtherLocalTool() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } // Mac Catalyst won't have `Process`, but it is supported for executables. #if !targetEnvironment(macCatalyst) let fooBinary = productsDirectory.appendingPathComponent("MyOtherLocalTool") let process = Process() process.executableURL = fooBinary let pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "") #endif } /// Returns path to the built products directory. var productsDirectory: URL { #if os(macOS) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return bundle.bundleURL.deletingLastPathComponent() } fatalError("couldn't find the products directory") #else return Bundle.main.bundleURL #endif } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginNoPreBuildCommands/Tests/MySourceGenPluginNoPreBuildCommandsTests/lunch.txt ================================================ coffee ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "MySourceGenPlugin", products: [ // The product that vends MySourceGenBuildToolPlugin to client packages. .plugin( name: "MySourceGenBuildToolPlugin", targets: ["MySourceGenBuildToolPlugin"] ), // The product that vends the MySourceGenBuildTool executable to client packages. .executable( name: "MySourceGenBuildTool", targets: ["MySourceGenBuildTool"] ), // The product that vends MySourceGenPrebuildPlugin to client packages. .plugin( name: "MySourceGenPrebuildPlugin", targets: ["MySourceGenPrebuildPlugin"] ), ], targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // A local tool that uses a prebuild plugin. .executableTarget( name: "MyOtherLocalTool", plugins: [ "MySourceGenPrebuildPlugin", ] ), // The plugin that generates build tool commands to invoke MySourceGenBuildTool. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool(), dependencies: [ "MySourceGenBuildTool", ] ), // The plugin that generates prebuild commands (currently to invoke a system tool). .plugin( name: "MySourceGenPrebuildPlugin", capability: .buildTool() ), // The command line tool that generates source files. .executableTarget( name: "MySourceGenBuildTool", dependencies: [ "MySourceGenBuildToolLib", ] ), // A library used by MySourceGenBuildTool (not the client). .target( name: "MySourceGenBuildToolLib" ), // A runtime library that the client needs to link against. .target( name: "MySourceGenRuntimeLib" ), // Unit tests for the plugin. .testTarget( name: "MySourceGenPluginTests", dependencies: [ "MySourceGenRuntimeLib", ], plugins: [ "MySourceGenBuildToolPlugin", "MySourceGenPrebuildPlugin", ] ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { #if USE_CREATE let verb = "Creating" #else let verb = "Generating" #endif func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Build Tool Plugin!") guard let target = target as? SourceModuleTarget else { return [] } return try target.sourceFiles.map{ $0.url }.compactMap { (url: URL) -> Command? in guard url.pathExtension == "dat" else { return nil } let outputName = url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "\(verb) \(outputName) from \(url.lastPathComponent)", executable: try context.tool(named: "MySourceGenBuildTool").url, arguments: [ url.path, outputPath.path ], inputFiles: [ url, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Plugins/MySourceGenPrebuildPlugin/plugin.swift ================================================ import Foundation import PackagePlugin #if os(Android) let touchExe = "/system/bin/touch" #elseif os(Windows) let touchExe = "C:/Windows/System32/cmd.exe" #else let touchExe = "/usr/bin/touch" #endif @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the Prebuild Plugin!") guard let target = target as? SourceModuleTarget else { return [] } let outputPaths: [URL] = target.sourceFiles.filter{ $0.url.pathExtension == "dat" }.map { file in context.pluginWorkDirectoryURL.appendingPathComponent(file.url.lastPathComponent + ".swift") } let paths = outputPaths.map{ $0.path } #if os(Windows) let args = ["/c", "FOR %F IN (" + paths.joined(separator: " ") + ") DO TYPE NUL > %F"] #else let args = paths #endif var commands: [Command] = [] if !outputPaths.isEmpty { commands.append(.prebuildCommand( displayName: "Running prebuild command for target \(target.name)", executable: .init(fileURLWithPath: touchExe), arguments: args, outputFilesDirectory: context.pluginWorkDirectoryURL )) } return commands } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Sources/MyLocalTool/main.swift ================================================ print("Generated string Foo: '\(foo)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Sources/MyOtherLocalTool/main.swift ================================================ // print("Generated string Bar: '\(bar)'") // print("Generated string Baz: '\(baz)'") ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Sources/MySourceGenBuildTool/main.swift ================================================ import Foundation import MySourceGenBuildToolLib // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public let \(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Sources/MySourceGenBuildToolLib/library.swift ================================================ import Foundation extension String { public var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Sources/MySourceGenRuntimeLib/library.swift ================================================ public func GetLibraryName() -> String { return "MySourceGenRuntimeLib" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/MySourceGenPluginUsingURLBasedAPI/Tests/MySourceGenPluginTests/MySourceGenPluginTests.swift ================================================ import XCTest import class Foundation.Bundle final class SwiftyProtobufTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } // Mac Catalyst won't have `Process`, but it is supported for executables. #if !targetEnvironment(macCatalyst) let fooBinary = productsDirectory.appendingPathComponent("MySourceGenTool") let process = Process() process.executableURL = fooBinary let pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() let data = pipe.fileHandleForReading.readDataToEndOfFile() let output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, world!\n") #endif } /// Returns path to the built products directory. var productsDirectory: URL { #if os(macOS) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return bundle.bundleURL.deletingLastPathComponent() } fatalError("couldn't find the products directory") #else return Bundle.main.bundleURL #endif } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginCanBeReferencedByProductName/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "PluginCanBeReferencedByProductName", products: [ .plugin(name: "MyPluginProduct", targets: ["MyPlugin"]), ], targets: [ .target(name: "PluginCanBeReferencedByProductName", plugins: ["MyPluginProduct"]), .executableTarget(name: "Exec"), .plugin(name: "MyPlugin", capability: .buildTool(), dependencies: ["Exec"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginCanBeReferencedByProductName/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] { let output = context.pluginWorkDirectoryURL.appendingPathComponent("gen.swift") return [ .buildCommand(displayName: "Generating code", executable: try context.tool(named: "Exec").url, arguments: [output.path], outputFiles: [output]) ] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginCanBeReferencedByProductName/Sources/Exec/main.swift ================================================ import Foundation let output = ProcessInfo.processInfo.arguments[1] try "let stringConstant = \"Hello, World!\"".write(to: URL(fileURLWithPath: output), atomically: true, encoding: .utf8) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginCanBeReferencedByProductName/Sources/PluginCanBeReferencedByProductName/PluginCanBeReferencedByProductName.swift ================================================ public struct PluginCanBeReferencedByProductName { public private(set) var text = stringConstant public init() { } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyLibrary/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyLibrary", dependencies: [ .package(path: "../MyPlugin") ], targets: [ .target( name: "MyLibrary" ), .testTarget( name: "MyLibraryTests", dependencies: ["MyLibrary"] ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyLibrary/Sources/MyLibrary/library.swift ================================================ public func Foo() -> String { return "Foo" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyLibrary/Tests/MyLibraryTests/test.swift ================================================ import XCTest import MyLibrary final class MyLibraryTests: XCTestCase { func testLibrary() throws { XCTAssertEqual(Foo(), "Foo") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyPlugin/Libraries/LocalToolHelperLibrary/library.swift ================================================ public func LocalToolHelperFunction() -> String { return "local" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyPlugin/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyPlugin", products: [ .plugin( name: "MyPlugin", targets: ["MyPlugin"] ), ], dependencies: [ .package(path: "../RemoteTool"), ], targets: [ .plugin( name: "MyPlugin", capability: .command( intent: .custom( verb: "my-plugin", description: "Tester plugin" ) ), dependencies: [ .product(name: "RemoteTool", package: "RemoteTool"), "LocalTool", "ImpliedLocalTool", ] ), .executableTarget( name: "LocalTool", dependencies: ["LocalToolHelperLibrary"], path: "Tools/LocalTool" ), .executableTarget( name: "ImpliedLocalTool", dependencies: ["LocalToolHelperLibrary"], path: "Tools/ImpliedLocalTool" ), .target( name: "LocalToolHelperLibrary", path: "Libraries/LocalToolHelperLibrary" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyPlugin/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { for name in ["RemoteTool", "LocalTool", "ImpliedLocalTool"] { let tool = try context.tool(named: name) print("tool path is \(tool.path)") do { let process = Process() process.executableURL = URL(fileURLWithPath: tool.path.string) try process.run() } catch { print("error: \(error)") } } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyPlugin/Tools/ImpliedLocalTool/main.swift ================================================ import LocalToolHelperLibrary print("A message from the implied \(LocalToolHelperFunction()) tool.") ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/MyPlugin/Tools/LocalTool/main.swift ================================================ import LocalToolHelperLibrary print("A message from the \(LocalToolHelperFunction()) tool.") ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/RemoteTool/Libraries/RemoteToolHelperLibrary/library.swift ================================================ public func RemoteToolHelperLibraryFunction() -> String { return "remote" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/RemoteTool/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "RemoteTool", products: [ .executable( name: "RemoteTool", targets: ["RemoteTool"] ), ], targets: [ .executableTarget( name: "RemoteTool", dependencies: ["RemoteToolHelperLibrary"], path: "Tools/RemoteTool" ), .target( name: "RemoteToolHelperLibrary", path: "Libraries/RemoteToolHelperLibrary" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginUsingLocalAndRemoteTool/RemoteTool/Tools/RemoteTool/main.swift ================================================ import RemoteToolHelperLibrary print("A message from the \(RemoteToolHelperLibraryFunction()) tool.") ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginWithInternalExecutable/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "PluginWithInternalExecutable", products: [ .plugin( name: "PluginScriptProduct", targets: ["PluginScriptTarget"] ), ], targets: [ .plugin( name: "PluginScriptTarget", capability: .buildTool(), dependencies: [ "PluginExecutable", ] ), .executableTarget( name: "PluginExecutable" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginWithInternalExecutable/Plugins/PluginScriptTarget/Script.swift ================================================ import PackagePlugin import Foundation @main struct PluginScript: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { print("Hello from the plugin script!") guard let target = target as? SourceModuleTarget else { return [] } return try target.sourceFiles.map{ $0.url }.compactMap { (url: URL) -> Command? in guard url.pathExtension == "dat" else { return nil } let outputName = url.deletingPathExtension().appendingPathExtension("swift").lastPathComponent let outputPath = context.pluginWorkDirectoryURL.appendingPathComponent(outputName) return .buildCommand( displayName: "Generating \(outputName) from \(url.lastPathComponent)", executable: try context.tool(named: "PluginExecutable").url, arguments: [ url.path, outputPath.path, ], inputFiles: [ url, ], outputFiles: [ outputPath ] ) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginWithInternalExecutable/Sources/PluginExecutable/Utilities.swift ================================================ import Foundation extension String { var quotedForSourceCode: String { return "\"" + self .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") + "\"" } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginWithInternalExecutable/Sources/PluginExecutable/main.swift ================================================ import Foundation // Sample source generator tool that emits a Swift variable declaration of a string containing the hex representation of the contents of a file as a quoted string. The variable name is the base name of the input file. The input file is the first argument and the output file is the second. if ProcessInfo.processInfo.arguments.count != 3 { print("usage: MySourceGenBuildTool ") exit(1) } let inputFile = ProcessInfo.processInfo.arguments[1] let outputFile = ProcessInfo.processInfo.arguments[2] let variableName = URL(fileURLWithPath: inputFile).deletingPathExtension().lastPathComponent let inputData = FileManager.default.contents(atPath: inputFile) ?? Data() let dataAsHex = inputData.map { String(format: "%02hhx", $0) }.joined() let outputString = "public let \(variableName) = \(dataAsHex.quotedForSourceCode)\n" let outputData = outputString.data(using: .utf8) FileManager.default.createFile(atPath: outputFile, contents: outputData) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "PluginsAndSnippets", products: [ .plugin( name: "PluginScriptProduct", targets: [ "PluginScriptTarget" ], ), .library( name: "MyLib", targets: [ "MyLib", ], ), ], targets: [ .plugin( name: "PluginScriptTarget", capability: .command( intent: .custom( verb: "do-something", description: "Do something", ), ), ), .target(name: "MyLib"), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Plugins/PluginScriptTarget/Script.swift ================================================ import PackagePlugin @main struct PluginScript: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) async throws { if !arguments.contains("--skip-dump") { dump(context) } if let target = try context.package.targets(named: ["MySnippet"]).first as? SourceModuleTarget { print("type of snippet target: \(target.kind)") } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Snippets/ContainsMain.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book @main struct foo { static func main() { print("hello, snippets. File: \(#file)") } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Snippets/ImportsProductTarget.swift ================================================ import MyLib libraryCall() ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Snippets/MySnippet.swift ================================================ print("hello, snippets. File: \(#file)") ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Snippets/SubDirectory/main.swift ================================================ print("hello, snippets! File: \(#file)") ================================================ FILE: Fixtures/Miscellaneous/Plugins/PluginsAndSnippets/Sources/MyLib/MyLib.swift ================================================ public func libraryCall() { print("From library") print("hello, snippets. File: \(#file)") } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PrebuildDependsExecutableTarget/Package.swift ================================================ // swift-tools-version: 6.3 import PackageDescription let package = Package( name: "PrebuildDependsExecutableTarget", platforms: [ .macOS(.v13) ], dependencies: [ ], targets: [ .executableTarget(name: "MyExecutable"), .plugin( name: "MyPlugin", capability: .buildTool(), dependencies: [ "MyExecutable" ] ), .executableTarget( name: "MyClient", plugins: [ "MyPlugin", ] ), ], swiftLanguageModes: [.v5] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/PrebuildDependsExecutableTarget/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { let outputFilePath = context.pluginWorkDirectoryURL.appendingPathComponent("MyGeneratedFile.swift") // We are attempting to assemble a prebuild command that relies on an executable that hasn't // been built yet. This should result in an error in prebuild. let myExecutable = try context.tool(named: "MyExecutable") return [ .prebuildCommand( displayName: "Prebuild that runs MyExecutable", executable: myExecutable.url, arguments: ["--output-file-path", outputFilePath.path], outputFilesDirectory: context.pluginWorkDirectoryURL ) ] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PrebuildDependsExecutableTarget/Sources/MyClient/client.swift ================================================ @main struct Client { static func main() throws { print(MyGeneratedStruct.message) } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/PrebuildDependsExecutableTarget/Sources/MyExecutable/tool.swift ================================================ import Foundation @main struct Tool { static func main() async throws { print("warning: Whoops! Coming from the executable", to: &StdErr.shared) let path = CommandLine.arguments[2] print("Writing a file to \(path)") try #""" public struct MyGeneratedStruct { public static var message: String = "You got struct'd" } """#.write(to: URL(fileURLWithPath: path), atomically: true, encoding: .utf8) } } struct StdErr: TextOutputStream { static var shared: Self = .init() mutating func write(_ string: String) { string.withCString { ptr in _ = fputs(ptr, stderr) } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxTesterPlugin/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "SandboxTesterPlugin", targets: [ // A local tool that uses a build tool plugin. .executableTarget( name: "MyLocalTool", plugins: [ "MySourceGenBuildToolPlugin", ] ), // The plugin that tries to write outside the sandbox. .plugin( name: "MySourceGenBuildToolPlugin", capability: .buildTool() ), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxTesterPlugin/Plugins/MySourceGenBuildToolPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { guard let target = target as? SourceModuleTarget else { return [] } // Check that we can write to the output directory. let allowedOutputPath = context.pluginWorkDirectory.string + "/" + UUID().uuidString if mkdir(allowedOutputPath, 0o777) != 0 { throw StringError("unexpectedly could not write to '\(allowedOutputPath)': \(String(utf8String: strerror(errno)))") } rmdir(allowedOutputPath) // Check that we cannot write to the user's home directory. let disallowedOutputPath = NSHomeDirectory() + "/" + UUID().uuidString if mkdir(disallowedOutputPath, 0o777) == 0 { throw StringError("unexpectedly could write to '\(disallowedOutputPath)'") } // Check that we can write to the temporary directory. let allowedTemporaryPath = NSTemporaryDirectory() + "/" + UUID().uuidString if mkdir(allowedTemporaryPath, 0o777) != 0 { throw StringError("unexpectedly could not write to '\(allowedTemporaryPath)': \(String(utf8String: strerror(errno)))") } rmdir(allowedTemporaryPath) return [] } struct StringError: Error, CustomStringConvertible { var error: String init(_ error: String) { self.error = error } var description: String { error } } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxTesterPlugin/Sources/MyLocalTool/main.swift ================================================ print("Hello plugin") ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxViolatingBuildToolPluginCommands/MyLibrary/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyLibrary", dependencies: [ .package(path: "../MyPlugin") ], targets: [ .target( name: "MyLibrary", plugins: [ .plugin(name: "PackageScribblerPlugin", package: "MyPlugin") ]) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxViolatingBuildToolPluginCommands/MyLibrary/Sources/MyLibrary/library.swift ================================================ public func MyLibraryStruct() -> String { return "This is \(foo)" } ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxViolatingBuildToolPluginCommands/MyPlugin/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "MyPlugin", products: [ .plugin( name: "PackageScribblerPlugin", targets: ["PackageScribblerPlugin"] ), ], targets: [ .plugin( name: "PackageScribblerPlugin", capability: .buildTool() ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/SandboxViolatingBuildToolPluginCommands/MyPlugin/Plugins/PackageScribblerPlugin/plugin.swift ================================================ import PackagePlugin import Foundation @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { let outputDir = target.directory.appending("generated") try FileManager.default.createDirectory(atPath: outputDir.string, withIntermediateDirectories: true) return [ .prebuildCommand( displayName: "Creating Foo.swift in the target directory…", executable: Path("/bin/bash"), arguments: [ "-c", "echo 'let foo = \"\(target.name)\"' > '\(outputDir)/foo.swift'" ], outputFilesDirectory: outputDir) ] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/SwiftFilePlugin/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "SwiftFilePluginFixture", products: [ .library( name: "SwiftFilePluginFixture", targets: ["SwiftFilePluginFixture"] ), ], targets: [ .target( name: "SwiftFilePluginFixture", plugins: [ .plugin(name: "MyCustomBuildTool") ] ), .plugin( name: "MyCustomBuildTool", capability: .buildTool() ) ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/SwiftFilePlugin/Plugins/MyCustomBuildTool/SwiftToolsBuildPlugin.swift ================================================ import Foundation import PackagePlugin @main struct SwiftToolsBuildPlugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { let formatExecutable = context.package.directoryURL.appending(components: "SimpleSwiftScript.swift") return [.buildCommand( displayName: "Run a swift script", executable: formatExecutable, arguments: [], inputFiles: [formatExecutable], outputFiles: [] )] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/SwiftFilePlugin/SimpleSwiftScript.swift ================================================ #!/usr/bin/env swift print("Hello, Build Tool Plugin!") ================================================ FILE: Fixtures/Miscellaneous/Plugins/SwiftFilePlugin/Sources/SwiftFilePluginFixture/SwiftFilePluginFixture.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Dependencies/Library/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "Library", products: [ .library(name: "Library", targets: ["Library"]), ], dependencies: [ .package(path: "../PluginOnly") ], targets: [ .target(name: "Library", plugins: [.plugin(name: "MyPlugin", package: "PluginOnly")]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Dependencies/Library/Sources/Library/Library.swift ================================================ public struct Library { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Dependencies/PluginOnly/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "PluginOnly", products: [ .plugin(name: "MyPlugin", targets: ["MyPlugin"]), ], targets: [ .plugin(name: "MyPlugin", capability: .buildTool()), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Dependencies/PluginOnly/Plugins/MyPlugin/plugin.swift ================================================ import PackagePlugin @main struct MyPlugin: BuildToolPlugin { func createBuildCommands(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] { return [] } } ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "TransitivePluginOnlyDependency", dependencies: [ .package(path: "Dependencies/Library"), ], targets: [ .target(name: "TransitivePluginOnlyDependency", dependencies: ["Library"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Plugins/TransitivePluginOnlyDependency/Sources/TransitivePluginOnlyDependency/TransitivePluginOnlyDependency.swift ================================================ public struct TransitivePluginOnlyDependency { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Foo.swift ================================================ @available(macOS, obsoleted: 13.0) func foo() { } func bar() { foo() } ================================================ FILE: Fixtures/Miscellaneous/RequiresOlderDeploymentTarget/Package.swift ================================================ // swift-tools-version:6.1 import PackageDescription let package = Package( name: "Foo", platforms: [.macOS(.v12)], products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/RootPackageWithConditionals/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "client", products: [ .library(name: "client", targets: ["client"]), ], dependencies: [ ], targets: [ .target(name: "client", dependencies: [ .target(name: "linuxOnly", condition: .when(platforms: [.linux])) ]), .target(name: "linuxOnly"), ] ) ================================================ FILE: Fixtures/Miscellaneous/RootPackageWithConditionals/Sources/client/client.swift ================================================ public struct client { public private(set) var text = "Hello, World!" public init() { } } ================================================ FILE: Fixtures/Miscellaneous/RootPackageWithConditionals/Sources/linuxOnly/linuxOnly.swift ================================================ public struct linuxOnly { public private(set) var text = "Hello, World!" public init() { #if os(Linux) print("bestOS") #else #error("not linux") #endif } } ================================================ FILE: Fixtures/Miscellaneous/ShowExecutables/app/Package.swift ================================================ // swift-tools-version:5.10 import PackageDescription let package = Package( name: "Dealer", products: [ .executable( name: "dealer", targets: ["Dealer"] ), ], dependencies: [ .package(path: "../deck-of-playing-cards"), ], targets: [ .executableTarget( name: "Dealer", path: "./" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/ShowExecutables/app/main.swift ================================================ print("I'm the dealer") ================================================ FILE: Fixtures/Miscellaneous/ShowExecutables/deck-of-playing-cards/Package.swift ================================================ // swift-tools-version:5.10 import PackageDescription let package = Package( name: "deck-of-playing-cards", products: [ .executable( name: "deck", targets: ["Deck"] ), ], targets: [ .executableTarget( name: "Deck", path: "./" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/ShowExecutables/deck-of-playing-cards/main.swift ================================================ print("I'm a deck of cards") ================================================ FILE: Fixtures/Miscellaneous/ShowTraits/app/Package.swift ================================================ // swift-tools-version:6.1 import PackageDescription let package = Package( name: "Dealer", products: [ .executable( name: "dealer", targets: ["Dealer"] ), ], traits: [ .trait(name: "trait1", description: "this trait is the default in app"), .trait(name: "trait2", description: "this trait is not the default in app"), .default(enabledTraits: ["trait1"]), ], dependencies: [ .package(path: "../deck-of-playing-cards", traits: ["trait3"]), ], targets: [ .executableTarget( name: "Dealer", path: "./" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/ShowTraits/app/main.swift ================================================ print("I'm the dealer") ================================================ FILE: Fixtures/Miscellaneous/ShowTraits/deck-of-playing-cards/Package.swift ================================================ // swift-tools-version:6.1 import PackageDescription let package = Package( name: "deck-of-playing-cards", products: [ .executable( name: "deck", targets: ["Deck"] ), ], traits: [ .trait(name: "trait3", description: "This trait is in a different package and not default.") ], targets: [ .executableTarget( name: "Deck", path: "./" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/ShowTraits/deck-of-playing-cards/main.swift ================================================ print("I'm a deck of cards") ================================================ FILE: Fixtures/Miscellaneous/Simple/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/Miscellaneous/Simple/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/SkipTests/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/SkipTests/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Example", targets: [ .target( name: "Example", dependencies: []), .testTarget( name: "ExampleTests", dependencies: ["Example"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/SkipTests/Sources/Example/Example.swift ================================================ struct Example { var text = "Hello, World!" var bool = false } ================================================ FILE: Fixtures/Miscellaneous/SkipTests/Tests/ExampleTests/MoreTests.swift ================================================ import XCTest @testable import Example class MoreTests: XCTestCase { func testExample3() { XCTAssertEqual(Example().text, "Hello, World!") } func testExample4() { XCTAssertEqual(Example().bool, false) } } ================================================ FILE: Fixtures/Miscellaneous/SkipTests/Tests/ExampleTests/Tests.swift ================================================ import XCTest @testable import Example class SomeTests: XCTestCase { func testExample1() { XCTAssertEqual(Example().text, "Hello, World!") } func testExample2() { XCTAssertEqual(Example().bool, false) } } ================================================ FILE: Fixtures/Miscellaneous/Spaces Fixture/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Spaces Fixture", targets: [ .target( name: "Module Name 2", dependencies: ["Module Name 1"]), .target( name: "Module Name 1", dependencies: []), ] ) ================================================ FILE: Fixtures/Miscellaneous/Spaces Fixture/Sources/Module Name 1/Foo.swift ================================================ public class Foo { var bar: Int = 0 } ================================================ FILE: Fixtures/Miscellaneous/Spaces Fixture/Sources/Module Name 2/main.swift ================================================ import Module_Name_1 public class Foo { var bar: Int = 0 } ================================================ FILE: Fixtures/Miscellaneous/SwiftBuild/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "TestableExe", targets: [ .executableTarget( name: "Test", path: "." ), ] ) ================================================ FILE: Fixtures/Miscellaneous/SwiftBuild/main.swift ================================================ print("done") ================================================ FILE: Fixtures/Miscellaneous/SwiftPMXCTestHelper/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/Miscellaneous/SwiftPMXCTestHelper/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "SwiftPMXCTestHelper", targets: [ .target(name: "SwiftPMXCTestHelper", path: "Sources"), .testTarget(name: "SwiftPMXCTestHelperTests", dependencies: ["SwiftPMXCTestHelper"]), .testTarget(name: "ObjCTests"), ] ) ================================================ FILE: Fixtures/Miscellaneous/SwiftPMXCTestHelper/Sources/SwiftPMXCTestHelper.swift ================================================ struct SwiftPMXCTestHelper { } ================================================ FILE: Fixtures/Miscellaneous/SwiftPMXCTestHelper/Tests/ObjCTests/ObjCTests.m ================================================ @import XCTest; @interface ObjCTests: XCTestCase @end @implementation ObjCTests - (void)testThisThing { } - (void)test_example { } - (void)nonTest { } @end ================================================ FILE: Fixtures/Miscellaneous/SwiftPMXCTestHelper/Tests/SwiftPMXCTestHelperTests/SwiftPMXCTestHelperTests.swift ================================================ import XCTest @testable import SwiftPMXCTestHelper class SwiftPMXCTestHelperTests1: XCTestCase { func testExample1() { } func test_Example2() { } func testExample3(arg: String) { } func nontest() { } } ================================================ FILE: Fixtures/Miscellaneous/SwiftRun/Package.swift ================================================ // swift-tools-version: 5.6 import PackageDescription let package = Package( name: "TestableExe", targets: [ .executableTarget( name: "Test", path: "." ), ] ) ================================================ FILE: Fixtures/Miscellaneous/SwiftRun/main.swift ================================================ print("done") ================================================ FILE: Fixtures/Miscellaneous/SystemModules/CFake/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CFake" ) ================================================ FILE: Fixtures/Miscellaneous/SystemModules/CFake/module.modulemap ================================================ module CFake [system] { header "/tmp/fake.h" link "fake" export * } ================================================ FILE: Fixtures/Miscellaneous/SystemModules/TestExec/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "TestExec", dependencies: [ .package(url: "../CFake", from: "1.0.0"), ], targets: [ .target(name: "TestExec", path: "Sources"), ] ) ================================================ FILE: Fixtures/Miscellaneous/SystemModules/TestExec/Sources/main.swift ================================================ import CFake print("Hello, \(GetFakeString())!") ================================================ FILE: Fixtures/Miscellaneous/TIF/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "TIF", products: [ .library(name: "TIF", targets: ["TIF"]) ], targets: [ .target( name: "TIF", resources: [ .copy("some.txt") ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TIF/README.md ================================================ # TIF A description of this package. ================================================ FILE: Fixtures/Miscellaneous/TIF/Sources/TIF/SomeAlert.swift ================================================ // // SomeAlert.swift // MyFwk // // Created by ankit on 10/31/19. // Copyright © 2019 Ankit. All rights reserved. // import Cocoa public class SomeAlert: NSViewController { @IBOutlet var label: NSTextField! override public func viewDidLoad() { super.viewDidLoad() let bundlePath = Bundle.main.path(forResource: "TIF_TIF", ofType: "bundle")! let bundle = Bundle(path: bundlePath)! let txt = bundle.path(forResource: "some", ofType: "txt")! let c = FileManager.default.contents(atPath: txt)! label.stringValue = String(data:c, encoding: .utf8)! // Do view setup here. } } ================================================ FILE: Fixtures/Miscellaneous/TIF/Sources/TIF/SomeAlert.xib ================================================ ================================================ FILE: Fixtures/Miscellaneous/TIF/Sources/TIF/SomeAssets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Miscellaneous/TIF/Sources/TIF/SomeAssets.xcassets/this_is_fine.imageset/Contents.json ================================================ { "images" : [ { "filename" : "this_is_fine.jpg", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Miscellaneous/TIF/Sources/TIF/some.txt ================================================ This is being read from some.txt file in the bundle. ================================================ FILE: Fixtures/Miscellaneous/TargetMismatch/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Sample", products: [ .library( name: "Sample", targets: [ "Sample" ] ), ], targets: [ .target( name: "Sample" ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TargetMismatch/Sources/Sample/main.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Package.swift ================================================ // swift-tools-version:5.9 import PackageDescription let package = Package( name: "libPkg", products: [ .executable(name: "ExampleApp", targets: ["ExampleApp"]), .library(name: "MainLib", targets: ["MainLib"]), ], targets: [ .executableTarget(name: "ExampleApp", dependencies: ["MainLib"], packageAccess: false), .target(name: "MainLib", dependencies: ["Core"], packageAccess: true), .target(name: "Core", dependencies: ["DataManager"]), .target(name: "DataManager", dependencies: ["DataModel"]), .target(name: "DataModel"), .testTarget(name: "MainLibTests", dependencies: ["MainLib"]), .testTarget(name: "BlackBoxTests", dependencies: ["MainLib"], packageAccess: false) ] ) ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Sources/Core/Core.swift ================================================ import DataManager public struct PublicCore { public let publicVar: Int public init(publicVar: Int) { self.publicVar = publicVar } public func publicCoreFunc() { managePublicFunc() } } ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Sources/DataManager/File.swift ================================================ import DataModel public func managePublicFunc() -> PublicData? { return nil } ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Sources/DataModel/File.swift ================================================ public class PublicData {} ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Sources/ExampleApp/main.swift ================================================ import MainLib publicFunc() ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Sources/MainLib/Lib.swift ================================================ import Core public func publicFunc() -> Int { print("public decl") return PublicCore(publicVar: 10).publicVar } ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Tests/BlackBoxTests/BlackBoxTests.swift ================================================ import MainLib import XCTest class BlackBoxTests: XCTestCase { func testBlackBox() { let x = publicFunc() XCTAssertTrue(x > 0) } } ================================================ FILE: Fixtures/Miscellaneous/TargetPackageAccess/libPkg/Tests/MainLibTests/MainLibTests.swift ================================================ import MainLib import XCTest class TestMainLib: XCTestCase { func testMainLib() { let x = publicFunc() XCTAssertTrue(x > 0) } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Async/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Async", targets: [ .target(name: "Async"), .testTarget(name: "AsyncTests", dependencies: ["Async"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Async/Sources/Async/Async.swift ================================================ struct Async { } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Async/Tests/AsyncTests/SwiftTests.swift ================================================ import XCTest @testable import Async @available(macOS 12.0, *) class AsyncTests: XCTestCase { func testAsync() async { } func testAsyncThrows() async throws { } @MainActor func testMainActor() async { XCTAssertTrue(Thread.isMainThread) } func testNotAsync() { XCTAssertTrue(Thread.isMainThread) } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Deprecation/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Simple"), .testTarget(name: "SimpleTests", dependencies: ["Simple"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Deprecation/Sources/Simple/Simple.swift ================================================ struct Simple { func hello() {} @available(*, deprecated, message: "use hello instead") func deprecatedHello() {} } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Deprecation/Tests/SimpleTests/SwiftTests.swift ================================================ import XCTest @testable import Simple class SimpleTests: XCTestCase { func testHello() { Simple().hello() } @available(*, deprecated, message: "testing deprecated API") func testDeprecatedHello() { Simple().deprecatedHello() } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Simple"), .testTarget(name: "SimpleTests", dependencies: ["Simple"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Sources/Simple/Simple.swift ================================================ struct Simple { } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Tests/SimpleTests/SwiftTests1.swift ================================================ import XCTest @testable import Simple class SimpleTests1: XCTestCase { func testExample1() { } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Tests/SimpleTests/SwiftTests2.swift ================================================ import XCTest @testable import Simple class SimpleTests2: XCTestCase { func testExample2() { } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Tests/SimpleTests/SwiftTests3.swift ================================================ import XCTest @testable import Simple extension SimpleTests1 { func testExample1_a() { } } extension SimpleTests2 { func testExample2_a() { } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Extensions/Tests/SimpleTests/SwiftTests4.swift ================================================ import XCTest @testable import Simple class SimpleTests4: XCTestCase { func testExample() { } func testExample1() { } func testExample2() { } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/IgnoresLinuxMain/Package.swift ================================================ // swift-tools-version:5.10 import PackageDescription let package = Package( name: "IgnoresLinuxMain", targets: [ .testTarget(name: "IgnoresLinuxMainTests"), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/IgnoresLinuxMain/Tests/IgnoresLinuxMainTests/SomeTest.swift ================================================ import XCTest final class SomeTests: XCTestCase { func testSomething() {} } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/IgnoresLinuxMain/Tests/LinuxMain.swift ================================================ fatalError("Should not use the contents of LinuxMain.swift") ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/NoTests/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Simple"), .testTarget(name: "SimpleTests", dependencies: ["Simple"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/NoTests/Sources/Simple/Simple.swift ================================================ struct Simple { } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/NoTests/Tests/SimpleTests/SwiftTests.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Simple/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription let package = Package( name: "Simple", targets: [ .target(name: "Simple", plugins: ["SimplePlugin"]), .testTarget(name: "SimpleTests", dependencies: ["Simple"]), .plugin(name: "SimplePlugin", capability: .buildTool()), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Simple/Plugins/SimplePlugin/plugin.swift ================================================ import PackagePlugin @main struct Simple: BuildToolPlugin { func createBuildCommands(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] { return [] } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Simple/Sources/Simple/Simple.swift ================================================ struct Simple { } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Simple/Tests/SimpleTests/SwiftTests.swift ================================================ import XCTest @testable import Simple class SimpleTests: XCTestCase { func testExample1() { } func test_Example2() { } func testThrowing() throws { } func testWithArgs(arg: String) { } func nontest() { } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Subclass/Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "Subclass", targets: [ .target(name: "Subclass"), .testTarget(name: "Module1Tests", dependencies: ["Subclass"]), .testTarget(name: "Module2Tests", dependencies: ["Subclass"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Subclass/Sources/Subclass/Subclass.swift ================================================ struct Subclass { } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Subclass/Tests/Module1Tests/Tests1.swift ================================================ import XCTest class Tests1: XCTestCase { func test11() { print("->Module1::Tests1::test11") } func test12() { print("->Module1::Tests1::test12") } func test13() { print("->Module1::Tests1::test13") } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Subclass/Tests/Module1Tests/Tests2.swift ================================================ import XCTest class Tests3: Tests2 { override func test11() { print("->Module1::Tests3::test11") } override func test21() { print("->Module1::Tests3::test21") } func test31() { print("->Module1::Tests3::test31") } func test32() { print("->Module1::Tests3::test32") } func test33() { print("->Module1::Tests3::test33") } } class Tests2: Tests1 { func test21() { print("->Module1::Tests2::test21") } func test22() { print("->Module1::Tests2::test22") } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/Subclass/Tests/Module2Tests/Test1.swift ================================================ import XCTest class Tests1: XCTestCase { func test11() { print("->Module2::Tests1::test11") } func test12() { print("->Module2::Tests1::test12") } func test13() { print("->Module2::Tests1::test13") } } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/SwiftTesting/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "SwiftTesting", targets: [ .testTarget(name: "SwiftTestingTests"), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/SwiftTesting/Sources/SwiftTesting/SwiftTesting.swift ================================================ ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/SwiftTesting/Tests/SwiftTestingTests/SwiftTestingTests.swift ================================================ import Testing @Test("SOME TEST FUNCTION") func someTestFunction() {} ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/hello world/Package.swift ================================================ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "hello world", products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "hello world", targets: ["hello world"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "hello world", dependencies: []), .testTarget( name: "hello world tests", dependencies: ["hello world"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/hello world/Sources/hello world/hello world.swift ================================================ struct hello_world { var text = "Hello, World!" } ================================================ FILE: Fixtures/Miscellaneous/TestDiscovery/hello world/Tests/hello world tests/hello world tests.swift ================================================ import XCTest @testable import hello_world final class hello_worldTests: XCTestCase { func testExample() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. XCTAssertEqual(hello_world().text, "Hello, World!") } } ================================================ FILE: Fixtures/Miscellaneous/TestMultipleFailureSwiftTesting/Package.swift ================================================ // swift-tools-version: 6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "TestMultipleFailureSwiftTesting", targets: [ .testTarget( name: "TestMultipleFailureSwiftTestingTests" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/TestMultipleFailureSwiftTesting/Tests/TestMultipleFailureSwiftTestingTests/TestMultipleFailureSwiftTestingTests.swift ================================================ import Testing @Test func testFailure1() async throws { #expect(Bool(false), "ST Test failure 1") } @Test func testFailure2() async throws { #expect(Bool(false), "ST Test failure 2") } @Test func testFailure3() async throws { #expect(Bool(false), "ST Test failure 3") } @Test func testFailure4() async throws { #expect(Bool(false), "ST Test failure 4") } @Test func testFailure5() async throws { #expect(Bool(false), "ST Test failure 5") } @Test func testFailure6() async throws { #expect(Bool(false), "ST Test failure 6") } @Test func testFailure7() async throws { #expect(Bool(false), "ST Test failure 7") } @Test func testFailure8() async throws { #expect(Bool(false), "ST Test failure 8") } @Test func testFailure9() async throws { #expect(Bool(false), "ST Test failure 9") } @Test func testFailure10() async throws { #expect(Bool(false), "ST Test failure 10") } ================================================ FILE: Fixtures/Miscellaneous/TestMultipleFailureXCTest/Package.swift ================================================ // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "TestMultipleFailureXCTest", targets: [ .testTarget( name: "TestMultipleFailureXCTestTests" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/TestMultipleFailureXCTest/Tests/TestMultipleFailureXCTestTests/TestMultipleFailureXCTestTests.swift ================================================ import XCTest final class TestMultipleFailureXCTestTests: XCTestCase { func testFailure1() throws { XCTAssertFalse(true, "Test failure 1") } func testFailure2() throws { XCTAssertFalse(true, "Test failure 2") } func testFailure3() throws { XCTAssertFalse(true, "Test failure 3") } func testFailure4() throws { XCTAssertFalse(true, "Test failure 4") } func testFailure5() throws { XCTAssertFalse(true, "Test failure 5") } func testFailure6() throws { XCTAssertFalse(true, "Test failure 6") } func testFailure7() throws { XCTAssertFalse(true, "Test failure 7") } func testFailure8() throws { XCTAssertFalse(true, "Test failure 8") } func testFailure9() throws { XCTAssertFalse(true, "Test failure 9") } func testFailure10() throws { XCTAssertFalse(true, "Test failure 10") } } ================================================ FILE: Fixtures/Miscellaneous/TestSingleFailureSwiftTesting/Package.swift ================================================ // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "TestFailuresSwiftTesting", targets: [ .testTarget( name: "TestFailuresSwiftTestingTests" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/TestSingleFailureSwiftTesting/Tests/TestFailuresSwiftTestingTests/TestFailuresSwiftTestingTests.swift ================================================ import Testing @Test func example() async throws { #expect(Bool(false), "Purposely failing & validating XML espace \"'<>") } ================================================ FILE: Fixtures/Miscellaneous/TestSingleFailureXCTest/Package.swift ================================================ // swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "TestFailures", targets: [ .testTarget( name: "TestFailuresTests" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/TestSingleFailureXCTest/Tests/TestFailuresTests/TestFailuresTests.swift ================================================ import XCTest final class TestFailuresTests: XCTestCase { func testExample() throws { XCTAssertFalse(true, "Purposely failing & validating XML espace \"'<>") } } ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let package = Package( name: "TestableAsyncExe", platforms: [ .macOS(.v10_15), ], targets: [ .executableTarget( name: "TestableAsyncExe1" ), .executableTarget( name: "TestableAsyncExe2" ), .executableTarget( name: "TestableAsyncExe3" ), .executableTarget( name: "TestableAsyncExe4" ), .testTarget( name: "TestableAsyncExeTests", dependencies: [ "TestableAsyncExe1", "TestableAsyncExe2", "TestableAsyncExe3", "TestableAsyncExe4", ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Sources/TestableAsyncExe1/main.swift ================================================ public func GetAsyncGreeting1() async -> String { return "Hello, async world" } await print("\(GetAsyncGreeting1())!") ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Sources/TestableAsyncExe2/main.swift ================================================ public func GetAsyncGreeting2() async -> String { return "Hello, async planet" } await print("\(GetAsyncGreeting2())!") ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Sources/TestableAsyncExe3/NonMain.swift ================================================ @main struct AsyncMain3 { static func main() async { print(await getGreeting3()) } static func getGreeting3() async -> String { return "Hello, async galaxy" } } ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Sources/TestableAsyncExe4/NonMain.swift ================================================ @main struct AsyncMain4 { static func main() async { print(await getGreeting4()) } static func getGreeting4() async -> String { return "Hello, async universe" } } ================================================ FILE: Fixtures/Miscellaneous/TestableAsyncExe/Tests/TestableAsyncExeTests/TestableAsyncExeTests.swift ================================================ import XCTest @testable import TestableAsyncExe1 @testable import TestableAsyncExe2 @testable import TestableAsyncExe3 @testable import TestableAsyncExe4 final class TestableAsyncExeTests: XCTestCase { func testExample() async throws { let greeting1 = await GetAsyncGreeting1() print(greeting1) XCTAssertEqual(greeting1, "Hello, async world") let greeting2 = await GetAsyncGreeting2() print(greeting2) XCTAssertEqual(greeting2, "Hello, async planet") let greeting3 = await AsyncMain3.getGreeting3() print(greeting3) XCTAssertEqual(greeting3, "Hello, async galaxy") let greeting4 = await AsyncMain4.getGreeting4() print(greeting4) XCTAssertEqual(greeting4, "Hello, async universe") } } ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let package = Package( name: "TestableExe", targets: [ .executableTarget( name: "TestableExe1", linkerSettings: [ .linkedLibrary("swiftCore", .when(platforms: [.windows])), // for swift_addNewDSOImage ] ), .executableTarget( name: "TestableExe2", linkerSettings: [ .linkedLibrary("swiftCore", .when(platforms: [.windows])), // for swift_addNewDSOImage ] ), .executableTarget( name: "TestableExe3", linkerSettings: [ .linkedLibrary("swiftCore", .when(platforms: [.windows])), // for swift_addNewDSOImage ] ), .testTarget( name: "TestableExeTests", dependencies: [ "TestableExe1", "TestableExe2", "TestableExe3", ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Sources/TestableExe1/main.swift ================================================ public func GetGreeting1() -> String { return "Hello, world" } print("\(GetGreeting1())!") ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Sources/TestableExe2/main.swift ================================================ public func GetGreeting2() -> String { return "Hello, planet" } print("\(GetGreeting2())!") ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Sources/TestableExe3/include/TestableExe3.h ================================================ const char * GetGreeting3(); ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Sources/TestableExe3/main.c ================================================ #include #include "include/TestableExe3.h" const char * GetGreeting3() { return "Hello, universe"; } int main() { printf("%s!\n", GetGreeting3()); } ================================================ FILE: Fixtures/Miscellaneous/TestableExe/Tests/TestableExeTests/TestableExeTests.swift ================================================ import XCTest @testable import TestableExe1 @testable import TestableExe2 // import TestableExe3 import class Foundation.Bundle final class TestableExeTests: XCTestCase { #if os(Windows) let eol = "\r\n" #else let eol = "\n" #endif func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. print(GetGreeting1()) XCTAssertEqual(GetGreeting1(), "Hello, world") print(GetGreeting2()) XCTAssertEqual(GetGreeting2(), "Hello, planet") // XCTAssertEqual(String(cString: GetGreeting3()), "Hello, universe") // Some of the APIs that we use below are available in macOS 10.13 and above. guard #available(macOS 10.13, *) else { return } var execPath = productsDirectory.appendingPathComponent("TestableExe1") var process = Process() process.executableURL = execPath var pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() var data = pipe.fileHandleForReading.readDataToEndOfFile() var output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, world!\(eol)") execPath = productsDirectory.appendingPathComponent("TestableExe2") process = Process() process.executableURL = execPath pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() data = pipe.fileHandleForReading.readDataToEndOfFile() output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, planet!\(eol)") execPath = productsDirectory.appendingPathComponent("TestableExe3") process = Process() process.executableURL = execPath pipe = Pipe() process.standardOutput = pipe try process.run() process.waitUntilExit() data = pipe.fileHandleForReading.readDataToEndOfFile() output = String(data: data, encoding: .utf8) XCTAssertEqual(output, "Hello, universe!\(eol)") } /// Returns path to the built products directory. var productsDirectory: URL { #if os(macOS) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return bundle.bundleURL.deletingLastPathComponent() } fatalError("couldn't find the products directory") #else return Bundle.main.bundleURL #endif } static var allTests = [ ("testExample", testExample), ] } ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithDifferentProductName/Package.swift ================================================ // swift-tools-version: 5.5 import PackageDescription let package = Package( name: "TestableExe", products: [ .executable(name: "testable-exe", targets: ["TestableExe"]) ], targets: [ .executableTarget( name: "TestableExe" ), .testTarget( name: "TestableExeTests", dependencies: [ "TestableExe", ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithDifferentProductName/Sources/TestableExe/main.swift ================================================ public func functionFromTestableExecutable() { print("Hello, world") } functionFromTestableExecutable() ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithDifferentProductName/Tests/TestableExeTests/TestableExeTests.swift ================================================ import XCTest @testable import TestableExe final class TestableExeTests: XCTestCase { func testExample() throws { functionFromTestableExecutable() } } ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithResources/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "TestableExe", targets: [ .executableTarget( name: "TestableExe", resources: [.embedInCode("foo.txt")] ), .testTarget( name: "TestableExeTests", dependencies: [ "TestableExe", ] ), ] ) ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithResources/Sources/TestableExe/foo.txt ================================================ bar ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithResources/Sources/TestableExe/main.swift ================================================ public func GetGreeting1() -> String { return String(decoding: PackageResources.foo_txt, as: UTF8.self) } print("\(GetGreeting1())!") ================================================ FILE: Fixtures/Miscellaneous/TestableExeWithResources/Tests/TestableExeTests/TestableExeTests.swift ================================================ import XCTest @testable import TestableExe final class TestableExeTests: XCTestCase { func testExample() throws { XCTAssertEqual(GetGreeting1(), "bar\n") } } ================================================ FILE: Fixtures/Miscellaneous/Unicode/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription import Foundation /// This string demonstrates as many complications of Unicode as possible. let complicatedString = "πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄" // π U+03C0: A simple BMP scalar. //‎ שּׁ U+FB2C: Changes under both NFC and NFD. // µ U+00B5: Changes under NFKC and NFKD. // 𝄞 U+1D11E: Simple non‐BMP scalar. // 🇺🇳 U+1F1FA U+1F1F3: Multi‐scalar character. // 🇮🇱 U+1F1EE U+1F1F1: Second consecutive regional indicator. (Complicated grapheme breaking.) // x̱̱̱̱̱̄̄̄̄̄ U+0078 (U+0331 U+0304) × 5: Extremely long combining sequence. (Also reordrant under normalization.) // The following verifies that sources haven’t been normalized, which would reduce the test’s effectiveness. var verify = "\u{03C0}\u{0FB2C}\u{00B5}\u{1D11E}\u{1F1FA}\u{1F1F3}\u{1F1EE}\u{1F1F1}\u{0078}\u{0331}\u{0304}\u{0331}\u{0304}\u{0331}\u{0304}\u{0331}\u{0304}\u{0331}\u{0304}" assert( complicatedString.unicodeScalars.elementsEqual(verify.unicodeScalars), "\(complicatedString) ≠ \(verify)") let package = Package( name: complicatedString, products: [ .library( name: complicatedString, targets: [complicatedString]), .executable(name: complicatedString + "‐tool", targets: [complicatedString + "‐tool"]) ], dependencies: [ .package(url: "../UnicodeDependency‐\(complicatedString)", from: "1.0.0") ], targets: [ .target( name: complicatedString, dependencies: [.product(name: "UnicodeDependency‐\(complicatedString)")]), .target( name: complicatedString + "‐tool", dependencies: [.target(name: complicatedString)]), .testTarget( name: complicatedString + "Tests", dependencies: [.target(name: complicatedString)]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Unicode/README.md ================================================ # Unicode This fixture makes extensive use of exotic Unicode. While deliberately trying to break a as many common false assumptions as possible, *this is a valid package*, and clients are encouraged to test their functionality with it. A tool that successfully handles this package is unlikely to encounter problems with any real‐world package in any human language. The neighbouring package `UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄` must be placed next this package and tagged with version 1.0.0. (This is necessary to use Unicode in dependency URLs in this package’s manifest.) ================================================ FILE: Fixtures/Miscellaneous/Unicode/Sources/πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/πשּׁµ𝄞🇺🇳x̱̱̱̱̱̄̄̄̄̄.swift ================================================ public struct πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄ { public init() {} public var πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄ = "Hello, World!" } ================================================ FILE: Fixtures/Miscellaneous/Unicode/Sources/πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄‐tool/main.swift ================================================ import π_µ_____x__________ print(πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄().πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄) ================================================ FILE: Fixtures/Miscellaneous/Unicode/Tests/LinuxMain.swift ================================================ import XCTest import π_µ_____x__________Tests var tests = [XCTestCaseEntry]() tests += π_µ_____x__________Tests.__allTests() XCTMain(tests) ================================================ FILE: Fixtures/Miscellaneous/Unicode/Tests/πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests/XCTestManifests.swift ================================================ #if !canImport(ObjectiveC) import XCTest extension πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests = [ ("testπשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄", testπשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄), ] } public func __allTests() -> [XCTestCaseEntry] { return [ testCase(πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests.__allTests__πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests), ] } #endif ================================================ FILE: Fixtures/Miscellaneous/Unicode/Tests/πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests/πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests.swift ================================================ import XCTest // TODO: - Can imports be made less ugly? (SR‐10839) //@testable import πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄ @testable import π_µ_____x__________ // (These characters all work for identifiers. See below.) final class πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄Tests: XCTestCase { func testπשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄() { XCTAssertEqual(πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄().πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄, "Hello, World!") } } ================================================ FILE: Fixtures/Miscellaneous/Unicode/Utilities/SomeOtherPackage/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription let package = Package( name: "SomeOtherPackage", dependencies: [ .package(path: "../../"), ], targets: [ .target( name: "SomeOtherPackage", dependencies: ["πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄"]), ] ) ================================================ FILE: Fixtures/Miscellaneous/Unicode/Utilities/SomeOtherPackage/README.md ================================================ # SomeOtherPackage This nested utility package refers back to the main repository as a local dependency. If client tools accidentally pick this package up as part of the main repository package, dependency resolution could become circular or otherwise problematic. (Prior to direct Xcode support for packages, this repository structure was a common way of hiding executable utilities from `generate-xcodeproj`, so that the main package would still be viable for iOS.) ================================================ FILE: Fixtures/Miscellaneous/Unicode/Utilities/SomeOtherPackage/Sources/SomeOtherPackage/main.swift ================================================ print("Hello, world!") ================================================ FILE: Fixtures/Miscellaneous/UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/Package.swift ================================================ // swift-tools-version:5.1 import PackageDescription let package = Package( name: "UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄", products: [ .library( name: "UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄", targets: ["UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄"]), ], targets: [ .target( name: "UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄", dependencies: []), ] ) ================================================ FILE: Fixtures/Miscellaneous/UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/README.md ================================================ # UnicodeDependency‐πשּׁµ𝄞🇺🇳x̱̱̱̱̱̄̄̄̄̄ A description of this package. ================================================ FILE: Fixtures/Miscellaneous/UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/Sources/UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄/UnicodeDependency‐πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄.swift ================================================ struct UnicodeDependency_UnicodeDependency_πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄ { var text = "Hello, World!" } ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/A/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "A", products: [ .executable(name: "aexec", targets: ["ATarget"]) ], dependencies: [ .package(url: "../B", from: "1.0.0"), .package(url: "../C", from: "1.0.0") ], targets: [ .target(name: "ATarget", dependencies: [ .product(name: "BLibrary") ]) ]) ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/A/Sources/ATarget/main.swift ================================================ import BTarget1 BTarget1() ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/B/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "B", products: [ .library(name: "BLibrary", targets: ["BTarget1"]), .executable(name: "bexec", targets: ["BTarget2"]) ], targets: [ .target(name: "BTarget1", dependencies: []), .target(name: "BTarget2", dependencies: []) ]) ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/B/Sources/BTarget1/BTarget1.swift ================================================ public struct BTarget1 { public init() {} } ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/B/Sources/BTarget2/main.swift ================================================ print("BTarget2") ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/C/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "C", products: [ .executable(name: "cexec", targets: ["CTarget"]) ], targets: [ .target(name: "CTarget", dependencies: []) ]) ================================================ FILE: Fixtures/Miscellaneous/UnreachableTargets/C/Sources/CTarget/main.swift ================================================ print("CTarget") ================================================ FILE: Fixtures/Miscellaneous/VersionSpecificManifest/Foo.swift ================================================ public func foo() { {}() } ================================================ FILE: Fixtures/Miscellaneous/VersionSpecificManifest/Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/VersionSpecificManifest/Package@swift-5.0.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "Foo", targets: ["Foo"]), ], targets: [ .target(name: "Foo", path: "./"), ] ) ================================================ FILE: Fixtures/Miscellaneous/WarningWithinFunction/Package.swift ================================================ // swift-tools-version: 5.7 import PackageDescription let package = Package( name: "app", products: [ .executable(name: "app", targets: ["app"]) ], targets: [ .executableTarget( name: "app", path: "./" ) ] ) ================================================ FILE: Fixtures/Miscellaneous/WarningWithinFunction/app.swift ================================================ @main struct App { public static func main() { var myvariable = 0 } } ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps1/AppPkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "AppPkg", dependencies: [ .package(path: "../UtilsPkg"), ], targets: [ .executableTarget( name: "App", dependencies: [ "Utils", .product(name: "Utils", package: "UtilsPkg", moduleAliases: ["Utils": "GameUtils"]) ], path: "./Sources/App"), .target( name: "Utils", dependencies: [], path: "./Sources/Utils" ) ] ) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps1/AppPkg/Sources/App/main.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import Utils import GameUtils Utils.echoModule() let level = LevelDetector.detect(for: "TestUser") print(level) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps1/AppPkg/Sources/Utils/FileUtils.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ public func echoModule() { print("Utils") } ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps1/UtilsPkg/Package.swift ================================================ // swift-tools-version:5.5 import PackageDescription let package = Package( name: "UtilsPkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []), ] ) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps1/UtilsPkg/Sources/Utils/FileUtils.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ public struct LevelDetector: Equatable { public static func detect(for user: String) -> Int { return user.count } } ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/Apkg/Package.swift ================================================ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Apkg", products: [ .executable(name: "AApp", targets: ["AApp"]), .library(name: "Utils", type: .dynamic, targets: ["Utils"]), ], targets: [ .executableTarget(name: "AApp", dependencies: ["Utils"]), .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/Apkg/Sources/AApp/main.swift ================================================ import Utils utilsInA() ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/Apkg/Sources/Utils/File.swift ================================================ public func utilsInA() { print("Utils in A") } ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/AppPkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "AppPkg", dependencies: [ .package(path: "../Apkg"), .package(path: "../Bpkg"), ], targets: [ .executableTarget( name: "App", dependencies: [ .product(name: "Utils", package: "Apkg", moduleAliases: ["Utils": "AUtils"] ), .product(name: "Utils", package: "Bpkg", moduleAliases: ["Utils": "BUtils"] ) ] ), ] ) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/AppPkg/Sources/App/main.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import AUtils import BUtils utilsInA() utilsInB() ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/Bpkg/Package.swift ================================================ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Bpkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/DirectDeps2/Bpkg/Sources/Utils/File.swift ================================================ public func utilsInB() { print("Utils in B") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/APkg/Package.swift ================================================ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "APkg", products: [ .library(name: "A", targets: ["A"]), ], dependencies: [ .package(path: "../BPkg"), .package(path: "../CPkg"), ], targets: [ .target(name: "A", dependencies: [ .product(name: "Utils", package: "BPkg", moduleAliases: ["Utils": "FooUtils"] ), .product(name: "Utils", package: "CPkg", moduleAliases: ["Utils": "CarUtils"] ), ]), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/APkg/Sources/A/File.swift ================================================ import FooUtils import CarUtils public func funcInA() { print("func in A") utilsInB() utilsInC() } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/AppPkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "AppPkg", dependencies: [ .package(path: "../APkg"), .package(path: "../XPkg"), ], targets: [ .executableTarget( name: "App", dependencies: [ .product(name: "A", package: "APkg", moduleAliases: ["FooUtils": "AFooUtils"] ), .product(name: "X", package: "XPkg", moduleAliases: ["Utils": "XUtils", "FooUtils": "XFooUtils"] ) ]), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/AppPkg/Sources/App/main.swift ================================================ import A import X import AFooUtils import CarUtils import XFooUtils import XUtils funcInA() funcInX() ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/BPkg/Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "BPkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/BPkg/Sources/Utils/File.swift ================================================ public func utilsInB() { print("utils in B") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/CPkg/Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "CPkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/CPkg/Sources/Utils/File.swift ================================================ public func utilsInC() { print("utils in C") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/XPkg/Package.swift ================================================ // swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "XPkg", products: [ .library(name: "X", targets: ["X"]), ], dependencies: [ .package(path: "../YPkg"), ], targets: [ .target(name: "X", dependencies: [ "Utils", .product(name: "Utils", package: "YPkg", moduleAliases: ["Utils": "FooUtils"] ), ]), .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/XPkg/Sources/Utils/File.swift ================================================ public func utilsInX() { print("utils in X") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/XPkg/Sources/X/File.swift ================================================ import Utils import FooUtils public func funcInX() { print("func in X") utilsInX() utilsInY() } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/YPkg/Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "YPkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []) ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps1/YPkg/Sources/Utils/File.swift ================================================ public func utilsInY() { print("utils in Y") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Apkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "Apkg", products: [ .library(name: "A", targets: ["A"]), ], dependencies: [ .package(path: "../Bpkg"), .package(path: "../Cpkg"), ], targets: [ .target(name: "A", dependencies: [ .product(name: "Utils", package: "Bpkg", moduleAliases: ["Utils": "BUtils"]), .product(name: "Utils", package: "Cpkg", moduleAliases: ["Utils": "CUtils"]), ] ), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Apkg/Sources/A/File.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import BUtils import CUtils public func funcA() { print("func A") BUtils.funcB() CUtils.funcC() } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/AppPkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "AppPkg", dependencies: [ .package(path: "../Apkg"), .package(path: "../Xpkg"), ], targets: [ .executableTarget( name: "App", dependencies: [ .product(name: "A", package: "Apkg" ), .product(name: "Utils", package: "Xpkg", moduleAliases: ["Utils": "XUtils"] ), ]), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/AppPkg/Sources/App/main.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ import A import XUtils print("START") funcA() funcX() ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Bpkg/Package.swift ================================================ // swift-tools-version:5.7 import PackageDescription let package = Package( name: "Bpkg", products: [ .library(name: "Utils", type: .static, targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Bpkg/Sources/Utils/File.swift ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ public func funcB() { print("func B") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Cpkg/Package.swift ================================================ // swift-tools-version: 5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Cpkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Cpkg/Sources/Utils/File.swift ================================================ public func funcC() { print("func C") } ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Xpkg/Package.swift ================================================ // swift-tools-version: 5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Xpkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: []), ] ) ================================================ FILE: Fixtures/ModuleAliasing/NestedDeps2/Xpkg/Sources/Utils/File.swift ================================================ public func funcX() { print("func X") } ================================================ FILE: Fixtures/ModuleMaps/Direct/App/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "App", dependencies: [ .package(url: "../CFoo", from: "1.0.0"), ], targets: [ .target(name: "App", path: "./"), ] ) ================================================ FILE: Fixtures/ModuleMaps/Direct/App/main.swift ================================================ import CFoo print(foo()) ================================================ FILE: Fixtures/ModuleMaps/Direct/CFoo/C/foo.c ================================================ int foo() { return 123; } ================================================ FILE: Fixtures/ModuleMaps/Direct/CFoo/C/foo.h ================================================ int foo(); ================================================ FILE: Fixtures/ModuleMaps/Direct/CFoo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "CFoo" ) ================================================ FILE: Fixtures/ModuleMaps/Direct/CFoo/module.modulemap ================================================ module CFoo { header "C/foo.h" link "foo" export * } ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageA/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "packageA", dependencies: [ .package(url: "../packageB", from: "1.0.0"), ], targets: [ .target(name: "packageA", dependencies: ["packageB"], path: "Sources"), ] ) ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageA/Sources/main.swift ================================================ /** * Copyright IBM Corporation 2016 * Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ import y let myY = Y() print("calling Y.bar()") myY.bar() /* import x let myX = X() print("calling X.foo()") myX.foo() */ ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageB/.gitignore ================================================ .build Packages ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageB/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "packageB", products: [ .library(name: "packageB", targets: ["y"]), ], dependencies: [ .package(url: "../packageC", from: "1.0.0"), ], targets: [ .target(name: "y", dependencies: ["packageC"]), ] ) ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageB/Sources/y/y.swift ================================================ /** * Copyright IBM Corporation 2016 * Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ import x public class Y { public init() {} public func bar() { print("Y.bar() called") let myX = X() myX.foo() } } ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageC/.gitignore ================================================ .build Packages ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageC/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "packageC", products: [ .library(name: "packageC", targets: ["x"]), ], dependencies: [ .package(url: "../packageD", from: "1.0.0"), ], targets: [ .target(name: "x", dependencies: ["CFoo"]), ] ) ================================================ FILE: Fixtures/ModuleMaps/Transitive/packageC/Sources/x/x.swift ================================================ /** * Copyright IBM Corporation 2016 * Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ import CFoo public class X { public init() {} public func foo() { print("X.foo() called") let jpegData = CFoo.foo() print(jpegData) } } ================================================ FILE: Fixtures/PIFBuilder/BasicExecutable/Package.swift ================================================ // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "BasicExecutable", targets: [ .executableTarget( name: "Executable", ), ] ) ================================================ FILE: Fixtures/PIFBuilder/BasicExecutable/Sources/BasicExecutable/BasicExecutable.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book @main struct BasicExecutable { static func main() { print("Hello, world!") } } ================================================ FILE: Fixtures/PIFBuilder/CCPackage/Package.swift ================================================ // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "CCPackage", products: [ .library(name: "CCTarget", type: .static, targets: ["CCTarget"]), ], targets: [ .target(name: "CCTarget", ), .executableTarget(name: "executable", dependencies: ["CCTarget"]), ] ) ================================================ FILE: Fixtures/PIFBuilder/CCPackage/Sources/CCTarget/include/test.h ================================================ #include ================================================ FILE: Fixtures/PIFBuilder/CCPackage/Sources/CCTarget/test.cc ================================================ #include ================================================ FILE: Fixtures/PIFBuilder/CCPackage/Sources/executable/executable.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book @main struct Executable { static func main() { print("Hello, world!") } } ================================================ FILE: Fixtures/PIFBuilder/ConditionalBuildSettings/Package.swift ================================================ // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "ConditionalBuildSettings", products: [ .library( name: "ConditionalBuildSettings", type: .dynamic, targets: ["ConditionalBuildSettings"] ), ], targets: [ .target( name: "ConditionalBuildSettings", linkerSettings: [ .unsafeFlags(["-Xlinker", "-interposable"], .when(configuration: .debug)), ] ), ] ) ================================================ FILE: Fixtures/PIFBuilder/ConditionalBuildSettings/Sources/ConditionalBuildSettings/ConditionalBuildSettings.swift ================================================ public func placeholder() {} ================================================ FILE: Fixtures/PIFBuilder/Library/.gitignore ================================================ .DS_Store /.build /Packages xcuserdata/ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc ================================================ FILE: Fixtures/PIFBuilder/Library/Package.swift ================================================ // swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Library", products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "LibraryAuto", targets: ["Library"] ), .library( name: "LibraryStatic", type: .static, targets: ["Library"] ), .library( name: "LibraryDynamic", type: .dynamic, targets: ["Library"] ), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( name: "Library" ), .testTarget( name: "LibraryTests", dependencies: ["Library"] ), ] ) ================================================ FILE: Fixtures/PIFBuilder/Library/Sources/Library/Library.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book ================================================ FILE: Fixtures/PIFBuilder/Library/Tests/LibraryTests/LibraryTests.swift ================================================ import Testing @testable import Library @Test func example() async throws { // Write your test here and use APIs like `#expect(...)` to check expected conditions. } ================================================ FILE: Fixtures/PIFBuilder/PackageWithSDKSpecialization/Package.swift ================================================ // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "PackageWithSDKSpecialization", platforms: [ .macOS("10.15.foo") ], products: [ .library( name: "PackageWithSDKSpecialization", targets: ["PackageWithSDKSpecialization"]), ], targets: [ .target( name: "PackageWithSDKSpecialization", dependencies: [] ), .target( name: "Executable", dependencies: ["PackageWithSDKSpecialization"] ), ] ) ================================================ FILE: Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/Executable/main.swift ================================================ print("Hello, world!") ================================================ FILE: Fixtures/PIFBuilder/PackageWithSDKSpecialization/Sources/PackageWithSDKSpecialization/PackageWithSDKSpecialization.swift ================================================ struct PackageWithSDKSpecialization { var text = "Hello, World!" } ================================================ FILE: Fixtures/PIFBuilder/Simple/.gitignore ================================================ .DS_Store /.build /Packages xcuserdata/ DerivedData/ .swiftpm/configuration/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc ================================================ FILE: Fixtures/PIFBuilder/Simple/Package.swift ================================================ // swift-tools-version: 6.2 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Simple", products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "Simple", targets: ["Simple"] ), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( name: "Simple" ), .testTarget( name: "SimpleTests", dependencies: ["Simple"] ), ] ) ================================================ FILE: Fixtures/PIFBuilder/Simple/Sources/Simple/Simple.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book public struct Person { public let name: String public init(name: String) { self.name = name } } extension Person: CustomStringConvertible { public var description: String { return name } } public func greet(person: Person? = nil) -> String { let name = if let person { person.name } else { "World" } return "Hello, \(name)!" } ================================================ FILE: Fixtures/PIFBuilder/Simple/Tests/SimpleTests/SimpleTests.swift ================================================ import Testing import XCTest import Simple final public class XCTesting: XCTestCase { func testGreetWithEmptyArgument() { let actual = greet() XCTAssertEqual(actual, "Hello, World!") } func testGreetWithNonEmptyArgument() { let name = "MyName" let person = Person(name: name) let actual = greet(person: person) XCTAssertEqual(actual, "Hello, \(name)!") } } @Suite struct STTestTests { @Test("STTest tests") func testGreetWithEmptyArgument() { let actual = greet() #expect(actual == "Hello, World!") } @Test("STTest tests") func testGreetWithNonEmptyArgument() { let name = "MyName" let person = Person(name: name) let actual = greet(person: person) #expect(actual == "Hello, \(name)!") } } ================================================ FILE: Fixtures/PIFBuilder/UnknownPlatforms/Package.swift ================================================ // swift-tools-version: 6.2 import PackageDescription let package = Package( name: "UnknownPlatforms", targets: [ .executableTarget( name: "UnknownPlatforms", swiftSettings: [ .define("FOO", .when(platforms: [.custom("DoesNotExist")])), .define("BAR", .when(platforms: [.linux])), .define("BAZ", .when(platforms: [.macOS])), ], ), ] ) ================================================ FILE: Fixtures/PIFBuilder/UnknownPlatforms/Sources/UnknownPlatforms/UnknownPlatforms.swift ================================================ // The Swift Programming Language // https://docs.swift.org/swift-book @main struct UnknownPlatforms { static func main() { print("Hello, world!") } } ================================================ FILE: Fixtures/PartiallyUnusedDependency/Dep/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "Dep", products: [ .library( name: "MyDynamicLibrary", type: .dynamic, targets: ["MyDynamicLibrary"] ), .executable( name: "MySupportExecutable", targets: ["MySupportExecutable"] ) ], targets: [ .target( name: "MyDynamicLibrary" ), .executableTarget( name: "MySupportExecutable", dependencies: ["MyDynamicLibrary"] ) ] ) ================================================ FILE: Fixtures/PartiallyUnusedDependency/Dep/Sources/MyDynamicLibrary/Dep.swift ================================================ public func sayHello() { print("hello!") } ================================================ FILE: Fixtures/PartiallyUnusedDependency/Dep/Sources/MySupportExecutable/exe.swift ================================================ import MyDynamicLibrary @main struct Entry { static func main() { print("running support tool") sayHello() } } ================================================ FILE: Fixtures/PartiallyUnusedDependency/Package.swift ================================================ // swift-tools-version: 6.0 import PackageDescription let package = Package( name: "PartiallyUnusedDependency", products: [ .executable( name: "MyExecutable", targets: ["MyExecutable"] ), ], dependencies: [ .package(path: "Dep") ], targets: [ .executableTarget( name: "MyExecutable", dependencies: [.product(name: "MyDynamicLibrary", package: "Dep")] ), .plugin( name: "dump-artifacts-plugin", capability: .command( intent: .custom(verb: "dump-artifacts-plugin", description: "Dump Artifacts"), permissions: [] ) ) ] ) ================================================ FILE: Fixtures/PartiallyUnusedDependency/Plugins/dump-artifacts-plugin.swift ================================================ import PackagePlugin @main struct DumpArtifactsPlugin: CommandPlugin { func performCommand( context: PluginContext, arguments: [String] ) throws { do { var parameters = PackageManager.BuildParameters() parameters.configuration = .debug parameters.logging = .concise let result = try packageManager.build(.all(includingTests: false), parameters: parameters) print("succeeded: \(result.succeeded)") for artifact in result.builtArtifacts { print("artifact-path: \(artifact.path.string)") print("artifact-kind: \(artifact.kind)") } } catch { print("error from the plugin host: \\(error)") } } } ================================================ FILE: Fixtures/PartiallyUnusedDependency/Sources/MyExecutable/PartiallyUnusedDependency.swift ================================================ import MyDynamicLibrary @main struct Entry { static func main() { print("Hello, world!") sayHello() } } ================================================ FILE: Fixtures/Resources/EmbedInCodeSimple/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "EmbedInCodeSimple", targets: [ .executableTarget(name: "EmbedInCodeSimple", resources: [.embedInCode("best.txt")]), ] ) ================================================ FILE: Fixtures/Resources/EmbedInCodeSimple/Sources/EmbedInCodeSimple/best.txt ================================================ hello world ================================================ FILE: Fixtures/Resources/EmbedInCodeSimple/Sources/EmbedInCodeSimple/main.swift ================================================ import Foundation print("\(String(decoding: Data(PackageResources.best_txt), as: UTF8.self))") ================================================ FILE: Fixtures/Resources/FoundationlessClient/AppPkg/Package.swift ================================================ // swift-tools-version:999.0 import PackageDescription let package = Package( name: "AppPkg", dependencies: [ .package(path: "../UtilsPkg"), ], targets: [ .executableTarget( name: "App", dependencies: [ .product(name: "Utils", package: "UtilsPkg") ], path: "./Sources/App"), ] ) ================================================ FILE: Fixtures/Resources/FoundationlessClient/AppPkg/Sources/App/main.swift ================================================ import Utils // Note the lack of 'import Foundation'. // The purpose of this fixture is to test that the following line of code // expectedly *doesn't* compile: print(FooUtils.foo.trimmingCharacters(in: .whitespaces)) ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsPkg/Package.swift ================================================ // swift-tools-version:999.0 import PackageDescription let package = Package( name: "UtilsPkg", products: [ .library(name: "Utils", targets: ["Utils"]), ], targets: [ .target(name: "Utils", dependencies: [], resources: [ .copy("foo.txt"), ]), ] ) ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsPkg/Sources/Utils/FooUtils.swift ================================================ @frozen public enum FooUtils { } extension FooUtils { public static let foo: String = "Hello, World!" } ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsPkg/Sources/Utils/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsWithFoundationPkg/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription // This package acts as a regression test for the FoundationlessPackages to // assert that Swift targets with resources are not affected by using // `@_implementationOnly import Foundation` in the generated resource accessor. let package = Package( name: "UtilsWithFoundationPkg", targets: [ .target( name: "UtilsWithFoundationPkg", resources: [ .copy("foo.txt"), ] ) ] ) ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsWithFoundationPkg/Sources/UtilsWithFoundationPkg/FooUtils.swift ================================================ import Foundation @frozen public enum FooUtils { } extension FooUtils { public static let foo: String = "Hello, World!" } ================================================ FILE: Fixtures/Resources/FoundationlessClient/UtilsWithFoundationPkg/Sources/UtilsWithFoundationPkg/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Localized/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Localized", defaultLocalization: "es", targets: [ .target(name: "exe"), ] ) ================================================ FILE: Fixtures/Resources/Localized/Sources/exe/Resources/de.lproj/Localizable.strings ================================================ "hello_world" = "Hallo Welt!"; ================================================ FILE: Fixtures/Resources/Localized/Sources/exe/Resources/es.lproj/Localizable.strings ================================================ "hello_world" = "¡Hola Mundo!"; ================================================ FILE: Fixtures/Resources/Localized/Sources/exe/Resources/fr.lproj/Localizable.strings ================================================ "hello_world" = "Bonjour le monde !"; ================================================ FILE: Fixtures/Resources/Localized/Sources/exe/main.swift ================================================ import Foundation func localizationBundle(forLanguage language: String) -> Bundle? { if let path = Bundle.module.path(forResource: language, ofType: "lproj") { return Bundle(path: path) } else { return nil } } // Spanish localization (based on defaultLocalization). print(NSLocalizedString("hello_world", bundle: .module, comment: "")) // German localization. if let germanBundle = localizationBundle(forLanguage: "de") { print(NSLocalizedString("hello_world", bundle: germanBundle, comment: "")) } // French localization. if let frenchBundle = localizationBundle(forLanguage: "fr") { print(NSLocalizedString("hello_world", bundle: frenchBundle, comment: "")) } ================================================ FILE: Fixtures/Resources/Moved/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Resources", targets: [ .target( name: "SwiftyResource", resources: [ .copy("foo.txt"), ] ), .target( name: "SeaResource", resources: [ .copy("foo.txt"), ] ), ] ) ================================================ FILE: Fixtures/Resources/Moved/Sources/SeaResource/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Moved/Sources/SeaResource/main.m ================================================ #import int main(int argc, const char * argv[]) { @autoreleasepool { NSBundle *bundle = SWIFTPM_MODULE_BUNDLE; NSString *foo = [bundle pathForResource:@"foo" ofType:@"txt"]; NSData *data = [NSFileManager.defaultManager contentsAtPath:foo]; NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; printf("%s", contents.UTF8String); } return 0; } ================================================ FILE: Fixtures/Resources/Moved/Sources/SwiftyResource/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Moved/Sources/SwiftyResource/main.swift ================================================ import Foundation let bundle = Bundle.module let foo = bundle.path(forResource: "foo", ofType: "txt")! let contents = FileManager.default.contents(atPath: foo)! print(String(data: contents, encoding: .utf8)!, terminator: "") ================================================ FILE: Fixtures/Resources/ResourceRules/Package.swift ================================================ // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "ResourceRules", targets: [ .executableTarget(name: "ResourceRules", resources: [ .copy("CopiedAssets.xcassets"), .process("ProcessedAssets.xcassets") ]), ] ) ================================================ FILE: Fixtures/Resources/ResourceRules/Sources/ResourceRules/CopiedAssets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Resources/ResourceRules/Sources/ResourceRules/CopiedAssets.xcassets/pixel.imageset/Contents.json ================================================ { "images" : [ { "filename" : "pixel.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Resources/ResourceRules/Sources/ResourceRules/ProcessedAssets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Resources/ResourceRules/Sources/ResourceRules/ProcessedAssets.xcassets/processedpixel.imageset/Contents.json ================================================ { "images" : [ { "filename" : "processedpixel.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Fixtures/Resources/ResourceRules/Sources/ResourceRules/main.swift ================================================ import Foundation import AppKit @main struct Entry { public static func main() { guard Bundle.module.url(forResource: "CopiedAssets", withExtension: "xcassets") != nil else { print("Failed to lookup unprocessed asset catalog") return } guard Bundle.module.image(forResource: "processedpixel") != nil else { print("Failed to lookup processed asset from catalog") return } print("succeeded") } } ================================================ FILE: Fixtures/Resources/Simple/Package.swift ================================================ // swift-tools-version:5.3 import PackageDescription let package = Package( name: "Resources", targets: [ .target( name: "SwiftyResource", resources: [ .copy("foo.txt"), ] ), .target( name: "SeaResource", resources: [ .copy("foo.txt"), ] ), .target( name: "ClangResource", resources: [ .copy("foo.txt"), ] ), .testTarget( name: "ClangResourceTests", dependencies: ["ClangResource"] ), .target( name: "CPPResource", resources: [ .copy("foo.txt"), ] ), .target( name: "MixedClangResource", resources: [ .copy("foo.txt"), ] ), ] ) ================================================ FILE: Fixtures/Resources/Simple/Sources/CPPResource/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Simple/Sources/CPPResource/main.mm ================================================ #import int main(int argc, const char * argv[]) { @autoreleasepool { NSBundle *bundle = SWIFTPM_MODULE_BUNDLE; NSString *foo = [bundle pathForResource:@"foo" ofType:@"txt"]; NSData *data = [NSFileManager.defaultManager contentsAtPath:foo]; NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; printf("%s", contents.UTF8String); } return 0; } ================================================ FILE: Fixtures/Resources/Simple/Sources/ClangResource/Package.m ================================================ #import #import "Package.h" @implementation Package + (NSBundle *)resourceBundle { return SWIFTPM_MODULE_BUNDLE; } @end ================================================ FILE: Fixtures/Resources/Simple/Sources/ClangResource/foo.txt ================================================ ================================================ FILE: Fixtures/Resources/Simple/Sources/ClangResource/include/Package.h ================================================ #import @interface Package : NSObject + (NSBundle *)resourceBundle; @end ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/Foo.m ================================================ #import #import "Foo.h" @implementation Foo @end ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/bar.c ================================================ #include "bar.h" ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/bar.h ================================================ #ifndef foo_h #define foo_h #include #endif /* foo_h */ ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/baz.S ================================================ ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/foo.txt ================================================ ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/include/Foo.h ================================================ #import @interface Foo : NSObject @end ================================================ FILE: Fixtures/Resources/Simple/Sources/MixedClangResource/qux.cpp ================================================ ================================================ FILE: Fixtures/Resources/Simple/Sources/SeaResource/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Simple/Sources/SeaResource/main.m ================================================ #import int main(int argc, const char * argv[]) { @autoreleasepool { NSBundle *bundle = SWIFTPM_MODULE_BUNDLE; NSString *foo = [bundle pathForResource:@"foo" ofType:@"txt"]; NSData *data = [NSFileManager.defaultManager contentsAtPath:foo]; NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; printf("%s", contents.UTF8String); } return 0; } ================================================ FILE: Fixtures/Resources/Simple/Sources/SwiftyResource/foo.txt ================================================ foo ================================================ FILE: Fixtures/Resources/Simple/Sources/SwiftyResource/main.swift ================================================ import Foundation let bundle = Bundle.module let foo = bundle.path(forResource: "foo", ofType: "txt")! let contents = FileManager.default.contents(atPath: foo)! print(String(data: contents, encoding: .utf8)!, terminator: "") ================================================ FILE: Fixtures/Resources/Simple/Tests/ClangResourceTests/ClangResourceTests.m ================================================ #import @import ClangResource; @interface ClangResourceTests : XCTestCase @end @implementation ClangResourceTests - (void)testResourceBundleIsNonNil { XCTAssertNotNil([Package resourceBundle]); } @end ================================================ FILE: Fixtures/Signing/Certificates/Test_ec_key.pem ================================================ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIGfOkQcQq6oTC06KkGMVBAr2MiYFRaLo4/wKdNBpIjhnoAoGCCqGSM49 AwEHoUQDQgAE6SjFVQRtU/+ywvxslaVsl+iZf65YgkQShuxsbAbNJBTVkEkMGyNL 8nbaj6B4Jskjo1loNPLirNE7mKeTLYbrcw== -----END EC PRIVATE KEY----- ================================================ FILE: Fixtures/Signing/Certificates/Test_rsa_key.pem ================================================ -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA13XgJ9lIhR2LefNxQdo3tVrbXEZ3o4T8+MgteVJVohbPMypf yGgGlJJ/r7+hhL/klsPDyR4SAtgLZUGFVt3WzGMolGyV11VUTTFHMWZ10tcgrUmR 5wg2n5E59FsJf3y3WTs5CpD2tM8igWyAUOyS/MWvhgnMtvBG8I4Mg9xyyWi/GW3g PLXfnyULW/v2Zg+yG9j+/Bbpx+AP8TCvWoiPyiLEZ/DKZK2kC+8mkwOtHYDMkBO5 2nIrxopB42VUWYBfAzHm0M2XlEuc26PVojqno2ht5WU486uJXzWILvW3zFdlNDF/ SLeqQy1mNLRt5/An6la7e3sjOcuI1W2Qe7dkrwIDAQABAoIBAES+eUx9iSPfr1az k5k9NLUKTh785MMpdUUzKT8iQ+w5dtaOWI0qk57ntxGuBKzERPzNbTRIAdsib1BZ PV/f297ObG4ezxgrQ4B1jo92b3Vb6jMf3AtolXUH8wPB4B/q/Nzdhm+WnQBHbmz4 31/ye1tm/3+2tLhRpXCvAdM4jO8xhJlH+Pxg20fliAuiJ+ggSL56CyBR4kg80KtA omeGB1DOVFd23aDO/79Mii/2tf6EpmVFB/4zBkPHOH3zucwt8XUttwBeOcGdIbP+ CiU9VdZmG0XOJfC3apAXf9YwU3WVbmbvUWSwt6iHGZD4AuKY2R0ECTZnYS8ThDhd ZwPXzCECgYEA6xe9MpBCIVRK51Hb083mDg16UjRvPJA4T8w9xFg4UtAwe/u3CC67 4fAOSe0P3NtsXhcQFby7PEJwoeo2Hn6hUifxVMsKWmHb+FCg+CG/oBSwRKCa5BwG WpJ0jEt6KHZf0u+b/N1aOjVi/9tMrsHXFV3s2Gm9LQqA8u8izshDqakCgYEA6p8t KVK2mA+JjvSGyR6WfpVZ1OIi6CEEUhRU3aNHRB2zPf6J3PQLjz+Ad50BCVHXQSy/ aG3LpR44eUu5Q9AmTwDr8eiC8AT6uyE19zJHbK//E40Bn6khQvtymwByjav/5ZB+ ZAhE7E31eCZO8bqufSlnMNTD0Z8oqB5YR8uDApcCgYAkPcGd5N089Bij9luUGD6p 1ewQdiLbzEPSEWNIPG1aXtvKkTBTI5k1KGObg98ZJf5btuR05WZb0MY6P7feFZla 5+ttLevHqSRW8F8QQWugCvBtc/DMz4EvPzqWUiBf0nfNNcDvR1RcetRrKux0WE+G 7LbRWeOe6OqeCL1t8TN1GQKBgHPaH6m8/w689VbSpc+fu/5Lby0wcL4gt4p0IafD nUgkRkLBcn/ZPfABEkV+EGnysJCtMOK2/IzPDGHQo2251YDDWr576lPskYZfks86 U4x2p0SXJwsYr6Tslp21LduI5/YKUG7Cqo3ovOIUQH0ailihXiP9m6fhqGjDeyIQ euOHAoGAfDpntw1HRuk812au430Stl5eaTsH+w1msLLKZOukr6qWc2xFeC3fYPWQ BBkyzM3p6Se9FsfHY6LMxrEkz9fSdeVOeHenyUCTMqhqrc6o9f79zIlocsMzVGsK XKcULjpf67Igyx12eh3rqAEKwm6PGhbv9pK5/NpuzsP1atArMRg= -----END RSA PRIVATE KEY----- ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyMigration/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription let package = Package( name: "ExistentialAnyMigration", targets: [ .target(name: "Diagnostics", path: "Sources", exclude: ["Fixed"]), ] ) ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyMigration/Sources/Fixed/Test.swift ================================================ protocol P { } protocol Q { } func test1(_: any P) { } func test2(_: (any P).Protocol) { } func test3() { let _: [(any P)?] = [] } func test4() { var x = 42 } func test5(_: any P & Q) { } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyMigration/Sources/Test.swift ================================================ protocol P { } protocol Q { } func test1(_: P) { } func test2(_: P.Protocol) { } func test3() { let _: [P?] = [] } func test4() { var x = 42 } func test5(_: P & Q) { } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription let package = Package( name: "ExistentialAnyMigration", platforms: [ .macOS(.v10_15) ], targets: [ .target(name: "Library", dependencies: ["CommonLibrary"], plugins: [.plugin(name: "Plugin")]), .plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]), .executableTarget(name: "Tool", dependencies: ["CommonLibrary"]), .target(name: "CommonLibrary"), ] ) ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Plugins/Plugin/Plugin.swift ================================================ import PackagePlugin import Foundation @main struct Plugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { let tool = try context.tool(named: "Tool") let output = context.pluginWorkDirectory.appending(["generated.swift"]) return [ .buildCommand( displayName: "Plugin", executable: tool.path, arguments: [output], inputFiles: [], outputFiles: [output]) ] } } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/CommonLibrary/Common.swift ================================================ public func common() {} protocol P {} func needsMigration(_ p: P) {} ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Library/Test.swift ================================================ import CommonLibrary func bar() { generatedFunction() common() } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithCommonPluginDependencyMigration/Sources/Tool/tool.swift ================================================ import Foundation import CommonLibrary @main struct Entry { public static func main() async throws { common() let outputPath = CommandLine.arguments[1] let contents = """ func generatedFunction() {} """ FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8)) } } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription let package = Package( name: "ExistentialAnyMigration", platforms: [ .macOS(.v10_15) ], targets: [ .target(name: "Library", plugins: [.plugin(name: "Plugin")]), .plugin(name: "Plugin", capability: .buildTool, dependencies: ["Tool"]), .executableTarget(name: "Tool"), ] ) ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Plugins/Plugin/Plugin.swift ================================================ import PackagePlugin import Foundation @main struct Plugin: BuildToolPlugin { func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] { let tool = try context.tool(named: "Tool") let output = context.pluginWorkDirectory.appending(["generated.swift"]) return [ .buildCommand( displayName: "Plugin", executable: tool.path, arguments: [output], inputFiles: [], outputFiles: [output]) ] } } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Library/Test.swift ================================================ protocol P { } func test1(_: P) { } func test2(_: P.Protocol) { } func test3() { let _: [P?] = [] } func test4() { var x = 42 } func bar() { generatedFunction() } ================================================ FILE: Fixtures/SwiftMigrate/ExistentialAnyWithPluginMigration/Sources/Tool/tool.swift ================================================ import Foundation @main struct Entry { public static func main() async throws { let outputPath = CommandLine.arguments[1] let contents = """ func generatedFunction() {} func dontmodifyme(_: P) {} """ FileManager.default.createFile(atPath: outputPath, contents: contents.data(using: .utf8)) } } ================================================ FILE: Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Package.swift ================================================ // swift-tools-version:6.2 import PackageDescription let package = Package( name: "InferIsolatedConformancesMigration", targets: [ .target(name: "Diagnostics", path: "Sources", exclude: ["Fixed"]), ] ) ================================================ FILE: Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Fixed/Test.swift ================================================ @MainActor class C: nonisolated Equatable { let name = "Hello" nonisolated static func ==(lhs: C, rhs: C) -> Bool { lhs.name == rhs.name } } ================================================ FILE: Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Fixed/Test2.swift ================================================ protocol P {} protocol Q {} @MainActor struct S: nonisolated P & Q {} ================================================ FILE: Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Test.swift ================================================ @MainActor class C: Equatable { let name = "Hello" nonisolated static func ==(lhs: C, rhs: C) -> Bool { lhs.name == rhs.name } } ================================================ FILE: Fixtures/SwiftMigrate/InferIsolatedConformancesMigration/Sources/Test2.swift ================================================ protocol P {} protocol Q {} @MainActor struct S: P & Q {} ================================================ FILE: Fixtures/SwiftMigrate/StrictMemorySafetyMigration/Package.swift ================================================ // swift-tools-version:6.2 import PackageDescription let package = Package( name: "StrictMemorySafetyMigration", targets: [ .target(name: "Diagnostics", path: "Sources", exclude: ["Fixed"]), ] ) ================================================ FILE: Fixtures/SwiftMigrate/StrictMemorySafetyMigration/Sources/Fixed/Test.swift ================================================ @unsafe func f() { } func g() { unsafe f() } ================================================ FILE: Fixtures/SwiftMigrate/StrictMemorySafetyMigration/Sources/Test.swift ================================================ @unsafe func f() { } func g() { f() } ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Package.swift ================================================ // swift-tools-version:5.8 import PackageDescription var swiftSettings: [SwiftSetting] = [] let package = Package( name: "WithErrors", targets: [ .target( name: "CannotFindSettings", swiftSettings: swiftSettings ), .target(name: "A"), .target(name: "B"), ] ) package.targets.append( .target( name: "CannotFindTarget", swiftSettings: swiftSettings ), ) ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Package.updated.targets-A-B.swift ================================================ // swift-tools-version:5.8 import PackageDescription var swiftSettings: [SwiftSetting] = [] let package = Package( name: "WithErrors", targets: [ .target( name: "CannotFindSettings", swiftSettings: swiftSettings ), .target(name: "A",swiftSettings: [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InferIsolatedConformances"),]), .target(name: "B",swiftSettings: [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InferIsolatedConformances"),]), ] ) package.targets.append( .target( name: "CannotFindTarget", swiftSettings: swiftSettings ), ) ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Package.updated.targets-A.swift ================================================ // swift-tools-version:5.8 import PackageDescription var swiftSettings: [SwiftSetting] = [] let package = Package( name: "WithErrors", targets: [ .target( name: "CannotFindSettings", swiftSettings: swiftSettings ), .target(name: "A",swiftSettings: [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InferIsolatedConformances"),]), .target(name: "B"), ] ) package.targets.append( .target( name: "CannotFindTarget", swiftSettings: swiftSettings ), ) ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Package.updated.targets-all.swift ================================================ // swift-tools-version:5.8 import PackageDescription var swiftSettings: [SwiftSetting] = [] let package = Package( name: "WithErrors", targets: [ .target( name: "CannotFindSettings", swiftSettings: swiftSettings ), .target(name: "A",swiftSettings: [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InferIsolatedConformances"),]), .target(name: "B",swiftSettings: [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InferIsolatedConformances"),]), ] ) package.targets.append( .target( name: "CannotFindTarget", swiftSettings: swiftSettings ), ) ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Sources/A/File.swift ================================================ public func foo() {} ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Sources/B/File.swift ================================================ public func foo() {} ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Sources/CannotFindSettings/File.swift ================================================ public func foo() {} ================================================ FILE: Fixtures/SwiftMigrate/UpdateManifest/Sources/CannotFindTarget/File.swift ================================================ public func foo() {} ================================================ FILE: Fixtures/SwiftSDKs/Package.swift ================================================ // This empty file tells test fixture logic to copy this directory's content to the test case temp directory. ================================================ FILE: Fixtures/Traits/DisablingEmptyDefaultsExample/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "DisablingEmptyDefaultsExample", dependencies: [ .package( path: "../Package11", traits: [] ), ], targets: [ .executableTarget( name: "DisablingEmptyDefaultsExample" ), ] ) ================================================ FILE: Fixtures/Traits/DisablingEmptyDefaultsExample/Sources/DisablingEmptyDefaultsExample/Example.swift ================================================ @main struct Example { static func main() { } } ================================================ FILE: Fixtures/Traits/Example/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "TraitsExample", traits: [ .default( enabledTraits: [ "Package1", "Package2", "Package3", "Package4", "BuildCondition1", ] ), "Package1", "Package2", "Package3", "Package4", "Package5", "Package7", "Package9", "Package10", "BuildCondition1", "BuildCondition2", "BuildCondition3", "ExtraTrait", ], dependencies: [ .package( path: "../Package1", traits: ["Package1Trait1"] ), .package( path: "../Package2", traits: ["Package2Trait1"] ), .package( path: "../Package3" ), .package( path: "../Package4", traits: [] ), .package( path: "../Package5", traits: ["Package5Trait1"] ), .package( path: "../Package7" ), .package( path: "../Package9" ), .package( path: "../Package10", traits: ["Package10Trait2"] ), ], targets: [ .executableTarget( name: "Example", dependencies: [ .product( name: "Package1Library1", package: "Package1", condition: .when(traits: ["Package1"]) ), .product( name: "Package2Library1", package: "Package2", condition: .when(traits: ["Package2"]) ), .product( name: "Package3Library1", package: "Package3", condition: .when(traits: ["Package3"]) ), .product( name: "Package4Library1", package: "Package4", condition: .when(traits: ["Package4"]) ), .product( name: "Package5Library1", package: "Package5", condition: .when(traits: ["Package5"]) ), .product( name: "Package7Library1", package: "Package7", condition: .when(traits: ["Package7"]) ), .product( name: "Package9Library1", package: "Package9", condition: .when(traits: ["Package9"]) ), .product( name: "Package10Library1", package: "Package10", condition: .when(traits: ["Package10"]) ), .product( name: "Package10Library2", package: "Package10", condition: .when(traits: ["Package10", "ExtraTrait"]) ) ], swiftSettings: [ .define("DEFINE1", .when(traits: ["BuildCondition1"])), .define("DEFINE2", .when(traits: ["BuildCondition2"])), .define("DEFINE3", .when(traits: ["BuildCondition3"])), ] ), .testTarget( name: "ExampleTests", dependencies: [ .product( name: "Package1Library1", package: "Package1", condition: .when(traits: ["Package1"]) ), .product( name: "Package2Library1", package: "Package2", condition: .when(traits: ["Package2"]) ), .product( name: "Package3Library1", package: "Package3", condition: .when(traits: ["Package3"]) ), .product( name: "Package4Library1", package: "Package4", condition: .when(traits: ["Package4"]) ), .product( name: "Package5Library1", package: "Package5", condition: .when(traits: ["Package5"]) ), .product( name: "Package7Library1", package: "Package7", condition: .when(traits: ["Package7"]) ), .product( name: "Package9Library1", package: "Package9", condition: .when(traits: ["Package9"]) ), .product( name: "Package10Library1", package: "Package10", condition: .when(traits: ["Package10"]) ), ], swiftSettings: [ .define("DEFINE1", .when(traits: ["BuildCondition1"])), .define("DEFINE2", .when(traits: ["BuildCondition2"])), .define("DEFINE3", .when(traits: ["BuildCondition3"])), ] ) ] ) ================================================ FILE: Fixtures/Traits/Example/Sources/Example/Example.swift ================================================ #if Package1 import Package1Library1 #endif #if Package2 import Package2Library1 #endif #if Package3 import Package3Library1 #endif #if Package4 import Package4Library1 #endif #if Package5 import Package5Library1 #endif #if Package7 import Package7Library1 #endif #if Package9 import Package9Library1 #endif #if Package10 import Package10Library1 import Package10Library2 #endif #if ExtraTrait import Package10Library2 #endif @main struct Example { static func main() { #if Package1 Package1Library1.hello() #endif #if Package2 Package2Library1.hello() #endif #if Package3 Package3Library1.hello() #endif #if Package4 Package4Library1.hello() #endif #if Package5 Package5Library1.hello() #endif #if Package7 Package7Library1.hello() #endif #if Package9 Package9Library1.hello() #endif #if Package10 Package10Library1.hello() Package10Library2.hello() #endif #if ExtraTrait Package10Library2.hello() #endif #if DEFINE1 print("DEFINE1 enabled") #else print("DEFINE1 disabled") #endif #if DEFINE2 print("DEFINE2 enabled") #else print("DEFINE2 disabled") #endif #if DEFINE3 print("DEFINE3 enabled") #else print("DEFINE3 disabled") #endif } } ================================================ FILE: Fixtures/Traits/Example/Tests/ExampleTests/Tests.swift ================================================ #if Package1 import Package1Library1 #endif #if Package2 import Package2Library1 #endif #if Package3 import Package3Library1 #endif #if Package4 import Package4Library1 #endif #if Package5 import Package5Library1 #endif #if Package7 import Package7Library1 #endif #if Package9 import Package9Library1 #endif #if Package10 import Package10Library1 #endif import XCTest final class Tests: XCTestCase { func testTraits() { #if Package1 Package1Library1.hello() #endif #if Package2 Package2Library1.hello() #endif #if Package3 Package3Library1.hello() #endif #if Package4 Package4Library1.hello() #endif #if Package5 Package5Library1.hello() #endif #if Package7 Package7Library1.hello() #endif #if Package9 Package9Library1.hello() #endif #if Package10 Package10Library1.hello() #endif #if DEFINE1 print("DEFINE1 enabled") #else print("DEFINE1 disabled") #endif #if DEFINE2 print("DEFINE2 enabled") #else print("DEFINE2 disabled") #endif #if DEFINE3 print("DEFINE3 enabled") #else print("DEFINE3 disabled") #endif } } ================================================ FILE: Fixtures/Traits/Package1/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package1", products: [ .library( name: "Package1Library1", targets: ["Package1Library1"] ), ], traits: [ "Package1Trait1" ], targets: [ .target( name: "Package1Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package1/Sources/Package1Library1/Library.swift ================================================ public func hello() { #if Package1Trait1 print("Package1Library1 trait1 enabled") #else print("Package1Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package10/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package10", products: [ .library( name: "Package10Library1", targets: ["Package10Library1"] ), .library( name: "Package10Library2", targets: ["Package10Library2"] ), ], traits: [ "Package10Trait1", "Package10Trait2" ], targets: [ .target( name: "Package10Library1" ), .target( name: "Package10Library2" ), .plugin( name: "SymbolGraphExtract", capability: .command( intent: .custom(verb: "extract", description: "") ) ), ] ) ================================================ FILE: Fixtures/Traits/Package10/Plugins/SymbolGraphExtract/Plugin.swift ================================================ import PackagePlugin @main struct SymbolGraphExtractPlugin: CommandPlugin { func performCommand( context: PluginContext, arguments: [String] ) throws { let result = try self.packageManager.getSymbolGraph(for: context.package.targets.first!, options: .init()) print(result.directoryPath) } } ================================================ FILE: Fixtures/Traits/Package10/Sources/Package10Library1/Library.swift ================================================ public func hello() { #if Package10Trait1 print("Package10Library1 trait1 enabled") #else print("Package10Library1 trait1 disabled") #endif #if Package10Trait2 print("Package10Library1 trait2 enabled") #else print("Package10Library1 trait2 disabled") #endif } #if Package10Trait1 public struct TypeGatedByPackage10Trait1 {} #endif #if Package10Trait2 public struct TypeGatedByPackage10Trait2 {} #endif ================================================ FILE: Fixtures/Traits/Package10/Sources/Package10Library2/Library.swift ================================================ public func hello() { print("Package10Library2 has been included.") } ================================================ FILE: Fixtures/Traits/Package11/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package11", products: [ .library( name: "Package11Library1", targets: ["Package11Library1"] ), ], targets: [ .target( name: "Package11Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package11/Sources/Package11Library1/Library.swift ================================================ public func hello() { print("Package11Library1") } ================================================ FILE: Fixtures/Traits/Package2/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package2", products: [ .library( name: "Package2Library1", targets: ["Package2Library1"] ), ], traits: [ Trait(name: "Package2Trait1", enabledTraits: ["Package2Trait2"]), "Package2Trait2", ], targets: [ .target( name: "Package2Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package2/Sources/Package2Library1/Library.swift ================================================ public func hello() { #if Package2Trait2 print("Package2Library1 trait2 enabled") #else print("Package2Library1 trait2 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package3/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package3", products: [ .library( name: "Package3Library1", targets: ["Package3Library1"] ), ], traits: [ .default(enabledTraits: ["Package3Trait3"]), .trait(name: "Package3Trait1", enabledTraits: ["Package3Trait2"]), .trait(name: "Package3Trait2", enabledTraits: ["Package3Trait3"]), "Package3Trait3", ], targets: [ .target( name: "Package3Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package3/Sources/Package3Library1/Library.swift ================================================ public func hello() { #if Package3Trait3 print("Package3Library1 trait3 enabled") #else print("Package3Library1 trait3 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package4/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package4", products: [ .library( name: "Package4Library1", targets: ["Package4Library1"] ), ], traits: [ .default(enabledTraits: ["Package4Trait1"]), "Package4Trait1", ], targets: [ .target( name: "Package4Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package4/Sources/Package4Library1/Library.swift ================================================ public func hello() { #if Package4Trait1 print("Package4Library1 trait1 enabled") #else print("Package4Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package5/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package5", products: [ .library( name: "Package5Library1", targets: ["Package5Library1"] ), ], traits: [ "Package5Trait1" ], dependencies: [ .package( path: "../Package6", traits: [ Package.Dependency.Trait(name: "Package6Trait1", condition: .when(traits: ["Package5Trait1"])) ] ) ], targets: [ .target( name: "Package5Library1", dependencies: [ .product( name: "Package6Library1", package: "Package6" ) ] ), ] ) ================================================ FILE: Fixtures/Traits/Package5/Sources/Package5Library1/Library.swift ================================================ #if Package5Trait1 import Package6Library1 #endif public func hello() { #if Package5Trait1 print("Package5Library1 trait1 enabled") Package6Library1.hello() #else print("Package5Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package6/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package6", products: [ .library( name: "Package6Library1", targets: ["Package6Library1"] ), ], traits: [ "Package6Trait1" ], targets: [ .target( name: "Package6Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package6/Sources/Package6Library1/Library.swift ================================================ public func hello() { #if Package6Trait1 print("Package6Library1 trait1 enabled") #else print("Package6Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package7/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package7", products: [ .library( name: "Package7Library1", targets: ["Package7Library1"] ), ], traits: [ "Package7Trait1" ], dependencies: [ .package( path: "../Package8" ) ], targets: [ .target( name: "Package7Library1", dependencies: [ .product( name: "Package8Library1", package: "Package8", condition: .when(traits: ["Package7Trait1"]) ) ] ), ] ) ================================================ FILE: Fixtures/Traits/Package7/Sources/Package7Library1/Library.swift ================================================ #if Package7Trait1 import Package8Library1 #endif public func hello() { #if Package7Trait1 print("Package7Library1 trait1 enabled") Package8Library1.hello() #else print("Package7Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package8/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package8", products: [ .library( name: "Package8Library1", targets: ["Package8Library1"] ), ], traits: [ "Package8Trait1" ], targets: [ .target( name: "Package8Library1" ), ] ) ================================================ FILE: Fixtures/Traits/Package8/Sources/Package6Library1/Library.swift ================================================ public func hello() { #if Package8Trait1 print("Package8Library1 trait1 enabled") #else print("Package8Library1 trait1 disabled") #endif } ================================================ FILE: Fixtures/Traits/Package9/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "Package9", products: [ .library( name: "Package9Library1", targets: ["Package9Library1"] ), ], dependencies: [ .package( path: "../Package10", traits: ["Package10Trait1"] ) ], targets: [ .target( name: "Package9Library1", dependencies: [ .product( name: "Package10Library1", package: "Package10" ) ] ), ] ) ================================================ FILE: Fixtures/Traits/Package9/Sources/Package9Library1/Library.swift ================================================ import Package10Library1 public func hello() { Package10Library1.hello() } ================================================ FILE: Fixtures/Traits/PackageConditionalDeps/Package.swift ================================================ // swift-tools-version: 6.1 import PackageDescription let package = Package( name: "PackageConditionalDeps", products: [ .library( name: "PackageConditionalDeps", targets: ["PackageConditionalDeps"] ), ], traits: [ .default(enabledTraits: ["EnablePackage1Dep"]), "EnablePackage1Dep", "EnablePackage2Dep" ], dependencies: [ .package(path: "../Package1"), .package(path: "../Package2"), ], targets: [ .target( name: "PackageConditionalDeps", dependencies: [ .product( name: "Package1Library1", package: "Package1", condition: .when(traits: ["EnablePackage1Dep"]) ), .product( name: "Package2Library1", package: "Package2", condition: .when(traits: ["EnablePackage2Dep"]) ) ] ), ] ) ================================================ FILE: Fixtures/Traits/PackageConditionalDeps/Sources/PackageConditionalDeps/PackageConditionalDeps.swift ================================================ public func nothingHappens() { // Do nothing. } ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ExecutableNew", targets: [ .target(name: "ExecutableSwift"), .target(name: "ExecutableC"), .target(name: "ExecutableCxx"), ] ) ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/README.md ================================================ # ExecutableMixed A description of this package. ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/Sources/ExecutableC/c.c ================================================ int main() { return 0; } ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/Sources/ExecutableCxx/cxx.cpp ================================================ int main() { return 0; } ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableMixed/Sources/ExecutableSwift/main.swift ================================================ print("Hello, world!") ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableNew/.gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableNew/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "ExecutableNew", targets: [ .target(name: "ExecutableNew"), ] ) ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableNew/README.md ================================================ # ExecutableNew A description of this package. ================================================ FILE: Fixtures/ValidLayouts/SingleModule/ExecutableNew/Sources/ExecutableNew/main.swift ================================================ print("Hello, world!") ================================================ FILE: Fixtures/ValidLayouts/SingleModule/Library/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Library", targets: [ .target(name: "Library"), ] ) ================================================ FILE: Fixtures/ValidLayouts/SingleModule/Library/Sources/Library/Foo.swift ================================================ class Foo { var bar: Int = 0 } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .executable(name: "bar", targets: ["bar"]), .executable(name: "cbar", targets: ["cbar"]), .library(name: "BarLib", targets: ["BarLib"]), ], targets: [ .target(name: "bar", dependencies: ["BarLib"]), .target(name: "cbar"), .target(name: "BarLib"), ], swiftLanguageVersions: [.v4_2], cLanguageStandard: .c11, cxxLanguageStandard: .cxx14 ) ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Bar/Sources/BarLib/BarLib.swift ================================================ public struct BarInfo { public static let name: String = "bar" } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Bar/Sources/bar/main.swift ================================================ import BarLib func main() { print("Hello from \(BarInfo.name)") } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Bar/Sources/cbar/main.c ================================================ #include int main(void) { printf("Hello from cbar"); } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Foo/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", dependencies: [ .package(path: "../Bar") ], targets: [ .target(name: "foo", dependencies: [ "FooLib", "cfoo", .product(name: "bar", package: "Bar") ]), .target(name: "cfoo"), .target(name: "FooLib", dependencies: [ .product(name: "BarLib", package: "Bar"), ]), ], swiftLanguageVersions: [.v4_2, .v5] ) ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Foo/Sources/FooLib/FooLib.swift ================================================ public struct FooInfo { public static let name: String = "bar" } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Foo/Sources/cfoo/main.c ================================================ #include int main(void) { printf("Hello from cfoo"); } ================================================ FILE: Fixtures/XCBuild/ExecutableProducts/Foo/Sources/foo/main.swift ================================================ import FooLib import BarLib func main() { print("Hello from \(FooInfo.name)") print("Hello from \(BarInfo.name)") } ================================================ FILE: Fixtures/XCBuild/Libraries/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "BarLib", type: .dynamic, targets: ["BarLib"]), ], targets: [ .target(name: "BarLib"), ], swiftLanguageVersions: [.v4_2], cLanguageStandard: .c11, cxxLanguageStandard: .cxx14 ) ================================================ FILE: Fixtures/XCBuild/Libraries/Bar/Sources/BarLib/BarLib.swift ================================================ import Foundation @objcMembers public class BarInfo: NSObject { public static let name = "Bar" } ================================================ FILE: Fixtures/XCBuild/Libraries/Foo/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", products: [ .library(name: "FooLib", type: .static, targets: ["FooLib"]), ], dependencies: [ .package(path: "../Bar") ], targets: [ .target(name: "FooLib", dependencies: ["CFooLib"]), .target(name: "CFooLib", dependencies: [ .product(name: "BarLib", package: "Bar"), ]), ], swiftLanguageVersions: [.v4_2, .v5] ) ================================================ FILE: Fixtures/XCBuild/Libraries/Foo/Sources/CFooLib/CFooLib.m ================================================ @import Foundation; @import BarLib; #import "CFooLib.h" @implementation CFooInfo + (NSString*)name { return [NSString stringWithFormat:@"CFoo %@", [BarInfo name]]; } @end ================================================ FILE: Fixtures/XCBuild/Libraries/Foo/Sources/CFooLib/include/CFooLib.h ================================================ @import Foundation; @interface CFooInfo: NSObject + (nonnull NSString*)name; @end ================================================ FILE: Fixtures/XCBuild/Libraries/Foo/Sources/FooLib/FooLib.swift ================================================ import CFooLib import BarLib public struct FooInfo { public static let name = "Foo \(BarInfo.name) \(CFooInfo.name)" } ================================================ FILE: Fixtures/XCBuild/SystemTargets/Foo/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Foo", targets: [ .target(name: "foo", dependencies: ["SystemLib"]), .systemLibrary(name: "SystemLib", pkgConfig: "libsys"), ] ) ================================================ FILE: Fixtures/XCBuild/SystemTargets/Foo/Sources/SystemLib/module.modulemap ================================================ module SystemLib [system] { header "../../../Inputs/libsys.h" export * } ================================================ FILE: Fixtures/XCBuild/SystemTargets/Foo/Sources/foo/main.swift ================================================ import SystemLib print(String(cString: GetSystemLibName()!)) ================================================ FILE: Fixtures/XCBuild/SystemTargets/Inputs/libsys.c ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ const char* GetSystemLibName() { return "SystemLibrary"; } ================================================ FILE: Fixtures/XCBuild/SystemTargets/Inputs/libsys.h ================================================ /* This source file is part of the Swift.org open source project Copyright (c) 2020 Apple Inc. and the Swift project authors Licensed under Apache License v2.0 with Runtime Library Exception See http://swift.org/LICENSE.txt for license information See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ const char* GetSystemLibName(); ================================================ FILE: Fixtures/XCBuild/SystemTargets/Inputs/libsys.pc ================================================ Name: SystemLibrary URL: http://127.0.0.1/ Description: The one and only SystemLibrary Version: 1.0.0 Cflags: -I${pcfiledir} Libs: -L${pcfiledir} -lsys ================================================ FILE: Fixtures/XCBuild/TestProducts/Bar/Package.swift ================================================ // swift-tools-version:4.2 import PackageDescription let package = Package( name: "Bar", products: [ .library(name: "BarLib", targets: ["BarLib"]), ], targets: [ .target(name: "BarLib"), ], swiftLanguageVersions: [.v4_2], cLanguageStandard: .c11, cxxLanguageStandard: .cxx14 ) ================================================ FILE: Fixtures/XCBuild/TestProducts/Bar/Sources/BarLib/BarLib.m ================================================ #import "BarLib.h" @implementation BarInfo + (NSString*)name { return @"Bar"; } @end ================================================ FILE: Fixtures/XCBuild/TestProducts/Bar/Sources/BarLib/include/BarLib.h ================================================ @import Foundation; @interface BarInfo: NSObject + (nonnull NSString*)name; @end ================================================ FILE: Fixtures/XCBuild/TestProducts/Foo/Package.swift ================================================ // swift-tools-version:5.2 import PackageDescription let package = Package( name: "Foo", dependencies: [ .package(path: "../Bar") ], targets: [ .target(name: "FooLib", dependencies: [ .product(name: "BarLib", package: "Bar"), ]), .testTarget(name: "FooTests", dependencies: ["FooLib"]), .testTarget(name: "CFooTests", dependencies: ["FooLib"]), ], swiftLanguageVersions: [.v4_2, .v5] ) ================================================ FILE: Fixtures/XCBuild/TestProducts/Foo/Sources/FooLib/FooLib.swift ================================================ import Foundation @objcMembers public class FooInfo: NSObject { public static let name = "Foo" } ================================================ FILE: Fixtures/XCBuild/TestProducts/Foo/Tests/CFooTests/tests.m ================================================ @import XCTest; @import Foundation; @import FooLib; @import BarLib; @interface CFooTests: XCTestCase @end @implementation CFooTests - (void)testFoo { XCTAssert([[FooInfo name] isEqualTo:@"Foo"]); } - (void)testBar { XCTAssert([[BarInfo name] isEqualTo:@"Bar"]); } @end ================================================ FILE: Fixtures/XCBuild/TestProducts/Foo/Tests/FooTests/FooTests.swift ================================================ import XCTest import FooLib import BarLib final class FooTests: XCTestCase { func testFoo() { XCTAssertEqual(FooInfo.name, "Foo") } func testBar() { XCTAssertEqual(BarInfo.name(), "Bar") } } ================================================ FILE: LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Runtime Library Exception to the Apache 2.0 License: ## As an exception, if you use this Software to compile your source code and portions of this Software are embedded into the binary product as a result, you may redistribute such product without providing attribution as would otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. ================================================ FILE: NOTICE.txt ================================================ The SwiftPM Project ==================== Please visit the SwiftPM web site for more information: * https://github.com/swiftlang/swift-package-manager Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors The Swift Project licenses this file to you under the Apache License, version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Also, please refer to each LICENSE.txt file, which is located in the 'license' directory of the distribution file, for the license terms of the components that this product depends on. ------------------------------------------------------------------------------- The dependency resolver is influenced by Dart project (pub tool). * LICENSE (BSD 3-Clause "New" or "Revised" License): * https://github.com/dart-lang/pub/blob/master/LICENSE // ignore-unacceptable-language * HOMEPAGE: * https://dart.dev * https://github.com/dart-lang/pub --- This product contains a derivation of Vapor's JWTKit library, specifically `JWTParser.swift`, `JWTSerializer.swift` and `Base64URL.swift`. * LICENSE (MIT License): * https://www.apache.org/licenses/LICENSE-2.0 * HOMEPAGE: * https://vapor.codes * https://github.com/vapor/jwt-kit --- This product contains a derivation of OpenSSL's OCSP implementation, found under the `PackageCollectionsSigningLibc` module. * LICENSE (Apache License 2.0): * https://www.apache.org/licenses/LICENSE-2.0 * HOMEPAGE: * https://github.com/openssl/openssl --- The observability system is influenced by SwiftLog project. * LICENSE (Apache License 2.0): * https://www.apache.org/licenses/LICENSE-2.0 * HOMEPAGE: * https://github.com/apple/swift-log --- The observability system is influenced by SwiftMetrics project. * LICENSE (Apache License 2.0): * https://www.apache.org/licenses/LICENSE-2.0 * HOMEPAGE: * https://github.com/apple/swift-metrics --- The observability system is influenced by SwiftDistributedTracing project. * LICENSE (Apache License 2.0): * https://www.apache.org/licenses/LICENSE-2.0 * HOMEPAGE: * https://github.com/apple/swift-distributed-tracing-baggage --- ================================================ FILE: Package.swift ================================================ // swift-tools-version:6.1 //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.ProcessInfo import PackageDescription // When building the toolchain on the CI for ELF platforms, remove the CI's // stdlib absolute runpath and add ELF's $ORIGIN relative paths before installing. let swiftpmLinkSettings: [LinkerSetting] let packageLibraryLinkSettings: [LinkerSetting] if let resourceDirPath = ProcessInfo.processInfo.environment["SWIFTCI_INSTALL_RPATH_OS"] { swiftpmLinkSettings = [.unsafeFlags([ "-no-toolchain-stdlib-rpath", "-Xlinker", "-rpath", "-Xlinker", "$ORIGIN/../lib/swift/\(resourceDirPath)", ])] packageLibraryLinkSettings = [.unsafeFlags([ "-no-toolchain-stdlib-rpath", "-Xlinker", "-rpath", "-Xlinker", "$ORIGIN/../../\(resourceDirPath)", ])] } else { swiftpmLinkSettings = [] packageLibraryLinkSettings = [] } // Common experimental flags to be added to all targets. let commonExperimentalFeatures: [SwiftSetting] = [ .enableExperimentalFeature("MemberImportVisibility"), ] // Certain targets fail to compile with MemberImportVisibility enabled on 6.0.3 // but work with >=6.1. These targets opt in to using `swift6CompatibleExperimentalFeatures`. #if swift(>=6.1) let swift6CompatibleExperimentalFeatures = commonExperimentalFeatures #else let swift6CompatibleExperimentalFeatures: [SwiftSetting] = [] #endif /** SwiftPMDataModel is the subset of SwiftPM product that includes just its data model. This allows some clients (such as IDEs) that use SwiftPM's data model but not its build system to not have to depend on SwiftDriver, SwiftLLBuild, etc. We should probably have better names here, though that could break some clients. */ let swiftPMDataModelProduct = ( name: "SwiftPMDataModel", targets: [ "PackageCollections", "PackageCollectionsModel", "PackageGraph", "PackageLoading", "PackageMetadata", "PackageModel", "SourceControl", "Workspace", ] ) /** The `libSwiftPM` set of interfaces to programmatically work with Swift packages. `libSwiftPM` includes all of the SwiftPM code except the command line tools, while `libSwiftPMDataModel` includes only the data model. NOTE: This API is *unstable* and may change at any time. */ let swiftPMProduct = ( name: "SwiftPM", targets: swiftPMDataModelProduct.targets + [ "Build", "LLBuildManifest", "SourceKitLSPAPI", "SPMLLBuild", ] ) #if os(Windows) let includeDynamicLibrary: Bool = false let systemSQLitePkgConfig: String? = nil #else let includeDynamicLibrary: Bool = true var systemSQLitePkgConfig: String? = "sqlite3" if ProcessInfo.processInfo.environment["SWIFTCI_INSTALL_RPATH_OS"] == "android" { systemSQLitePkgConfig = nil } #endif /** An array of products which have two versions listed: one dynamically linked, the other with the automatic linking type with `-auto` suffix appended to product's name. */ let autoProducts = [swiftPMProduct, swiftPMDataModelProduct] let shouldUseSwiftBuildFramework = (ProcessInfo.processInfo.environment["SWIFTPM_SWBUILD_FRAMEWORK"] != nil) let swiftDriverDeps: [Target.Dependency] let swiftTSCBasicsDeps: [Target.Dependency] let swiftToolsCoreSupportAutoDeps: [Target.Dependency] let swiftTSCTestSupportDeps: [Target.Dependency] let swiftToolsProtocolsDeps: [Target.Dependency] if shouldUseSwiftBuildFramework { swiftDriverDeps = [] swiftTSCBasicsDeps = [] swiftToolsCoreSupportAutoDeps = [] swiftTSCTestSupportDeps = [] swiftToolsProtocolsDeps = [] } else { swiftDriverDeps = [ .product(name: "SwiftDriver", package: "swift-driver") ] swiftTSCBasicsDeps = [ .product(name: "TSCBasic", package: "swift-tools-support-core"), ] swiftToolsCoreSupportAutoDeps = [ .product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core") ] swiftTSCTestSupportDeps = [ .product(name: "TSCTestSupport", package: "swift-tools-support-core"), ] swiftToolsProtocolsDeps = [ .product(name: "BuildServerProtocol", package: "swift-tools-protocols", condition: .when(platforms: [.macOS, .linux, .windows, .android, .openbsd, .custom("freebsd")])), .product(name: "LanguageServerProtocol", package: "swift-tools-protocols", condition: .when(platforms: [.macOS, .linux, .windows, .android, .openbsd, .custom("freebsd")])), .product(name: "LanguageServerProtocolTransport", package: "swift-tools-protocols", condition: .when(platforms: [.macOS, .linux, .windows, .android, .openbsd, .custom("freebsd")])), ] } let package = Package( name: "SwiftPM", platforms: [ .macOS(.v14), .iOS(.v17), .macCatalyst(.v17), ], products: autoProducts.flatMap { (includeDynamicLibrary ? [ .library( name: $0.name, type: .dynamic, targets: $0.targets ), ] : []) + [ .library( name: "\($0.name)-auto", targets: $0.targets ), ] } + [ .library( name: "XCBuildSupport", targets: ["XCBuildSupport"] ), .library( name: "PackageDescription", type: .dynamic, targets: ["PackageDescription", "CompilerPluginSupport"] ), .library( name: "AppleProductTypes", type: .dynamic, targets: ["AppleProductTypes"] ), .library( name: "PackagePlugin", type: .dynamic, targets: ["PackagePlugin"] ), .library( name: "PackageCollectionsModel", targets: ["PackageCollectionsModel"] ), .library( name: "SwiftPMPackageCollections", targets: [ "PackageCollections", "PackageCollectionsModel", "PackageCollectionsSigning", "PackageModel", ] ), ], targets: [ // The `AppleProductTypes` target provides additional product types // to `Package.swift` manifests. Here we build a debug version of the // library; the bootstrap scripts build the deployable version. .target( name: "AppleProductTypes", // Note: We use `-module-link-name` so clients link against the // AppleProductTypes library when they import it without further // messing with the manifest loader. dependencies: ["PackageDescription"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-package-description-version", "999.0"]), .unsafeFlags(["-enable-library-evolution"], .when(platforms: [.macOS])), .unsafeFlags(["-Xfrontend", "-module-link-name", "-Xfrontend", "AppleProductTypes"]) ]), .target( name: "SourceKitLSPAPI", dependencies: [ "Basics", "Build", "PackageGraph", "PackageLoading", "PackageModel", "SPMBuildCore", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .enableExperimentalFeature("AccessLevelOnImport"), .unsafeFlags(["-static"]), ] ), // MARK: SwiftPM specific support libraries .systemLibrary(name: "SPMSQLite3", pkgConfig: systemSQLitePkgConfig), .target( name: "_AsyncFileSystem", dependencies: [ .product(name: "SystemPackage", package: "swift-system"), ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .enableExperimentalFeature("StrictConcurrency"), .enableExperimentalFeature("AccessLevelOnImport"), .enableExperimentalFeature("InternalImportsByDefault"), .unsafeFlags(["-static"]), ] ), .target( name: "Basics", dependencies: [ "_AsyncFileSystem", .target(name: "SPMSQLite3", condition: .when(platforms: [.macOS, .iOS, .tvOS, .watchOS, .visionOS, .macCatalyst, .linux, .openbsd, .custom("freebsd")])), .product(name: "SwiftToolchainCSQLite", package: "swift-toolchain-sqlite", condition: .when(platforms: [.windows, .android])), .product(name: "DequeModule", package: "swift-collections"), .product(name: "OrderedCollections", package: "swift-collections"), .product(name: "SystemPackage", package: "swift-system"), ] + swiftToolsCoreSupportAutoDeps, exclude: ["CMakeLists.txt", "Vendor/README.md"], swiftSettings: swift6CompatibleExperimentalFeatures + [ .enableExperimentalFeature("StrictConcurrency"), .enableExperimentalFeature("AccessLevelOnImport"), .unsafeFlags(["-static"]), ] ), .target( /** The llbuild manifest model */ name: "LLBuildManifest", dependencies: ["Basics"], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Package registry support */ name: "PackageRegistry", dependencies: [ "Basics", "PackageFingerprint", "PackageLoading", "PackageModel", "PackageSigning", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Source control operations */ name: "SourceControl", dependencies: [ "Basics", "PackageModel", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Shim for llbuild library */ name: "SPMLLBuild", dependencies: ["Basics"], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** API for deserializing diagnostics and applying fix-its */ name: "SwiftFixIt", dependencies: [ "Basics", ] + swiftTSCBasicsDeps + swiftSyntaxDependencies( ["SwiftDiagnostics", "SwiftIDEUtils", "SwiftParser", "SwiftSyntax"] ), exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** API for inspecting symbols defined in binaries */ name: "BinarySymbols", dependencies: [ "Basics", ] + swiftTSCBasicsDeps, exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), // MARK: Project Model .target( /** Primitive Package model objects */ name: "PackageModel", dependencies: ["Basics"], exclude: ["CMakeLists.txt", "README.md"], swiftSettings: swift6CompatibleExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** SBOM (Software Bill of Materials) model objects */ name: "SBOMModel", dependencies: ["Basics", "PackageCollections", "PackageGraph", "PackageModel", "SourceControl", "SwiftBuildSupport"], exclude: ["CMakeLists.txt", "README.md"], resources: [ .copy("CycloneDX/Resources/cyclonedx-1.7.schema.json"), .copy("SPDX/Resources/spdx-3.0.1.schema.json"), ], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Package model conventions and loading support */ name: "PackageLoading", dependencies: [ "Basics", "PackageModel", "SourceControl", ], exclude: ["CMakeLists.txt", "README.md"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), // MARK: Package Dependency Resolution .target( /** Data structures and support for complete package graphs */ name: "PackageGraph", dependencies: [ "Basics", "PackageLoading", "PackageModel", .product(name: "OrderedCollections", package: "swift-collections"), ], exclude: ["CMakeLists.txt", "README.md"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), // MARK: Package Collections .target( /** Package collections models */ name: "PackageCollectionsModel", dependencies: [], exclude: [ "Formats/v1.md", "CMakeLists.txt", ], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Data structures and support for package collections */ name: "PackageCollections", dependencies: [ "Basics", "PackageCollectionsModel", "PackageCollectionsSigning", "PackageModel", "SourceControl", ], exclude: ["CMakeLists.txt"], swiftSettings: swift6CompatibleExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "PackageCollectionsSigning", dependencies: [ .product(name: "Crypto", package: "swift-crypto"), .product(name: "X509", package: "swift-certificates"), "Basics", "PackageCollectionsModel", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "PackageFingerprint", dependencies: [ "Basics", "PackageModel", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "PackageSigning", dependencies: [ .product(name: "Crypto", package: "swift-crypto"), .product(name: "X509", package: "swift-certificates"), "Basics", "PackageModel", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), // MARK: Documentation .target( name: "PackageManagerDocs", exclude: ["README.md"], ), // MARK: Package Manager Functionality .target( /** Builds Modules and Products */ name: "SPMBuildCore", dependencies: [ "Basics", "PackageGraph", .product(name: "OrderedCollections", package: "swift-collections"), ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Builds Modules and Products */ name: "Build", dependencies: [ "Basics", "LLBuildManifest", "PackageGraph", "SPMBuildCore", "SPMLLBuild", .product(name: "OrderedCollections", package: "swift-collections"), "DriverSupport", ] + swiftDriverDeps, exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "DriverSupport", dependencies: [ "Basics", "PackageModel", ] + swiftDriverDeps, exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Support for building using Xcode's build system */ name: "XCBuildSupport", dependencies: [ "SPMBuildCore", "PackageGraph", .product(name: "OrderedCollections", package: "swift-collections"), ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "SwiftBuildSupport", dependencies: [ "SPMBuildCore", "PackageGraph", ], exclude: ["CMakeLists.txt", "README.md"], swiftSettings: commonExperimentalFeatures ), .target( /** High level functionality */ name: "Workspace", dependencies: [ "Basics", "PackageFingerprint", "PackageGraph", "PackageModel", "PackageRegistry", "PackageSigning", "SourceControl", "SPMBuildCore", .product(name: "OrderedCollections", package: "swift-collections"), ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( // ** High level interface for package discovery */ name: "PackageMetadata", dependencies: [ "Basics", "PackageCollections", "PackageModel", "PackageRegistry", "PackageSigning", ], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), // MARK: BSP .target( name: "SwiftPMBuildServer", dependencies: [ "Basics", "Build", "PackageGraph", "PackageLoading", "PackageModel", "SPMBuildCore", "SourceControl", "SourceKitLSPAPI", "SwiftBuildSupport", "Workspace" ] + swiftTSCBasicsDeps + swiftToolsProtocolsDeps, exclude: [ "CMakeLists.txt", ], ), // MARK: Commands .target( /** Minimal set of commands required for bootstrapping a new SwiftPM */ name: "CoreCommands", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "Build", "PackageLoading", "PackageModel", "PackageGraph", "Workspace", "XCBuildSupport", "SwiftBuildSupport", "SBOMModel", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** High-level commands */ name: "Commands", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), .product(name: "OrderedCollections", package: "swift-collections"), .product(name: "SystemPackage", package: "swift-system"), "Basics", "BinarySymbols", "Build", "CoreCommands", "PackageGraph", "SBOMModel", "SourceControl", "Workspace", "XCBuildSupport", "SwiftBuildSupport", "SwiftFixIt", "SwiftPMBuildServer", ] + swiftSyntaxDependencies(["SwiftIDEUtils", "SwiftRefactor"]), exclude: ["CMakeLists.txt", "README.md"], swiftSettings: swift6CompatibleExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Interacts with Swift SDKs used for cross-compilation */ name: "SwiftSDKCommand", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "CoreCommands", "SPMBuildCore", "PackageModel", ], exclude: ["CMakeLists.txt", "README.md"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Interacts with package collections */ name: "PackageCollectionsCommand", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "Commands", "CoreCommands", "PackageCollections", "PackageModel", ], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( /** Interact with package registry */ name: "PackageRegistryCommand", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "Commands", "CoreCommands", "PackageGraph", "PackageLoading", "PackageModel", "PackageRegistry", "PackageSigning", "SourceControl", "SPMBuildCore", "Workspace", ], exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-static"]), ] ), .target( name: "QueryEngine", dependencies: [ "_AsyncFileSystem", "Basics", .product(name: "Crypto", package: "swift-crypto"), ], exclude: ["CMakeLists.txt"], swiftSettings: [ .enableExperimentalFeature("StrictConcurrency=complete"), .unsafeFlags(["-static"]), ] ), .executableTarget( /** The main executable provided by SwiftPM */ name: "swift-package", dependencies: ["Basics", "Commands"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Builds packages */ name: "swift-build", dependencies: ["Commands"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Builds SwiftPM itself for bootstrapping (minimal version of `swift-build`) */ name: "swift-bootstrap", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), .product(name: "OrderedCollections", package: "swift-collections"), "Basics", "Build", "PackageGraph", "PackageLoading", "PackageModel", "XCBuildSupport", "SwiftBuildSupport", ], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Interacts with Swift SDKs used for cross-compilation */ name: "swift-sdk", dependencies: ["Commands", "SwiftSDKCommand"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Deprecated command superseded by `swift-sdk` */ name: "swift-experimental-sdk", dependencies: ["Commands", "SwiftSDKCommand"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Runs package tests */ name: "swift-test", dependencies: ["Commands"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Runs an executable product */ name: "swift-run", dependencies: ["Commands"], exclude: ["CMakeLists.txt"] ), .executableTarget( /** Interacts with package collections */ name: "swift-package-collection", dependencies: ["Commands", "PackageCollectionsCommand"] ), .executableTarget( /** Multi-command entry point for SwiftPM. */ name: "swift-package-manager", dependencies: [ "Basics", "Commands", "SwiftSDKCommand", "PackageCollectionsCommand", "PackageRegistryCommand", ], linkerSettings: swiftpmLinkSettings ), .executableTarget( /** Interact with package registry */ name: "swift-package-registry", dependencies: ["Commands", "PackageRegistryCommand"] ), .executableTarget( /** Utility to produce the artifacts for prebuilts */ name: "swift-build-prebuilts", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), "Basics", "Workspace", ], exclude: [ "build.sh" ] ), // The `PackageDescription` target provides the API that is available // to `Package.swift` manifests. Here we build a debug version of the // library; the bootstrap scripts build the deployable version. .target( name: "PackageDescription", path: "Sources/Runtimes/PackageDescription", exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .define("USE_IMPL_ONLY_IMPORTS"), .unsafeFlags(["-package-description-version", "999.0"]), .unsafeFlags(["-enable-library-evolution"]), ], linkerSettings: packageLibraryLinkSettings ), // The `PackagePlugin` target provides the API that is available to // plugin scripts. Here we build a debug version of the library; the // bootstrap scripts build the deployable version. .target( name: "PackagePlugin", path: "Sources/Runtimes/PackagePlugin", exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-package-description-version", "999.0"]), .unsafeFlags(["-enable-library-evolution"]), ], linkerSettings: packageLibraryLinkSettings ), // MARK: Support for Swift macros, should eventually move to a plugin-based solution .target( name: "CompilerPluginSupport", dependencies: ["PackageDescription"], path: "Sources/Runtimes/CompilerPluginSupport", exclude: ["CMakeLists.txt"], swiftSettings: commonExperimentalFeatures + [ .unsafeFlags(["-package-description-version", "999.0"]), .unsafeFlags(["-enable-library-evolution"]), ] ), // MARK: Additional Test Dependencies .target( /** SwiftPM internal build test suite support library */ name: "_InternalBuildTestSupport", dependencies: [ "Build", "XCBuildSupport", "SwiftBuildSupport", "_InternalTestSupport" ], swiftSettings: [ .unsafeFlags(["-static"]), ] ), .target( /** SwiftPM internal test suite support library */ name: "_InternalTestSupport", dependencies: [ "Basics", "DriverSupport", "PackageFingerprint", "PackageGraph", "PackageLoading", "PackageRegistry", "PackageSigning", "SourceControl", .product(name: "OrderedCollections", package: "swift-collections"), "Workspace", ] + swiftTSCTestSupportDeps, swiftSettings: [ .unsafeFlags(["-static"]), ] ), .target( /** SwiftPM internal test suite support library */ name: "_IntegrationTestSupport", dependencies: [ "_InternalTestSupport", ] + swiftTSCTestSupportDeps, ), .target( /** Test for thread-sanitizer. */ name: "tsan_utils", dependencies: [], swiftSettings: [ .unsafeFlags(["-static"]), ] ), // MARK: SwiftPM tests .testTarget( name: "_AsyncFileSystemTests", dependencies: [ "_AsyncFileSystem", "_InternalTestSupport", ] ), .testTarget( name: "SourceKitLSPAPITests", dependencies: [ "SourceKitLSPAPI", "_InternalTestSupport", ] ), .testTarget( name: "BasicsTests", dependencies: [ "Basics", "_InternalTestSupport", "tsan_utils", ], exclude: [ "Archiver/Inputs/archive.tar.gz", "Archiver/Inputs/archive.zip", "Archiver/Inputs/invalid_archive.tar.gz", "Archiver/Inputs/invalid_archive.zip", "processInputs/long-stdout-stderr", "processInputs/long-stdout-stderr.bat", "processInputs/exit4", "processInputs/exit4.bat", "processInputs/simple-stdout-stderr", "processInputs/simple-stdout-stderr.bat", "processInputs/deadlock-if-blocking-io", "processInputs/deadlock-if-blocking-io.bat", "processInputs/echo", "processInputs/echo.bat", "processInputs/in-to-out", "processInputs/in-to-out.bat", ] ), .testTarget( name: "BuildTests", dependencies: ["Build", "PackageModel", "Commands", "_InternalTestSupport", "_InternalBuildTestSupport"] ), .testTarget( name: "LLBuildManifestTests", dependencies: ["Basics", "LLBuildManifest", "_InternalTestSupport"] ), .testTarget( name: "WorkspaceTests", dependencies: ["Workspace", "_InternalTestSupport"] ), .testTarget( name: "PackageDescriptionTests", dependencies: ["PackageDescription"] ), .testTarget( name: "SPMBuildCoreTests", dependencies: ["SPMBuildCore", "_InternalTestSupport"] ), .testTarget( name: "PackageLoadingTests", dependencies: ["PackageLoading", "_InternalTestSupport"], exclude: ["Inputs", "pkgconfigInputs"] ), .testTarget( name: "PackageModelTests", dependencies: ["PackageModel", "_InternalTestSupport"] ), .testTarget( name: "PackageGraphTests", dependencies: ["PackageGraph", "_InternalTestSupport"], swiftSettings: commonExperimentalFeatures ), .testTarget( name: "PackageGraphPerformanceTests", dependencies: ["PackageGraph", "_InternalTestSupport"], exclude: [ "Inputs/PerfectHTTPServer.json", "Inputs/ZewoHTTPServer.json", "Inputs/SourceKitten.json", "Inputs/kitura.json", ] ), .testTarget( name: "PackageCollectionsModelTests", dependencies: ["PackageCollectionsModel", "_InternalTestSupport"] ), .testTarget( name: "PackageCollectionsSigningTests", dependencies: ["PackageCollectionsSigning", "_InternalTestSupport"] ), .testTarget( name: "PackageCollectionsTests", dependencies: ["PackageCollections", "_InternalTestSupport", "tsan_utils"] ), .testTarget( name: "PackageFingerprintTests", dependencies: ["PackageFingerprint", "_InternalTestSupport"] ), .testTarget( name: "PackagePluginAPITests", dependencies: ["PackagePlugin", "_InternalTestSupport"] ), .testTarget( name: "PackageRegistryTests", dependencies: ["_InternalTestSupport", "PackageRegistry"] ), .testTarget( name: "PackageSigningTests", dependencies: ["_InternalTestSupport", "PackageSigning"] ), .testTarget( name: "SBOMModelTests", dependencies: ["SBOMModel", "_InternalTestSupport"], resources: [ .copy("testfiles"), ] ), .testTarget( name: "QueryEngineTests", dependencies: ["QueryEngine", "_InternalTestSupport"] ), .testTarget( name: "SourceControlTests", dependencies: ["SourceControl", "_InternalTestSupport"], exclude: ["Inputs/TestRepo.tgz"] ), .testTarget( name: "SwiftFixItTests", dependencies: ["SwiftFixIt", "_InternalTestSupport"] ), .testTarget( name: "BinarySymbolsTests", dependencies: ["BinarySymbols", "_InternalTestSupport"] ), .testTarget( name: "XCBuildSupportTests", dependencies: ["XCBuildSupport", "_InternalTestSupport", "_InternalBuildTestSupport"], exclude: ["Inputs/Foo.pc"] ), .testTarget( name: "FunctionalPerformanceTests", dependencies: [ "swift-package-manager", "_InternalTestSupport", ] ), .testTarget( name: "SwiftBuildSupportTests", dependencies: ["SwiftBuildSupport", "_InternalTestSupport", "_InternalBuildTestSupport"] ), .testTarget( name: "BuildMetalTests", dependencies: [ "_InternalTestSupport", "Basics" ] ), // Examples (These are built to ensure they stay up to date with the API.) .executableTarget( name: "package-info", dependencies: ["Workspace"], path: "Examples/package-info/Sources/package-info" ) ], swiftLanguageModes: [.v5] ) #if canImport(Darwin) package.targets.append(contentsOf: [ .executableTarget( name: "swiftpm-testing-helper" ) ]) #endif // rdar://101868275 "error: cannot find 'XCTAssertEqual' in scope" can affect almost any functional test, so we flat out // disable them all until we know what is going on if ProcessInfo.processInfo.environment["SWIFTCI_DISABLE_SDK_DEPENDENT_TESTS"] == nil { package.targets.append(contentsOf: [ .testTarget( name: "FunctionalTests", dependencies: [ "swift-package-manager", "PackageModel", "_InternalTestSupport", ] ), .executableTarget( name: "dummy-swiftc", dependencies: [ "Basics", ] ), .testTarget( name: "_InternalTestSupportTests", dependencies: [ "_InternalTestSupport" ] ), .testTarget( name: "IntegrationTests", dependencies: [ "_IntegrationTestSupport", "_InternalTestSupport", ] + swiftTSCTestSupportDeps + swiftToolsCoreSupportAutoDeps, ), .testTarget( name: "CommandsTests", dependencies: [ "swift-package-manager", "Basics", "Build", "Commands", "PackageModel", "PackageRegistryCommand", "SourceControl", "_InternalTestSupport", "Workspace", "dummy-swiftc", ] ), .testTarget( name: "SwiftPMBuildServerTests", dependencies: [ "SwiftPMBuildServer", "_InternalTestSupport", ] + swiftToolsProtocolsDeps ), ]) } func swiftSyntaxDependencies(_ names: [String]) -> [Target.Dependency] { /// Whether swift-syntax is being built as a single dynamic library instead of as a separate library per module. /// /// This means that the swift-syntax symbols don't need to be statically linked, which allows us to stay below the /// maximum number of exported symbols on Windows, in turn allowing us to build sourcekit-lsp using SwiftPM on Windows /// and run its tests. let buildDynamicSwiftSyntaxLibrary = ProcessInfo.processInfo.environment["SWIFTSYNTAX_BUILD_DYNAMIC_LIBRARY"] != nil if buildDynamicSwiftSyntaxLibrary { return [.product(name: "_SwiftSyntaxDynamic", package: "swift-syntax")] } else { return names.map { .product(name: $0, package: "swift-syntax") } } } // Add package dependency on llbuild when not bootstrapping. // // When bootstrapping SwiftPM, we can't use llbuild as a package dependency it // will provided by whatever build system (SwiftCI, bootstrap script) is driving // the build process. So, we only add these dependencies if SwiftPM is being // built directly using SwiftPM. It is a bit unfortunate that we've add the // package dependency like this but there is no other good way of expressing // this right now. /// When not using local dependencies, the branch to use for llbuild and TSC repositories. let relatedDependenciesBranch = "main" if ProcessInfo.processInfo.environment["SWIFTPM_LLBUILD_FWK"] == nil { if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { package.dependencies += [ .package(url: "https://github.com/swiftlang/swift-llbuild.git", branch: relatedDependenciesBranch), ] } else { // In Swift CI, use a local path to llbuild to interoperate with tools // like `update-checkout`, which control the sources externally. package.dependencies += [ .package(name: "swift-llbuild", path: "../llbuild"), ] } package.targets.first(where: { $0.name == "SPMLLBuild" })!.dependencies += [ .product(name: "llbuildSwift", package: "swift-llbuild"), ] } if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { package.dependencies += [ // These need to match the versions in the swiftlang/swift repo, // utils/update_checkout/update-checkout-config.json // They are used to build the official swift toolchain. .package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch), .package(url: "https://github.com/apple/swift-argument-parser.git", revision: "1.6.1"), .package(url: "https://github.com/apple/swift-crypto.git", revision: "3.12.5"), .package(url: "https://github.com/apple/swift-system.git", revision: "1.5.0"), .package(url: "https://github.com/apple/swift-collections.git", revision: "1.1.6"), .package(url: "https://github.com/apple/swift-certificates.git", revision: "1.10.1"), .package(url: "https://github.com/swiftlang/swift-toolchain-sqlite.git", revision: "1.0.7"), // Not in toolchain, used for use in previewing documentation .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"), ] if !swiftDriverDeps.isEmpty { package.dependencies += [ .package(url: "https://github.com/swiftlang/swift-tools-support-core.git", branch: relatedDependenciesBranch), .package(url: "https://github.com/swiftlang/swift-driver.git", branch: relatedDependenciesBranch), ] } } else { package.dependencies += [ .package(path: "../swift-argument-parser"), .package(path: "../swift-crypto"), .package(path: "../swift-syntax"), .package(path: "../swift-system"), .package(path: "../swift-collections"), .package(path: "../swift-certificates"), .package(path: "../swift-toolchain-sqlite"), ] if !swiftDriverDeps.isEmpty { package.dependencies += [ .package(path: "../swift-tools-support-core"), .package(path: "../swift-driver"), ] } } /// If ENABLE_APPLE_PRODUCT_TYPES is set in the environment, then also define ENABLE_APPLE_PRODUCT_TYPES in each of the regular targets and test targets. if ProcessInfo.processInfo.environment["ENABLE_APPLE_PRODUCT_TYPES"] == "1" { for target in package.targets.filter({ $0.type == .regular || $0.type == .test }) { target.swiftSettings = (target.swiftSettings ?? []) + [ .define("ENABLE_APPLE_PRODUCT_TYPES") ] } } if !shouldUseSwiftBuildFramework { let swiftbuildsupport: Target = package.targets.first(where: { ["SwiftBuildSupport", "SwiftPMBuildServer", "SwiftPMBuildServerTests"].contains($0.name) } )! swiftbuildsupport.dependencies += [ .product(name: "SwiftBuild", package: "swift-build"), ] swiftbuildsupport.dependencies += [ // This is here to statically link the build service in the same executable as SwiftPM .product(name: "SWBBuildService", package: "swift-build"), ] if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { package.dependencies += [ .package(url: "https://github.com/swiftlang/swift-build.git", branch: relatedDependenciesBranch), .package(url: "https://github.com/swiftlang/swift-tools-protocols.git", branch: relatedDependenciesBranch), ] } else { package.dependencies += [ .package(path: "../swift-build"), .package(path: "../swift-tools-protocols"), ] } } ================================================ FILE: README.md ================================================ # Swift Package Manager Project The Swift Package Manager is a tool for managing distribution of source code, aimed at making it easy to share your code and reuse others’ code. The tool directly addresses the challenges of compiling and linking Swift packages, managing dependencies, versioning, and supporting flexible distribution and collaboration models. We’ve designed the system to make it easy to share packages on services like GitHub, but packages are also great for private personal development, sharing code within a team, or at any other granularity. Swift Package Manager includes a build system that can build for macOS and Linux. Starting with Xcode 11, Xcode integrates with SwiftPM to provide support for including packages in iOS, macOS, watchOS, and tvOS applications. The [SourceKit-LSP](https://github.com/swiftlang/sourcekit-lsp) project leverages libSwiftPM and provides [Language Server Protocol](https://langserver.org/) implementation for editors that support LSP. --- ## Table of Contents * [Getting Started](#getting-started) * [Documentation](#documentation) * [System Requirements](#system-requirements) * [Installation](#installation) * [Contributing](#contributing) * [Reporting issues](#reporting-issues) * [License](#license) --- ## Getting Started Please use [this guide](https://www.swift.org/documentation/package-manager/) for learning package manager basics. --- ## Documentation For Quick Help use the `swift package --help` command. For documentation on using Swift Package Manager, creating packages, and more, see the [Package Manager Docs](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs). For documentation on developing the Swift Package Manager itself, see the [contribution guide](CONTRIBUTING.md). For detailed documentation on the package manifest API, see [PackageDescription API](https://docs.swift.org/swiftpm/documentation/packagedescription). For release notes with information about changes between versions, see the [release notes](Documentation/ReleaseNotes). --- ## System Requirements The package manager’s system requirements are the same as [those for Swift](https://github.com/swiftlang/swift/blob/main/docs/HowToGuides/GettingStarted.md#system-requirements) with the caveat that the package manager requires Git at runtime as well as build-time. --- ## Installation The package manager is available as part the Swift toolchains available on [Swift.org](https://swift.org/download/) including snapshots for the latest versions built from `main` branch. For installation instructions for downloaded snapshots, please see the [Getting Started](https://swift.org/getting-started/#installing-swift) section of [Swift.org](https://swift.org). The Swift Package Manager is also included in Xcode 8.0 and all subsequent releases. You can verify your installation by typing `swift package --version` in a terminal: ```sh $ swift package --version Apple Swift Package Manager - ... ``` ## Contributing There are several ways to contribute to Swift Package Manager. To learn about the policies, best practices that govern contributions to the Swift project and instructions for setting up the development environment please read the [Contributor Guide](CONTRIBUTING.md). The Swift package manager uses [llbuild](https://github.com/apple/swift-llbuild) as the underlying build system for compiling source files. It is also open source and part of the Swift project. --- ## Reporting issues If you have any trouble with the package manager, help is available. We recommend: * The [Swift Forums](https://forums.swift.org/c/development/swiftpm/), * SwiftPM's [bug tracker](https://github.com/swiftlang/swift-package-manager/issues) When reporting an issue please follow the bug reporting guidelines, they can be found in [contribution guide](./CONTRIBUTING.md#reporting-issues). If you’re not comfortable sharing your question with the list, contact details for the code owners can be found in [CODEOWNERS](CODEOWNERS); however, Swift Forums is usually the best place to go for help. --- ## License Copyright 2015 - 2025 Apple Inc. and the Swift project authors. Licensed under Apache License v2.0 with Runtime Library Exception. See [https://swift.org/LICENSE.txt](https://swift.org/LICENSE.txt) for license information. See [https://swift.org/CONTRIBUTORS.txt](https://swift.org/CONTRIBUTORS.txt) for Swift project authors. ================================================ FILE: Sources/AppleProductTypes/Product.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// @_spi(PackageProductSettings) import PackageDescription #if ENABLE_APPLE_PRODUCT_TYPES extension Product { /// Creates an iOS application package product. /// /// - Parameters: /// - name: The name of the application product. /// - targets: The targets to include in the application product; one and only one of them should be an executable target. /// - settings: The settings that define the core properties of the application. public static func iOSApplication( name: String, targets: [String], bundleIdentifier: String? = nil, teamIdentifier: String? = nil, displayVersion: String? = nil, bundleVersion: String? = nil, iconAssetName: String? = nil, accentColorAssetName: String? = nil, supportedDeviceFamilies: [ProductSetting.IOSAppInfo.DeviceFamily], supportedInterfaceOrientations: [ProductSetting.IOSAppInfo.InterfaceOrientation], capabilities: [ProductSetting.IOSAppInfo.Capability] = [], additionalInfoPlistContentFilePath: String? = nil ) -> Product { return iOSApplication( name: name, targets: targets, bundleIdentifier: bundleIdentifier, teamIdentifier: teamIdentifier, displayVersion: displayVersion, bundleVersion: bundleVersion, appIcon: iconAssetName.map({ .asset($0) }), accentColor: accentColorAssetName.map({ .asset($0) }), supportedDeviceFamilies: supportedDeviceFamilies, supportedInterfaceOrientations: supportedInterfaceOrientations, capabilities: capabilities, additionalInfoPlistContentFilePath: additionalInfoPlistContentFilePath ) } /// Creates an iOS application package product. /// /// - Parameters: /// - name: The name of the application product. /// - targets: The targets to include in the application product; one and only one of them should be an executable target. /// - settings: The settings that define the core properties of the application. @available(_PackageDescription, introduced: 5.6) public static func iOSApplication( name: String, targets: [String], bundleIdentifier: String? = nil, teamIdentifier: String? = nil, displayVersion: String? = nil, bundleVersion: String? = nil, appIcon: ProductSetting.IOSAppInfo.AppIcon? = nil, accentColor: ProductSetting.IOSAppInfo.AccentColor? = nil, supportedDeviceFamilies: [ProductSetting.IOSAppInfo.DeviceFamily], supportedInterfaceOrientations: [ProductSetting.IOSAppInfo.InterfaceOrientation], capabilities: [ProductSetting.IOSAppInfo.Capability] = [], appCategory: ProductSetting.IOSAppInfo.AppCategory? = nil, additionalInfoPlistContentFilePath: String? = nil ) -> Product { return .executable(name: name, targets: targets, settings: [ bundleIdentifier.map{ .bundleIdentifier($0) }, teamIdentifier.map{ .teamIdentifier($0) }, displayVersion.map{ .displayVersion($0) }, bundleVersion.map{ .bundleVersion($0) }, .iOSAppInfo(ProductSetting.IOSAppInfo( appIcon: appIcon, accentColor: accentColor, supportedDeviceFamilies: supportedDeviceFamilies, supportedInterfaceOrientations: supportedInterfaceOrientations, capabilities: capabilities, appCategory: appCategory, additionalInfoPlistContentFilePath: additionalInfoPlistContentFilePath )) ].compactMap{ $0 }) } } #endif ================================================ FILE: Sources/Basics/Archiver/Archiver.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency import struct Foundation.URL /// The `Archiver` protocol abstracts away the different operations surrounding archives. public protocol Archiver: Sendable { /// A set of extensions the current archiver supports. var supportedExtensions: Set { get } /// Asynchronously extracts the contents of an archive to a destination folder. /// /// - Parameters: /// - archivePath: The `AbsolutePath` to the archive to extract. /// - destinationPath: The `AbsolutePath` to the directory to extract to. /// - completion: The completion handler that will be called when the operation finishes to notify of its success. @available(*, noasync, message: "Use the async alternative") func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) /// Asynchronously compress the contents of a directory to a destination archive. /// /// - Parameters: /// - directory: The `AbsolutePath` to the archive to extract. /// - destinationPath: The `AbsolutePath` to the directory to extract to. func compress( directory: AbsolutePath, to destinationPath: AbsolutePath ) async throws /// Asynchronously validates if a file is an archive. /// /// - Parameters: /// - path: The `AbsolutePath` to the archive to validate. /// - completion: The completion handler that will be called when the operation finishes to notify of its success. @available(*, noasync, message: "Use the async alternative") func validate( path: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) } extension Archiver { /// Asynchronously extracts the contents of an archive to a destination folder. /// /// - Parameters: /// - archivePath: The `AbsolutePath` to the archive to extract. /// - destinationPath: The `AbsolutePath` to the directory to extract to. public func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath ) async throws { try await withCheckedThrowingContinuation { continuation in self.extract(from: archivePath, to: destinationPath, completion: { continuation.resume(with: $0) }) } } /// Asynchronously validates if a file is an archive. /// /// - Parameters: /// - path: The `AbsolutePath` to the archive to validate. public func validate( path: AbsolutePath ) async throws -> Bool { try await withCheckedThrowingContinuation { continuation in self.validate(path: path, completion: { continuation.resume(with: $0) }) } } package func isFileSupported(_ lastPathComponent: String) -> Bool { self.supportedExtensions.contains(where: { lastPathComponent.hasSuffix($0) }) } } ================================================ FILE: Sources/Basics/Archiver/TarArchiver.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Dispatch.DispatchQueue import struct Dispatch.DispatchTime import struct TSCBasic.FileSystemError /// An `Archiver` that handles Tar archives using the command-line `tar` tool. public struct TarArchiver: Archiver { public let supportedExtensions: Set = ["tar", "tar.gz"] /// The file-system implementation used for various file-system operations and checks. private let fileSystem: FileSystem /// Helper for cancelling in-flight requests private let cancellator: Cancellator /// The underlying command internal let tarCommand: String /// Creates a `TarArchiver`. /// /// - Parameters: /// - fileSystem: The file system to used by the `TarArchiver`. /// - cancellator: Cancellation handler public init(fileSystem: FileSystem, cancellator: Cancellator? = .none) { self.fileSystem = fileSystem self.cancellator = cancellator ?? Cancellator(observabilityScope: .none) #if os(Windows) self.tarCommand = "tar.exe" #else self.tarCommand = "tar" #endif } public func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) { do { guard self.fileSystem.exists(archivePath) else { throw FileSystemError(.noEntry, archivePath.underlying) } guard self.fileSystem.isDirectory(destinationPath) else { throw FileSystemError(.notDirectory, destinationPath.underlying) } let process = AsyncProcess( arguments: [self.tarCommand, "zxf", archivePath.pathString, "-C", destinationPath.pathString] ) guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } DispatchQueue.sharedConcurrent.async { defer { self.cancellator.deregister(registrationKey) } completion(.init(catching: { try process.launch() let processResult = try process.waitUntilExit() guard processResult.exitStatus == .terminated(code: 0) else { throw try StringError(processResult.utf8stderrOutput()) } })) } } catch { return completion(.failure(error)) } } public func compress( directory: AbsolutePath, to destinationPath: AbsolutePath ) async throws { guard self.fileSystem.isDirectory(directory) else { throw FileSystemError(.notDirectory, directory.underlying) } let process = AsyncProcess( arguments: [self.tarCommand, "acf", destinationPath.pathString, directory.basename], environment: .current, workingDirectory: directory.parentDirectory ) guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } defer { self.cancellator.deregister(registrationKey) } try process.launch() let processResult = try await process.waitUntilExit() guard processResult.exitStatus == .terminated(code: 0) else { throw try StringError(processResult.utf8stderrOutput()) } } public func validate(path: AbsolutePath, completion: @escaping @Sendable (Result) -> Void) { do { guard self.fileSystem.exists(path) else { throw FileSystemError(.noEntry, path.underlying) } let process = AsyncProcess(arguments: [self.tarCommand, "tf", path.pathString]) guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } DispatchQueue.sharedConcurrent.async { defer { self.cancellator.deregister(registrationKey) } completion(.init(catching: { try process.launch() let processResult = try process.waitUntilExit() return processResult.exitStatus == .terminated(code: 0) })) } } catch { return completion(.failure(error)) } } public func cancel(deadline: DispatchTime) throws { try self.cancellator.cancel(deadline: deadline) } } ================================================ FILE: Sources/Basics/Archiver/UniversalArchiver.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// An `Archiver` that handles multiple formats by delegating to other existing archivers each dedicated to its own /// format. public struct UniversalArchiver: Archiver { public let supportedExtensions: Set /// Errors specific to the implementation of ``UniversalArchiver``. enum Error: Swift.Error { case unknownFormat([String], AbsolutePath) case noFileNameExtension(AbsolutePath) var description: String { switch self { case .unknownFormat(let ext, let path): return "unknown format with extension \(ext.joined(separator: ".")) at path `\(path)`" case .noFileNameExtension(let path): return "file at path `\(path)` has no extension to detect archival format from" } } } /// A dictionary that maps file extension strings to archiver instances that supports these extensions. private let formatMapping: [String: any Archiver] public init(_ fileSystem: any FileSystem, _ cancellator: Cancellator? = nil) { var formatMapping = [String: any Archiver]() var supportedExtensions = Set() for archiver in [ ZipArchiver(fileSystem: fileSystem, cancellator: cancellator), TarArchiver(fileSystem: fileSystem, cancellator: cancellator), ] as [any Archiver] { supportedExtensions.formUnion(archiver.supportedExtensions) for ext in archiver.supportedExtensions { formatMapping[ext] = archiver } } self.formatMapping = formatMapping self.supportedExtensions = supportedExtensions } private func archiver(for archivePath: AbsolutePath) throws -> any Archiver { guard var extensions = archivePath.allExtensions, extensions.count > 0 else { throw Error.noFileNameExtension(archivePath) } // None of the archivers support extensions with more than 2 extension components if extensions.count > 2 { extensions = extensions.suffix(2) } if let archiver = self.formatMapping[extensions.joined(separator: ".")] { return archiver } else if let lastExtension = extensions.last, let archiver = self.formatMapping[lastExtension] { return archiver } else { throw Error.unknownFormat(extensions, archivePath) } } public func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) { do { let archiver = try archiver(for: archivePath) archiver.extract(from: archivePath, to: destinationPath, completion: completion) } catch { completion(.failure(error)) } } public func compress( directory: AbsolutePath, to destinationPath: AbsolutePath ) async throws { let archiver = try archiver(for: destinationPath) try await archiver.compress(directory: directory, to: destinationPath) } public func validate( path: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) { do { let archiver = try archiver(for: path) archiver.validate(path: path, completion: completion) } catch { completion(.failure(error)) } } } ================================================ FILE: Sources/Basics/Archiver/ZipArchiver.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Dispatch import struct TSCBasic.FileSystemError #if os(Windows) import WinSDK #endif /// An `Archiver` that handles ZIP archives using the command-line `zip` and `unzip` tools. public struct ZipArchiver: Archiver, Cancellable { public var supportedExtensions: Set { ["zip"] } /// The file-system implementation used for various file-system operations and checks. private let fileSystem: FileSystem /// Helper for cancelling in-flight requests private let cancellator: Cancellator /// Absolute path to the Windows tar in the system folder #if os(Windows) internal let windowsTar: String #else internal let unzip = "unzip" internal let zip = "zip" #endif #if os(FreeBSD) internal let tar = "tar" #endif /// Creates a `ZipArchiver`. /// /// - Parameters: /// - fileSystem: The file-system to be used by the `ZipArchiver`. /// - cancellator: Cancellation handler public init(fileSystem: FileSystem, cancellator: Cancellator? = .none) { self.fileSystem = fileSystem self.cancellator = cancellator ?? Cancellator(observabilityScope: .none) #if os(Windows) var tarPath: PWSTR? defer { CoTaskMemFree(tarPath) } let hr = withUnsafePointer(to: FOLDERID_System) { id in SHGetKnownFolderPath(id, DWORD(KF_FLAG_DEFAULT.rawValue), nil, &tarPath) } if hr == S_OK, let tarPath { windowsTar = String(decodingCString: tarPath, as: UTF16.self) + "\\tar.exe" } else { windowsTar = "tar.exe" } #endif } public func extract( from archivePath: AbsolutePath, to destinationPath: AbsolutePath, completion: @escaping @Sendable (Result) -> Void ) { do { guard self.fileSystem.exists(archivePath) else { throw FileSystemError(.noEntry, archivePath.underlying) } guard self.fileSystem.isDirectory(destinationPath) else { throw FileSystemError(.notDirectory, destinationPath.underlying) } #if os(Windows) // FileManager lost the ability to detect tar.exe as executable. // It's part of system32 anyway so use the absolute path. let process = AsyncProcess(arguments: [windowsTar, "xf", archivePath.pathString, "-C", destinationPath.pathString]) #else let process = AsyncProcess(arguments: [ self.unzip, archivePath.pathString, "-d", destinationPath.pathString, ]) #endif guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } DispatchQueue.sharedConcurrent.async { defer { self.cancellator.deregister(registrationKey) } completion(.init(catching: { try process.launch() let processResult = try process.waitUntilExit() guard processResult.exitStatus == .terminated(code: 0) else { throw try StringError(processResult.utf8stderrOutput()) } })) } } catch { return completion(.failure(error)) } } public func compress( directory: AbsolutePath, to destinationPath: AbsolutePath ) async throws { guard self.fileSystem.isDirectory(directory) else { throw FileSystemError(.notDirectory, directory.underlying) } #if os(Windows) let process = AsyncProcess( // FIXME: are these the right arguments? arguments: [windowsTar, "-a", "-c", "-f", destinationPath.pathString, directory.basename], workingDirectory: directory.parentDirectory ) #elseif os(FreeBSD) // On FreeBSD, the unzip command is available in base but not the zip command. // Therefore; we use libarchive(bsdtar) to produce the ZIP archive instead. let process = AsyncProcess( arguments: [ self.tar, "-c", "--format", "zip", "-f", destinationPath.pathString, directory.basename, ], workingDirectory: directory.parentDirectory ) #else // This is to work around `swift package-registry publish` tool failing on // Amazon Linux 2 due to it having an earlier Glibc version (rdar://116370323) // and therefore posix_spawn_file_actions_addchdir_np is unavailable. // Instead of passing `workingDirectory` param to TSC.Process, which will trigger // SPM_posix_spawn_file_actions_addchdir_np_supported check, we shell out and // do `cd` explicitly before `zip`. let process = AsyncProcess( arguments: [ "/bin/sh", "-c", "cd \(directory.parentDirectory.underlying.pathString) && \(self.zip) -ry \(destinationPath.pathString) \(directory.basename)" ] ) #endif guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } defer { self.cancellator.deregister(registrationKey) } try process.launch() let processResult = try await process.waitUntilExit() guard processResult.exitStatus == .terminated(code: 0) else { throw try StringError(processResult.utf8stderrOutput()) } } public func validate(path: AbsolutePath, completion: @escaping @Sendable (Result) -> Void) { do { guard self.fileSystem.exists(path) else { throw FileSystemError(.noEntry, path.underlying) } #if os(Windows) let process = AsyncProcess(arguments: [windowsTar, "tf", path.pathString]) #else let process = AsyncProcess(arguments: [self.unzip, "-t", path.pathString]) #endif guard let registrationKey = self.cancellator.register(process) else { throw CancellationError.failedToRegisterProcess(process) } DispatchQueue.sharedConcurrent.async { defer { self.cancellator.deregister(registrationKey) } completion(.init(catching: { try process.launch() let processResult = try process.waitUntilExit() return processResult.exitStatus == .terminated(code: 0) })) } } catch { return completion(.failure(error)) } } public func cancel(deadline: DispatchTime) throws { try self.cancellator.cancel(deadline: deadline) } } ================================================ FILE: Sources/Basics/ArrayHelpers.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2025 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// public func nextItem(in array: [T], after item: T) -> T? { for (index, element) in array.enumerated() { if element == item { let nextIndex = index + 1 return nextIndex < array.count ? array[nextIndex] : nil } } return nil // Item not found or it's the last item } /// Determines if an array contains all elements of a subset array in any order. /// - Parameters: /// - array: The array to search within /// - subset: The subset array to check for /// - shouldBeContiguous: if `true`, the subset match must be contiguous sequenence /// - Returns: `true` if all elements in `subset` are present in `array`, `false` otherwise public func contains(array: [T], subset: [T], shouldBeContiguous: Bool = true) -> Bool { if shouldBeContiguous { return containsContiguousSubset(array: array, subset: subset) } else { return containsNonContiguousSubset(array: array, subset: subset) } } /// Determines if an array contains all elements of a subset array in any order. /// - Parameters: /// - array: The array to search within /// - subset: The subset array to check for /// - Returns: `true` if all elements in `subset` are present in `array`, `false` otherwise internal func containsNonContiguousSubset(array: [T], subset: [T]) -> Bool { for element in subset { if !array.contains(element) { return false } } return true } /// Determines if an array contains a contiguous subsequence matching the subset array. /// - Parameters: /// - array: The array to search within /// - subset: The contiguous subset array to check for /// - Returns: `true` if `subset` appears as a contiguous subsequence in `array`, `false` otherwise internal func containsContiguousSubset(array: [T], subset: [T]) -> Bool { guard !subset.isEmpty else { return true } guard subset.count <= array.count else { return false } for startIndex in 0...(array.count - subset.count) { var matches = true for (offset, element) in subset.enumerated() { if array[startIndex + offset] != element { matches = false break } } if matches { return true } } return false } ================================================ FILE: Sources/Basics/AuthorizationProvider.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2021-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import TSCBasic import struct Foundation.Data import struct Foundation.Date import struct Foundation.URL #if canImport(Security) import Security #endif public protocol AuthorizationProvider: Sendable { func authentication(for url: URL) -> (user: String, password: String)? } public protocol AuthorizationWriter { func addOrUpdate( for url: URL, user: String, password: String, persist: Bool ) async throws func remove(for url: URL) async throws } public enum AuthorizationProviderError: Error { case invalidURLHost case notFound case other(String) } extension AuthorizationProvider { @Sendable public func httpAuthorizationHeader(for url: URL) -> String? { guard let (user, password) = self.authentication(for: url) else { return nil } let authString = "\(user):\(password)" let authData = Data(authString.utf8) return "Basic \(authData.base64EncodedString())" } } // MARK: - netrc public final class NetrcAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { // marked internal for testing internal let path: AbsolutePath private let fileSystem: FileSystem private let cache = ThreadSafeKeyValueStore() public init(path: AbsolutePath, fileSystem: FileSystem) throws { self.path = path self.fileSystem = fileSystem // validate file is okay at the time of initializing the provider _ = try Self.load(fileSystem: fileSystem, path: path) } public func addOrUpdate( for url: URL, user: String, password: String, persist: Bool = true ) async throws { guard let machine = Self.machine(for: url) else { throw AuthorizationProviderError.invalidURLHost } if !persist { self.cache[machine] = (user, password) return } // Same entry already exists, no need to add or update let netrc = try? Self.load(fileSystem: self.fileSystem, path: self.path) guard netrc?.machines .first(where: { $0.name.lowercased() == machine && $0.login == user && $0.password == password }) == nil else { return } do { // Append to end of file try self.fileSystem.withLock(on: self.path, type: .exclusive) { let contents = try? self.fileSystem.readFileContents(self.path).contents try self.fileSystem.writeFileContents(self.path) { stream in // Write existing contents if let contents, !contents.isEmpty { stream.write(contents) stream.write("\n") } stream.write("machine \(machine) login \(user) password \(password)") stream.write("\n") } } } catch { throw AuthorizationProviderError .other("Failed to update netrc file at \(self.path): \(error.interpolationDescription)") } } public func remove(for url: URL) async throws { throw AuthorizationProviderError .other("User must edit netrc file at \(self.path) manually to remove entries") } public func authentication(for url: URL) -> (user: String, password: String)? { if let machine = Self.machine(for: url), let cached = self.cache[machine] { return cached } return self.machine(for: url).map { (user: $0.login, password: $0.password) } } private func machine(for url: URL) -> Basics.Netrc.Machine? { // Since updates are appended to the end of the file, we // take the _last_ match to use the most recent entry. if let machine = Self.machine(for: url), let existing = self.machines.last(where: { $0.name.lowercased() == machine }) { return existing } // No match found. Use the first default if any. if let existing = self.machines.first(where: { $0.isDefault }) { return existing } return .none } // marked internal for testing internal var machines: [Basics.Netrc.Machine] { // this ignores any errors reading the file // initial validation is done at the time of initializing the provider // and if the file becomes corrupt at runtime it will handle it gracefully let netrc = try? Self.load(fileSystem: self.fileSystem, path: self.path) return netrc?.machines ?? [] } private static func load(fileSystem: FileSystem, path: AbsolutePath) throws -> Netrc? { do { return try NetrcParser.parse(fileSystem: fileSystem, path: path) } catch NetrcError.fileNotFound, NetrcError.machineNotFound { // These are recoverable errors. return .none } } private static func machine(for url: URL) -> String? { guard let host = url.host?.lowercased() else { return nil } return host.isEmpty ? nil : host } } // MARK: - Keychain #if canImport(Security) public final class KeychainAuthorizationProvider: AuthorizationProvider, AuthorizationWriter { private let observabilityScope: ObservabilityScope private let cache = ThreadSafeKeyValueStore() public init(observabilityScope: ObservabilityScope) { self.observabilityScope = observabilityScope } public func addOrUpdate( for url: URL, user: String, password: String, persist: Bool = true ) async throws { guard let protocolHostPort = ProtocolHostPort(from: url) else { throw AuthorizationProviderError.invalidURLHost } self.observabilityScope .emit(debug: "add/update credentials for '\(protocolHostPort)' [\(url.absoluteString)] in keychain") if !persist { self.cache[protocolHostPort.description] = (user, password) return } let passwordData = Data(password.utf8) if !(try self.update(protocolHostPort: protocolHostPort, account: user, password: passwordData)) { try self.create(protocolHostPort: protocolHostPort, account: user, password: passwordData) } } public func remove(for url: URL) async throws { guard let protocolHostPort = ProtocolHostPort(from: url) else { throw AuthorizationProviderError.invalidURLHost } self.observabilityScope .emit(debug: "remove credentials for '\(protocolHostPort)' [\(url.absoluteString)] from keychain") try self.delete(protocolHostPort: protocolHostPort) } public func authentication(for url: URL) -> (user: String, password: String)? { guard let protocolHostPort = ProtocolHostPort(from: url) else { return nil } if let cached = self.cache[protocolHostPort.description] { return cached } self.observabilityScope .emit(debug: "search credentials for '\(protocolHostPort)' [\(url.absoluteString)] in keychain") do { guard let existingItems = try self.search(protocolHostPort: protocolHostPort) as? [[String: Any]] else { throw AuthorizationProviderError .other("Failed to extract credentials for '\(protocolHostPort)' from keychain") } // Log warning if there is more than one result if existingItems.count > 1 { self.observabilityScope .emit( warning: "multiple (\(existingItems.count)) keychain entries found for '\(protocolHostPort)' [\(url.absoluteString)]" ) } // Sort by modification timestamp let sortedItems = existingItems.sorted { switch ( $0[kSecAttrModificationDate as String] as? Date, $1[kSecAttrModificationDate as String] as? Date ) { case (nil, nil): return false case (_, nil): return true case (nil, _): return false case (.some(let left), .some(let right)): return left < right } } // Return most recently modified item guard let mostRecent = sortedItems.last, let created = mostRecent[kSecAttrCreationDate as String] as? Date, // Get password for this specific item let existingItem = try self.get( protocolHostPort: protocolHostPort, created: created, modified: mostRecent[kSecAttrModificationDate as String] as? Date ) as? [String: Any], let passwordData = existingItem[kSecValueData as String] as? Data, let account = existingItem[kSecAttrAccount as String] as? String else { throw AuthorizationProviderError .other("Failed to extract credentials for '\(protocolHostPort)' from keychain") } let password = String(decoding: passwordData, as: UTF8.self) return (user: account, password: password) } catch { switch error { case AuthorizationProviderError.notFound: self.observabilityScope.emit(debug: "no credentials found for '\(protocolHostPort)' in keychain") case AuthorizationProviderError.other(let detail): self.observabilityScope.emit(error: detail) default: self.observabilityScope.emit( error: "failed to find credentials for '\(protocolHostPort)' in keychain", underlyingError: error ) } return nil } } private func create(protocolHostPort: ProtocolHostPort, account: String, password: Data) throws { var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrProtocol as String: protocolHostPort.protocolCFString, kSecAttrServer as String: protocolHostPort.server, kSecAttrAccount as String: account, kSecValueData as String: password] if let port = protocolHostPort.port { query[kSecAttrPort as String] = port } let status = SecItemAdd(query as CFDictionary, nil) guard status == errSecSuccess else { throw AuthorizationProviderError .other("Failed to save credentials for '\(protocolHostPort)' to keychain: status \(status)") } } private func update(protocolHostPort: ProtocolHostPort, account: String, password: Data) throws -> Bool { var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrProtocol as String: protocolHostPort.protocolCFString, kSecAttrServer as String: protocolHostPort.server] if let port = protocolHostPort.port { query[kSecAttrPort as String] = port } let attributes: [String: Any] = [kSecAttrAccount as String: account, kSecValueData as String: password] let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary) guard status != errSecItemNotFound else { return false } guard status == errSecSuccess else { throw AuthorizationProviderError .other("Failed to update credentials for '\(protocolHostPort)' in keychain: status \(status)") } return true } private func delete(protocolHostPort: ProtocolHostPort) throws { var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrProtocol as String: protocolHostPort.protocolCFString, kSecAttrServer as String: protocolHostPort.server] if let port = protocolHostPort.port { query[kSecAttrPort as String] = port } let status = SecItemDelete(query as CFDictionary) guard status == errSecSuccess else { throw AuthorizationProviderError .other("Failed to delete credentials for '\(protocolHostPort)' from keychain: status \(status)") } } private func search(protocolHostPort: ProtocolHostPort) throws -> CFTypeRef? { var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrProtocol as String: protocolHostPort.protocolCFString, kSecAttrServer as String: protocolHostPort.server, kSecMatchLimit as String: kSecMatchLimitAll, // returns all matches kSecReturnAttributes as String: true] // https://developer.apple.com/documentation/security/keychain_services/keychain_items/searching_for_keychain_items // Can't combine `kSecMatchLimitAll` and `kSecReturnData` (which contains password) if let port = protocolHostPort.port { query[kSecAttrPort as String] = port } var items: CFTypeRef? // Search keychain for server's username and password, if any. let status = SecItemCopyMatching(query as CFDictionary, &items) guard status != errSecItemNotFound else { throw AuthorizationProviderError.notFound } guard status == errSecSuccess else { throw AuthorizationProviderError .other("Failed to find credentials for '\(protocolHostPort)' in keychain: status \(status)") } return items } private func get(protocolHostPort: ProtocolHostPort, created: Date, modified: Date?) throws -> CFTypeRef? { self.observabilityScope .emit(debug: "read credentials for '\(protocolHostPort)', created at \(created), in keychain") var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrProtocol as String: protocolHostPort.protocolCFString, kSecAttrServer as String: protocolHostPort.server, kSecAttrCreationDate as String: created, kSecMatchLimit as String: kSecMatchLimitOne, // limit to one match kSecReturnAttributes as String: true, kSecReturnData as String: true] // password if let port = protocolHostPort.port { query[kSecAttrPort as String] = port } if let modified { query[kSecAttrModificationDate as String] = modified } var item: CFTypeRef? // Search keychain for server's username and password, if any. let status = SecItemCopyMatching(query as CFDictionary, &item) guard status != errSecItemNotFound else { throw AuthorizationProviderError.notFound } guard status == errSecSuccess else { throw AuthorizationProviderError .other("Failed to find credentials for '\(protocolHostPort)' in keychain: status \(status)") } return item } struct ProtocolHostPort: Hashable, CustomStringConvertible { let `protocol`: String? let host: String let port: Int? var server: String { self.host } var protocolCFString: CFString { // See // https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values?language=swift // for a list of possible values for the `kSecAttrProtocol` attribute. switch self.protocol { case "https": return kSecAttrProtocolHTTPS case "http": return kSecAttrProtocolHTTP default: return kSecAttrProtocolHTTPS } } init?(from url: URL) { guard let host = url.host?.lowercased(), !host.isEmpty else { return nil } self.protocol = url.scheme?.lowercased() self.host = host self.port = url.port } var description: String { "\(self.protocol.map { "\($0)://" } ?? "")\(self.host)\(self.port.map { ":\($0)" } ?? "")" } } } #endif // MARK: - Composite public struct CompositeAuthorizationProvider: AuthorizationProvider { // marked internal for testing internal let providers: [AuthorizationProvider] private let observabilityScope: ObservabilityScope public init(_ providers: AuthorizationProvider..., observabilityScope: ObservabilityScope) { self.init(providers, observabilityScope: observabilityScope) } public init(_ providers: [AuthorizationProvider], observabilityScope: ObservabilityScope) { self.providers = providers self.observabilityScope = observabilityScope } public func authentication(for url: URL) -> (user: String, password: String)? { for provider in self.providers { if let authentication = provider.authentication(for: url) { switch provider { case let provider as NetrcAuthorizationProvider: self.observabilityScope.emit(info: "credentials for \(url) found in netrc file at \(provider.path)") #if canImport(Security) case is KeychainAuthorizationProvider: self.observabilityScope.emit(info: "credentials for \(url) found in keychain") #endif default: self.observabilityScope.emit(info: "credentials for \(url) found in \(provider)") } return authentication } } return nil } } ================================================ FILE: Sources/Basics/CMakeLists.txt ================================================ # This source file is part of the Swift open source project # # Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for Swift project authors add_library(Basics Archiver/Archiver.swift Archiver/TarArchiver.swift Archiver/ZipArchiver.swift Archiver/UniversalArchiver.swift AuthorizationProvider.swift Cancellator.swift Collections/ByteString+Extensions.swift Collections/Dictionary+Extensions.swift Collections/IdentifiableSet.swift Collections/String+Extensions.swift Concurrency/AsyncProcess.swift Concurrency/ConcurrencyHelpers.swift Concurrency/NSLock+Extensions.swift Concurrency/SendableBox.swift Concurrency/ThreadSafeArrayStore.swift Concurrency/ThreadSafeBox.swift Concurrency/ThreadSafeKeyValueStore.swift Concurrency/ThrowingDefer.swift Concurrency/TokenBucket.swift DispatchTimeInterval+Extensions.swift Environment/Environment.swift Environment/EnvironmentKey.swift Environment/EnvironmentShims.swift Errors.swift FileSystem/AbsolutePath.swift FileSystem/CommonParentDirectory.swift FileSystem/FileSystem+Extensions.swift FileSystem/InMemoryFileSystem.swift FileSystem/NativePathExtensions.swift FileSystem/RelativePath.swift FileSystem/TemporaryFile.swift FileSystem/TSCAdapters.swift FileSystem/VirtualFileSystem.swift FileSystem/VFSOverlay.swift Graph/AdjacencyMatrix.swift Graph/DirectedGraph.swift Graph/GraphAlgorithms.swift Graph/UndirectedGraph.swift SourceControlURL.swift HTTPClient/HTTPClient.swift HTTPClient/HTTPClientConfiguration.swift HTTPClient/HTTPClientError.swift HTTPClient/HTTPClientHeaders.swift HTTPClient/HTTPClientRequest.swift HTTPClient/HTTPClientResponse.swift HTTPClient/HTTPMethod.swift HTTPClient/LegacyHTTPClient.swift HTTPClient/LegacyHTTPClientRequest.swift HTTPClient/URLSessionHTTPClient.swift ImportScanning.swift JSON+Extensions.swift JSONDecoder+Extensions.swift Netrc.swift Observability.swift OSSignpost.swift Process.swift ProgressAnimation/NinjaProgressAnimation.swift ProgressAnimation/PercentProgressAnimation.swift ProgressAnimation/ProgressAnimationProtocol.swift ProgressAnimation/SingleLinePercentProgressAnimation.swift ProgressAnimation/ThrottledProgressAnimation.swift SQLite.swift Sandbox.swift SendableTimeInterval.swift Serialization/SerializedJSON.swift SwiftVersion.swift SQLiteBackedCache.swift TestingLibrary.swift Triple+Basics.swift URL.swift Version+Extensions.swift WritableByteStream+Extensions.swift Vendor/Triple.swift Vendor/Triple+Platforms.swift) target_link_libraries(Basics PUBLIC _AsyncFileSystem SwiftCollections::OrderedCollections TSCBasic TSCUtility) target_link_libraries(Basics PRIVATE SwiftCollections::DequeModule SPMSQLite3 TSCclibc) # NOTE(compnerd) workaround for CMake not setting up include flags yet set_target_properties(Basics PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) target_link_options(Basics PRIVATE "$<$:SHELL:-Xlinker -framework -Xlinker Security>") install(TARGETS Basics ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) set_property(GLOBAL APPEND PROPERTY SwiftPM_EXPORTS Basics) ================================================ FILE: Sources/Basics/Cancellator.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Dispatch import Foundation import class TSCBasic.Thread #if canImport(WinSDK) import WinSDK #elseif canImport(Android) import Android #endif public typealias CancellationHandler = @Sendable (DispatchTime) async throws -> Void public final class Cancellator: Cancellable, Sendable { public typealias RegistrationKey = String private let observabilityScope: ObservabilityScope? private let registry = ThreadSafeKeyValueStore() private let cancelling = ThreadSafeBox(false) private static let signalHandlerLock = NSLock() private static var isSignalHandlerInstalled = false public init(observabilityScope: ObservabilityScope?) { self.observabilityScope = observabilityScope } #if os(Windows) // unfortunately this is needed for C callback handlers used by Windows shutdown handler static var shared: Cancellator? #endif /// Installs signal handlers to terminate sub-processes on cancellation. public func installSignalHandlers() { Self.signalHandlerLock.withLock { precondition(!Self.isSignalHandlerInstalled) #if os(Windows) // Closures passed to `SetConsoleCtrlHandler` can't capture context, working around that with a global. Self.shared = self // set shutdown handler to terminate sub-processes, etc _ = SetConsoleCtrlHandler({ _ in // Terminate all processes on receiving an interrupt signal. try? Cancellator.shared?.cancel(deadline: .now() + .seconds(30)) // Reset the handler. _ = SetConsoleCtrlHandler(nil, false) // Exit as if by signal() TerminateProcess(GetCurrentProcess(), 3) return true }, true) #else // trap SIGINT to terminate sub-processes, etc signal(SIGINT, SIG_IGN) let interruptSignalSource = DispatchSource.makeSignalSource(signal: SIGINT) interruptSignalSource.setEventHandler { [weak self] in // cancel the trap? interruptSignalSource.cancel() // Terminate all processes on receiving an interrupt signal. try? self?.cancel(deadline: .now() + .seconds(30)) // Install the default signal handler. var action = sigaction() #if canImport(Darwin) || os(OpenBSD) || os(FreeBSD) action.__sigaction_u.__sa_handler = SIG_DFL #elseif canImport(Musl) action.__sa_handler.sa_handler = SIG_DFL #elseif os(Android) action.sa_handler = SIG_DFL #else action.__sigaction_handler = unsafeBitCast( SIG_DFL, to: sigaction.__Unnamed_union___sigaction_handler.self ) #endif sigaction(SIGINT, &action, nil) kill(getpid(), SIGINT) // ignore-unacceptable-language } interruptSignalSource.resume() #endif Self.isSignalHandlerInstalled = true } } @discardableResult public func register(name: String, handler: @escaping CancellationHandler) -> RegistrationKey? { if self.cancelling.get() { self.observabilityScope?.emit(debug: "not registering '\(name)' with terminator, termination in progress") return .none } let key = UUID().uuidString self.observabilityScope?.emit(debug: "registering '\(name)' with terminator") self.registry[key] = (name: name, handler: handler) return key } @discardableResult public func register(name: String, handler: Cancellable) -> RegistrationKey? { self.register(name: name, handler: handler.cancel(deadline:)) } @discardableResult public func register(name: String, handler: AsyncCancellable) -> RegistrationKey? { self.register(name: name, handler: handler.cancel(deadline:)) } @discardableResult public func register(name: String, handler: @escaping @Sendable () throws -> Void) -> RegistrationKey? { self.register(name: name, handler: { _ in try handler() }) } package func register(_ process: AsyncProcess) -> RegistrationKey? { self.register(name: "\(process.arguments.joined(separator: " "))", handler: process.terminate) } #if !canImport(Darwin) || os(macOS) public func register(_ process: Foundation.Process) -> RegistrationKey? { self.register(name: "\(process.description)", handler: process.terminate(timeout:)) } #endif public func deregister(_ key: RegistrationKey) { self.registry[key] = nil } public func cancel(deadline: DispatchTime) throws { self._cancel(deadline: deadline) } // marked internal for testing @discardableResult internal func _cancel(deadline: DispatchTime? = .none) -> Int { self.cancelling.put(true) self.observabilityScope? .emit(info: "starting cancellation cycle with \(self.registry.count) cancellation handlers registered") let deadline = deadline ?? .now() + .seconds(30) // deadline for individual handlers set slightly before overall deadline let delta: DispatchTimeInterval = .nanoseconds(abs(deadline.distance(to: .now()).nanoseconds() ?? 0) / 5) let handlersDeadline = deadline - delta let cancellationHandlers = self.registry.get() let cancelled = ThreadSafeArrayStore() let group = DispatchGroup() for (_, (name, handler)) in cancellationHandlers { group.enter() Task { defer { group.leave() } do { self.observabilityScope?.emit(debug: "cancelling '\(name)'") try await handler(handlersDeadline) cancelled.append(name) } catch { self.observabilityScope?.emit( warning: "failed cancelling '\(name)'", underlyingError: error ) } } } if case .timedOut = group.wait(timeout: deadline) { self.observabilityScope? .emit( warning: "timeout waiting for cancellation with \(cancellationHandlers.count - cancelled.count) cancellation handlers remaining" ) } else { self.observabilityScope?.emit(info: "cancellation cycle completed successfully") } self.cancelling.put(false) return cancelled.count } } public protocol Cancellable { func cancel(deadline: DispatchTime) throws -> Void } public protocol AsyncCancellable { func cancel(deadline: DispatchTime) async throws -> Void } public struct CancellationError: Error, CustomStringConvertible { public let description: String public init() { self.init(description: "Operation cancelled") } private init(description: String) { self.description = description } static func failedToRegisterProcess(_ process: AsyncProcess) -> Self { Self( description: """ failed to register a cancellation handler for this process invocation `\( process.arguments.joined(separator: " ") )` """ ) } } extension AsyncProcess { fileprivate func terminate(timeout: DispatchTime) { // send graceful shutdown signal self.signal(SIGINT) // start a thread to see if we need to terminate more forcibly let forceKillSemaphore = DispatchSemaphore(value: 0) let forceKillThread = TSCBasic.Thread { if case .timedOut = forceKillSemaphore.wait(timeout: timeout) { // send a force-kill signal // ignore-unacceptable-language #if os(Windows) self.signal(SIGTERM) #else self.signal(SIGKILL) #endif } } forceKillThread.start() _ = try? self.waitUntilExit() forceKillSemaphore.signal() // let the force-kill thread know we do not need it any more //ignore-unacceptable-language // join the force-kill thread thread so we don't exit before everything terminates //ignore-unacceptable-language forceKillThread.join() } } #if !canImport(Darwin) || os(macOS) extension Foundation.Process { fileprivate func terminate(timeout: DispatchTime) { guard self.isRunning else { return } // send graceful shutdown signal (SIGINT) self.interrupt() // start a thread to see if we need to terminate more forcibly let forceKillSemaphore = DispatchSemaphore(value: 0) let forceKillThread = TSCBasic.Thread { if case .timedOut = forceKillSemaphore.wait(timeout: timeout) { guard self.isRunning else { return } // force kill (SIGTERM) // ignore-unacceptable-language self.terminate() } } forceKillThread.start() self.waitUntilExit() forceKillSemaphore.signal() // let the force-kill thread know we do not need it any more //ignore-unacceptable-language // join the force-kill thread thread so we don't exit before everything terminates //ignore-unacceptable-language forceKillThread.join() } } #endif ================================================ FILE: Sources/Basics/Collections/ByteString+Extensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct TSCBasic.ByteString import struct TSCBasic.SHA256 extension ByteString { /// A lowercase, hexadecimal representation of the SHA256 hash /// generated for the byte string's contents. /// /// This property uses the CryptoKit implementation of /// Secure Hashing Algorithm 2 (SHA-2) hashing with a 256-bit digest, when available, /// falling back on a native implementation in Swift provided by TSCBasic. public var sha256Checksum: String { SHA256().hash(self).hexadecimalRepresentation } public init(json: SerializedJSON) { self.init(json.underlying.utf8) } } ================================================ FILE: Sources/Basics/Collections/Dictionary+Extensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import TSCBasic extension Dictionary { @inlinable @discardableResult public mutating func memoize(key: Key, body: () throws -> Value) rethrows -> Value { if let value = self[key] { return value } let value = try body() self[key] = value return value } } extension Dictionary { public init(throwingUniqueKeysWithValues keysAndValues: S) throws where S: Sequence, S.Element == (Key, Value) { self.init() for pair in keysAndValues { guard !self.keys.contains(pair.0) else { throw StringError("duplicate key found: '\(pair.0)'") } self[pair.0] = pair.1 } } } ================================================ FILE: Sources/Basics/Collections/IdentifiableSet.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct OrderedCollections.OrderedDictionary /// Replacement for `Set` elements that can't be `Hashable`, but can be `Identifiable`. public struct IdentifiableSet: Collection { public init() { self.storage = [:] } public init(_ sequence: some Sequence) { self.storage = .init(pickLastWhenDuplicateFound: sequence) } fileprivate typealias Storage = OrderedDictionary public struct Index: Comparable { public static func < (lhs: IdentifiableSet.Index, rhs: IdentifiableSet.Index) -> Bool { lhs.storageIndex < rhs.storageIndex } fileprivate let storageIndex: Storage.Index } private var storage: Storage public var startIndex: Index { Index(storageIndex: self.storage.elements.startIndex) } public var endIndex: Index { Index(storageIndex: self.storage.elements.endIndex) } public var values: some Sequence { self.storage.values } public subscript(position: Index) -> Element { self.storage.elements[position.storageIndex].value } public subscript(id: Element.ID) -> Element? { get { self.storage[id] } set { self.storage[id] = newValue } } public func index(after i: Index) -> Index { Index(storageIndex: self.storage.elements.index(after: i.storageIndex)) } public mutating func insert(_ element: Element) { self.storage[element.id] = element } public func union(_ otherSequence: some Sequence) -> Self { var result = self for element in otherSequence { result.storage[element.id] = element } return result } public mutating func formUnion(_ otherSequence: some Sequence) { for element in otherSequence { self.storage[element.id] = element } } public func intersection(_ otherSequence: some Sequence) -> Self { let keysToRemove = Set(self.storage.keys).subtracting(otherSequence.map(\.id)) var result = self for key in keysToRemove { result.storage.removeValue(forKey: key) } return result } public func subtracting(_ otherSequence: some Sequence) -> Self { var result = self for element in otherSequence { result.storage.removeValue(forKey: element.id) } return result } public func contains(id: Element.ID) -> Bool { self.storage.keys.contains(id) } public mutating func remove(id: Element.ID) -> Element? { self.storage.removeValue(forKey: id) } public mutating func remove(_ member: Element) -> Element? { self.storage.removeValue(forKey: member.id) } } extension OrderedDictionary where Value: Identifiable, Key == Value.ID { fileprivate init(pickLastWhenDuplicateFound sequence: some Sequence) { self.init(sequence.map { ($0.id, $0) }, uniquingKeysWith: { $1 }) } } extension IdentifiableSet: Equatable { public static func == (_ lhs: Self, _ rhs: Self) -> Bool { lhs.storage.keys == rhs.storage.keys } } extension IdentifiableSet: Hashable { public func hash(into hasher: inout Hasher) { for key in self.storage.keys { hasher.combine(key) } } } extension IdentifiableSet: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Element...) { self.init(elements) } } ================================================ FILE: Sources/Basics/Collections/String+Extensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct TSCBasic.SHA256 extension String { /// generated for the byte string's contents. /// /// This property uses the CryptoKit implementation of /// Secure Hashing Algorithm 2 (SHA-2) hashing with a 256-bit digest, when available, /// falling back on a native implementation in Swift provided by TSCBasic. public var sha256Checksum: String { SHA256().hash(self).hexadecimalRepresentation } /// Drops the given suffix from the string, if present. public func spm_dropPrefix(_ prefix: String) -> String { if self.hasPrefix(prefix) { return String(self.dropFirst(prefix.count)) } return self } public var isValidIdentifier: Bool { guard !isEmpty else { return false } return allSatisfy { $0.isLetter || $0.isNumber || $0 == "_" } } } ================================================ FILE: Sources/Basics/Concurrency/AsyncProcess.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency import Dispatch import Foundation #if os(Windows) import TSCLibc #elseif canImport(Android) import Android #endif #if !os(Windows) && !canImport(Darwin) #if USE_IMPL_ONLY_IMPORTS @_implementationOnly import func TSCclibc.SPM_posix_spawn_file_actions_addchdir_np_supported @_implementationOnly import func TSCclibc.SPM_posix_spawn_file_actions_addchdir_np #else private import func TSCclibc.SPM_posix_spawn_file_actions_addchdir_np_supported private import func TSCclibc.SPM_posix_spawn_file_actions_addchdir_np #endif // #if USE_IMPL_ONLY_IMPORTS #endif import class TSCBasic.CStringArray import class TSCBasic.LocalFileOutputByteStream import enum TSCBasic.SystemError import class TSCBasic.Thread import protocol TSCBasic.WritableByteStream /// Process result data which is available after process termination. package struct AsyncProcessResult: CustomStringConvertible, Sendable { package enum Error: Swift.Error, Sendable { /// The output is not a valid UTF8 sequence. case illegalUTF8Sequence /// The process had a non zero exit. case nonZeroExit(AsyncProcessResult) /// The process failed with a `SystemError` (this is used to still provide context on the process that was /// launched). case systemError(arguments: [String], underlyingError: Swift.Error) } package enum ExitStatus: Equatable, Sendable { /// The process was terminated normally with a exit code. case terminated(code: Int32) #if os(Windows) /// The process was terminated abnormally. case abnormal(exception: UInt32) #else /// The process was terminated due to a signal. case signalled(signal: Int32) #endif } /// The arguments with which the process was launched. package let arguments: [String] /// The environment with which the process was launched. package let environment: Environment /// The exit status of the process. package let exitStatus: ExitStatus /// The output bytes of the process. Available only if the process was /// asked to redirect its output and no stdout output closure was set. package let output: Result<[UInt8], Swift.Error> /// The output bytes of the process. Available only if the process was /// asked to redirect its output and no stderr output closure was set. package let stderrOutput: Result<[UInt8], Swift.Error> /// Create an instance using a POSIX process exit status code and output result. /// /// See `waitpid(2)` for information on the exit status code. package init( arguments: [String], environment: Environment, exitStatusCode: Int32, normal: Bool, output: Result<[UInt8], Swift.Error>, stderrOutput: Result<[UInt8], Swift.Error> ) { let exitStatus: ExitStatus #if os(Windows) if normal { exitStatus = .terminated(code: exitStatusCode) } else { exitStatus = .abnormal(exception: UInt32(exitStatusCode)) } #else if WIFSIGNALED(exitStatusCode) { exitStatus = .signalled(signal: WTERMSIG(exitStatusCode)) } else { precondition(WIFEXITED(exitStatusCode), "unexpected exit status \(exitStatusCode)") exitStatus = .terminated(code: WEXITSTATUS(exitStatusCode)) } #endif self.init( arguments: arguments, environment: environment, exitStatus: exitStatus, output: output, stderrOutput: stderrOutput ) } /// Create an instance using an exit status and output result. package init( arguments: [String], environment: Environment, exitStatus: ExitStatus, output: Result<[UInt8], Swift.Error>, stderrOutput: Result<[UInt8], Swift.Error> ) { self.arguments = arguments self.environment = environment self.output = output self.stderrOutput = stderrOutput self.exitStatus = exitStatus } /// Converts stdout output bytes to string, assuming they're UTF8. package func utf8Output() throws -> String { try String(decoding: output.get(), as: Unicode.UTF8.self) } /// Converts stderr output bytes to string, assuming they're UTF8. package func utf8stderrOutput() throws -> String { try String(decoding: stderrOutput.get(), as: Unicode.UTF8.self) } package var description: String { """ """ } } extension AsyncProcess: @unchecked Sendable {} extension DispatchQueue { // a shared concurrent queue for running concurrent asynchronous operations static let processConcurrent = DispatchQueue( label: "swift.org.swift-tsc.process.concurrent", attributes: .concurrent ) } /// Process allows spawning new subprocesses and working with them. /// /// Note: This class is thread safe. package final class AsyncProcess { /// Errors when attempting to invoke a process package enum Error: Swift.Error, Sendable { /// The program requested to be executed cannot be found on the existing search paths, or is not executable. case missingExecutableProgram(program: String) /// The current OS does not support the workingDirectory API. case workingDirectoryNotSupported /// The stdin could not be opened. case stdinUnavailable } package typealias ReadableStream = AsyncStream<[UInt8]> package enum OutputRedirection: Sendable { /// Do not redirect the output case none /// Collect stdout and stderr output and provide it back via ``AsyncProcessResult`` object. If /// `redirectStderr` is `true`, `stderr` be redirected to `stdout`. case collect(redirectStderr: Bool) /// Stream `stdout` and `stderr` via the corresponding closures. If `redirectStderr` is `true`, `stderr` will /// be redirected to `stdout`. case stream(stdout: OutputClosure, stderr: OutputClosure, redirectStderr: Bool) /// Stream stdout and stderr as `AsyncSequence` provided as an argument to closures passed to /// ``AsyncProcess/launch(stdoutStream:stderrStream:)``. case asyncStream( stdoutStream: ReadableStream, stdoutContinuation: ReadableStream.Continuation, stderrStream: ReadableStream, stderrContinuation: ReadableStream.Continuation ) /// Default collect OutputRedirection that defaults to not redirect stderr. Provided for API compatibility. package static let collect: Self = .collect(redirectStderr: false) /// Default stream OutputRedirection that defaults to not redirect stderr. Provided for API compatibility. package static func stream(stdout: @escaping OutputClosure, stderr: @escaping OutputClosure) -> Self { .stream(stdout: stdout, stderr: stderr, redirectStderr: false) } package var redirectsOutput: Bool { switch self { case .none: false case .collect, .stream, .asyncStream: true } } package var outputClosures: (stdoutClosure: OutputClosure, stderrClosure: OutputClosure)? { switch self { case let .stream(stdoutClosure, stderrClosure, _): (stdoutClosure: stdoutClosure, stderrClosure: stderrClosure) case let .asyncStream(_, stdoutContinuation, _, stderrContinuation): (stdoutClosure: { stdoutContinuation.yield($0) }, stderrClosure: { stderrContinuation.yield($0) }) case .collect, .none: nil } } package var redirectStderr: Bool { switch self { case .collect(let redirectStderr): redirectStderr case .stream(_, _, let redirectStderr): redirectStderr default: false } } } // process execution mutable state private enum State { case idle case readingOutput(sync: DispatchGroup) case outputReady(stdout: Result<[UInt8], Swift.Error>, stderr: Result<[UInt8], Swift.Error>) case complete(AsyncProcessResult) case failed(Swift.Error) } /// Typealias for process id type. #if !os(Windows) package typealias ProcessID = pid_t #else package typealias ProcessID = DWORD #endif /// Typealias for stdout/stderr output closure. package typealias OutputClosure = @Sendable ([UInt8]) -> Void /// Typealias for logging handling closure. package typealias LoggingHandler = @Sendable (String) -> Void /// Global logging handler storage. private static let _loggingHandler = ThreadSafeBox() /// Global logging handler. Use with care! preferably use instance level instead of setting one globally. package static var loggingHandler: LoggingHandler? { get { return _loggingHandler.get() ?? nil } @available( *, deprecated, message: "use instance level `loggingHandler` passed via `init` instead of setting one globally." ) set { _loggingHandler.put(newValue) } } package let loggingHandler: LoggingHandler? /// The arguments to execute. package let arguments: [String] package let environment: Environment /// The path to the directory under which to run the process. package let workingDirectory: AbsolutePath? /// The process id of the spawned process, available after the process is launched. #if os(Windows) private var _process: Foundation.Process? package var processID: ProcessID { DWORD(self._process?.processIdentifier ?? 0) } #else package private(set) var processID = ProcessID() #endif // process execution mutable state private var state: State = .idle private let stateLock = NSLock() private static let sharedCompletionQueue = DispatchQueue(label: "org.swift.tools-support-core.process-completion") private var completionQueue = AsyncProcess.sharedCompletionQueue // ideally we would use the state for this, but we need to access it while the waitForExit is locking state private var _launched = false private let launchedLock = NSLock() package var launched: Bool { self.launchedLock.withLock { self._launched } } /// How process redirects its output. package let outputRedirection: OutputRedirection /// Indicates if a new progress group is created for the child process. private let startNewProcessGroup: Bool /// Cache of validated executables. /// /// Key: Executable name or path. /// Value: Path to the executable, if found. private static let validatedExecutablesMap = ThreadSafeKeyValueStore() /// Create a new process instance. /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - workingDirectory: The path to the directory under which to run the process. /// - outputRedirection: How process redirects its output. Default value is .collect. /// - startNewProcessGroup: If true, a new progress group is created for the child making it /// continue running even if the parent is killed or interrupted. Default value is true. //ignore-unacceptable-language /// - loggingHandler: Handler for logging messages /// package init( arguments: [String], environment: Environment = .current, workingDirectory: AbsolutePath, outputRedirection: OutputRedirection = .collect, startNewProcessGroup: Bool = true, loggingHandler: LoggingHandler? = .none ) { self.arguments = arguments self.environment = environment self.workingDirectory = workingDirectory self.outputRedirection = outputRedirection self.startNewProcessGroup = startNewProcessGroup self.loggingHandler = loggingHandler ?? AsyncProcess.loggingHandler } /// Create a new process instance. /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - outputRedirection: How process redirects its output. Default value is .collect. /// - verbose: If true, launch() will print the arguments of the subprocess before launching it. /// - startNewProcessGroup: If true, a new progress group is created for the child making it /// continue running even if the parent is killed or interrupted. Default value is true. //ignore-unacceptable-language /// - loggingHandler: Handler for logging messages package init( arguments: [String], environment: Environment = .current, outputRedirection: OutputRedirection = .collect, startNewProcessGroup: Bool = true, loggingHandler: LoggingHandler? = .none, workingDirectory: AbsolutePath? = nil ) { self.arguments = arguments self.environment = environment self.workingDirectory = workingDirectory self.outputRedirection = outputRedirection self.startNewProcessGroup = startNewProcessGroup self.loggingHandler = loggingHandler ?? AsyncProcess.loggingHandler } package convenience init( args: [String], environment: Environment = .current, outputRedirection: OutputRedirection = .collect, loggingHandler: LoggingHandler? = .none ) { self.init( arguments: args, environment: environment, outputRedirection: outputRedirection, loggingHandler: loggingHandler ) } package convenience init( args: String..., environment: Environment = .current, outputRedirection: OutputRedirection = .collect, loggingHandler: LoggingHandler? = .none ) { self.init( arguments: args, environment: environment, outputRedirection: outputRedirection, loggingHandler: loggingHandler ) } /// Returns the path of the the given program if found in the search paths. /// /// The program can be executable name, relative path or absolute path. package static func findExecutable( _ program: String, workingDirectory: AbsolutePath? = nil ) -> AbsolutePath? { if let abs = try? AbsolutePath(validating: program) { return abs } let cwdOpt = workingDirectory ?? localFileSystem.currentWorkingDirectory // The program might be a multi-component relative path. if let rel = try? RelativePath(validating: program), rel.components.count > 1 { if let cwd = cwdOpt { let abs = AbsolutePath(cwd, rel) if localFileSystem.isExecutableFile(abs) { return abs } } return nil } // From here on out, the program is an executable name, i.e. it doesn't contain a "/" let lookup: () -> AbsolutePath? = { let envSearchPaths = getEnvSearchPaths( pathString: Environment.current[.path], currentWorkingDirectory: cwdOpt ) let value = lookupExecutablePath( filename: program, currentWorkingDirectory: cwdOpt, searchPaths: envSearchPaths ) return value } // This should cover the most common cases, i.e. when the cache is most helpful. if workingDirectory == localFileSystem.currentWorkingDirectory { return AsyncProcess.validatedExecutablesMap.memoize(program, body: lookup) } else { return lookup() } } /// Launch the subprocess. Returns a WritableByteStream object that can be used to communicate to the process's /// stdin. If needed, the stream can be closed using the close() API. Otherwise, the stream will be closed /// automatically. @discardableResult package func launch() throws -> any WritableByteStream { precondition( self.arguments.count > 0 && !self.arguments[0].isEmpty, "Need at least one argument to launch the process." ) self.launchedLock.withLock { precondition(!self._launched, "It is not allowed to launch the same process object again.") self._launched = true } // Print the arguments if we are verbose. if let loggingHandler = self.loggingHandler { loggingHandler(self.arguments.map { $0.spm_shellEscaped() }.joined(separator: " ")) } // Look for executable. let executable = self.arguments[0] guard let executablePath = AsyncProcess.findExecutable(executable, workingDirectory: workingDirectory) else { throw AsyncProcess.Error.missingExecutableProgram(program: executable) } #if os(Windows) let process = Foundation.Process() self._process = process process.arguments = Array(self.arguments.dropFirst()) // Avoid including the executable URL twice. if let workingDirectory { process.currentDirectoryURL = workingDirectory.asURL } process.executableURL = executablePath.asURL process.environment = .init(self.environment) let stdinPipe = Pipe() process.standardInput = stdinPipe let group = DispatchGroup() var stdout: [UInt8] = [] let stdoutLock = NSLock() var stderr: [UInt8] = [] let stderrLock = NSLock() if self.outputRedirection.redirectsOutput { let stdoutPipe = Pipe() let stderrPipe = Pipe() group.enter() stdoutPipe.fileHandleForReading.readabilityHandler = { (fh: FileHandle) in let data = (try? fh.read(upToCount: Int.max)) ?? Data() if data.count == 0 { stdoutPipe.fileHandleForReading.readabilityHandler = nil group.leave() } else { let contents = data.withUnsafeBytes { [UInt8]($0) } self.outputRedirection.outputClosures?.stdoutClosure(contents) stdoutLock.withLock { stdout += contents } } } group.enter() stderrPipe.fileHandleForReading.readabilityHandler = { (fh: FileHandle) in let data = (try? fh.read(upToCount: Int.max)) ?? Data() if data.count == 0 { stderrPipe.fileHandleForReading.readabilityHandler = nil group.leave() } else { let contents = data.withUnsafeBytes { [UInt8]($0) } self.outputRedirection.outputClosures?.stderrClosure(contents) stderrLock.withLock { stderr += contents } } } process.standardOutput = stdoutPipe process.standardError = stderrPipe } // first set state then start reading threads let sync = DispatchGroup() sync.enter() self.stateLock.withLock { self.state = .readingOutput(sync: sync) } group.notify(queue: self.completionQueue) { self.stateLock.withLock { self.state = .outputReady(stdout: .success(stdout), stderr: .success(stderr)) } sync.leave() } try process.run() return stdinPipe.fileHandleForWriting #elseif(!canImport(Darwin) || os(macOS)) // Initialize the spawn attributes. #if os(Android) var attributes: posix_spawnattr_t! = nil #elseif canImport(Darwin) || os(OpenBSD) || os(FreeBSD) var attributes: posix_spawnattr_t? = nil #else var attributes = posix_spawnattr_t() #endif posix_spawnattr_init(&attributes) defer { posix_spawnattr_destroy(&attributes) } // Unmask all signals. var noSignals = sigset_t() sigemptyset(&noSignals) posix_spawnattr_setsigmask(&attributes, &noSignals) // Reset all signals to default behavior. #if canImport(Darwin) var mostSignals = sigset_t() sigfillset(&mostSignals) sigdelset(&mostSignals, SIGKILL) sigdelset(&mostSignals, SIGSTOP) posix_spawnattr_setsigdefault(&attributes, &mostSignals) #else // On Linux, this can only be used to reset signals that are legal to // modify, so we have to take care about the set we use. var mostSignals = sigset_t() sigemptyset(&mostSignals) for i in 1 ..< SIGSYS { if i == SIGKILL || i == SIGSTOP { continue } sigaddset(&mostSignals, i) } posix_spawnattr_setsigdefault(&attributes, &mostSignals) #endif // Set the attribute flags. var flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF if self.startNewProcessGroup { // Establish a separate process group. flags |= POSIX_SPAWN_SETPGROUP posix_spawnattr_setpgroup(&attributes, 0) } posix_spawnattr_setflags(&attributes, Int16(flags)) // Setup the file actions. #if os(Android) var fileActions: posix_spawn_file_actions_t! = nil #elseif canImport(Darwin) || os(Android) || os(OpenBSD) || os(FreeBSD) var fileActions: posix_spawn_file_actions_t? = nil #else var fileActions = posix_spawn_file_actions_t() #endif posix_spawn_file_actions_init(&fileActions) defer { posix_spawn_file_actions_destroy(&fileActions) } if let workingDirectory = workingDirectory?.pathString { #if canImport(Darwin) posix_spawn_file_actions_addchdir_np(&fileActions, workingDirectory) #else guard SPM_posix_spawn_file_actions_addchdir_np_supported() else { throw AsyncProcess.Error.workingDirectoryNotSupported } SPM_posix_spawn_file_actions_addchdir_np(&fileActions, workingDirectory) #endif } var stdinPipe: [Int32] = [-1, -1] try open(pipe: &stdinPipe) guard let fp = fdopen(stdinPipe[1], "wb") else { throw AsyncProcess.Error.stdinUnavailable } let stdinStream = try LocalFileOutputByteStream(filePointer: fp, closeOnDeinit: true) // Dupe the read portion of the remote to 0. posix_spawn_file_actions_adddup2(&fileActions, stdinPipe[0], 0) // Close the other side's pipe since it was dupped to 0. posix_spawn_file_actions_addclose(&fileActions, stdinPipe[0]) posix_spawn_file_actions_addclose(&fileActions, stdinPipe[1]) var outputPipe: [Int32] = [-1, -1] var stderrPipe: [Int32] = [-1, -1] if self.outputRedirection.redirectsOutput { // Open the pipe. try open(pipe: &outputPipe) // Open the write end of the pipe. posix_spawn_file_actions_adddup2(&fileActions, outputPipe[1], 1) // Close the other ends of the pipe since they were dupped to 1. posix_spawn_file_actions_addclose(&fileActions, outputPipe[0]) posix_spawn_file_actions_addclose(&fileActions, outputPipe[1]) if self.outputRedirection.redirectStderr { // If merged was requested, send stderr to stdout. posix_spawn_file_actions_adddup2(&fileActions, 1, 2) } else { // If no redirect was requested, open the pipe for stderr. try open(pipe: &stderrPipe) posix_spawn_file_actions_adddup2(&fileActions, stderrPipe[1], 2) // Close the other ends of the pipe since they were dupped to 2. posix_spawn_file_actions_addclose(&fileActions, stderrPipe[0]) posix_spawn_file_actions_addclose(&fileActions, stderrPipe[1]) } } else { posix_spawn_file_actions_adddup2(&fileActions, 1, 1) posix_spawn_file_actions_adddup2(&fileActions, 2, 2) } var resolvedArgs = self.arguments if workingDirectory != nil { resolvedArgs[0] = executablePath.pathString } let argv = CStringArray(resolvedArgs) let envValues = environment.map { "\($0.0)=\($0.1)" } let env = CStringArray(envValues) let rv = posix_spawnp(&self.processID, argv.cArray[0]!, &fileActions, &attributes, argv.cArray, env.cArray) guard rv == 0 else { throw SystemError.posix_spawn(rv, self.arguments) } do { // Close the local read end of the input pipe. try close(fd: stdinPipe[0]) let group = DispatchGroup() if !self.outputRedirection.redirectsOutput { // no stdout or stderr in this case self.stateLock.withLock { self.state = .outputReady(stdout: .success([]), stderr: .success([])) } } else { var pending: Result<[UInt8], Swift.Error>? let pendingLock = NSLock() let outputClosures = self.outputRedirection.outputClosures // Close the local write end of the output pipe. try close(fd: outputPipe[1]) // Create a thread and start reading the output on it. group.enter() let stdoutThread = Thread { [weak self] in if let readResult = self?.readOutput( onFD: outputPipe[0], outputClosure: outputClosures?.stdoutClosure ) { pendingLock.withLock { if let stderrResult = pending { self?.stateLock.withLock { self?.state = .outputReady(stdout: readResult, stderr: stderrResult) } } else { pending = readResult } } group.leave() } else if let stderrResult = (pendingLock.withLock { pending }) { // TODO: this is more of an error self?.stateLock.withLock { self?.state = .outputReady(stdout: .success([]), stderr: stderrResult) } group.leave() } } // Only schedule a thread for stderr if no redirect was requested. var stderrThread: Thread? = nil if !self.outputRedirection.redirectStderr { // Close the local write end of the stderr pipe. try close(fd: stderrPipe[1]) // Create a thread and start reading the stderr output on it. group.enter() stderrThread = Thread { [weak self] in if let readResult = self?.readOutput( onFD: stderrPipe[0], outputClosure: outputClosures?.stderrClosure ) { pendingLock.withLock { if let stdoutResult = pending { self?.stateLock.withLock { self?.state = .outputReady(stdout: stdoutResult, stderr: readResult) } } else { pending = readResult } } group.leave() } else if let stdoutResult = (pendingLock.withLock { pending }) { // TODO: this is more of an error self?.stateLock.withLock { self?.state = .outputReady(stdout: stdoutResult, stderr: .success([])) } group.leave() } } } else { pendingLock.withLock { pending = .success([]) // no stderr in this case } } // first set state then start reading threads self.stateLock.withLock { self.state = .readingOutput(sync: group) } stdoutThread.start() stderrThread?.start() } return stdinStream } catch { throw AsyncProcessResult.Error.systemError(arguments: self.arguments, underlyingError: error) } #else preconditionFailure("Process spawning is not available") #endif // POSIX implementation } /// Executes the process I/O state machine, returning the result when finished. @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) @discardableResult package func waitUntilExit() async throws -> AsyncProcessResult { try await withCheckedThrowingContinuation { continuation in DispatchQueue.processConcurrent.async { self.waitUntilExit({ continuation.resume(with: $0) }) } } } /// Blocks the calling process until the subprocess finishes execution. @available(*, noasync) @discardableResult package func waitUntilExit() throws -> AsyncProcessResult { let group = DispatchGroup() group.enter() let resultBox = ThreadSafeBox?>() self.waitUntilExit { result in resultBox.put(result) group.leave() } group.wait() return try resultBox.get().unsafelyUnwrapped.get() } /// Executes the process I/O state machine, calling completion block when finished. private func waitUntilExit(_ completion: @Sendable @escaping (Result) -> Void) { self.stateLock.lock() switch self.state { case .idle: defer { self.stateLock.unlock() } preconditionFailure("The process is not yet launched.") case .complete(let result): self.stateLock.unlock() completion(.success(result)) case .failed(let error): self.stateLock.unlock() completion(.failure(error)) case .readingOutput(let sync): self.stateLock.unlock() sync.notify(queue: self.completionQueue) { self.waitUntilExit(completion) } case .outputReady(let stdoutResult, let stderrResult): defer { self.stateLock.unlock() } // Wait until process finishes execution. #if os(Windows) precondition(self._process != nil, "The process is not yet launched.") let p = self._process! p.waitUntilExit() let exitStatusCode = p.terminationStatus let normalExit = p.terminationReason == .exit #else var exitStatusCode: Int32 = 0 var result = waitpid(processID, &exitStatusCode, 0) while result == -1 && errno == EINTR { result = waitpid(self.processID, &exitStatusCode, 0) } if result == -1 { self.state = .failed(SystemError.waitpid(errno)) } let normalExit = !WIFSIGNALED(result) #endif // Construct the result. let executionResult = AsyncProcessResult( arguments: arguments, environment: environment, exitStatusCode: exitStatusCode, normal: normalExit, output: stdoutResult, stderrOutput: stderrResult ) self.state = .complete(executionResult) self.completionQueue.async { self.waitUntilExit(completion) } } } #if !os(Windows) /// Reads the given fd and returns its result. /// /// Closes the fd before returning. private func readOutput(onFD fd: Int32, outputClosure: OutputClosure?) -> Result<[UInt8], Swift.Error> { // Read all of the data from the output pipe. let N = 4096 var buf = [UInt8](repeating: 0, count: N + 1) var out = [UInt8]() var error: Swift.Error? = nil loop: while true { let n = read(fd, &buf, N) switch n { case -1: if errno == EINTR { continue } else { error = SystemError.read(errno) break loop } case 0: // Close the read end of the output pipe. // We should avoid closing the read end of the pipe in case // -1 because the child process may still have content to be // flushed into the write end of the pipe. If the read end of the // pipe is closed, then a write will cause a SIGPIPE signal to // be generated for the calling process. If the calling process is // ignoring this signal, then write fails with the error EPIPE. close(fd) break loop default: let data = buf[0 ..< n] if let outputClosure { outputClosure(Array(data)) } else { out += data } } } // Construct the output result. return error.map(Result.failure) ?? .success(out) } #endif /// Send a signal to the process. /// /// Note: This will signal all processes in the process group. package func signal(_ signal: Int32) { #if os(Windows) if signal == SIGINT { self._process?.interrupt() } else { self._process?.terminate() } #else assert(self.launched, "The process is not yet launched.") kill(self.startNewProcessGroup ? -self.processID : self.processID, signal) //ignore-unacceptable-language #endif } } extension AsyncProcess { /// Execute a subprocess and returns the result when it finishes execution /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages package static func popen( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) async throws -> AsyncProcessResult { let process = AsyncProcess( arguments: arguments, environment: environment, outputRedirection: .collect, loggingHandler: loggingHandler ) try process.launch() return try await process.waitUntilExit() } /// Execute a subprocess and returns the result when it finishes execution /// /// - Parameters: /// - args: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages package static func popen( args: String..., environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) async throws -> AsyncProcessResult { try await self.popen(arguments: args, environment: environment, loggingHandler: loggingHandler) } package typealias DuplexStreamHandler = @Sendable (_ stdinStream: WritableByteStream, _ stdoutStream: ReadableStream) async throws -> () package typealias ReadableStreamHandler = @Sendable (_ stderrStream: ReadableStream) async throws -> () /// Launches a new `AsyncProcess` instances, allowing the caller to consume `stdout` and `stderr` output /// with handlers that support structured concurrency. /// - Parameters: /// - arguments: CLI command used to launch the process. /// - environment: environment variables passed to the launched process. /// - loggingHandler: handler used for logging, /// - stdoutHandler: asynchronous bidirectional handler closure that receives `stdin` and `stdout` streams as /// arguments. /// - stderrHandler: asynchronous unidirectional handler closure that receives `stderr` stream as an argument. /// - Returns: ``AsyncProcessResult`` value as received from the underlying ``AsyncProcess/waitUntilExit()`` call /// made on ``AsyncProcess`` instance. package static func popen( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none, stdoutHandler: @escaping DuplexStreamHandler, stderrHandler: ReadableStreamHandler? = nil ) async throws -> AsyncProcessResult { let (stdoutStream, stdoutContinuation) = ReadableStream.makeStream() let (stderrStream, stderrContinuation) = ReadableStream.makeStream() let process = AsyncProcess( arguments: arguments, environment: environment, outputRedirection: .stream { stdoutContinuation.yield($0) } stderr: { stderrContinuation.yield($0) }, loggingHandler: loggingHandler ) return try await withThrowingTaskGroup(of: Void.self) { group in let stdinStream = try process.launch() group.addTask { try await stdoutHandler(stdinStream, stdoutStream) } if let stderrHandler { group.addTask { try await stderrHandler(stderrStream) } } defer { stdoutContinuation.finish() stderrContinuation.finish() } return try await process.waitUntilExit() } } /// Execute a subprocess and get its (UTF-8) output if it has a non zero exit. /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process output (stdout + stderr). @discardableResult package static func checkNonZeroExit( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) async throws -> String { let result = try await popen( arguments: arguments, environment: environment, loggingHandler: loggingHandler ) // Throw if there was a non zero termination. guard result.exitStatus == .terminated(code: 0) else { throw AsyncProcessResult.Error.nonZeroExit(result) } return try result.utf8Output() } /// Execute a subprocess and get its (UTF-8) output if it has a non zero exit. /// /// - Parameters: /// - args: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process output (stdout + stderr). @discardableResult package static func checkNonZeroExit( args: String..., environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) async throws -> String { try await self.checkNonZeroExit( arguments: args, environment: environment, loggingHandler: loggingHandler ) } } extension AsyncProcess { /// Execute a subprocess and calls completion block when it finishes execution /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - queue: Queue to use for callbacks /// - completion: A completion handler to return the process result @available(*, noasync) package static func popen( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none, queue: DispatchQueue? = nil, completion: @Sendable @escaping (Result) -> Void ) { let completionQueue = queue ?? Self.sharedCompletionQueue do { let process = AsyncProcess( arguments: arguments, environment: environment, outputRedirection: .collect, loggingHandler: loggingHandler ) process.completionQueue = completionQueue try process.launch() process.waitUntilExit(completion) } catch { completionQueue.async { completion(.failure(error)) } } } /// Execute a subprocess and block until it finishes execution /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process result. @available(*, noasync) @discardableResult package static func popen( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none, workingDirectory: AbsolutePath? = nil ) throws -> AsyncProcessResult { let process = AsyncProcess( arguments: arguments, environment: environment, outputRedirection: .collect, loggingHandler: loggingHandler, workingDirectory: workingDirectory ) try process.launch() return try process.waitUntilExit() } /// Execute a subprocess and block until it finishes execution /// /// - Parameters: /// - args: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process result. @available(*, noasync) @discardableResult package static func popen( args: String..., environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) throws -> AsyncProcessResult { try AsyncProcess.popen(arguments: args, environment: environment, loggingHandler: loggingHandler) } /// Execute a subprocess and get its (UTF-8) output if it has a non zero exit. /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process output (stdout + stderr). @available(*, noasync) @discardableResult package static func checkNonZeroExit( arguments: [String], environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) throws -> String { let process = AsyncProcess( arguments: arguments, environment: environment, outputRedirection: .collect, loggingHandler: loggingHandler ) try process.launch() let result = try process.waitUntilExit() // Throw if there was a non zero termination. guard result.exitStatus == .terminated(code: 0) else { throw AsyncProcessResult.Error.nonZeroExit(result) } return try result.utf8Output() } /// Execute a subprocess and get its (UTF-8) output if it has a non zero exit. /// /// - Parameters: /// - arguments: The arguments for the subprocess. /// - environment: The environment to pass to subprocess. By default the current process environment /// will be inherited. /// - loggingHandler: Handler for logging messages /// - Returns: The process output (stdout + stderr). @available(*, noasync) @discardableResult package static func checkNonZeroExit( args: String..., environment: Environment = .current, loggingHandler: LoggingHandler? = .none ) throws -> String { try self.checkNonZeroExit(arguments: args, environment: environment, loggingHandler: loggingHandler) } } extension AsyncProcess: Hashable { package func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } package static func == (lhs: AsyncProcess, rhs: AsyncProcess) -> Bool { ObjectIdentifier(lhs) == ObjectIdentifier(rhs) } } // MARK: - Private helpers #if !os(Windows) #if canImport(Darwin) private typealias swiftpm_posix_spawn_file_actions_t = posix_spawn_file_actions_t? #else private typealias swiftpm_posix_spawn_file_actions_t = posix_spawn_file_actions_t #endif private func WIFEXITED(_ status: Int32) -> Bool { _WSTATUS(status) == 0 } private func _WSTATUS(_ status: Int32) -> Int32 { status & 0x7F } private func WIFSIGNALED(_ status: Int32) -> Bool { (_WSTATUS(status) != 0) && (_WSTATUS(status) != 0x7F) } private func WEXITSTATUS(_ status: Int32) -> Int32 { (status >> 8) & 0xFF } private func WTERMSIG(_ status: Int32) -> Int32 { status & 0x7F } /// Open the given pipe. private func open(pipe buffer: inout [Int32]) throws { let rv = pipe(&buffer) guard rv == 0 else { throw SystemError.pipe(rv) } } /// Close the given fd. private func close(fd: Int32) throws { func innerClose(_ fd: inout Int32) throws { let rv = close(fd) guard rv == 0 else { throw SystemError.close(rv) } } var innerFd = fd try innerClose(&innerFd) } extension AsyncProcess.Error: CustomStringConvertible { package var description: String { switch self { case .missingExecutableProgram(let program): "could not find executable for '\(program)'" case .workingDirectoryNotSupported: "workingDirectory is not supported in this platform" case .stdinUnavailable: "could not open stdin on this platform" } } } extension AsyncProcess.Error: CustomNSError { package var errorUserInfo: [String: Any] { [NSLocalizedDescriptionKey: self.description] } } #endif extension AsyncProcessResult.Error: CustomStringConvertible { package var description: String { switch self { case .systemError(let arguments, let underlyingError): return "error while executing `\(arguments.joined(separator: " "))`: \(underlyingError)" case .illegalUTF8Sequence: return "illegal UTF8 sequence output" case .nonZeroExit(let result): var str = "" switch result.exitStatus { case .terminated(let code): str.append(contentsOf: "terminated(\(code)): ") #if os(Windows) case .abnormal(let exception): str.append(contentsOf: "abnormal(\(exception)): ") #else case .signalled(let signal): str.append(contentsOf: "signalled(\(signal)): ") #endif } // Strip sandbox information from arguments to keep things pretty. var args = result.arguments // This seems a little fragile. if args.first == "sandbox-exec", args.count > 3 { args = args.suffix(from: 3).map { $0 } } str.append(contentsOf: args.map { $0.spm_shellEscaped() }.joined(separator: " ")) // Include the output, if present. if let output = try? result.utf8Output() + result.utf8stderrOutput() { // We indent the output to keep it visually separated from everything else. let indentation = " " str.append(contentsOf: " output:\n") str.append(contentsOf: indentation) str.append(contentsOf: output.split(whereSeparator: { $0.isNewline }) .joined(separator: "\n\(indentation)")) if !output.hasSuffix("\n") { str.append(contentsOf: "\n") } } return str } } } #if os(Windows) extension FileHandle: WritableByteStream { package var position: Int { Int(offsetInFile) } package func write(_ byte: UInt8) { self.write(Data([byte])) } package func write(_ bytes: some Collection) { self.write(Data(bytes)) } package func flush() { synchronizeFile() } } #endif ================================================ FILE: Sources/Basics/Concurrency/ConcurrencyHelpers.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency import Dispatch import class Foundation.NSLock import class Foundation.ProcessInfo import class Foundation.Thread import struct Foundation.URL import struct Foundation.UUID import func TSCBasic.tsc_await public enum Concurrency { public static var maxOperations: Int { Environment.current["SWIFTPM_MAX_CONCURRENT_OPERATIONS"].flatMap(Int.init) ?? ProcessInfo.processInfo .activeProcessorCount } } @available(*, noasync, message: "This method blocks the current thread indefinitely. Calling it from the concurrency pool can cause deadlocks") public func unsafe_await(_ body: @Sendable @escaping () async -> T) -> T { let semaphore = DispatchSemaphore(value: 0) let box = ThreadSafeBox() Task { let localValue: T = await body() box.mutate { _ in localValue } semaphore.signal() } semaphore.wait() return box.get()! } extension Task where Failure == Never { /// Runs `block` in a new thread and suspends until it finishes execution. /// /// - note: This function should be used sparingly, such as for long-running operations that may block and therefore should not be run on the Swift Concurrency thread pool. Do not use this for operations for which there may be many concurrent invocations as it could lead to thread explosion. It is meant to be a bridge to pre-existing blocking code which can't easily be converted to use Swift concurrency features. public static func detachNewThread(name: String? = nil, _ block: @Sendable @escaping () -> Success) async -> Success { return await withCheckedContinuation { continuation in Thread.detachNewThread { Thread.current.name = name return continuation.resume(returning: block()) } } } } extension DispatchQueue { // a shared concurrent queue for running concurrent asynchronous operations public static let sharedConcurrent = DispatchQueue( label: "swift.org.swiftpm.shared.concurrent", attributes: .concurrent ) } extension DispatchQueue { package func scheduleOnQueue(work: @escaping @Sendable () throws -> T) async throws -> T { try await withCheckedThrowingContinuation { continuation in self.async { do { continuation.resume(returning: try work()) } catch { continuation.resume(throwing: error) } } } } package func asyncResult(_ callback: @escaping @Sendable (Result) -> Void, _ closure: @escaping @Sendable () async throws -> T) { let completion: @Sendable (Result) -> Void = { result in self.async { callback(result) } } Task { do { completion(.success(try await closure())) } catch { completion(.failure(error)) } } } } /// A queue for running async operations with a limit on the number of concurrent tasks. public final class AsyncOperationQueue: @unchecked Sendable { // This implementation is identical to the AsyncOperationQueue in swift-build. // Any modifications made here should also be made there. // https://github.com/swiftlang/swift-build/blob/main/Sources/SWBUtil/AsyncOperationQueue.swift#L13 fileprivate typealias ID = UUID fileprivate typealias WaitingContinuation = CheckedContinuation private let concurrentTasks: Int private var waitingTasks: [WorkTask] = [] private let waitingTasksLock = NSLock() fileprivate enum WorkTask { case creating(ID) case waiting(ID, WaitingContinuation) case running(ID) case cancelled(ID) var id: ID { switch self { case .creating(let id), .waiting(let id, _), .running(let id), .cancelled(let id): return id } } var continuation: WaitingContinuation? { guard case .waiting(_, let continuation) = self else { return nil } return continuation } } /// Creates an `AsyncOperationQueue` with a specified number of concurrent tasks. /// - Parameter concurrentTasks: The maximum number of concurrent tasks that can be executed concurrently. public init(concurrentTasks: Int) { self.concurrentTasks = concurrentTasks } deinit { waitingTasksLock.withLock { if !waitingTasks.isEmpty { preconditionFailure("Deallocated with waiting tasks") } } } /// Executes an asynchronous operation, ensuring that the number of concurrent tasks // does not exceed the specified limit. /// - Parameter operation: The asynchronous operation to execute. /// - Returns: The result of the operation. /// - Throws: An error thrown by the operation, or a `CancellationError` if the operation is cancelled. public func withOperation( _ operation: () async throws -> sending ReturnValue ) async throws -> ReturnValue { let taskId = try await waitIfNeeded() defer { signalCompletion(taskId) } return try await operation() } private func waitIfNeeded() async throws -> ID { let workTask = waitingTasksLock.withLock({ let shouldWait = waitingTasks.count >= concurrentTasks let workTask = shouldWait ? WorkTask.creating(ID()) : .running(ID()) waitingTasks.append(workTask) return workTask }) // If we aren't creating a task that needs to wait, we're under the concurrency limit. guard case .creating(let taskId) = workTask else { return workTask.id } enum TaskAction { case start(WaitingContinuation) case cancel(WaitingContinuation) } try await withTaskCancellationHandler { try await withCheckedThrowingContinuation { (continuation: WaitingContinuation) -> Void in let action: TaskAction? = waitingTasksLock.withLock { guard let index = waitingTasks.firstIndex(where: { $0.id == taskId }) else { // The task may have been marked as cancelled already and then removed from // waitingTasks in `signalCompletion`. return .cancel(continuation) } switch waitingTasks[index] { case .cancelled: // If the task was cancelled in between creating the task cancellation handler and acquiring the lock, // we should resume the continuation with a `CancellationError`. waitingTasks.remove(at: index) return .cancel(continuation) case .creating, .running, .waiting: // A task may have completed since we initially checked if we should wait. Check again in this locked // section and if we can start it, remove it from the waiting tasks and start it immediately. if waitingTasks.count >= concurrentTasks { waitingTasks[index] = .waiting(taskId, continuation) return nil } else { waitingTasks.remove(at: index) return .start(continuation) } } } switch action { case .some(.cancel(let continuation)): continuation.resume(throwing: _Concurrency.CancellationError()) case .some(.start(let continuation)): continuation.resume() case .none: return } } } onCancel: { let continuation: WaitingContinuation? = self.waitingTasksLock.withLock { guard let taskIndex = self.waitingTasks.firstIndex(where: { $0.id == taskId }) else { return nil } switch self.waitingTasks[taskIndex] { case .waiting(_, let continuation): self.waitingTasks.remove(at: taskIndex) // If the parent task is cancelled then we need to manually handle resuming the // continuation for the waiting task with a `CancellationError`. Return the continuation // here so it can be resumed once the `waitingTasksLock` is released. return continuation case .creating, .running: // If the task was still being created, mark it as cancelled in `waitingTasks` so that // the handler for `withCheckedThrowingContinuation` can immediately cancel it. self.waitingTasks[taskIndex] = .cancelled(taskId) return nil case .cancelled: preconditionFailure("Attempting to cancel a task that was already cancelled") } } continuation?.resume(throwing: _Concurrency.CancellationError()) } return workTask.id } private func signalCompletion(_ taskId: ID) { let continuationToResume = waitingTasksLock.withLock { () -> WaitingContinuation? in guard !waitingTasks.isEmpty else { return nil } // Remove the completed task from the list to decrement the active task count. if let taskIndex = self.waitingTasks.firstIndex(where: { $0.id == taskId }) { waitingTasks.remove(at: taskIndex) } // We cannot remove elements from `waitingTasks` while iterating over it, so we make // a pass to collect operations and then apply them after the loop. func createTaskListOperations() -> (CollectionDifference?, WaitingContinuation?) { var changes: [CollectionDifference.Change] = [] for (index, task) in waitingTasks.enumerated() { switch task { case .running: // Skip tasks that are already running, looking for the first one that is waiting or creating. continue case .creating: // If the next task is in the process of being created, let the // creation code in the `withCheckedThrowingContinuation` in `waitIfNeeded` // handle starting the task. break case .waiting: // Begin the next waiting task changes.append(.remove(offset: index, element: task, associatedWith: nil)) return (CollectionDifference(changes), task.continuation) case .cancelled: // If the next task is cancelled, continue removing cancelled // tasks until we find one that hasn't run yet, or we exaust the list of waiting tasks. changes.append(.remove(offset: index, element: task, associatedWith: nil)) continue } } return (CollectionDifference(changes), nil) } let (collectionOperations, continuation) = createTaskListOperations() if let operations = collectionOperations { guard let appliedDiff = waitingTasks.applying(operations) else { preconditionFailure("Failed to apply changes to waiting tasks") } waitingTasks = appliedDiff } return continuation } continuationToResume?.resume() } } ================================================ FILE: Sources/Basics/Concurrency/NSLock+Extensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.NSLock extension NSLock { /// Execute the given block while holding the lock. @discardableResult public func withLock(_ body: () throws -> T) rethrows -> T { lock() defer { unlock() } return try body() } } ================================================ FILE: Sources/Basics/Concurrency/SendableBox.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct Foundation.Date /// A `Sendable` storage that allows access from concurrently running tasks in /// an `async` closure. This type serves as a replacement for `ThreadSafeBox` /// implemented with Swift Concurrency primitives. public actor SendableBox { public init(_ value: Value) { self.value = value } public var value: Value public func set(_ value: Value) { self.value = value } } extension SendableBox where Value == Int { func increment() { self.value = value + 1 } func decrement() { self.value = value - 1 } } extension SendableBox where Value == Date { func resetDate() { value = Date() } } ================================================ FILE: Sources/Basics/Concurrency/ThreadSafeArrayStore.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.NSLock /// Thread-safe array like structure public final class ThreadSafeArrayStore { private var underlying: [Value] private let lock = NSLock() public init(_ seed: [Value] = []) { self.underlying = seed } public subscript(index: Int) -> Value? { self.lock.withLock { self.underlying[index] } } public func get() -> [Value] { self.lock.withLock { self.underlying } } @discardableResult public func clear() -> [Value] { self.lock.withLock { let underlying = self.underlying self.underlying.removeAll() return underlying } } @discardableResult public func append(_ item: Value) -> Int { self.lock.withLock { self.underlying.append(item) return self.underlying.count } } @discardableResult public func append(contentsOf items: [Value]) -> Int { self.lock.withLock { self.underlying.append(contentsOf: items) return self.underlying.count } } public var count: Int { self.lock.withLock { self.underlying.count } } public var isEmpty: Bool { self.lock.withLock { self.underlying.isEmpty } } public func map(_ transform: (Value) -> NewValue) -> [NewValue] { self.lock.withLock { self.underlying.map(transform) } } public func compactMap(_ transform: (Value) throws -> NewValue?) rethrows -> [NewValue] { try self.lock.withLock { try self.underlying.compactMap(transform) } } } extension ThreadSafeArrayStore: @unchecked Sendable where Value: Sendable {} ================================================ FILE: Sources/Basics/Concurrency/ThreadSafeBox.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.NSLock /// Thread-safe value boxing structure that provides synchronized access to a wrapped value. @dynamicMemberLookup public final class ThreadSafeBox { private var underlying: Value private let lock = NSLock() /// Creates a new thread-safe box with the given initial value. /// /// - Parameter seed: The initial value to store in the box. public init(_ seed: Value) { self.underlying = seed } /// Atomically mutates the stored value by applying a transformation function. /// /// The transformation function receives the current value and returns a new value /// to replace it. The entire operation is performed under a lock to ensure atomicity. /// /// - Parameter body: A closure that takes the current value and returns a new value. /// - Throws: Any error thrown by the transformation function. public func mutate(body: (Value) throws -> Value) rethrows { try self.lock.withLock { let value = try body(self.underlying) self.underlying = value } } /// Atomically mutates the stored value by applying an in-place transformation. /// /// The transformation function receives an inout reference to the current value, /// allowing direct modification. The entire operation is performed under a lock /// to ensure atomicity. /// /// - Parameter body: A closure that receives an inout reference to the current value. /// - Throws: Any error thrown by the transformation function. public func mutate(body: (inout Value) throws -> Void) rethrows { try self.lock.withLock { try body(&self.underlying) } } /// Atomically retrieves the current value from the box. /// /// - Returns: A copy of the current value stored in the box. public func get() -> Value { self.lock.withLock { self.underlying } } /// Atomically replaces the current value with a new value. /// /// - Parameter newValue: The new value to store in the box. public func put(_ newValue: Value) { self.lock.withLock { self.underlying = newValue } } /// Provides thread-safe read-only access to properties of the wrapped value. /// /// This subscript allows you to access properties of the wrapped value using /// dot notation while maintaining thread safety. /// /// - Parameter keyPath: A key path to a property of the wrapped value. /// - Returns: The value of the specified property. public subscript(dynamicMember keyPath: KeyPath) -> T { self.lock.withLock { self.underlying[keyPath: keyPath] } } /// Provides thread-safe read-write access to properties of the wrapped value. /// /// - Parameter keyPath: A writable key path to a property of the wrapped value. /// - Returns: The value of the specified property when getting. public subscript(dynamicMember keyPath: WritableKeyPath) -> T { get { self.lock.withLock { self.underlying[keyPath: keyPath] } } set { self.lock.withLock { self.underlying[keyPath: keyPath] = newValue } } } } // Extension for optional values to support empty initialization extension ThreadSafeBox { /// Creates a new thread-safe box initialized with nil for optional value types. /// /// This convenience initializer is only available when the wrapped value type is optional. public convenience init() where Value == Wrapped? { self.init(nil) } /// Takes the stored optional value, setting it to nil. /// - Returns: The previously stored value, or nil if none was present. public func takeValue() -> Value where Value == Wrapped? { self.lock.withLock { guard let value = self.underlying else { return nil } self.underlying = nil return value } } /// Atomically sets the stored optional value to nil. /// /// This method is only available when the wrapped value type is optional. public func clear() where Value == Wrapped? { self.lock.withLock { self.underlying = nil } } /// Atomically retrieves the stored value, returning a default if nil. /// /// This method is only available when the wrapped value type is optional. /// /// - Parameter defaultValue: The value to return if the stored value is nil. /// - Returns: The stored value if not nil, otherwise the default value. public func get(default defaultValue: Wrapped) -> Wrapped where Value == Wrapped? { self.lock.withLock { self.underlying ?? defaultValue } } /// Atomically computes and caches a value if not already present. /// /// If the box already contains a non-nil value, that value is returned immediately. /// Otherwise, the provided closure is executed to compute the value, which is then /// stored and returned. This method is only available when the wrapped value type is optional. /// /// - Parameter body: A closure that computes the value to store if none exists. /// - Returns: The cached value or the newly computed value. /// - Throws: Any error thrown by the computation closure. @discardableResult public func memoize(body: () throws -> Wrapped) rethrows -> Wrapped where Value == Wrapped? { try self.lock.withLock { if let value = self.underlying { return value } let value = try body() self.underlying = value return value } } /// Atomically computes and caches an optional value if not already present. /// /// If the box already contains a non-nil value, that value is returned immediately. /// Otherwise, the provided closure is executed to compute the value, which is then /// stored and returned. This method is only available when the wrapped value type is optional. /// /// If the returned value is `nil` subsequent calls to `memoize` or `memoizeOptional` will /// re-execute the closure. /// /// - Parameter body: A closure that computes the optional value to store if none exists. /// - Returns: The cached value or the newly computed value (which may be nil). /// - Throws: Any error thrown by the computation closure. @discardableResult public func memoizeOptional(body: () throws -> Wrapped?) rethrows -> Wrapped? where Value == Wrapped? { try self.lock.withLock { if let value = self.underlying { return value } let value = try body() self.underlying = value return value } } } extension ThreadSafeBox where Value == Int { /// Atomically increments the stored integer value by 1. /// /// This method is only available when the wrapped value type is Int. public func increment() { self.lock.withLock { self.underlying = self.underlying + 1 } } /// Atomically decrements the stored integer value by 1. /// /// This method is only available when the wrapped value type is Int. public func decrement() { self.lock.withLock { self.underlying = self.underlying - 1 } } } extension ThreadSafeBox where Value == String { /// Atomically appends a string to the stored string value. /// /// This method is only available when the wrapped value type is String. /// /// - Parameter value: The string to append to the current stored value. public func append(_ value: String) { self.mutate { existingValue in existingValue + value } } } extension ThreadSafeBox: @unchecked Sendable where Value: Sendable {} ================================================ FILE: Sources/Basics/Concurrency/ThreadSafeKeyValueStore.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020-2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency import class Foundation.NSLock /// Thread-safe dictionary with async memoization public actor ThrowingAsyncKeyValueMemoizer { var stored: [Key: Task] = [:] public init() { self.stored = [:] } public func memoize(_ key: Key, body: @Sendable @escaping () async throws -> Value) async throws -> Value { guard let existingTask = self.stored[key] else { let newTask = Task { try await body() } self.stored[key] = newTask return try await newTask.value } return try await existingTask.value } } public actor AsyncKeyValueMemoizer { var stored: [Key: Task] = [:] public init() { self.stored = [:] } public func memoize(_ key: Key, body: @Sendable @escaping () async -> Value) async -> Value { guard let existingTask = self.stored[key] else { let newTask = Task { await body() } self.stored[key] = newTask return await newTask.value } return await existingTask.value } } public actor AsyncThrowingValueMemoizer { var stored: ValueStorage? enum ValueStorage { case inProgress([CheckedContinuation]) case complete(Result) } public init() {} public func memoize(body: @Sendable () async throws -> Value) async throws -> Value { guard let stored else { self.stored = .inProgress([]) let result: Result do { result = try await .success(body()) } catch { result = .failure(error) } if case .inProgress(let array) = self.stored { self.stored = .complete(result) array.forEach { $0.resume(with: result)} } return try result.get() } switch stored { case .inProgress(let existing): return try await withCheckedThrowingContinuation { self.stored = .inProgress(existing + [$0]) } case .complete(let result): return try result.get() } } } /// Thread-safe dictionary like structure. public final class ThreadSafeKeyValueStore where Key: Hashable { private var underlying: [Key: Value] private let lock = NSLock() public init(_ seed: [Key: Value] = [:]) { self.underlying = seed } public func get() -> [Key: Value] { self.lock.withLock { self.underlying } } public subscript(key: Key) -> Value? { get { self.lock.withLock { self.underlying[key] } } set { self.lock.withLock { self.underlying[key] = newValue } } } @discardableResult public func memoize(_ key: Key, body: () throws -> Value) rethrows -> Value { try self.lock.withLock { try self.underlying.memoize(key: key, body: body) } } @discardableResult public func removeValue(forKey key: Key) -> Value? { self.lock.withLock { self.underlying.removeValue(forKey: key) } } @discardableResult public func clear() -> [Key: Value] { self.lock.withLock { let underlying = self.underlying self.underlying.removeAll() return underlying } } public var count: Int { self.lock.withLock { self.underlying.count } } public var isEmpty: Bool { self.lock.withLock { self.underlying.isEmpty } } public func contains(_ key: Key) -> Bool { self.lock.withLock { self.underlying.keys.contains(key) } } public func map(_ transform: ((key: Key, value: Value)) throws -> T) rethrows -> [T] { try self.lock.withLock { try self.underlying.map(transform) } } public func mapValues(_ transform: (Value) throws -> T) rethrows -> [Key: T] { try self.lock.withLock { try self.underlying.mapValues(transform) } } } extension ThreadSafeKeyValueStore: @unchecked Sendable where Key: Sendable, Value: Sendable {} ================================================ FILE: Sources/Basics/Concurrency/ThrowingDefer.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023-2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// Runs a cleanup closure (`deferred`) after a given `work` closure, /// making sure `deferred` is run also when `work` throws an error. /// - Parameters: /// - work: The work that should be performed. Will always be executed. /// - deferred: The cleanup that needs to be done in any case. /// - Throws: Any error thrown by `deferred` or `work` (in that order). /// - Returns: The result of `work`. /// - Note: If `work` **and** `deferred` throw an error, /// the one thrown by `deferred` is thrown from this function. /// - SeeAlso: ``withAsyncThrowing(do:defer:)`` public func withThrowing( do work: () throws -> T, defer deferred: () throws -> Void ) throws -> T { do { let result = try work() try deferred() return result } catch { try deferred() throw error } } /// Runs an async cleanup closure (`deferred`) after a given async `work` closure, /// making sure `deferred` is run also when `work` throws an error. /// - Parameters: /// - work: The work that should be performed. Will always be executed. /// - deferred: The cleanup that needs to be done in any case. /// - Throws: Any error thrown by `deferred` or `work` (in that order). /// - Returns: The result of `work`. /// - Note: If `work` **and** `deferred` throw an error, /// the one thrown by `deferred` is thrown from this function. /// - SeeAlso: ``withThrowing(do:defer:)`` public func withAsyncThrowing( do work: @Sendable () async throws -> T, defer deferred: @Sendable () async throws -> Void ) async throws -> T { do { let result = try await work() try await deferred() return result } catch { try await deferred() throw error } } ================================================ FILE: Sources/Basics/Concurrency/TokenBucket.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency private import DequeModule /// Type modeled after a "token bucket" pattern, which is similar to a semaphore, but is built with /// Swift Concurrency primitives. public actor TokenBucket { private var tokens: Int private var waiters: Deque> public init(tokens: Int) { self.tokens = tokens self.waiters = Deque() } /// Executes an `async` closure immediately when a token is available. /// Only the same number of closures will be executed concurrently as the number /// of `tokens` passed to ``TokenBucket/init(tokens:)``, all subsequent /// invocations of `withToken` will suspend until a "free" token is available. /// - Parameter body: The closure to invoke when a token is available. /// - Returns: Resulting value returned by `body`. public func withToken( _ body: @Sendable () async throws -> ReturnType ) async rethrows -> ReturnType { await self.getToken() defer { self.returnToken() } return try await body() } private func getToken() async { if self.tokens > 0 { self.tokens -= 1 return } await withCheckedContinuation { self.waiters.append($0) } } private func returnToken() { if let nextWaiter = self.waiters.popFirst() { nextWaiter.resume() } else { self.tokens += 1 } } } ================================================ FILE: Sources/Basics/DispatchTimeInterval+Extensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020-2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Dispatch import struct Foundation.TimeInterval extension DispatchTimeInterval { public func timeInterval() -> TimeInterval? { switch self { case .seconds(let value): return Double(value) case .milliseconds(let value): return Double(value) / 1000 case .microseconds(let value): return Double(value) / 1_000_000 case .nanoseconds(let value): return Double(value) / 1_000_000_000 default: return nil } } public func nanoseconds() -> Int? { switch self { case .seconds(let value): return value.multipliedReportingOverflow(by: 1_000_000_000).partialValue case .milliseconds(let value): return value.multipliedReportingOverflow(by: 1_000_000).partialValue case .microseconds(let value): return value.multipliedReportingOverflow(by: 1000).partialValue case .nanoseconds(let value): return value default: return nil } } public func milliseconds() -> Int? { switch self { case .seconds(let value): return value.multipliedReportingOverflow(by: 1000).partialValue case .milliseconds(let value): return value case .microseconds(let value): return Int(Double(value) / 1000) case .nanoseconds(let value): return Int(Double(value) / 1_000_000) default: return nil } } public func seconds() -> Int? { switch self { case .seconds(let value): return value case .milliseconds(let value): return Int(Double(value) / 1000) case .microseconds(let value): return Int(Double(value) / 1_000_000) case .nanoseconds(let value): return Int(Double(value) / 1_000_000_000) default: return nil } } public var descriptionInSeconds: String { switch self { case .seconds(let value): return "\(value)s" case .milliseconds(let value): return String(format: "%.2f", Double(value) / Double(1000)) + "s" case .microseconds(let value): return String(format: "%.2f", Double(value) / Double(1_000_000)) + "s" case .nanoseconds(let value): return String(format: "%.2f", Double(value) / Double(1_000_000_000)) + "s" case .never: return "n/a" #if canImport(Darwin) @unknown default: return "n/a" #endif } } } // remove when available to all platforms #if os(Linux) || os(Windows) || os(Android) || os(OpenBSD) || os(FreeBSD) extension DispatchTime { public func distance(to: DispatchTime) -> DispatchTimeInterval { let final = to.uptimeNanoseconds let point = self.uptimeNanoseconds let duration = Int64(bitPattern: final.subtractingReportingOverflow(point).partialValue) return .nanoseconds(duration >= Int.max ? Int.max : Int(duration)) } } #endif ================================================ FILE: Sources/Basics/Environment/Environment.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Foundation #if canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif os(Windows) import CRT import WinSDK #elseif canImport(Android) import Android #else import Darwin.C #endif // FIXME: Use Synchronization.Mutex when available private final class Mutex: @unchecked Sendable { var lock: NSLock var value: T init(value: T) { self.lock = .init() self.value = value } func withLock(_ body: (inout T) -> U) -> U { self.lock.lock() defer { self.lock.unlock() } return body(&self.value) } } // FIXME: This should come from Foundation // FIXME: package (public required by users) public struct Environment { var storage: [EnvironmentKey: String] } // MARK: - Accessors extension Environment { package init() { self.storage = .init() } package subscript(_ key: EnvironmentKey) -> String? { _read { yield self.storage[key] } _modify { yield &self.storage[key] } } } // MARK: - Conversions between Dictionary extension Environment { @_spi(SwiftPMInternal) public init(_ dictionary: [String: String]) { self.storage = .init() let sorted = dictionary.sorted { $0.key < $1.key } for (key, value) in sorted { self.storage[.init(key)] = value } } } extension [String: String] { @_spi(SwiftPMInternal) public init(_ environment: Environment) { self.init() let sorted = environment.sorted { $0.key < $1.key } for (key, value) in sorted { self[key.rawValue] = value } } } // MARK: - Path Modification extension Environment { package mutating func prependPath(key: EnvironmentKey, value: String) { guard !value.isEmpty else { return } if let existing = self[key] { self[key] = "\(value)\(Self.pathEntryDelimiter)\(existing)" } else { self[key] = value } } package mutating func appendPath(key: EnvironmentKey, value: String) { guard !value.isEmpty else { return } if let existing = self[key] { self[key] = "\(existing)\(Self.pathEntryDelimiter)\(value)" } else { self[key] = value } } package static var pathEntryDelimiter: String { #if os(Windows) ";" #else ":" #endif } } // MARK: - Global Environment extension Environment { fileprivate static let _cachedCurrent = Mutex(value: nil) /// Vends a copy of the current process's environment variables. /// /// Mutations to the current process's global environment are not reflected /// in the returned value. public static var current: Self { Self._cachedCurrent.withLock { cachedValue in if let cachedValue = cachedValue { return cachedValue } else { let current = Self(ProcessInfo.processInfo.environment) cachedValue = current return current } } } /// Temporary override environment variables /// /// WARNING! This method is not thread-safe. POSIX environments are shared /// between threads. This means that when this method is called simultaneously /// from different threads, the environment will neither be setup nor restored /// correctly. package static func makeCustom( _ environment: Self, body: () async throws -> T ) async throws -> T { let current = Self.current let state = environment.storage.keys.map { ($0, current[$0]) } let restore = { for (key, value) in state { try Self.set(key: key, value: value) } } let returnValue: T do { for (key, value) in environment { try Self.set(key: key, value: value) } returnValue = try await body() } catch { try? restore() throw error } try restore() return returnValue } /// Temporary override environment variables /// /// WARNING! This method is not thread-safe. POSIX environments are shared /// between threads. This means that when this method is called simultaneously /// from different threads, the environment will neither be setup nor restored /// correctly. package static func makeCustom( _ environment: Self, body: () throws -> T ) throws -> T { let current = Self.current let state = environment.storage.keys.map { ($0, current[$0]) } let restore = { for (key, value) in state { try Self.set(key: key, value: value) } } let returnValue: T do { for (key, value) in environment { try Self.set(key: key, value: value) } returnValue = try body() } catch { try? restore() throw error } try restore() return returnValue } struct UpdateEnvironmentError: CustomStringConvertible, Error { var function: StaticString var code: Int32 var description: String { "\(self.function) returned \(self.code)" } } /// Modifies the process's global environment. /// /// > Important: This operation is _not_ concurrency safe. package static func set(key: EnvironmentKey, value: String?) throws { #if os(Windows) func _SetEnvironmentVariableW(_ key: String, _ value: String?) -> Bool { key.withCString(encodedAs: UTF16.self) { key in if let value { value.withCString(encodedAs: UTF16.self) { value in SetEnvironmentVariableW(key, value) } } else { SetEnvironmentVariableW(key, nil) } } } #endif // Invalidate cached value after mutating the global environment. // This is potentially overly safe because we may not need to invalidate // the cache if the mutation fails. However this approach is easier to // read and reason about. defer { Self._cachedCurrent.withLock { $0 = nil } } if let value = value { #if os(Windows) guard _SetEnvironmentVariableW(key.rawValue, value) else { throw UpdateEnvironmentError( function: "SetEnvironmentVariableW", code: Int32(GetLastError()) ) } guard _putenv("\(key)=\(value)") == 0 else { throw UpdateEnvironmentError( function: "_putenv", code: Int32(GetLastError()) ) } #else guard setenv(key.rawValue, value, 1) == 0 else { throw UpdateEnvironmentError( function: "setenv", code: errno ) } #endif } else { #if os(Windows) guard _SetEnvironmentVariableW(key.rawValue, nil) else { throw UpdateEnvironmentError( function: "SetEnvironmentVariableW", code: Int32(GetLastError()) ) } guard _putenv("\(key)=") == 0 else { throw UpdateEnvironmentError( function: "_putenv", code: Int32(GetLastError()) ) } #else guard unsetenv(key.rawValue) == 0 else { throw UpdateEnvironmentError( function: "unsetenv", code: errno ) } #endif } } } // MARK: - Cachable Keys extension Environment { /// Returns a copy of `self` with known non-cacheable keys removed. /// /// - Issue: rdar://107029374 package var cachable: Environment { var cachable = Environment() for (key, value) in self { if !EnvironmentKey.nonCachable.contains(key) { cachable[key] = value } } return cachable } } // MARK: - Protocol Conformances extension Environment: Collection { public struct Index: Comparable { public static func < (lhs: Self, rhs: Self) -> Bool { lhs.underlying < rhs.underlying } var underlying: Dictionary.Index } public typealias Element = (key: EnvironmentKey, value: String) public var startIndex: Index { Index(underlying: self.storage.startIndex) } public var endIndex: Index { Index(underlying: self.storage.endIndex) } public subscript(index: Index) -> Element { self.storage[index.underlying] } public func index(after index: Self.Index) -> Self.Index { Index(underlying: self.storage.index(after: index.underlying)) } } extension Environment: CustomStringConvertible { public var description: String { let body = self .sorted { $0.key < $1.key } .map { "\"\($0.rawValue)=\($1)\"" } .joined(separator: ", ") return "[\(body)]" } } extension Environment: Encodable { public func encode(to encoder: any Encoder) throws { try self.storage.encode(to: encoder) } } extension Environment: Equatable {} extension Environment: ExpressibleByDictionaryLiteral { public typealias Key = EnvironmentKey public typealias Value = String public init(dictionaryLiteral elements: (Key, Value)...) { self.storage = .init() for (key, value) in elements { self.storage[key] = value } } } extension Environment: Decodable { public init(from decoder: any Decoder) throws { self.storage = try .init(from: decoder) } } extension Environment: Sendable {} ================================================ FILE: Sources/Basics/Environment/EnvironmentKey.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// A key used to access values in an ``Environment``. /// /// This type respects the compiled platform's case sensitivity requirements. public struct EnvironmentKey { public var rawValue: String package init(_ rawValue: String) { self.rawValue = rawValue } } extension EnvironmentKey { package static let path: Self = "PATH" package static var libraryPath: Self { #if os(Windows) path #elseif canImport(Darwin) "DYLD_LIBRARY_PATH" #else "LD_LIBRARY_PATH" #endif } /// A set of known keys which should not be included in cache keys. package static let nonCachable: Set = [ "TERM", "TERM_PROGRAM", "TERM_PROGRAM_VERSION", "TERM_SESSION_ID", "ITERM_PROFILE", "ITERM_SESSION_ID", "SECURITYSESSIONID", "LaunchInstanceID", "LC_TERMINAL", "LC_TERMINAL_VERSION", "CLICOLOR", "LS_COLORS", "VSCODE_IPC_HOOK_CLI", "HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET", "SSH_AUTH_SOCK", ] } extension EnvironmentKey: CodingKeyRepresentable {} extension EnvironmentKey: Comparable { public static func < (lhs: Self, rhs: Self) -> Bool { // Even on windows use a stable sort order. lhs.rawValue < rhs.rawValue } } extension EnvironmentKey: CustomStringConvertible { public var description: String { self.rawValue } } extension EnvironmentKey: Encodable { public func encode(to encoder: any Encoder) throws { try self.rawValue.encode(to: encoder) } } extension EnvironmentKey: Equatable { public static func == (_ lhs: Self, _ rhs: Self) -> Bool { #if os(Windows) lhs.rawValue.lowercased() == rhs.rawValue.lowercased() #else lhs.rawValue == rhs.rawValue #endif } } extension EnvironmentKey: ExpressibleByStringLiteral { public init(stringLiteral rawValue: String) { self.init(rawValue) } } extension EnvironmentKey: Decodable { public init(from decoder: any Decoder) throws { self.rawValue = try String(from: decoder) } } extension EnvironmentKey: Hashable { public func hash(into hasher: inout Hasher) { #if os(Windows) self.rawValue.lowercased().hash(into: &hasher) #else self.rawValue.hash(into: &hasher) #endif } } extension EnvironmentKey: RawRepresentable { public init?(rawValue: String) { self.rawValue = rawValue } } extension EnvironmentKey: Sendable {} ================================================ FILE: Sources/Basics/Environment/EnvironmentShims.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct TSCBasic.ProcessEnvironmentBlock import Dispatch // FIXME: remove ProcessEnvironmentBlockShims // only needed outside this module for Git extension Environment { @_spi(ProcessEnvironmentBlockShim) public init(_ processEnvironmentBlock: ProcessEnvironmentBlock) { self.init() for (key, value) in processEnvironmentBlock { self[.init(key.value)] = value } } } extension ProcessEnvironmentBlock { @_spi(ProcessEnvironmentBlockShim) public init(_ environment: Environment) { self.init() for (key, value) in environment { self[.init(key.rawValue)] = value } } } ================================================ FILE: Sources/Basics/Errors.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import protocol Foundation.LocalizedError import class Foundation.NSError import var Foundation.NSLocalizedDescriptionKey import struct TSCBasic.StringError public typealias StringError = TSCBasic.StringError public struct InternalError: Error { private let description: String public init(_ description: String) { assertionFailure(description) self.description = "Internal error. Please file a bug at https://github.com/swiftlang/swift-package-manager/issues with this info. \(description)" } } /// Wraps another error and provides additional context when printed. /// This is useful for user facing errors that need to provide a user friendly message /// explaning why an error might have occured, while still showing the detailed underlying error. public struct ErrorWithContext: Error { public let error: E public let context: String public init(_ error: E, _ context: String) { self.error = error self.context = context } } extension ErrorWithContext: LocalizedError { public var errorDescription: String? { return (context.split(separator: "\n") + [error.interpolationDescription]) .map { "\t\($0)" } .joined(separator: "\n") } } extension Error { public var interpolationDescription: String { switch self { // special case because `LocalizedError` conversion will hide the underlying error case let _error as DecodingError: return "\(_error)" case let _error as LocalizedError: var description = _error.errorDescription ?? _error.localizedDescription if let recoverySuggestion = _error.recoverySuggestion { description += ". \(recoverySuggestion)" } return description case let _error as NSError: guard var description = _error.userInfo[NSLocalizedDescriptionKey] as? String else { return "\(self)" } if let localizedRecoverySuggestion = _error.localizedRecoverySuggestion { description += ". \(localizedRecoverySuggestion)" } return description default: return "\(self)" } } } ================================================ FILE: Sources/Basics/FileSystem/AbsolutePath.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct Foundation.URL import struct TSCBasic.AbsolutePath // public for transition public typealias TSCAbsolutePath = TSCBasic.AbsolutePath /// Represents an absolute file system path, independently of what (or whether /// anything at all) exists at that path in the file system at any given time. /// An absolute path always starts with a `/` character, and holds a normalized /// string representation. This normalization is strictly syntactic, and does /// not access the file system in any way. /// /// The absolute path string is normalized by: /// - Collapsing `..` path components /// - Removing `.` path components /// - Removing any trailing path separator /// - Removing any redundant path separators /// /// This string manipulation may change the meaning of a path if any of the /// path components are symbolic links on disk. However, the file system is /// never accessed in any way when initializing an AbsolutePath. /// /// Note that `~` (home directory resolution) is *not* done as part of path /// normalization, because it is normally the responsibility of the shell and /// not the program being invoked (e.g. when invoking `cd ~`, it is the shell /// that evaluates the tilde; the `cd` command receives an absolute path). public struct AbsolutePath: Hashable, Sendable { /// Root directory (whose string representation is just a path separator). public static let root = Self(TSCAbsolutePath.root) internal let underlying: TSCAbsolutePath // public for transition public init(_ underlying: TSCAbsolutePath) { self.underlying = underlying } /// Initializes the AbsolutePath from `absStr`, which must be an absolute /// path (i.e. it must begin with a path separator; this initializer does /// not interpret leading `~` characters as home directory specifiers). /// The input string will be normalized if needed, as described in the /// documentation for AbsolutePath. public init(validating pathString: String) throws { self.underlying = try .init(validating: pathString) } /// Initializes an AbsolutePath from a string that may be either absolute /// or relative; if relative, `basePath` is used as the anchor; if absolute, /// it is used as is, and in this case `basePath` is ignored. public init(validating pathString: String, relativeTo basePath: AbsolutePath) throws { self.underlying = try .init(validating: pathString, relativeTo: basePath.underlying) } /// Initializes the AbsolutePath by concatenating a relative path to an /// existing absolute path, and renormalizing if necessary. public init(_ absolutePath: AbsolutePath, _ relativeTo: RelativePath) { self.underlying = .init(absolutePath.underlying, relativeTo.underlying) } /// Convenience initializer that appends a string to a relative path. public init(_ absolutePath: AbsolutePath, validating relativePathString: String) throws { try self.init(absolutePath, RelativePath(validating: relativePathString)) } /// Directory component. An absolute path always has a non-empty directory /// component (the directory component of the root path is the root itself). public var dirname: String { self.underlying.dirname } /// Last path component (including the suffix, if any). it is never empty. public var basename: String { self.underlying.basename } /// Returns the basename without the extension. public var basenameWithoutExt: String { self.underlying.basenameWithoutExt } /// Suffix (including leading `.` character) if any. Note that a basename /// that starts with a `.` character is not considered a suffix, nor is a /// trailing `.` character. public var suffix: String? { self.underlying.suffix } /// Extension of the give path's basename. This follow same rules as /// suffix except that it doesn't include leading `.` character. public var `extension`: String? { self.underlying.extension } /// Absolute path of parent directory. This always returns a path, because /// every directory has a parent (the parent directory of the root directory /// is considered to be the root directory itself). public var parentDirectory: AbsolutePath { Self(self.underlying.parentDirectory) } /// True if the path is the root directory. public var isRoot: Bool { self.underlying.isRoot } /// NOTE: We will most likely want to add other `appending()` methods, such /// as `appending(suffix:)`, and also perhaps `replacing()` methods, /// such as `replacing(suffix:)` or `replacing(basename:)` for some /// of the more common path operations. /// NOTE: We may want to consider adding operators such as `+` for appending /// a path component. /// NOTE: We will want to add a method to return the lowest common ancestor /// path. /// Normalized string representation (the normalization rules are described /// in the documentation of the initializer). This string is never empty. public var pathString: String { self.underlying.pathString } } extension AbsolutePath { /// Returns an array of strings that make up the path components of the /// absolute path. This is the same sequence of strings as the basenames /// of each successive path component, starting from the root. Therefore /// the first path component of an absolute path is always `/`. public var components: [String] { self.underlying.components } /// Returns the absolute path with the relative path applied. public func appending(_ relativePath: RelativePath) -> AbsolutePath { Self(self.underlying.appending(relativePath.underlying)) } /// Returns the absolute path with an additional literal component appended. /// /// This method accepts pseudo-path like '.' or '..', but should not contain "/". public func appending(component: String) -> AbsolutePath { Self(self.underlying.appending(component: component)) } /// Returns the absolute path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(components: [String]) -> AbsolutePath { Self(self.underlying.appending(components: components)) } /// Returns the absolute path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(components: String...) -> AbsolutePath { Self(self.underlying.appending(components: components)) } /// Returns the absolute path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(_ component: String) -> AbsolutePath { self.appending(component: component) } /// Returns the absolute path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(_ components: String...) -> AbsolutePath { self.appending(components: components) } /// Returns the absolute path with additional extension appended. /// public func appending(extension: String) -> AbsolutePath { guard !self.isRoot else { return self } let `extension` = `extension`.spm_dropPrefix(".") return self.parentDirectory.appending("\(basename).\(`extension`)") } } extension AbsolutePath { /// Returns a relative path that, when concatenated to `base`, yields the /// callee path itself. If `base` is not an ancestor of the callee, the /// returned path will begin with one or more `..` path components. /// /// Because both paths are absolute, they always have a common ancestor /// (the root path, if nothing else). Therefore, any path can be made /// relative to any other path by using a sufficient number of `..` path /// components. /// /// This method is strictly syntactic and does not access the file system /// in any way. Therefore, it does not take symbolic links into account. public func relative(to base: AbsolutePath) -> RelativePath { RelativePath(self.underlying.relative(to: base.underlying)) } /// Returns true if the path is an ancestor of the given path. /// /// This method is strictly syntactic and does not access the file system /// in any way. public func isAncestor(of descendant: AbsolutePath) -> Bool { self.underlying.isAncestor(of: descendant.underlying) } /// Returns true if the path is an ancestor of or equal to the given path. /// /// This method is strictly syntactic and does not access the file system /// in any way. public func isAncestorOfOrEqual(to descendant: AbsolutePath) -> Bool { self.underlying.isAncestorOfOrEqual(to: descendant.underlying) } /// Returns true if the path is a descendant of the given path. /// /// This method is strictly syntactic and does not access the file system /// in any way. public func isDescendant(of ancestor: AbsolutePath) -> Bool { self.underlying.isDescendant(of: ancestor.underlying) } /// Returns true if the path is a descendant of or equal to the given path. /// /// This method is strictly syntactic and does not access the file system /// in any way. public func isDescendantOfOrEqual(to ancestor: AbsolutePath) -> Bool { self.underlying.isDescendantOfOrEqual(to: ancestor.underlying) } } extension AbsolutePath { /// Unlike ``AbsolutePath//extension``, this property returns all characters after the first `.` character in a /// filename. If no dot character is present in the filename or first dot is the last character, `nil` is returned. public var allExtensions: [String]? { guard let firstDot = self.basename.firstIndex(of: ".") else { return nil } var extensions = String(self.basename[firstDot ..< self.basename.endIndex]) guard extensions.count > 1 else { return nil } extensions.removeFirst() return extensions.split(separator: ".").map(String.init) } /// Returns the basename dropping any possible extension. public var basenameWithoutAnyExtension: String { var basename = self.basename if let index = basename.firstIndex(of: ".") { basename.removeSubrange(index ..< basename.endIndex) } return String(basename) } } extension AbsolutePath: Codable { public func encode(to encoder: Encoder) throws { try self.underlying.encode(to: encoder) } public init(from decoder: Decoder) throws { try self = .init(TSCAbsolutePath(from: decoder)) } } // Make absolute paths Comparable. extension AbsolutePath: Comparable { public static func < (lhs: AbsolutePath, rhs: AbsolutePath) -> Bool { lhs.underlying < rhs.underlying } } /// Make absolute paths CustomStringConvertible and CustomDebugStringConvertible. extension AbsolutePath: CustomStringConvertible, CustomDebugStringConvertible { public var description: String { self.underlying.description } public var debugDescription: String { self.underlying.debugDescription } } extension AbsolutePath { public var asURL: Foundation.URL { self.underlying.asURL } } extension AbsolutePath { /// Returns a path suitable for display to the user (if possible, it is made /// to be relative to the current working directory). public func prettyPath(cwd: AbsolutePath? = localFileSystem.currentWorkingDirectory) -> String { self.underlying.prettyPath(cwd: cwd?.underlying) } } extension AbsolutePath { public var escapedPathString: String { self.pathString.replacing("\\", with: "\\\\") } } extension TSCAbsolutePath { public init(_ path: AbsolutePath) { self = path.underlying } } ================================================ FILE: Sources/Basics/FileSystem/CommonParentDirectory.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2026 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// Returns the common parent directory of the given absolute paths. /// /// This function finds the deepest directory that is an ancestor of all the provided paths. /// If the paths have no common ancestor other than the root directory, it returns the root. /// If the array is empty, it returns the root directory. /// /// - Parameter paths: An array of absolute paths to find the common parent for /// - Returns: The common parent directory as an AbsolutePath /// /// Examples: /// - `["/a/b/c", "/a/b/d"]` → `"/a/b"` /// - `["/usr/local/bin", "/usr/local/lib"]` → `"/usr/local"` /// - `["/a/b", "/x/y"]` → `"/"` /// - `[]` → `"/"` public func getCommonParentDirectory(paths: [AbsolutePath]) throws-> AbsolutePath { // Handle empty array case guard !paths.isEmpty else { return AbsolutePath.root } // Handle single path case guard paths.count > 1 else { return paths[0] } // Get the components of all paths let allComponents = paths.map { $0.components } // Find the minimum length to avoid index out of bounds let minLength = allComponents.map { $0.count }.min() ?? 0 // Find the common prefix by comparing components at each position var commonComponents: [String] = [] for index in 0.. Bool { self.exists(path.underlying, followSymlink: followSymlink) } /// exists override with default value. public func exists(_ path: AbsolutePath) -> Bool { self.exists(path.underlying) } /// Check whether the given path is accessible and a directory. public func isDirectory(_ path: AbsolutePath) -> Bool { self.isDirectory(path.underlying) } /// Check whether the given path is accessible and a file. public func isFile(_ path: AbsolutePath) -> Bool { self.isFile(path.underlying) } /// Check whether the given path is an accessible and executable file. public func isExecutableFile(_ path: AbsolutePath) -> Bool { self.isExecutableFile(path.underlying) } /// Check whether the given path is accessible and is a symbolic link. public func isSymlink(_ path: AbsolutePath) -> Bool { self.isSymlink(path.underlying) } /// Check whether the given path is accessible and readable. public func isReadable(_ path: AbsolutePath) -> Bool { self.isReadable(path.underlying) } /// Check whether the given path is accessible and writable. public func isWritable(_ path: AbsolutePath) -> Bool { self.isWritable(path.underlying) } /// Returns `true` if a given path has a quarantine attribute applied if when file system supports this attribute. /// Returns `false` if such attribute is not applied or it isn't supported. public func hasAttribute(_ name: FileSystemAttribute, _ path: AbsolutePath) -> Bool { self.hasAttribute(name, path.underlying) } /// Get the contents of the given directory, in an undefined order. public func getDirectoryContents(_ path: AbsolutePath) throws -> [String] { try self.getDirectoryContents(path.underlying) } /// Get the current working directory (similar to `getcwd(3)`), which can be /// different for different (virtualized) implementations of a FileSystem. /// The current working directory can be empty if e.g. the directory became /// unavailable while the current process was still working in it. /// This follows the POSIX `getcwd(3)` semantics. public var currentWorkingDirectory: AbsolutePath? { self.currentWorkingDirectory.flatMap { AbsolutePath($0) } } /// Change the current working directory. /// - Parameters: /// - path: The path to the directory to change the current working directory to. public func changeCurrentWorkingDirectory(to path: AbsolutePath) throws { try self.changeCurrentWorkingDirectory(to: path.underlying) } /// Get the home directory of current user public var homeDirectory: AbsolutePath { get throws { try AbsolutePath(self.homeDirectory) } } /// Get the caches directory of current user public var cachesDirectory: AbsolutePath? { self.cachesDirectory.flatMap { AbsolutePath($0) } } /// Get the temp directory public var tempDirectory: AbsolutePath { get throws { try AbsolutePath(self.tempDirectory) } } /// Create the given directory. public func createDirectory(_ path: AbsolutePath) throws { try self.createDirectory(path.underlying) } /// Create the given directory. /// /// - recursive: If true, create missing parent directories if possible. public func createDirectory(_ path: AbsolutePath, recursive: Bool) throws { try self.createDirectory(path.underlying, recursive: recursive) } /// Creates a symbolic link of the source path at the target path /// - Parameters: /// - path: The path at which to create the link. /// - destination: The path to which the link points to. /// - relative: If `relative` is true, the symlink contents will be a relative path, otherwise it will be /// absolute. public func createSymbolicLink(_ path: AbsolutePath, pointingAt destination: AbsolutePath, relative: Bool) throws { try self.createSymbolicLink(path.underlying, pointingAt: destination.underlying, relative: relative) } /// Get the contents of a file. /// /// - Returns: The file contents as bytes, or nil if missing. public func readFileContents(_ path: AbsolutePath) throws -> ByteString { try self.readFileContents(path.underlying) } /// Write the contents of a file. public func writeFileContents(_ path: AbsolutePath, bytes: ByteString) throws { try self.writeFileContents(path.underlying, bytes: bytes) } /// Write the contents of a file. public func writeFileContents(_ path: AbsolutePath, bytes: ByteString, atomically: Bool) throws { try self.writeFileContents(path.underlying, bytes: bytes, atomically: atomically) } /// Write to a file from a stream producer. public func writeFileContents(_ path: AbsolutePath, body: (WritableByteStream) -> Void) throws { try self.writeFileContents(path.underlying, body: body) } /// Recursively deletes the file system entity at `path`. /// /// If there is no file system entity at `path`, this function does nothing (in particular, this is not considered /// to be an error). public func removeFileTree(_ path: AbsolutePath) throws { try self.removeFileTree(path.underlying) } /// Change file mode. public func chmod(_ mode: FileMode, path: AbsolutePath, options: Set) throws { try self.chmod(mode, path: path.underlying, options: options) } // Change file mode. public func chmod(_ mode: FileMode, path: AbsolutePath) throws { try self.chmod(mode, path: path.underlying) } /// Returns the file info of the given path. /// /// The method throws if the underlying stat call fails. public func getFileInfo(_ path: AbsolutePath) throws -> FileInfo { try self.getFileInfo(path.underlying) } /// Copy a file or directory. public func copy(from source: AbsolutePath, to destination: AbsolutePath) throws { try self.copy(from: source.underlying, to: destination.underlying) } /// Move a file or directory. public func move(from source: AbsolutePath, to destination: AbsolutePath) throws { try self.move(from: source.underlying, to: destination.underlying) } /// Execute the given block while holding the lock. public func withLock(on path: AbsolutePath, type: FileLock.LockType, blocking: Bool = true, _ body: () throws -> T) throws -> T { try self.withLock(on: path.underlying, type: type, blocking: blocking, body) } /// Execute the given block while holding the lock. public func withLock(on path: AbsolutePath, type: FileLock.LockType, blocking: Bool = true, _ body: () async throws -> T) async throws -> T { return try await FileLock.withLock(fileToLock: path.underlying, type: type, blocking: blocking, body: body) } /// Returns any known item replacement directories for a given path. These may be used by platform-specific /// libraries to handle atomic file system operations, such as deletion. func itemReplacementDirectories(for path: AbsolutePath) throws -> [AbsolutePath] { return try self.itemReplacementDirectories(for: path.underlying).compactMap { AbsolutePath($0) } } } // MARK: - user level extension FileSystem { /// SwiftPM directory under user's home directory (~/.swiftpm) /// or under $XDG_CONFIG_HOME/swiftpm if the environmental variable is defined public var dotSwiftPM: AbsolutePath { get throws { if let configurationDirectory = Environment.current["XDG_CONFIG_HOME"] { return try AbsolutePath(validating: configurationDirectory).appending("swiftpm") } else { return try self.homeDirectory.appending(".swiftpm") } } } private var idiomaticSwiftPMDirectory: AbsolutePath? { get throws { try FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first .flatMap { try AbsolutePath(validating: $0.path) }?.appending("org.swift.swiftpm") } } } // MARK: - cache extension FileSystem { private var idiomaticUserCacheDirectory: AbsolutePath? { // in TSC: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask) self.cachesDirectory } /// SwiftPM cache directory under user's caches directory (if exists) public var swiftPMCacheDirectory: AbsolutePath { get throws { if let path = self.idiomaticUserCacheDirectory { return path.appending("org.swift.swiftpm") } else { return try self.dotSwiftPMCachesDirectory } } } private var dotSwiftPMCachesDirectory: AbsolutePath { get throws { try self.dotSwiftPM.appending("cache") } } } extension FileSystem { public func getOrCreateSwiftPMCacheDirectory() throws -> AbsolutePath { let idiomaticCacheDirectory = try self.swiftPMCacheDirectory // Create idiomatic if necessary if !self.exists(idiomaticCacheDirectory) { try self.createDirectory(idiomaticCacheDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !self.exists(try self.dotSwiftPM) { try self.createDirectory(self.dotSwiftPM, recursive: true) } // Create ~/.swiftpm/cache symlink if necessary // locking ~/.swiftpm to protect from concurrent access try self.withLock(on: self.dotSwiftPM, type: .exclusive) { if !self.exists(try self.dotSwiftPMCachesDirectory, followSymlink: false) { try self.createSymbolicLink( dotSwiftPMCachesDirectory, pointingAt: idiomaticCacheDirectory, relative: false ) } } return idiomaticCacheDirectory } } extension FileSystem { private var dotSwiftPMInstalledBinsDir: AbsolutePath { get throws { try self.dotSwiftPM.appending("bin") } } public func getOrCreateSwiftPMInstalledBinariesDirectory() throws -> AbsolutePath { let idiomaticInstalledBinariesDirectory = try self.dotSwiftPMInstalledBinsDir // Create idiomatic if necessary if !self.exists(idiomaticInstalledBinariesDirectory) { try self.createDirectory(idiomaticInstalledBinariesDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !self.exists(try self.dotSwiftPM) { try self.createDirectory(self.dotSwiftPM, recursive: true) } // Create ~/.swiftpm/bin symlink if necessary // locking ~/.swiftpm to protect from concurrent access try self.withLock(on: self.dotSwiftPM, type: .exclusive) { if !self.exists(try self.dotSwiftPMInstalledBinsDir, followSymlink: false) { try self.createSymbolicLink( self.dotSwiftPMInstalledBinsDir, pointingAt: idiomaticInstalledBinariesDirectory, relative: false ) } } return idiomaticInstalledBinariesDirectory } } // MARK: - configuration extension FileSystem { /// SwiftPM config directory under user's config directory (if exists) public var swiftPMConfigurationDirectory: AbsolutePath { get throws { if let path = try self.idiomaticSwiftPMDirectory { return path.appending("configuration") } else { return try self.dotSwiftPMConfigurationDirectory } } } private var dotSwiftPMConfigurationDirectory: AbsolutePath { get throws { try self.dotSwiftPM.appending("configuration") } } } extension FileSystem { public func getOrCreateSwiftPMConfigurationDirectory(warningHandler: @escaping (String) -> Void) throws -> AbsolutePath { let idiomaticConfigurationDirectory = try self.swiftPMConfigurationDirectory // temporary 5.6, remove on next version: transition from previous configuration location if !self.exists(idiomaticConfigurationDirectory) { try self.createDirectory(idiomaticConfigurationDirectory, recursive: true) } let handleExistingFiles = { (configurationFiles: [AbsolutePath]) in for file in configurationFiles { let destination = idiomaticConfigurationDirectory.appending(component: file.basename) if !self.exists(destination) { try self.copy(from: file, to: destination) } else { // Only emit a warning if source and destination file differ in their contents. let srcContents = try? self.readFileContents(file) let dstContents = try? self.readFileContents(destination) if srcContents != dstContents { warningHandler( "Usage of \(file) has been deprecated. Please delete it and use the new \(destination) instead." ) } } } } // in the case where ~/.swiftpm/configuration is not the idiomatic location (eg on macOS where its // /Users//Library/org.swift.swiftpm/configuration) if try idiomaticConfigurationDirectory != self.dotSwiftPMConfigurationDirectory { // copy the configuration files from old location (eg /Users//Library/org.swift.swiftpm) to new one // (eg /Users//Library/org.swift.swiftpm/configuration) // but leave them there for backwards compatibility (eg older xcode) let oldConfigDirectory = idiomaticConfigurationDirectory.parentDirectory if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { let configurationFiles = try self.getDirectoryContents(oldConfigDirectory) .map { oldConfigDirectory.appending(component: $0) } .filter { self.isFile($0) && !self.isSymlink($0) && $0 .extension != "lock" && ((try? self.readFileContents($0)) ?? []).count > 0 } try handleExistingFiles(configurationFiles) } // in the case where ~/.swiftpm/configuration is the idiomatic location (eg on Linux) } else { // copy the configuration files from old location (~/.swiftpm/config) to new one (~/.swiftpm/configuration) // but leave them there for backwards compatibility (eg older toolchain) let oldConfigDirectory = try self.dotSwiftPM.appending("config") if self.exists(oldConfigDirectory, followSymlink: false) && self.isDirectory(oldConfigDirectory) { let configurationFiles = try self.getDirectoryContents(oldConfigDirectory) .map { oldConfigDirectory.appending(component: $0) } .filter { self.isFile($0) && !self.isSymlink($0) && $0 .extension != "lock" && ((try? self.readFileContents($0)) ?? []).count > 0 } try handleExistingFiles(configurationFiles) } } // ~temporary 5.6 migration // Create idiomatic if necessary if !self.exists(idiomaticConfigurationDirectory) { try self.createDirectory(idiomaticConfigurationDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !self.exists(try self.dotSwiftPM) { try self.createDirectory(self.dotSwiftPM, recursive: true) } // Create ~/.swiftpm/configuration symlink if necessary // locking ~/.swiftpm to protect from concurrent access try self.withLock(on: self.dotSwiftPM, type: .exclusive) { if !self.exists(try self.dotSwiftPMConfigurationDirectory, followSymlink: false) { try self.createSymbolicLink( dotSwiftPMConfigurationDirectory, pointingAt: idiomaticConfigurationDirectory, relative: false ) } } return idiomaticConfigurationDirectory } } // MARK: - security extension FileSystem { /// SwiftPM security directory under user's security directory (if exists) public var swiftPMSecurityDirectory: AbsolutePath { get throws { if let path = try self.idiomaticSwiftPMDirectory { return path.appending("security") } else { return try self.dotSwiftPMSecurityDirectory } } } private var dotSwiftPMSecurityDirectory: AbsolutePath { get throws { try self.dotSwiftPM.appending("security") } } } extension FileSystem { public func getOrCreateSwiftPMSecurityDirectory() throws -> AbsolutePath { let idiomaticSecurityDirectory = try self.swiftPMSecurityDirectory // temporary 5.6, remove on next version: transition from ~/.swiftpm/security to idiomatic location + symbolic // link if try idiomaticSecurityDirectory != self.dotSwiftPMSecurityDirectory && self.exists(try self.dotSwiftPMSecurityDirectory) && self.isDirectory(try self.dotSwiftPMSecurityDirectory) { try self.removeFileTree(self.dotSwiftPMSecurityDirectory) } // ~temporary 5.6 migration // Create idiomatic if necessary if !self.exists(idiomaticSecurityDirectory) { try self.createDirectory(idiomaticSecurityDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !self.exists(try self.dotSwiftPM) { try self.createDirectory(self.dotSwiftPM, recursive: true) } // Create ~/.swiftpm/security symlink if necessary // locking ~/.swiftpm to protect from concurrent access try self.withLock(on: self.dotSwiftPM, type: .exclusive) { if !self.exists(try self.dotSwiftPMSecurityDirectory, followSymlink: false) { try self.createSymbolicLink( dotSwiftPMSecurityDirectory, pointingAt: idiomaticSecurityDirectory, relative: false ) } } return idiomaticSecurityDirectory } } // MARK: - Swift SDKs private let swiftSDKsDirectoryName = "swift-sdks" extension FileSystem { /// Path to Swift SDKs directory (if exists) public var swiftSDKsDirectory: AbsolutePath { get throws { if let path = try idiomaticSwiftPMDirectory { return path.appending(component: swiftSDKsDirectoryName) } else { return try dotSwiftPMSwiftSDKsDirectory } } } private var dotSwiftPMSwiftSDKsDirectory: AbsolutePath { get throws { try dotSwiftPM.appending(component: swiftSDKsDirectoryName) } } public func getSharedSwiftSDKsDirectory(explicitDirectory: AbsolutePath?) throws -> AbsolutePath { if let explicitDirectory { // Create the explicit SDKs path if necessary if !exists(explicitDirectory) { try createDirectory(explicitDirectory, recursive: true) } return explicitDirectory } else { return try swiftSDKsDirectory } } public func getOrCreateSwiftPMSwiftSDKsDirectory() throws -> AbsolutePath { let idiomaticSwiftSDKDirectory = try swiftSDKsDirectory // Create idiomatic if necessary if !exists(idiomaticSwiftSDKDirectory) { try createDirectory(idiomaticSwiftSDKDirectory, recursive: true) } // Create ~/.swiftpm if necessary if !exists(try dotSwiftPM) { try createDirectory(dotSwiftPM, recursive: true) } // Create ~/.swiftpm/swift-sdks symlink if necessary // locking ~/.swiftpm to protect from concurrent access try withLock(on: dotSwiftPM, type: .exclusive) { if !exists(try dotSwiftPMSwiftSDKsDirectory, followSymlink: false) { try createSymbolicLink( dotSwiftPMSwiftSDKsDirectory, pointingAt: idiomaticSwiftSDKDirectory, relative: false ) } } return idiomaticSwiftSDKDirectory } } // MARK: - Utilities extension FileSystem { @_disfavoredOverload public func readFileContents(_ path: AbsolutePath) throws -> Data { try Data(self.readFileContents(path).contents) } @_disfavoredOverload public func readFileContents(_ path: AbsolutePath) throws -> String { try String(decoding: self.readFileContents(path), as: UTF8.self) } public func writeFileContents(_ path: AbsolutePath, data: Data) throws { try self._writeFileContents(path, bytes: .init(data)) } public func writeFileContents(_ path: AbsolutePath, string: String) throws { try self._writeFileContents(path, bytes: .init(encodingAsUTF8: string)) } private func _writeFileContents(_ path: AbsolutePath, bytes: ByteString) throws { // using the "body" variant since it creates the directory first // we should probably fix TSC to be consistent about this behavior try self.writeFileContents(path, body: { $0.send(bytes) }) } } extension FileSystem { /// Write bytes to the path if the given contents are different. public func writeIfChanged(path: AbsolutePath, string: String) throws { try writeIfChanged(path: path, bytes: .init(encodingAsUTF8: string)) } public func writeIfChanged(path: AbsolutePath, data: Data) throws { try writeIfChanged(path: path, bytes: .init(data)) } /// Write bytes to the path if the given contents are different. public func writeIfChanged(path: AbsolutePath, bytes: ByteString) throws { try createDirectory(path.parentDirectory, recursive: true) // Return if the contents are same. if isFile(path), try readFileContents(path) == bytes { return } try writeFileContents(path, bytes: bytes) } } extension FileSystem { public func forceCreateDirectory(at path: AbsolutePath) throws { try self.createDirectory(path.parentDirectory, recursive: true) if self.exists(path) { try self.removeFileTree(path) } try self.createDirectory(path, recursive: true) } } extension FileSystem { public func stripFirstLevel(of path: AbsolutePath) throws { let topLevelDirectories = try self.getDirectoryContents(path) .map { path.appending(component: $0) } .filter { self.isDirectory($0) } guard topLevelDirectories.count == 1, let rootDirectory = topLevelDirectories.first else { throw StringError("stripFirstLevel requires single top level directory") } let tempDirectory = path.parentDirectory.appending(component: UUID().uuidString) try self.move(from: rootDirectory, to: tempDirectory) let rootContents = try self.getDirectoryContents(tempDirectory) for entry in rootContents { try self.move(from: tempDirectory.appending(component: entry), to: path.appending(component: entry)) } try self.removeFileTree(tempDirectory) } } // MARK: - Locking extension FileLock { public static func prepareLock( fileToLock: AbsolutePath, at lockFilesDirectory: AbsolutePath? = nil ) throws -> FileLock { return try Self.prepareLock(fileToLock: fileToLock.underlying, at: lockFilesDirectory?.underlying) } } /// Convenience initializers for testing purposes. extension InMemoryFileSystem { /// Create a new file system with the given files, provided as a map from /// file path to contents. public convenience init(files: [String: ByteString]) { self.init() for (path, contents) in files { let path = try! AbsolutePath(validating: path) try! createDirectory(path.parentDirectory, recursive: true) try! writeFileContents(path, bytes: contents) } } /// Create a new file system with an empty file at each provided path. public convenience init(emptyFiles files: String...) { self.init(emptyFiles: files) } /// Create a new file system with an empty file at each provided path. public convenience init(emptyFiles files: [String]) { self.init() self.createEmptyFiles(at: .root, files: files) } } extension FileSystem { public func createEmptyFiles(at root: AbsolutePath, files: String...) { self.createEmptyFiles(at: root, files: files) } public func createEmptyFiles(at root: AbsolutePath, files: [String]) { do { try createDirectory(root, recursive: true) for path in files { let path = try AbsolutePath(validating: String(path.dropFirst()), relativeTo: root) try createDirectory(path.parentDirectory, recursive: true) try writeFileContents(path, bytes: "") } } catch { fatalError("Failed to create empty files: \(error)") } } } extension FileSystem { /// Do a deep enumeration, passing each file to block public func enumerate(directory: AbsolutePath, block: (AbsolutePath) throws -> ()) throws { for file in try getDirectoryContents(directory) { let path = directory.appending(file) if isDirectory(path) { try enumerate(directory: path, block: block) } else { try block(path) } } } } ================================================ FILE: Sources/Basics/FileSystem/InMemoryFileSystem.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.NSLock import class Dispatch.DispatchQueue import struct TSCBasic.AbsolutePath import struct TSCBasic.ByteString import class TSCBasic.FileLock import enum TSCBasic.FileMode import struct TSCBasic.FileSystemError /// Concrete FileSystem implementation which simulates an empty disk. public final class InMemoryFileSystem: FileSystem { /// Private internal representation of a file system node. /// Not thread-safe. private class Node { /// The actual node data. let contents: NodeContents /// Whether the node has executable bit enabled. var isExecutable: Bool init(_ contents: NodeContents, isExecutable: Bool = false) { self.contents = contents self.isExecutable = isExecutable } /// Creates deep copy of the object. func copy() -> Node { return Node(contents.copy()) } } /// Private internal representation the contents of a file system node. /// Not thread-safe. private enum NodeContents { case file(ByteString) case directory(DirectoryContents) case symlink(String) /// Creates deep copy of the object. func copy() -> NodeContents { switch self { case .file(let bytes): return .file(bytes) case .directory(let contents): return .directory(contents.copy()) case .symlink(let path): return .symlink(path) } } } /// Private internal representation the contents of a directory. /// Not thread-safe. private final class DirectoryContents { var entries: [String: Node] init(entries: [String: Node] = [:]) { self.entries = entries } /// Creates deep copy of the object. func copy() -> DirectoryContents { let contents = DirectoryContents() for (key, node) in entries { contents.entries[key] = node.copy() } return contents } } /// The root node of the filesystem. private var root: Node /// Protects `root` and everything underneath it. /// FIXME: Using a single lock for this is a performance problem, but in /// reality, the only practical use for InMemoryFileSystem is for unit /// tests. private let lock = NSLock() /// A map that keeps weak references to all locked files. private var lockFiles = Dictionary>() /// Used to access lockFiles in a thread safe manner. private let lockFilesLock = NSLock() /// Exclusive file system lock vended to clients through `withLock()`. /// Used to ensure that DispatchQueues are released when they are no longer in use. private struct WeakReference { weak var reference: Value? init(_ value: Value?) { self.reference = value } } public init() { root = Node(.directory(DirectoryContents())) } /// Creates deep copy of the object. public func copy() -> InMemoryFileSystem { return lock.withLock { let fs = InMemoryFileSystem() fs.root = root.copy() return fs } } /// Private function to look up the node corresponding to a path. /// Not thread-safe. private func getNode(_ path: TSCBasic.AbsolutePath, followSymlink: Bool = true) throws -> Node? { func getNodeInternal(_ path: TSCBasic.AbsolutePath) throws -> Node? { // If this is the root node, return it. if path.isRoot { return root } // Otherwise, get the parent node. guard let parent = try getNodeInternal(path.parentDirectory) else { return nil } // If we didn't find a directory, this is an error. guard case .directory(let contents) = parent.contents else { throw FileSystemError(.notDirectory, path.parentDirectory) } // Return the directory entry. let node = contents.entries[path.basename] switch node?.contents { case .directory, .file: return node case .symlink(let destination): let destination = try TSCBasic.AbsolutePath(validating: destination, relativeTo: path.parentDirectory) return followSymlink ? try getNodeInternal(destination) : node case .none: return nil } } // Get the node that corresponds to the path. return try getNodeInternal(path) } // MARK: FileSystem Implementation public func exists(_ path: TSCBasic.AbsolutePath, followSymlink: Bool) -> Bool { return lock.withLock { do { switch try getNode(path, followSymlink: followSymlink)?.contents { case .file, .directory, .symlink: return true case .none: return false } } catch { return false } } } public func isDirectory(_ path: TSCBasic.AbsolutePath) -> Bool { return lock.withLock { do { if case .directory? = try getNode(path)?.contents { return true } return false } catch { return false } } } public func isFile(_ path: TSCBasic.AbsolutePath) -> Bool { return lock.withLock { do { if case .file? = try getNode(path)?.contents { return true } return false } catch { return false } } } public func isSymlink(_ path: TSCBasic.AbsolutePath) -> Bool { return lock.withLock { do { if case .symlink? = try getNode(path, followSymlink: false)?.contents { return true } return false } catch { return false } } } public func isReadable(_ path: TSCBasic.AbsolutePath) -> Bool { self.exists(path) } public func isWritable(_ path: TSCBasic.AbsolutePath) -> Bool { self.exists(path) } public func isExecutableFile(_ path: TSCBasic.AbsolutePath) -> Bool { (try? self.getNode(path)?.isExecutable) ?? false } public func updatePermissions(_ path: AbsolutePath, isExecutable: Bool) throws { try lock.withLock { guard let node = try self.getNode(path.underlying, followSymlink: true) else { throw FileSystemError(.noEntry, path) } node.isExecutable = isExecutable } } /// Virtualized current working directory. private var _currentWorkingDirectory: TSCBasic.AbsolutePath = try! .init(validating: "/") public var currentWorkingDirectory: TSCBasic.AbsolutePath? { return _currentWorkingDirectory } public func changeCurrentWorkingDirectory(to path: TSCBasic.AbsolutePath) throws { return try lock.withLock { // Verify the path exists and is a directory guard let node = try getNode(path) else { throw FileSystemError(.noEntry, path) } guard case .directory = node.contents else { throw FileSystemError(.notDirectory, path) } _currentWorkingDirectory = path } } public var homeDirectory: TSCBasic.AbsolutePath { get throws { // FIXME: Maybe we should allow setting this when creating the fs. return try .init(validating: "/home/user") } } public var cachesDirectory: TSCBasic.AbsolutePath? { return try? self.homeDirectory.appending(component: "caches") } public var tempDirectory: TSCBasic.AbsolutePath { get throws { return try .init(validating: "/tmp") } } public func getDirectoryContents(_ path: TSCBasic.AbsolutePath) throws -> [String] { return try lock.withLock { guard let node = try getNode(path) else { throw FileSystemError(.noEntry, path) } guard case .directory(let contents) = node.contents else { throw FileSystemError(.notDirectory, path) } // FIXME: Perhaps we should change the protocol to allow lazy behavior. return [String](contents.entries.keys) } } /// Not thread-safe. private func _createDirectory(_ path: TSCBasic.AbsolutePath, recursive: Bool) throws { // Ignore if client passes root. guard !path.isRoot else { return } // Get the parent directory node. let parentPath = path.parentDirectory guard let parent = try getNode(parentPath) else { // If the parent doesn't exist, and we are recursive, then attempt // to create the parent and retry. if recursive && path != parentPath { // Attempt to create the parent. try _createDirectory(parentPath, recursive: true) // Re-attempt creation, non-recursively. return try _createDirectory(path, recursive: false) } else { // Otherwise, we failed. throw FileSystemError(.noEntry, parentPath) } } // Check that the parent is a directory. guard case .directory(let contents) = parent.contents else { // The parent isn't a directory, this is an error. throw FileSystemError(.notDirectory, parentPath) } // Check if the node already exists. if let node = contents.entries[path.basename] { // Verify it is a directory. guard case .directory = node.contents else { // The path itself isn't a directory, this is an error. throw FileSystemError(.notDirectory, path) } // We are done. return } // Otherwise, the node does not exist, create it. contents.entries[path.basename] = Node(.directory(DirectoryContents())) } public func createDirectory(_ path: TSCBasic.AbsolutePath, recursive: Bool) throws { return try lock.withLock { try _createDirectory(path, recursive: recursive) } } public func createSymbolicLink( _ path: TSCBasic.AbsolutePath, pointingAt destination: TSCBasic.AbsolutePath, relative: Bool ) throws { return try lock.withLock { // Create directory to destination parent. guard let destinationParent = try getNode(path.parentDirectory) else { throw FileSystemError(.noEntry, path.parentDirectory) } // Check that the parent is a directory. guard case .directory(let contents) = destinationParent.contents else { throw FileSystemError(.notDirectory, path.parentDirectory) } guard contents.entries[path.basename] == nil else { throw FileSystemError(.alreadyExistsAtDestination, path) } let destination = relative ? destination.relative(to: path.parentDirectory).pathString : destination.pathString contents.entries[path.basename] = Node(.symlink(destination)) } } public func readFileContents(_ path: TSCBasic.AbsolutePath) throws -> ByteString { return try lock.withLock { // Get the node. guard let node = try getNode(path) else { throw FileSystemError(.noEntry, path) } // Check that the node is a file. guard case .file(let contents) = node.contents else { // The path is a directory, this is an error. throw FileSystemError(.isDirectory, path) } // Return the file contents. return contents } } public func writeFileContents(_ path: TSCBasic.AbsolutePath, bytes: ByteString) throws { return try lock.withLock { // It is an error if this is the root node. let parentPath = path.parentDirectory guard path != parentPath else { throw FileSystemError(.isDirectory, path) } // Get the parent node. guard let parent = try getNode(parentPath) else { throw FileSystemError(.noEntry, parentPath) } // Check that the parent is a directory. guard case .directory(let contents) = parent.contents else { // The parent isn't a directory, this is an error. throw FileSystemError(.notDirectory, parentPath) } // Check if the node exists. if let node = contents.entries[path.basename] { // Verify it is a file. guard case .file = node.contents else { // The path is a directory, this is an error. throw FileSystemError(.isDirectory, path) } } // Write the file. contents.entries[path.basename] = Node(.file(bytes)) } } public func writeFileContents(_ path: TSCBasic.AbsolutePath, bytes: ByteString, atomically: Bool) throws { // In memory file system's writeFileContents is already atomic, so ignore the parameter here // and just call the base implementation. try writeFileContents(path, bytes: bytes) } public func removeFileTree(_ path: TSCBasic.AbsolutePath) throws { return lock.withLock { // Ignore root and get the parent node's content if its a directory. guard !path.isRoot, let parent = try? getNode(path.parentDirectory), case .directory(let contents) = parent.contents else { return } // Set it to nil to release the contents. contents.entries[path.basename] = nil } } public func chmod(_ mode: FileMode, path: TSCBasic.AbsolutePath, options: Set) throws { // FIXME: We don't have these semantics in InMemoryFileSystem. } /// Private implementation of core copying function. /// Not thread-safe. private func _copy(from sourcePath: TSCBasic.AbsolutePath, to destinationPath: TSCBasic.AbsolutePath) throws { // Get the source node. guard let source = try getNode(sourcePath) else { throw FileSystemError(.noEntry, sourcePath) } // Create directory to destination parent. guard let destinationParent = try getNode(destinationPath.parentDirectory) else { throw FileSystemError(.noEntry, destinationPath.parentDirectory) } // Check that the parent is a directory. guard case .directory(let contents) = destinationParent.contents else { throw FileSystemError(.notDirectory, destinationPath.parentDirectory) } guard contents.entries[destinationPath.basename] == nil else { throw FileSystemError(.alreadyExistsAtDestination, destinationPath) } contents.entries[destinationPath.basename] = source } public func copy(from sourcePath: TSCBasic.AbsolutePath, to destinationPath: TSCBasic.AbsolutePath) throws { return try lock.withLock { try _copy(from: sourcePath, to: destinationPath) } } public func move(from sourcePath: TSCBasic.AbsolutePath, to destinationPath: TSCBasic.AbsolutePath) throws { return try lock.withLock { // Get the source parent node. guard let sourceParent = try getNode(sourcePath.parentDirectory) else { throw FileSystemError(.noEntry, sourcePath.parentDirectory) } // Check that the parent is a directory. guard case .directory(let contents) = sourceParent.contents else { throw FileSystemError(.notDirectory, sourcePath.parentDirectory) } try _copy(from: sourcePath, to: destinationPath) contents.entries[sourcePath.basename] = nil } } public func withLock( on path: TSCBasic.AbsolutePath, type: FileLock.LockType = .exclusive, _ body: () throws -> T ) throws -> T { let resolvedPath: TSCBasic.AbsolutePath = try lock.withLock { if case let .symlink(destination) = try getNode(path)?.contents { return try .init(validating: destination, relativeTo: path.parentDirectory) } else { return path } } let fileQueue: DispatchQueue = lockFilesLock.withLock { if let queueReference = lockFiles[resolvedPath], let queue = queueReference.reference { return queue } else { let queue = DispatchQueue(label: "org.swift.swiftpm.in-memory-file-system.file-queue", attributes: .concurrent) lockFiles[resolvedPath] = WeakReference(queue) return queue } } return try fileQueue.sync(flags: type == .exclusive ? .barrier : .init() , execute: body) } public func withLock(on path: TSCBasic.AbsolutePath, type: FileLock.LockType, blocking: Bool, _ body: () throws -> T) throws -> T { try self.withLock(on: path, type: type, body) } } // Internal state of `InMemoryFileSystem` is protected with a lock in all of its `public` methods. extension InMemoryFileSystem: @unchecked Sendable {} ================================================ FILE: Sources/Basics/FileSystem/NativePathExtensions.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Foundation import struct TSCBasic.AbsolutePath extension AbsolutePath { /// Returns the File System Representation of the `AbsolutePath`'s /// `pathString` property converted into a `URL`. public func _nativePathString(escaped: Bool) -> String { return URL(fileURLWithPath: self.pathString).withUnsafeFileSystemRepresentation { let repr = String(cString: $0!) if escaped { return repr.replacing("\\", with: "\\\\") } return repr } } } extension DefaultStringInterpolation { public mutating func appendInterpolation(_ value: AbsolutePath) { self.appendInterpolation(value._nativePathString(escaped: false)) } } extension SerializedJSON.StringInterpolation { public mutating func appendInterpolation(_ value: AbsolutePath) { self.appendInterpolation(value._nativePathString(escaped: false)) } } ================================================ FILE: Sources/Basics/FileSystem/RelativePath.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2023 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct TSCBasic.RelativePath // public for transition public typealias TSCRelativePath = TSCBasic.RelativePath /// Represents a relative file system path. A relative path never starts with /// a `/` character, and holds a normalized string representation. As with /// AbsolutePath, the normalization is strictly syntactic, and does not access /// the file system in any way. /// /// The relative path string is normalized by: /// - Collapsing `..` path components that aren't at the beginning /// - Removing extraneous `.` path components /// - Removing any trailing path separator /// - Removing any redundant path separators /// - Replacing a completely empty path with a `.` /// /// This string manipulation may change the meaning of a path if any of the /// path components are symbolic links on disk. However, the file system is /// never accessed in any way when initializing a RelativePath. public struct RelativePath: Hashable, Sendable { let underlying: TSCBasic.RelativePath // public for transition public init(_ underlying: TSCBasic.RelativePath) { self.underlying = underlying } /// Convenience initializer that verifies that the path is relative. public init(validating pathString: String) throws { self.underlying = try .init(validating: pathString) } /// Directory component. For a relative path without any path separators, /// this is the `.` string instead of the empty string. public var dirname: String { self.underlying.dirname } /// Last path component (including the suffix, if any). It is never empty. public var basename: String { self.underlying.basename } /// Returns the basename without the extension. public var basenameWithoutExt: String { self.underlying.basenameWithoutExt } /// Suffix (including leading `.` character) if any. Note that a basename /// that starts with a `.` character is not considered a suffix, nor is a /// trailing `.` character. public var suffix: String? { self.underlying.suffix } /// Extension of the give path's basename. This follow same rules as /// suffix except that it doesn't include leading `.` character. public var `extension`: String? { self.underlying.extension } /// Normalized string representation (the normalization rules are described /// in the documentation of the initializer). This string is never empty. public var pathString: String { self.underlying.pathString } } extension RelativePath { /// Returns an array of strings that make up the path components of the /// relative path. This is the same sequence of strings as the basenames /// of each successive path component. Therefore the returned array of /// path components is never empty; even an empty path has a single path /// component: the `.` string. public var components: [String] { self.underlying.components } /// Returns the relative path with the given relative path applied. public func appending(_ subpath: RelativePath) -> RelativePath { Self(self.underlying.appending(subpath.underlying)) } /// Returns the relative path with an additional literal component appended. /// /// This method accepts pseudo-path like '.' or '..', but should not contain "/". public func appending(component: String) -> RelativePath { Self(self.underlying.appending(component: component)) } /// Returns the relative path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(components: [String]) -> RelativePath { Self(self.underlying.appending(components: components)) } /// Returns the relative path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(components: String...) -> RelativePath { Self(self.underlying.appending(components: components)) } /// Returns the relative path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(_ component: String) -> RelativePath { self.appending(component: component) } /// Returns the relative path with additional literal components appended. /// /// This method should only be used in cases where the input is guaranteed /// to be a valid path component (i.e., it cannot be empty, contain a path /// separator, or be a pseudo-path like '.' or '..'). public func appending(_ components: String...) -> RelativePath { self.appending(components: components) } } extension RelativePath: Codable { public func encode(to encoder: Encoder) throws { try self.underlying.encode(to: encoder) } public init(from decoder: Decoder) throws { self = try .init(TSCBasic.RelativePath(from: decoder)) } } /// Make relative paths CustomStringConvertible and CustomDebugStringConvertible. extension RelativePath: CustomStringConvertible { public var description: String { self.underlying.description } public var debugDescription: String { self.underlying.debugDescription } } extension TSCRelativePath { public init(_ path: RelativePath) { self = path.underlying } } ================================================ FILE: Sources/Basics/FileSystem/TSCAdapters.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import func TSCBasic.getEnvSearchPaths import func TSCBasic.lookupExecutablePath import func TSCBasic.makeDirectories import func TSCBasic.resolveSymlinks import func TSCBasic.walk import func TSCBasic.withTemporaryDirectory import struct TSCBasic.FileSystemError import class TSCBasic.LocalFileOutputByteStream import enum TSCBasic.ProcessEnv import class TSCBasic.RecursibleDirectoryContentsGenerator public func resolveSymlinks(_ path: AbsolutePath) throws -> AbsolutePath { try AbsolutePath(TSCBasic.resolveSymlinks(path.underlying)) } public func withTemporaryDirectory( dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", _ body: (AbsolutePath, @escaping (AbsolutePath) -> Void) throws -> Result ) throws -> Result { try TSCBasic.withTemporaryDirectory(dir: dir?.underlying, prefix: prefix) { path, callback in let callback2 = { (path: AbsolutePath) in callback(path.underlying) } return try body(AbsolutePath(path), callback2) } } public func withTemporaryDirectory( dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", _ body: (AbsolutePath, @escaping (AbsolutePath) async -> Void) async throws -> Result ) async throws -> Result { try await TSCBasic.withTemporaryDirectory(dir: dir?.underlying, prefix: prefix) { path, callback in let callback2: (AbsolutePath) async -> Void = { (path: AbsolutePath) in await callback(path.underlying) } return try await body(AbsolutePath(path), callback2) } } public func withTemporaryDirectory( dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", removeTreeOnDeinit: Bool = false, _ body: (AbsolutePath) throws -> Result ) throws -> Result { try TSCBasic.withTemporaryDirectory(dir: dir?.underlying, prefix: prefix, removeTreeOnDeinit: removeTreeOnDeinit) { try body(AbsolutePath($0)) } } public func withTemporaryDirectory( dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", removeTreeOnDeinit: Bool = false, _ body: (AbsolutePath) async throws -> Result ) async throws -> Result { try await TSCBasic.withTemporaryDirectory( dir: dir?.underlying, prefix: prefix, removeTreeOnDeinit: removeTreeOnDeinit ) { try await body(AbsolutePath($0)) } } /// Lookup an executable path from an environment variable value, current working /// directory or search paths. Only return a value that is both found and executable. /// /// This method searches in the following order: /// * If env value is a valid absolute path, return it. /// * If env value is relative path, first try to locate it in current working directory. /// * Otherwise, in provided search paths. /// /// - Parameters: /// - filename: The name of the file to find. /// - currentWorkingDirectory: The current working directory to look in. /// - searchPaths: The additional search paths to look in if not found in cwd. /// - Returns: Valid path to executable if present, otherwise nil. public func lookupExecutablePath( filename: String?, currentWorkingDirectory: AbsolutePath? = localFileSystem.currentWorkingDirectory, searchPaths: [AbsolutePath] = [] ) -> AbsolutePath? { TSCBasic.lookupExecutablePath( filename: filename, currentWorkingDirectory: currentWorkingDirectory?.underlying, searchPaths: searchPaths.map(\.underlying) ).flatMap { AbsolutePath($0) } } /// Create a list of AbsolutePath search paths from a string, such as the PATH environment variable. /// /// - Parameters: /// - pathString: The path string to parse. /// - currentWorkingDirectory: The current working directory, the relative paths will be converted to absolute paths /// based on this path. /// - Returns: List of search paths. public func getEnvSearchPaths( pathString: String?, currentWorkingDirectory: AbsolutePath? ) -> [AbsolutePath] { TSCBasic.getEnvSearchPaths( pathString: pathString, currentWorkingDirectory: currentWorkingDirectory?.underlying ).map { AbsolutePath($0) } } public func walk( _ path: AbsolutePath, fileSystem: FileSystem = localFileSystem, recursively: Bool = true ) throws -> WalkResult { let result = try TSCBasic.walk( path.underlying, fileSystem: fileSystem, recursively: recursively ) return WalkResult(result) } public class WalkResult: IteratorProtocol, Sequence { private let underlying: TSCBasic.RecursibleDirectoryContentsGenerator init(_ underlying: TSCBasic.RecursibleDirectoryContentsGenerator) { self.underlying = underlying } public func next() -> AbsolutePath? { self.underlying.next().flatMap { AbsolutePath($0) } } } public func makeDirectories(_ path: AbsolutePath) throws { try TSCBasic.makeDirectories(path.underlying) } extension TSCBasic.LocalFileOutputByteStream { public convenience init(_ path: AbsolutePath, closeOnDeinit: Bool = true, buffered: Bool = true) throws { try self.init(path.underlying, closeOnDeinit: closeOnDeinit, buffered: buffered) } } extension TSCBasic.ProcessEnv { public static func chdir(_ path: AbsolutePath) throws { try self.chdir(path.underlying) } } extension TSCBasic.FileSystemError { @_disfavoredOverload public init(_ kind: Kind, _ path: AbsolutePath? = nil) { self.init(kind, path?.underlying) } } ================================================ FILE: Sources/Basics/FileSystem/TemporaryFile.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import _Concurrency import Foundation import enum TSCBasic.TempFileError /// Creates a temporary directory and evaluates a closure with the directory path as an argument. /// The temporary directory will live on disk while the closure is evaluated and will be deleted when /// the cleanup closure is called. This allows the temporary directory to have an arbitrary lifetime. /// /// - Parameters: /// - fileSystem: `FileSystem` which is used to construct temporary directory. /// - dir: If specified the temporary directory will be created in this directory otherwise environment /// variables TMPDIR, TEMP and TMP will be checked for a value (in that order). If none of the env /// variables are set, dir will be set to `/tmp/`. /// - prefix: The prefix to the temporary file name. /// - body: A closure to execute that receives the absolute path of the directory as an argument. /// If `body` has a return value, that value is also used as the /// return value for the `withTemporaryDirectory` function. /// The cleanup block should be called when the temporary directory is no longer needed. /// /// - Throws: An error when creating directory and rethrows all errors from `body`. public func withTemporaryDirectory( fileSystem: FileSystem = localFileSystem, dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", _ body: @escaping @Sendable (AbsolutePath, @escaping (AbsolutePath) -> Void) async throws -> Result ) throws -> Task { let temporaryDirectory = try createTemporaryDirectory(fileSystem: fileSystem, dir: dir, prefix: prefix) let task: Task = Task { try await withTaskCancellationHandler { try await body(temporaryDirectory) { path in try? fileSystem.removeFileTree(path) } } onCancel: { try? fileSystem.removeFileTree(temporaryDirectory) } } return task } /// Creates a temporary directory and evaluates a closure with the directory path as an argument. /// The temporary directory will live on disk while the closure is evaluated and will be deleted afterwards. /// /// - Parameters: /// - fileSystem: `FileSystem` which is used to construct temporary directory. /// - dir: If specified the temporary directory will be created in this directory otherwise environment /// variables TMPDIR, TEMP and TMP will be checked for a value (in that order). If none of the env /// variables are set, dir will be set to `/tmp/`. /// - prefix: The prefix to the temporary file name. /// - removeTreeOnDeinit: If enabled try to delete the whole directory tree otherwise remove only if its empty. /// - body: A closure to execute that receives the absolute path of the directory as an argument. /// If `body` has a return value, that value is also used as the /// return value for the `withTemporaryDirectory` function. /// /// - Throws: An error when creating directory and rethrows all errors from `body`. @discardableResult public func withTemporaryDirectory( fileSystem: FileSystem = localFileSystem, dir: AbsolutePath? = nil, prefix: String = "TemporaryDirectory", removeTreeOnDeinit: Bool = false, _ body: @escaping @Sendable (AbsolutePath) async throws -> Result ) throws -> Task { try withTemporaryDirectory(fileSystem: fileSystem, dir: dir, prefix: prefix) { path, cleanup in defer { if removeTreeOnDeinit { cleanup(path) } } return try await body(path) } } private func createTemporaryDirectory( fileSystem: FileSystem, dir: AbsolutePath?, prefix: String ) throws -> AbsolutePath { // This random generation is needed so that // it is more or less equal to generation using `mkdtemp` function let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" let randomSuffix = String((0 ..< 6).map { _ in letters.randomElement()! }) let tempDirectory = try dir ?? fileSystem.tempDirectory guard fileSystem.isDirectory(tempDirectory) else { throw TempFileError.couldNotFindTmpDir(tempDirectory.pathString) } // Construct path to the temporary directory. let templatePath = try AbsolutePath(validating: prefix + ".\(randomSuffix)", relativeTo: tempDirectory) try fileSystem.createDirectory(templatePath, recursive: true) return templatePath } ================================================ FILE: Sources/Basics/FileSystem/VFSOverlay.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import class Foundation.JSONEncoder public struct VFSOverlay: Encodable { public struct File: Encodable { enum CodingKeys: String, CodingKey { case externalContents = "external-contents" case name case type } private let externalContents: String private let name: String private let type = "file" public init(name: String, externalContents: String) { self.name = name self.externalContents = externalContents } } enum CodingKeys: String, CodingKey { case roots case useExternalNames = "use-external-names" case version } private let roots: [File] private let useExternalNames = false private let version = 0 public init(roots: [File]) { self.roots = roots } public func write(to path: AbsolutePath, fileSystem: FileSystem) throws { // VFS overlay files are YAML, but ours is simple enough that it works when being written using `JSONEncoder`. try JSONEncoder.makeWithDefaults(prettified: false).encode(path: path, fileSystem: fileSystem, self) } } ================================================ FILE: Sources/Basics/FileSystem/VirtualFileSystem.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2021 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import Foundation import struct TSCBasic.ByteString import struct TSCBasic.FileInfo import enum TSCBasic.FileMode private enum DirectoryNode: Codable { case directory(name: String, isSymlink: Bool, children: [DirectoryNode]) case file(name: String, isExecutable: Bool, isSymlink: Bool, contents: Data?) case root(children: [DirectoryNode]) var children: [DirectoryNode] { switch self { case .directory(_, _, let children): return children case .file: return [] case .root(let children): return children } } var name: String { switch self { case .directory(let name, _, _): return name case .file(let name, _, _, _): return name case .root: return AbsolutePath.root.pathString } } var fileAttributeType: FileAttributeType { switch self { case .directory: return .typeDirectory case .file(_, _, let isSymlink, _): return isSymlink ? .typeSymbolicLink : .typeRegular case .root: return .typeDirectory } } var isDirectory: Bool { switch self { case .directory: return true case .file: return false case .root: return true } } var isFile: Bool { switch self { case .directory: return false case .file: return true case .root: return false } } var isRoot: Bool { switch self { case .directory: return false case .file: return false case .root: return true } } var isSymlink: Bool { switch self { case .directory(_, let isSymlink, _): return isSymlink case .file(_, _, let isSymlink, _): return isSymlink case .root: return false } } } private enum Errors: Swift.Error, LocalizedError { case noSuchFileOrDirectory(path: AbsolutePath) case notAFile(path: AbsolutePath) case readOnlyFileSystem case unhandledDirectoryNode(path: AbsolutePath) public var errorDescription: String? { switch self { case .noSuchFileOrDirectory(let path): return "no such file or directory: \(path.pathString)" case .notAFile(let path): return "not a file: \(path.pathString)" case .readOnlyFileSystem: return "read-only filesystem" case .unhandledDirectoryNode(let path): return "unhandled directory node: \(path.pathString)" } } } extension FileSystem { fileprivate func getDirectoryNodes( _ path: AbsolutePath, includeContents: [AbsolutePath] ) throws -> [DirectoryNode] { try getDirectoryContents(path).compactMap { let current = path.appending(component: $0) let isSymlink = isSymlink(current) if isFile(current) { let contents: Data? if includeContents.contains(current) { contents = try readFileContents(current) } else { contents = nil } return .file( name: $0, isExecutable: isExecutableFile(current), isSymlink: isSymlink, contents: contents ) } else if isDirectory(current) { if $0.hasPrefix(".") { return nil } // we ignore hidden files return .directory( name: $0, isSymlink: isSymlink, children: try getDirectoryNodes(current, includeContents: includeContents) ) } else { throw Errors.unhandledDirectoryNode(path: current) } } } } /// A JSON-backed, read-only virtual file system. public class VirtualFileSystem: FileSystem { private let root: DirectoryNode public init(path: TSCAbsolutePath, fs: FileSystem) throws { self.root = try JSONDecoder.makeWithDefaults() .decode(path: AbsolutePath(path), fileSystem: fs, as: DirectoryNode.self) assert(self.root.isRoot, "VFS needs to have a root node") } /// Write information about the directory tree at `directoryPath` into a JSON file at `vfsPath`. This can later be used to construct a `VirtualFileSystem` object. public static func serializeDirectoryTree( _ directoryPath: AbsolutePath, into vfsPath: AbsolutePath, fs: FileSystem, includeContents: [AbsolutePath] ) throws { let data = try JSONEncoder.makeWithDefaults().encode( DirectoryNode.root( children: fs.getDirectoryNodes( directoryPath, includeContents: includeContents ) ) ) try data.write(to: URL(fileURLWithPath: vfsPath.pathString)) } private func findNode(_ path: TSCAbsolutePath, followSymlink: Bool) -> DirectoryNode? { var current: DirectoryNode? = self.root for component in path.components { if component == AbsolutePath.root.pathString { continue } guard followSymlink, current?.isSymlink == false else { return nil } current = current?.children.first(where: { $0.name == component }) } return current } public func exists(_ path: TSCAbsolutePath, followSymlink: Bool) -> Bool { findNode(path, followSymlink: followSymlink) != nil } public func isDirectory(_ path: TSCAbsolutePath) -> Bool { findNode(path, followSymlink: true)?.isDirectory == true } public func isFile(_ path: TSCAbsolutePath) -> Bool { findNode(path, followSymlink: true)?.isFile == true } public func isExecutableFile(_ path: TSCAbsolutePath) -> Bool { guard let node = findNode(path, followSymlink: true) else { return false } if case .file(_, let isExecutable, _, _) = node { return isExecutable } else { return false } } public func isSymlink(_ path: TSCAbsolutePath) -> Bool { findNode(path, followSymlink: true)?.isSymlink == true } public func isReadable(_ path: TSCAbsolutePath) -> Bool { self.exists(path) } public func isWritable(_: TSCAbsolutePath) -> Bool { false } public func getDirectoryContents(_ path: TSCAbsolutePath) throws -> [String] { guard let node = findNode(path, followSymlink: true) else { throw Errors.noSuchFileOrDirectory(path: AbsolutePath(path)) } return node.children.map(\.name) } public let currentWorkingDirectory: TSCAbsolutePath? = nil public func changeCurrentWorkingDirectory(to path: TSCAbsolutePath) throws { throw Errors.readOnlyFileSystem } public var homeDirectory = TSCAbsolutePath.root public var cachesDirectory: TSCAbsolutePath? = nil public var tempDirectory = TSCAbsolutePath.root public func createSymbolicLink( _ path: TSCAbsolutePath, pointingAt destination: TSCAbsolutePath, relative: Bool ) throws { throw Errors.readOnlyFileSystem } public func removeFileTree(_: TSCAbsolutePath) throws { throw Errors.readOnlyFileSystem } public func copy(from sourcePath: TSCAbsolutePath, to destinationPath: TSCAbsolutePath) throws { throw Errors.readOnlyFileSystem } public func move(from sourcePath: TSCAbsolutePath, to destinationPath: TSCAbsolutePath) throws { throw Errors.readOnlyFileSystem } public func createDirectory(_ path: TSCAbsolutePath, recursive: Bool) throws { throw Errors.readOnlyFileSystem } public func readFileContents(_ path: TSCAbsolutePath) throws -> ByteString { guard let node = findNode(path, followSymlink: true) else { throw Errors.noSuchFileOrDirectory(path: AbsolutePath(path)) } switch node { case .directory: throw Errors.notAFile(path: AbsolutePath(path)) case .file(_, _, _, let contents): if let contents { return ByteString(contents) } else { return "" } case .root: throw Errors.notAFile(path: AbsolutePath(path)) } } public func writeFileContents(_ path: TSCAbsolutePath, bytes: ByteString) throws { throw Errors.readOnlyFileSystem } public func chmod(_ mode: FileMode, path: TSCAbsolutePath, options: Set) throws { throw Errors.readOnlyFileSystem } public func getFileInfo(_ path: TSCAbsolutePath) throws -> FileInfo { guard let node = findNode(path, followSymlink: true) else { throw Errors.noSuchFileOrDirectory(path: AbsolutePath(path)) } let attrs: [FileAttributeKey: Any] = [ .systemNumber: NSNumber(value: UInt64(0)), .systemFileNumber: UInt64(0), .posixPermissions: NSNumber(value: Int16(0)), .type: node.fileAttributeType, .size: UInt64(0), .modificationDate: Date(), ] return FileInfo(attrs) } } // `VirtualFileSystem` is read-only, so it can be marked as `Sendable`. extension VirtualFileSystem: @unchecked Sendable {} ================================================ FILE: Sources/Basics/Graph/AdjacencyMatrix.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// A matrix storing bits of `true`/`false` state for a given combination of row and column indices. Used as /// a square matrix indicating edges in graphs, where rows and columns are indices in a storage of graph's nodes. /// /// For example, in a graph that contains 3 nodes `matrix[row: 1, column: 2]` evaluating to `true` means an edge /// between nodes with indices `1` and `2` exists. `matrix[row: 1, column: 2]` evaluating to `false` means that no /// edge exists. /// /// See https://en.wikipedia.org/wiki/Adjacency_matrix for more details. struct AdjacencyMatrix { let columns: Int let rows: Int private var bytes: [UInt8] /// Allocates a new bit matrix with a given size. /// - Parameters: /// - rows: Number of rows in the matrix. /// - columns: Number of columns in the matrix. init(rows: Int, columns: Int) { self.columns = columns self.rows = rows let (quotient, remainder) = (rows * columns).quotientAndRemainder(dividingBy: 8) self.bytes = .init(repeating: 0, count: quotient + (remainder > 0 ? 1 : 0)) } var bitCount: Int { bytes.count * 8 } private func calculateOffsets(row: Int, column: Int) -> (byteOffset: Int, bitOffsetInByte: Int) { let totalBitOffset = row * columns + column return (byteOffset: totalBitOffset / 8, bitOffsetInByte: totalBitOffset % 8) } subscript(row: Int, column: Int) -> Bool { get { let (byteOffset, bitOffsetInByte) = calculateOffsets(row: row, column: column) let result = (self.bytes[byteOffset] >> bitOffsetInByte) & 1 return result == 1 } set { let (byteOffset, bitOffsetInByte) = calculateOffsets(row: row, column: column) self.bytes[byteOffset] |= 1 << bitOffsetInByte } } } ================================================ FILE: Sources/Basics/Graph/DirectedGraph.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// private import DequeModule /// Directed graph that stores edges in [adjacency lists](https://en.wikipedia.org/wiki/Adjacency_list). @_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) public struct DirectedGraph { public init(nodes: [Node]) { self.nodes = nodes self.edges = .init(repeating: [], count: nodes.count) } public private(set) var nodes: [Node] private var edges: [[Int]] public mutating func addEdge(source: Int, destination: Int) { self.edges[source].append(destination) } /// Checks whether a path via previously created edges between two given nodes exists. /// - Parameters: /// - source: `Index` of a node to start traversing edges from. /// - destination: `Index` of a node to which a path could exist via edges from `source`. /// - Returns: `true` if a path from `source` to `destination` exists, `false` otherwise. @_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) public func areNodesConnected(source: Int, destination: Int) -> Bool { var todo = Deque([source]) var done = Set() while !todo.isEmpty { let nodeIndex = todo.removeFirst() for reachableIndex in self.edges[nodeIndex] { if reachableIndex == destination { return true } else if !done.contains(reachableIndex) { todo.append(reachableIndex) } } done.insert(nodeIndex) } return false } } ================================================ FILE: Sources/Basics/Graph/GraphAlgorithms.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2015-2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import struct OrderedCollections.OrderedSet /// Implements a pre-order depth-first search. /// /// The cycles are handled by skipping cycle points but it should be possible to /// to extend this in the future to provide a callback for every cycle. /// /// - Parameters: /// - nodes: The list of input nodes to sort. /// - successors: A closure for fetching the successors of a particular node. /// - onUnique: A callback to indicate the the given node is being processed for the first time. /// - onDuplicate: A callback to indicate that the node was already processed at least once. /// /// - Complexity: O(v + e) where (v, e) are the number of vertices and edges /// reachable from the input nodes via the relation. public func depthFirstSearch( _ nodes: [T], successors: (T) throws -> [T], onUnique: (T) throws -> Void, onDuplicate: (T, T) -> Void ) rethrows { var stack = OrderedSet() var visited = Set() for node in nodes { precondition(stack.isEmpty) stack.append(node) while !stack.isEmpty { let curr = stack.removeLast() let visitResult = visited.insert(curr) if visitResult.inserted { try onUnique(curr) } else { onDuplicate(visitResult.memberAfterInsert, curr) continue } for succ in try successors(curr) { stack.append(succ) } } } } public func depthFirstSearch( _ nodes: [T], successors: (T) async throws -> [T], onUnique: (T) async throws -> Void, onDuplicate: (T, T) async -> Void ) async rethrows { var stack = OrderedSet() var visited = Set() for node in nodes { precondition(stack.isEmpty) stack.append(node) while !stack.isEmpty { let curr = stack.removeLast() let visitResult = visited.insert(curr) if visitResult.inserted { try await onUnique(curr) } else { await onDuplicate(visitResult.memberAfterInsert, curr) continue } for succ in try await successors(curr) { stack.append(succ) } } } } private struct TraversalNode: Hashable { let parent: T? let curr: T } /// Implements a pre-order depth-first search that traverses the whole graph and /// doesn't distinguish between unique and duplicate nodes. The method expects /// the graph to be acyclic but doesn't check that. /// /// - Parameters: /// - nodes: The list of input nodes to sort. /// - successors: A closure for fetching the successors of a particular node. /// - onNext: A callback to indicate the node currently being processed /// including its parent (if any) and its depth. /// /// - Complexity: O(v + e) where (v, e) are the number of vertices and edges /// reachable from the input nodes via the relation. public func depthFirstSearch( _ nodes: [T], successors: (T) throws -> [T], onNext: (T, _ parent: T?) throws -> Void ) rethrows { var stack = OrderedSet>() for node in nodes { precondition(stack.isEmpty) stack.append(TraversalNode(parent: nil, curr: node)) while !stack.isEmpty { let node = stack.removeLast() try onNext(node.curr, node.parent) for succ in try successors(node.curr) { stack.append( TraversalNode( parent: node.curr, curr: succ ) ) } } } } ================================================ FILE: Sources/Basics/Graph/UndirectedGraph.swift ================================================ //===----------------------------------------------------------------------===// // // This source file is part of the Swift open source project // // Copyright (c) 2024 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// private import DequeModule /// Undirected graph that stores edges in an [adjacency matrix](https://en.wikipedia.org/wiki/Adjacency_matrix). @_spi(DontAdoptOutsideOfSwiftPMExposedForBenchmarksAndTestsOnly) public struct UndirectedGraph { public init(nodes: [Node]) { self.nodes = nodes self.edges = .init(rows: nodes.count, columns: nodes.count) } private var nodes: [Node] private var edges: AdjacencyMatrix public mutating func addEdge(source: Int, destination: Int) { // Adjacency matrix is symmetrical for undirected graphs. self.edges[source, destination] = true self.edges[destination, source] = true } /// Checks whether a connection via previously created edges between two given nodes exists. /// - Parameters: /// - source: `Index` of a node to start traversing edges from. /// - destination: `Index` of a node to which a connection could exist via edges from `source`. /// - Returns: `true` if a path from `source` to `destination` exists, `false` otherwise. public func areNodesConnected(source: Int, destination: Int) -> Bool { var todo = Deque([source]) var done = Set() while !todo.isEmpty { let nodeIndex = todo.removeFirst() for reachableIndex in self.edges.nodesAdjacentTo(nodeIndex) { if reachableIndex == destination { return true } else if !done.contains(reachableIndex) { todo.append(reachableIndex) } } done.insert(nodeIndex) } return false } } private extension AdjacencyMatrix { func nodesAdjacentTo(_ nodeIndex: Int) -> [Int] { var result = [Int]() for i in 0..