All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.swiftpm.plugins.SwiftPackageManagerExportPlugin Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2018 the original author or 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.
 */

package org.gradle.swiftpm.plugins;

import org.gradle.api.Action;
import org.gradle.api.Incubating;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ProjectDependency;
import org.gradle.api.artifacts.component.ModuleComponentSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.ExactVersionSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.LatestVersionSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.SubVersionSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.Version;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionParser;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionRangeSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelector;
import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.strategy.VersionSelectorScheme;
import org.gradle.api.internal.artifacts.ivyservice.projectmodule.ProjectDependencyPublicationResolver;
import org.gradle.api.provider.Provider;
import org.gradle.internal.component.external.model.DefaultModuleComponentSelector;
import org.gradle.language.cpp.CppApplication;
import org.gradle.language.cpp.CppLibrary;
import org.gradle.language.swift.SwiftApplication;
import org.gradle.language.swift.SwiftLibrary;
import org.gradle.language.swift.SwiftVersion;
import org.gradle.nativeplatform.Linkage;
import org.gradle.swiftpm.Package;
import org.gradle.swiftpm.internal.AbstractProduct;
import org.gradle.swiftpm.internal.BranchDependency;
import org.gradle.swiftpm.internal.DefaultExecutableProduct;
import org.gradle.swiftpm.internal.DefaultLibraryProduct;
import org.gradle.swiftpm.internal.DefaultPackage;
import org.gradle.swiftpm.internal.DefaultTarget;
import org.gradle.swiftpm.internal.Dependency;
import org.gradle.swiftpm.internal.SwiftPmTarget;
import org.gradle.swiftpm.internal.VersionDependency;
import org.gradle.swiftpm.tasks.GenerateSwiftPackageManagerManifest;
import org.gradle.vcs.VersionControlSpec;
import org.gradle.vcs.git.GitVersionControlSpec;
import org.gradle.vcs.internal.VcsResolver;

import javax.inject.Inject;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;

/**
 * A plugin that produces a Swift Package Manager manifests from the Gradle model.
 *
 * 

This plugin should only be applied to the root project of a build.

* * @since 4.6 */ @Incubating public class SwiftPackageManagerExportPlugin implements Plugin { private final VcsResolver vcsResolver; private final VersionSelectorScheme versionSelectorScheme; private final ProjectDependencyPublicationResolver publicationResolver; private final VersionParser versionParser; @Inject public SwiftPackageManagerExportPlugin(VcsResolver vcsResolver, VersionSelectorScheme versionSelectorScheme, ProjectDependencyPublicationResolver publicationResolver, VersionParser versionParser) { this.vcsResolver = vcsResolver; this.versionSelectorScheme = versionSelectorScheme; this.publicationResolver = publicationResolver; this.versionParser = versionParser; } @Override public void apply(final Project project) { final GenerateSwiftPackageManagerManifest manifestTask = project.getTasks().create("generateSwiftPmManifest", GenerateSwiftPackageManagerManifest.class); manifestTask.getManifestFile().set(project.getLayout().getProjectDirectory().file("Package.swift")); // Defer attaching the model until all components have been (most likely) configured // TODO - make this relationship explicit to make this more reliable and offer better diagnostics project.afterEvaluate(new Action() { @Override public void execute(Project project) { Provider products = project.getProviders().provider(new MemoizingCallable(new PackageFactory(project))); manifestTask.getPackage().set(products); } }); } private static class MemoizingCallable implements Callable { private Package result; private Callable delegate; MemoizingCallable(Callable delegate) { this.delegate = delegate; } @Override public Package call() throws Exception { if (result == null) { result = delegate.call(); delegate = null; } return result; } } private class PackageFactory implements Callable { private final Project project; PackageFactory(Project project) { this.project = project; } @Override public Package call() { Set products = new LinkedHashSet(); List targets = new ArrayList(); List dependencies = new ArrayList(); SwiftVersion swiftLanguageVersion = null; for (Project p : project.getAllprojects()) { for (CppApplication application : p.getComponents().withType(CppApplication.class)) { DefaultTarget target = new DefaultTarget(application.getBaseName().get(), p.getProjectDir(), application.getCppSource()); collectDependencies(application.getImplementationDependencies(), dependencies, target); DefaultExecutableProduct product = new DefaultExecutableProduct(p.getName(), target); // TODO - set header dir for applications products.add(product); targets.add(target); } for (CppLibrary library : p.getComponents().withType(CppLibrary.class)) { DefaultTarget target = new DefaultTarget(library.getBaseName().get(), p.getProjectDir(), library.getCppSource()); collectDependencies(library.getImplementationDependencies(), dependencies, target); Set headerDirs = library.getPublicHeaderDirs().getFiles(); if (!headerDirs.isEmpty()) { // TODO - deal with more than one directory target.setPublicHeaderDir(headerDirs.iterator().next()); } targets.add(target); if (library.getLinkage().get().contains(Linkage.SHARED)) { products.add(new DefaultLibraryProduct(p.getName(), target, Linkage.SHARED)); } if (library.getLinkage().get().contains(Linkage.STATIC)) { products.add(new DefaultLibraryProduct(p.getName() + "Static", target, Linkage.STATIC)); } } for (SwiftApplication application : p.getComponents().withType(SwiftApplication.class)) { DefaultTarget target = new DefaultTarget(application.getModule().get(), p.getProjectDir(), application.getSwiftSource()); swiftLanguageVersion = max(swiftLanguageVersion, application.getSourceCompatibility().getOrNull()); collectDependencies(application.getImplementationDependencies(), dependencies, target); DefaultExecutableProduct product = new DefaultExecutableProduct(p.getName(), target); products.add(product); targets.add(target); } for (SwiftLibrary library : p.getComponents().withType(SwiftLibrary.class)) { DefaultTarget target = new DefaultTarget(library.getModule().get(), p.getProjectDir(), library.getSwiftSource()); swiftLanguageVersion = max(swiftLanguageVersion, library.getSourceCompatibility().getOrNull()); collectDependencies(library.getImplementationDependencies(), dependencies, target); targets.add(target); if (library.getLinkage().get().contains(Linkage.SHARED)) { products.add(new DefaultLibraryProduct(p.getName(), target, Linkage.SHARED)); } if (library.getLinkage().get().contains(Linkage.STATIC)) { products.add(new DefaultLibraryProduct(p.getName() + "Static", target, Linkage.STATIC)); } } } return new DefaultPackage(products, targets, dependencies, swiftLanguageVersion); } private SwiftVersion max(SwiftVersion v1, SwiftVersion v2) { if (v1 == null) { return v2; } if (v2 == null) { return v1; } if (v1.compareTo(v2) > 0) { return v1; } return v2; } private void collectDependencies(Configuration configuration, Collection dependencies, DefaultTarget target) { for (org.gradle.api.artifacts.Dependency dependency : configuration.getAllDependencies()) { if (dependency instanceof ProjectDependency) { ProjectDependency projectDependency = (ProjectDependency) dependency; SwiftPmTarget identifier = publicationResolver.resolve(SwiftPmTarget.class, projectDependency); target.getRequiredTargets().add(identifier.getTargetName()); } else if (dependency instanceof ExternalModuleDependency) { ExternalModuleDependency externalDependency = (ExternalModuleDependency) dependency; ModuleComponentSelector depSelector = DefaultModuleComponentSelector.newSelector(externalDependency); VersionControlSpec vcsSpec = vcsResolver.locateVcsFor(depSelector); if (vcsSpec == null || !(vcsSpec instanceof GitVersionControlSpec)) { throw new InvalidUserDataException(String.format("Cannot determine the Git URL for dependency on %s:%s.", dependency.getGroup(), dependency.getName())); } GitVersionControlSpec gitSpec = (GitVersionControlSpec) vcsSpec; dependencies.add(toSwiftPmDependency(externalDependency, gitSpec)); target.getRequiredProducts().add(externalDependency.getName()); } else { throw new InvalidUserDataException(String.format("Cannot map a dependency of type %s (%s)", dependency.getClass().getSimpleName(), dependency)); } } } private Dependency toSwiftPmDependency(ExternalModuleDependency externalDependency, GitVersionControlSpec gitSpec) { if (externalDependency.getVersionConstraint().getBranch() != null) { if (externalDependency.getVersion() != null) { throw new InvalidUserDataException(String.format("Cannot map a dependency on %s:%s that defines both a branch (%s) and a version constraint (%s).", externalDependency.getGroup(), externalDependency.getName(), externalDependency.getVersionConstraint().getBranch(), externalDependency.getVersion())); } return new BranchDependency(gitSpec.getUrl(), externalDependency.getVersionConstraint().getBranch()); } String versionSelectorString = externalDependency.getVersion(); VersionSelector versionSelector = versionSelectorScheme.parseSelector(versionSelectorString); if (versionSelector instanceof LatestVersionSelector) { LatestVersionSelector latestVersionSelector = (LatestVersionSelector) versionSelector; if (latestVersionSelector.getSelectorStatus().equals("integration")) { return new BranchDependency(gitSpec.getUrl(), "master"); } } else if (versionSelector instanceof ExactVersionSelector) { return new VersionDependency(gitSpec.getUrl(), versionSelector.getSelector()); } else if (versionSelector instanceof VersionRangeSelector) { VersionRangeSelector versionRangeSelector = (VersionRangeSelector) versionSelector; if (versionRangeSelector.isLowerInclusive()) { return new VersionDependency(gitSpec.getUrl(), versionRangeSelector.getLowerBound(), versionRangeSelector.getUpperBound(), versionRangeSelector.isUpperInclusive()); } } else if (versionSelector instanceof SubVersionSelector) { SubVersionSelector subVersionSelector = (SubVersionSelector) versionSelector; String prefix = subVersionSelector.getPrefix(); // TODO - take care of this in the selector parser if (prefix.endsWith(".")) { String versionString = prefix.substring(0, prefix.length() - 1); Version version = versionParser.transform(versionString); if (version.getNumericParts().length == 1) { Long part1 = version.getNumericParts()[0]; return new VersionDependency(gitSpec.getUrl(), part1 + ".0.0"); } if (version.getNumericParts().length == 2) { Long part1 = version.getNumericParts()[0]; Long part2 = version.getNumericParts()[1]; return new VersionDependency(gitSpec.getUrl(), part1 + "." + part2 + ".0", part1 + "." + (part2 + 1) + ".0", false); } } } throw new InvalidUserDataException(String.format("Cannot map a dependency on %s:%s with version constraint (%s).", externalDependency.getGroup(), externalDependency.getName(), externalDependency.getVersion())); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy