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

com.sap.psr.vulas.python.pip.PipInstalledPackage Maven / Gradle / Ivy

There is a newer version: 3.1.15
Show newest version
/**
 * This file is part of Eclipse Steady.
 *
 * 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.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
 */
package com.sap.psr.vulas.python.pip;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sap.psr.vulas.Construct;
import com.sap.psr.vulas.ConstructId;
import com.sap.psr.vulas.DirAnalyzer;
import com.sap.psr.vulas.FileAnalysisException;
import com.sap.psr.vulas.FileAnalyzer;
import com.sap.psr.vulas.FileAnalyzerFactory;
import com.sap.psr.vulas.python.PythonArchiveAnalyzer;
import com.sap.psr.vulas.shared.enums.DigestAlgorithm;
import com.sap.psr.vulas.shared.enums.PropertySource;
import com.sap.psr.vulas.shared.json.model.Library;
import com.sap.psr.vulas.shared.json.model.LibraryId;
import com.sap.psr.vulas.shared.json.model.Property;
import com.sap.psr.vulas.shared.util.DirUtil;
import com.sap.psr.vulas.shared.util.DirnamePatternSearch;
import com.sap.psr.vulas.shared.util.FileUtil;
import com.sap.psr.vulas.shared.util.FilenamePatternSearch;
import com.sap.psr.vulas.shared.util.StringList;

/**
 * 

PipInstalledPackage class.

* */ public class PipInstalledPackage implements Comparable { private final static Log log = LogFactory.getLog(PipInstalledPackage.class); private static final String LOCATION = "Location"; private static final String REQUIRES = "Requires"; private String name = null; private String version = null; private Map properties = new HashMap(); private String digest = null; private Map constructs = null; private String downloadUrl = null; private Path downloadPath = null; private Path eggFile = null; private Path pyFile = null; private Path pyDir = null; private FileAnalyzer fileAnalyzer = null; /** *

Constructor for PipInstalledPackage.

* * @param _name a {@link java.lang.String} object. * @param _version a {@link java.lang.String} object. */ public PipInstalledPackage(String _name, String _version) { this.name = _name; this.version = _version; } /** *

Getter for the field properties.

* * @return a {@link java.util.Map} object. */ public Map getProperties() { return properties; } /** * Returns the installation path of the Python package. * * @return a {@link java.nio.file.Path} object. */ public Path getInstallPath() { return Paths.get(this.properties.get(LOCATION)); } /** *

Getter for the field downloadUrl.

* * @return a {@link java.lang.String} object. */ public String getDownloadUrl() { return downloadUrl; } /** *

Setter for the field downloadUrl.

* * @param downloadUrl a {@link java.lang.String} object. */ public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; } /** * Returns the download path of the Python package. This path is extracted from the output of "pip install". * * @return a {@link java.nio.file.Path} object. */ public Path getDownloadPath() { return downloadPath; } /** *

Setter for the field downloadPath.

* * @param downloadPath a {@link java.nio.file.Path} object. */ public void setDownloadPath(Path downloadPath) { this.downloadPath = downloadPath; } /** * Returns a {@link Library} representing the analyzed archive. * * @throws com.sap.psr.vulas.FileAnalysisException * @return a {@link com.sap.psr.vulas.shared.json.model.Library} object. */ public Library getLibrary() throws FileAnalysisException { Library lib = null; if(this.fileAnalyzer!=null && this.fileAnalyzer instanceof PythonArchiveAnalyzer) { lib = ((PythonArchiveAnalyzer)this.fileAnalyzer).getLibrary(); lib.setLibraryId(new LibraryId(this.getName(), this.getName(), this.getVersion())); } else { lib = new Library(); lib.setDigest(this.getDigest()); lib.setDigestAlgorithm(DigestAlgorithm.MD5); lib.setLibraryId(new LibraryId(this.getName(), this.getName(), this.getVersion())); if(this.getConstructs()!=null) lib.setConstructs(ConstructId.getSharedType(this.getConstructs().keySet())); } final Set p = new HashSet(); for(String key: this.getProperties().keySet()) { p.add(new Property(PropertySource.PIP, key, this.getProperties().get(key))); } lib.setProperties(p); return lib; } /** * Returns true if this package requieres the given package, as indicated by the 'Requires' property, false otherwise. * * @param _pack a {@link com.sap.psr.vulas.python.pip.PipInstalledPackage} object. * @return a boolean. * @throws java.lang.IllegalStateException if any. */ public boolean requires(PipInstalledPackage _pack) throws IllegalStateException { if(this.properties==null || !this.properties.containsKey(REQUIRES)) throw new IllegalStateException("Property [" + REQUIRES + "] not known"); final String[] packs = this.properties.get(REQUIRES).split(","); for(int i=0; i properties) { this.properties.putAll(properties); } /** *

Getter for the field name.

* * @return a {@link java.lang.String} object. */ public String getName() { return name; } /** *

Getter for the field version.

* * @return a {@link java.lang.String} object. */ public String getVersion() { return version; } /** {@inheritDoc} */ @Override public String toString() { final StringBuffer b = new StringBuffer(); b.append("[").append(this.getName()).append(":").append(this.getVersion()).append("]"); return b.toString(); } /** *

Getter for the field digest.

* * @return a {@link java.lang.String} object. */ public String getDigest() { if(this.downloadPath==null && (this.properties==null || !this.properties.containsKey(LOCATION))) throw new IllegalStateException(this + " does not have local download path nor property [" + LOCATION + "]"); if(this.digest==null) { // Take the downloaded file if(this.downloadPath!=null) { this.digest = FileUtil.getDigest(this.downloadPath.toFile(), DigestAlgorithm.MD5); log.info("Computed MD5 [" + this.digest + "] from downloaded file [" + this.downloadPath + "]"); } // Search in site-packages (location property) else { this.eggFile = this.searchEgg(); this.pyFile = this.searchPyFile(); this.pyDir = this.searchPyDir(); if(this.eggFile!=null) { this.digest = FileUtil.getDigest(this.eggFile.toFile(), DigestAlgorithm.MD5); log.info("Computed MD5 [" + this.digest + "] from egg file [" + this.eggFile + "]"); } else if(this.pyFile!=null) { this.digest = FileUtil.getDigest(this.pyFile.toFile(), DigestAlgorithm.MD5); log.info("Computed MD5 [" + this.digest + "] from file [" + this.pyFile + "]"); } else if(this.pyDir!=null) { this.digest = DirUtil.getDigest(this.pyDir.toFile(), new String[] {".pyc"}, DigestAlgorithm.MD5); log.info("Computed MD5 [" + this.digest + "] from directory [" + this.pyDir + "]"); } else { log.error("Cannot compute MD5 of " + this); } } } return this.digest; } /** * * @return * @throws FileAnalysisException */ private Map getConstructs() throws FileAnalysisException { if(this.fileAnalyzer==null) { // Get from archive if(this.downloadPath!=null) { this.fileAnalyzer = FileAnalyzerFactory.buildFileAnalyzer(this.downloadPath.toFile()); if(this.fileAnalyzer!=null) { this.constructs = this.fileAnalyzer.getConstructs(); log.info("Got [" + this.constructs.size() + "] constructs from downloaded file [" + this.downloadPath + "]"); } } // Get from file else { if(this.eggFile!=null) { this.fileAnalyzer = FileAnalyzerFactory.buildFileAnalyzer(this.eggFile.toFile()); this.constructs = this.fileAnalyzer.getConstructs(); log.info("Got [" + this.constructs.size() + "] constructs from egg [" + this.eggFile + "]"); } // Get from file else if(this.pyFile!=null) { this.fileAnalyzer = FileAnalyzerFactory.buildFileAnalyzer(this.pyFile.toFile()); this.constructs = this.fileAnalyzer.getConstructs(); log.info("Got [" + this.constructs.size() + "] constructs from file [" + this.pyFile + "]"); } // Get from dir else if(this.pyDir!=null) { this.fileAnalyzer = FileAnalyzerFactory.buildFileAnalyzer(this.pyDir.toFile()); this.constructs = this.fileAnalyzer.getConstructs(); log.info("Got [" + this.constructs.size() + "] constructs from directory [" + this.pyDir + "]"); } // Error else { log.error("Cannot get constructs of " + this); } } } return this.constructs; } /** *

getNestedArchives.

* * @return a {@link java.util.Set} object. */ public Set getNestedArchives() { if(this.fileAnalyzer!=null && !(this.fileAnalyzer instanceof DirAnalyzer)) { return this.fileAnalyzer.getChilds(true); } else { return null; } } /** {@inheritDoc} */ public int compareTo(Object _other) { if(_other instanceof PipInstalledPackage) { final PipInstalledPackage other = (PipInstalledPackage)_other; int i = this.name.compareTo(other.getName()); if(i==0) i = this.version.compareTo(other.getVersion()); return i; } else { throw new IllegalArgumentException("Cannot compare with object of type [" + _other.getClass() + "]"); } } /** * Searches for an egg file in the location of this installed package. * @return */ private Path searchEgg() { Path file = null; final String name = this.getName().replaceAll("-", "_"); final Path location = Paths.get(this.properties.get(LOCATION)); FilenamePatternSearch fns = new FilenamePatternSearch("^" + name + "-" + this.version + "-.*egg$"); Set files = fns.search(location, 0); if(files.size()==0) { log.info("No egg file found for " + this + " in path [" + location + "]"); } else if(files.size()==1) { file = files.iterator().next(); log.info("Egg file [" + file + "] found for " + this + " in path [" + location + "]"); } else { log.info(files.size() + " egg files found for " + this + " in path [" + location + "]"); } return file; } /** * Searches for an egg file in the location of this installed package. * @return */ private Path searchPyFile() { Path file = null; final String name = this.getName().replaceAll("-", "_"); final Path location = Paths.get(this.properties.get(LOCATION)); FilenamePatternSearch fns = new FilenamePatternSearch("^" + name + ".py$"); Set files = fns.search(location, 0); if(files.size()==0) { log.info("No python file found for " + this + " in path [" + location + "]"); } else if(files.size()==1) { file = files.iterator().next(); log.info("Python file [" + file + "] found for " + this + " in path [" + location + "]"); } else { log.info(files.size() + " python files found for " + this + " in path [" + location + "]"); } return file; } /** * Searches for an egg directory in the location of this installed package. * @return */ private Path searchPyDir() { // Search for .py Path file = Paths.get(Paths.get(this.properties.get(LOCATION)).toString()); if(FileUtil.isAccessibleDirectory(file) && !file.toString().endsWith("site-packages")) return file; // Search for --py3.6.egg final String name = this.getName().replaceAll("-", "_"); final Path location = Paths.get(this.properties.get(LOCATION)); DirnamePatternSearch dns = new DirnamePatternSearch("^" + name + "-" + this.version + "-.*egg$"); Set files = dns.search(location, 0); if(files.size()==0) { log.info("No python dir found for " + this + " in path [" + location + "]"); file = null; } else if(files.size()==1) { log.info("Python dir [" + file + "] found for " + this + " in path [" + location + "]"); file = files.iterator().next(); } else { log.info(files.size() + " python dirs found for " + this + " in path [" + location + "]"); file = null; } return file; } /** * Filter the given packages according to whether the artifact name is (or is not, depending on the boolean flag) contained in the given filter. * * @param _packages a {@link java.util.Set} object. * @param _filter a {@link com.sap.psr.vulas.shared.util.StringList} object. * @param _include a boolean. * @return a {@link java.util.Set} object. */ public static Set filterUsingArtifact(Set _packages, StringList _filter, boolean _include) { final Set r = new HashSet(); for(PipInstalledPackage p: _packages) { try { if(_include) { if(_filter.contains(p.getLibrary().getLibraryId().getArtifact())) r.add(p); } else { if(!_filter.contains(p.getLibrary().getLibraryId().getArtifact())) r.add(p); } } catch (FileAnalysisException e) { log.error("Error getting library ID of package [" + p + "]: " + e.getMessage(), e); } } return r; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PipInstalledPackage other = (PipInstalledPackage) obj; if (name == null) { if (other.name != null) return false; } else if (!this.getStandardDistributionName().equals(other.getStandardDistributionName())) return false; if (version == null) { if (other.version != null) return false; } else if (!version.equals(other.version)) return false; return true; } /** * https://stackoverflow.com/questions/19097057/pip-e-no-magic-underscore-to-dash-replacement * https://www.python.org/dev/peps/pep-0008/#package-and-module-names * * @return a {@link java.lang.String} object. */ public String getStandardDistributionName() { return PipInstalledPackage.getStandardDistributionName(this.getName()); } /** *

getStandardDistributionName.

* * @param _name a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public static String getStandardDistributionName(String _name) { return _name.toLowerCase().replaceAll("\\p{Punct}", "_"); } /** * Returns true if the standard distribution name of this package is equal to the one of the given package. * * @param _other a {@link com.sap.psr.vulas.python.pip.PipInstalledPackage} object. * @see PipInstalledPackage#getStandardDistributionName() * @return a boolean. */ public boolean equalsStandardDistributionName(PipInstalledPackage _other) { return this.getStandardDistributionName().equals(_other.getStandardDistributionName()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy