org.xwiki.contrib.repository.pypi.internal.dto.wheelMetadata.RequiredDistributions.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.contrib.repository.pypi.internal.dto.wheelMetadata.RequiredDistributions.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.contrib.repository.pypi.internal.dto.wheelMetadata;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.http.HttpException;
import org.xwiki.contrib.repository.pypi.internal.PypiExtensionRepository;
import org.xwiki.contrib.repository.pypi.internal.PypiParameters;
import org.xwiki.contrib.repository.pypi.internal.dto.pypiJsonApi.PypiPackageJSONDto;
import org.xwiki.contrib.repository.pypi.internal.dto.pypiJsonApi.PypiPackageUrlDto;
import org.xwiki.contrib.repository.pypi.internal.utils.PypiUtils;
import org.xwiki.extension.DefaultExtensionDependency;
import org.xwiki.extension.ExtensionDependency;
import org.xwiki.extension.ResolveException;
import org.xwiki.extension.version.InvalidVersionRangeException;
import org.xwiki.extension.version.VersionConstraint;
import org.xwiki.extension.version.internal.DefaultVersion;
import org.xwiki.extension.version.internal.DefaultVersionConstraint;
import org.xwiki.extension.version.internal.DefaultVersionRangeCollection;

/**
 * @version $Id: 81a55f3a16b33bcf2696d0cac493b25c946b6ee4 $
 * @since 1.0
 */
public class RequiredDistributions {
    private static Pattern requiredDist = Pattern.compile("^Requires-Dist: .*");

    private static Pattern requiredDistVersion = Pattern.compile("^(Requires-Dist: )(\\S+)( )(\\(.*\\))(.*)");

    private static Pattern requiredDistExtra = Pattern.compile("^Requires-Dist: .*extra ==.*");

    private static Pattern requiredDistNoVersion = Pattern.compile("^(Requires-Dist: )([^\\s;]+)(.*)");

    private LinkedList<ExtensionDependency> dependencies;

    public RequiredDistributions(LinkedList<ExtensionDependency> dependencies) {
        this.dependencies = dependencies;
    }

    public LinkedList<ExtensionDependency> getDependencies() {
        return dependencies;
    }

    public void setDependencies(LinkedList<ExtensionDependency> dependencies) {
        this.dependencies = dependencies;
    }

    public static RequiredDistributions resolveDependenciesFromFile(InputStream is,
            PypiExtensionRepository pypiExtensionRepository) throws ResolveException {

        LinkedList<ExtensionDependency> dependencies = new LinkedList<>();

        try (BufferedReader buffer = new BufferedReader(new InputStreamReader(is))) {
            List<String> lines = buffer.lines().collect(Collectors.toList());
            for (String line : lines) {
                if (requiredDist.matcher(line).matches()) {
                    String packageName;
                    VersionConstraint versionConstraint;

                    if (requiredDistExtra.matcher(line).matches()) {
                        continue; // those dependencies are optional
                    }
                    if (requiredDistVersion.matcher(line).matches()) {
                        Matcher matcher = requiredDistVersion.matcher(line);
                        matcher.find();
                        packageName = matcher.group(2);
                        String versionPart = matcher.group(4);
                        versionConstraint = getVersionOfDependency(versionPart);
                    } else if (requiredDistNoVersion.matcher(line).matches()) {
                        Matcher matcher = requiredDistNoVersion.matcher(line);
                        matcher.find();
                        packageName = matcher.group(2);
                        //find newest version of that package
                        versionConstraint = getNewestVersionConstraint(packageName, pypiExtensionRepository);
                    } else {
                        continue;
                    }
                    dependencies.add(new DefaultExtensionDependency(
                            PypiParameters.DEFAULT_GROUPID + ":" + packageName, versionConstraint));
                }
            }
        } catch (IOException e) {
            throw new ResolveException("Could not open downloaded package to read dependencies");
        }
        return new RequiredDistributions(dependencies);
    }

    private static VersionConstraint getNewestVersionConstraint(String packageName,
            PypiExtensionRepository pypiExtensionRepository) throws ResolveException {
        try {
            PypiPackageJSONDto pypiPackageData = pypiExtensionRepository.getPypiPackageData(packageName,
                    Optional.empty());
            String version = pypiPackageData.getInfo().getVersion();
            return new DefaultVersionConstraint(
                    Collections.singleton(new DefaultVersionRangeCollection("(," + version + "]")),
                    new DefaultVersion(version));
        } catch (HttpException e) {
            throw new ResolveException(
                    "Cannot obtain version of dependency for dependency package: " + packageName);
        } catch (InvalidVersionRangeException e) {
            //shouldNeverHappen
            throw new ResolveException("Problem with version range spec.", e);
        }
    }

    private static VersionConstraint getVersionOfDependency(String versionPart) throws ResolveException {
        String[] versionsIndications = versionPart.substring(1, versionPart.length() - 1).split(",");

        return Arrays.stream(versionsIndications).map(versionInd -> {
            try {
                if (versionInd.contains(">=")) {
                    String version = versionInd.replace(">=", "");
                    return new DefaultVersionConstraint(
                            Collections.singleton(new DefaultVersionRangeCollection("[" + version + ",)")),
                            new DefaultVersion(version));
                } else if (versionInd.contains("==")) {
                    String version = versionInd.replace("==", "");
                    return new DefaultVersionConstraint(
                            Collections.singleton(new DefaultVersionRangeCollection("(," + version + "]")),
                            new DefaultVersion(version));
                } else if (versionInd.contains("<=")) {
                    String version = versionInd.replace("<=", "");
                    return new DefaultVersionConstraint(
                            Collections.singleton(new DefaultVersionRangeCollection("(," + version + "]")),
                            new DefaultVersion(version));
                }
                return null;
            } catch (InvalidVersionRangeException e) {
                //shouldNeverHappen
                return null;
            }
        }).filter(Objects::nonNull).findFirst().orElse(null);
    }
}