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

org.whitesource.fs.FileSystemAgent Maven / Gradle / Ivy

Go to download

File System Agent is a simple java command line tool which extracts descriptive information from your open source libraries

There is a newer version: 18.9.1.1
Show newest version
/**
 * Copyright (C) 2014 WhiteSource Ltd.
 * 

* 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.whitesource.fs; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.whitesource.agent.*; import org.whitesource.agent.api.model.AgentProjectInfo; import org.whitesource.agent.api.model.Coordinates; import org.whitesource.agent.dependency.resolver.ViaMultiModuleAnalyzer; import org.whitesource.agent.dependency.resolver.docker.DockerResolver; import org.whitesource.agent.dependency.resolver.gradle.GradleDependencyResolver; import org.whitesource.agent.dependency.resolver.maven.MavenDependencyResolver; import org.whitesource.agent.dependency.resolver.npm.NpmLsJsonDependencyCollector; import org.whitesource.agent.dependency.resolver.packageManger.PackageManagerExtractor; import org.whitesource.agent.utils.CommandLineProcess; import org.whitesource.agent.utils.FilesUtils; import org.whitesource.agent.utils.LoggerFactory; import org.whitesource.agent.utils.Pair; import org.whitesource.fs.configuration.ScmConfiguration; import org.whitesource.fs.configuration.ScmRepositoriesParser; import org.whitesource.scm.ScmConnector; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; /** * File System Agent. * * @author Itai Marko * @author tom.shapira * @author anna.rozin */ public class FileSystemAgent { /* --- Static members --- */ private Logger logger = LoggerFactory.getLogger(FileSystemAgent.class); private static final String NPM_COMMAND = NpmLsJsonDependencyCollector.isWindows() ? "npm.cmd" : "npm"; private static final String PACKAGE_LOCK = "package-lock.json"; private static final String PACKAGE_JSON = "package.json"; /* --- Members --- */ private List dependencyDirs; private final FSAConfiguration config; private boolean projectPerSubFolder; /* --- Constructors --- */ public FileSystemAgent(FSAConfiguration config, List dependencyDirs) { this.config = config; projectPerSubFolder = config.getRequest().isProjectPerSubFolder(); if (projectPerSubFolder) { this.dependencyDirs = new LinkedList<>(); for (String directory : dependencyDirs) { File file = new File(directory); if (file.isDirectory()) { List directories = new FilesUtils().getSubDirectories(directory, config.getAgent().getProjectPerFolderIncludes(), config.getAgent().getProjectPerFolderExcludes(), config.getAgent().isFollowSymlinks(), config.getAgent().getGlobCaseSensitive()); directories.forEach(subDir -> this.dependencyDirs.add(subDir.toString())); //In case no sub-folders were found, put the top folder path as the dependencyDirs. if (CollectionUtils.isEmpty(directories)) { this.dependencyDirs = dependencyDirs; } } else if (file.isFile()) { this.dependencyDirs.add(directory); } else { logger.warn("{} is not a file nor a directory .", directory); } } } else { this.dependencyDirs = dependencyDirs; } } /* --- Overridden methods --- */ public ProjectsDetails createProjects() { ProjectsDetails projects = new ProjectsDetails(new ArrayList<>(), StatusCode.SUCCESS, Constants.EMPTY_STRING); // Use FSA a as a package manger extractor for Debian/RPM/Arch Linux/Alpine // Check if scanPackageManager==true - This is the first priority and overrides other scans if (config.isScanProjectManager()) { Collection tempProjects = new PackageManagerExtractor().createProjects(); ProjectsDetails projectsDetails = new ProjectsDetails(tempProjects, StatusCode.SUCCESS, Constants.EMPTY_STRING); String projectName = config.getRequest().getProjectName(); addSingleProjectToProjects(projectsDetails, projectName, projects); return projects; } // Check if docker.scanImages==true - This scans Docker Images, and should not scan any folders, so we exit // after the scan is done if (config.isScanDockerImages()) { Collection tempDockerProjects = new DockerResolver(config).resolveDockerImages(); return new ProjectsDetails(tempDockerProjects, StatusCode.SUCCESS, Constants.EMPTY_STRING); } if (config.isSetUpMuiltiModuleFile()) { ViaMultiModuleAnalyzer viaMultiModuleAnalyzer = new ViaMultiModuleAnalyzer(config.getDependencyDirs().get(0), new MavenDependencyResolver(false, new String[]{Constants.NONE}, false, false, false, false), Constants.TARGET, config.getAnalyzeMultiModule()); if (viaMultiModuleAnalyzer.getBomFiles().isEmpty()) { viaMultiModuleAnalyzer = new ViaMultiModuleAnalyzer(config.getDependencyDirs().get(0), new GradleDependencyResolver(false, false, false, Constants.EMPTY_STRING, new String[]{Constants.NONE}, Constants.EMPTY_STRING, false), Constants.BUILD + File.separator + Constants.LIBS, config.getAnalyzeMultiModule()); } if (!viaMultiModuleAnalyzer.getBomFiles().isEmpty()) { viaMultiModuleAnalyzer.writeFile(); } else { logger.error("Multi-module analysis could not establish the appPath based on the specified path. Please review the specified -d path."); Main.exit(StatusCode.ERROR.getValue()); } logger.info("The multi-module analysis setup file was created successfully."); Main.exit(StatusCode.SUCCESS.getValue()); } // Scan folders and create a project per folder if (projectPerSubFolder) { if (this.config.getSender().isEnableImpactAnalysis()) { logger.warn("Could not executing VIA impact analysis with the 'projectPerFolder' flag"); return projects; } Map> appPathsToDependencyDirs = new HashMap<>(); Set setDirs = new HashSet<>(1); for (String directory : dependencyDirs) { setDirs.add(directory); appPathsToDependencyDirs.put(FSAConfiguration.DEFAULT_KEY, setDirs); ProjectsDetails projectsDetails = getProjects(Collections.singletonList(directory), appPathsToDependencyDirs); String projectName = new File(directory).getName(); addSingleProjectToProjects(projectsDetails, projectName, projects); // return on the first project that fails if (!projectsDetails.getStatusCode().equals(StatusCode.SUCCESS)) { // return status code if there is a failure return new ProjectsDetails(new ArrayList<>(), projects.getStatusCode(), projects.getDetails()); } appPathsToDependencyDirs.clear(); setDirs.clear(); } if (CollectionUtils.isEmpty(projects.getProjects())) { logger.warn("projectPerFolder = true, No sub-folders were found in project folder, scanning main project folder"); projectPerSubFolder = false; } else { return projects; } } // Scan folders and create one project for all folders together if (!projectPerSubFolder) { // This 'if' is always true now, but keep it maybe we will do other checks in the future... projects = getProjects(dependencyDirs, config.getAppPathsToDependencyDirs()); if (!projects.getProjects().isEmpty()) { AgentProjectInfo projectInfo = projects.getProjects().stream().findFirst().get(); if (projectInfo.getCoordinates() == null) { // use token or name + version String projectToken = config.getRequest().getProjectToken(); if (StringUtils.isNotBlank(projectToken)) { projectInfo.setProjectToken(projectToken); } else { String projectName = config.getRequest().getProjectName(); String projectVersion = config.getRequest().getProjectVersion(); projectInfo.setCoordinates(new Coordinates(null, projectName, projectVersion)); } } } return projects; } // todo: check for duplicates projects return projects; } /* --- Private methods --- */ private void addSingleProjectToProjects(ProjectsDetails projectsDetails, String projectName, ProjectsDetails projects) { if (projectsDetails == null || projects == null || projectName == null) { logger.debug("projectsDetails {} , projects {} , projectName {}", projectsDetails, projectName, projects); return; } if (projectsDetails.getProjects().size() == 1) { String projectVersion = config.getRequest().getProjectVersion(); AgentProjectInfo projectInfo = projectsDetails.getProjects().stream().findFirst().get(); projectInfo.setCoordinates(new Coordinates(null, projectName, projectVersion)); LinkedList viaComponents = projectsDetails.getProjectToViaComponents().get(projectInfo); projects.getProjectToViaComponents().put(projectInfo, viaComponents); } else { for (AgentProjectInfo projectInfo : projectsDetails.getProjects()) { logger.debug("Project not added - {}", projectInfo); } } } private ProjectsDetails getProjects(List scannerBaseDirs, Map> appPathsToDependencyDirs) { // create getScm connector final StatusCode[] success = new StatusCode[]{StatusCode.SUCCESS}; String separatorFiles = NpmLsJsonDependencyCollector.isWindows() ? "\\" : "/"; Collection scmPaths = new ArrayList<>(); final boolean[] hasScmConnectors = new boolean[1]; List scmConnectors = null; if (StringUtils.isNotBlank(config.getScm().getRepositoriesPath())) { Collection scmConfigurations = new ScmRepositoriesParser().parseRepositoriesFile( config.getScm().getRepositoriesPath(), config.getScm().getType(), config.getScm().getPpk(), config.getScm().getUser(), config.getScm().getPass()); scmConnectors = scmConfigurations.stream() .map(scm -> ScmConnector.create(scm.getType(), scm.getUrl(), scm.getPpk(), scm.getUser(), scm.getPass(), scm.getBranch(), scm.getTag())) .collect(Collectors.toList()); } else { scmConnectors = Arrays.asList(ScmConnector.create( config.getScm().getType(), config.getScm().getUrl(), config.getScm().getPpk(), config.getScm().getUser(), config.getScm().getPass(), config.getScm().getBranch(), config.getScm().getTag())); } if (scmConnectors != null && scmConnectors.stream().anyMatch(scm -> scm != null)) { //scannerBaseDirs.clear(); scmConnectors.stream().forEach(scmConnector -> { if (scmConnector != null) { logger.info("Connecting to SCM"); String scmPath = scmConnector.cloneRepository().getPath(); Pair result = npmInstallScmRepository(config.getScm().isNpmInstall(), config.getScm().getNpmInstallTimeoutMinutes(), scmConnector, separatorFiles, scmPath); scmPath = result.getKey(); success[0] = result.getValue(); scmPaths.add(scmPath); scannerBaseDirs.add(scmPath); if (!appPathsToDependencyDirs.containsKey(FSAConfiguration.DEFAULT_KEY)) { appPathsToDependencyDirs.put(FSAConfiguration.DEFAULT_KEY, new HashSet<>()); } appPathsToDependencyDirs.get(FSAConfiguration.DEFAULT_KEY).add(scmPath); hasScmConnectors[0] = true; } }); } if (StringUtils.isNotBlank(config.getAgent().getError())) { logger.error(config.getAgent().getError()); if (scmConnectors != null) { scmConnectors.forEach(scmConnector -> scmConnector.deleteCloneDirectory()); } return new ProjectsDetails(new ArrayList<>(), StatusCode.ERROR, config.getAgent().getError()); // TODO this is within a try frame. Throw an exception instead } Map> projectToAppPathAndLanguage; ViaLanguage viaLanguage = getIaLanguage(config.getRequest().getIaLanguage()); ProjectConfiguration projectConfiguration = new ProjectConfiguration(config.getAgent(), scannerBaseDirs, appPathsToDependencyDirs, false); projectToAppPathAndLanguage = new FileSystemScanner(config.getResolver(), config.getAgent() , config.getSender().isEnableImpactAnalysis(), viaLanguage) .createProjects(projectConfiguration); ProjectsDetails projectsDetails = new ProjectsDetails(projectToAppPathAndLanguage, success[0], Constants.EMPTY_STRING); // delete all temp scm files scmPaths.forEach(directory -> { if (directory != null) { try { FileUtils.forceDelete(new File(directory)); } catch (IOException e) { // do nothing } } }); return projectsDetails; } private ViaLanguage getIaLanguage(String iaLanguage) { ViaLanguage[] values = ViaLanguage.values(); if (iaLanguage != null) { for (ViaLanguage value : values) { if (value.toString().toLowerCase().equals(iaLanguage.toLowerCase())) { return value; } } } return null; } private Pair npmInstallScmRepository(boolean scmNpmInstall, int npmInstallTimeoutMinutes, ScmConnector scmConnector, String separatorFiles, String pathToCloneRepoFiles) { StatusCode success = StatusCode.SUCCESS; File packageJson = new File(pathToCloneRepoFiles + separatorFiles + PACKAGE_JSON); boolean npmInstallFailed = false; if (scmNpmInstall && packageJson.exists()) { // execute 'npm install' File packageLock = new File(pathToCloneRepoFiles + separatorFiles + PACKAGE_LOCK); if (packageLock.exists()) { packageLock.delete(); } CommandLineProcess npmInstall = new CommandLineProcess(pathToCloneRepoFiles, new String[]{NPM_COMMAND, Constants.INSTALL}); logger.info("Found package.json file, executing 'npm install' on {}", scmConnector.getUrl()); try { npmInstall.executeProcessWithoutOutput(); npmInstall.setTimeoutProcessMinutes(npmInstallTimeoutMinutes); if (npmInstall.isErrorInProcess()) { npmInstallFailed = true; logger.error("Failed to run 'npm install' on {}", scmConnector.getUrl()); } } catch (IOException e) { npmInstallFailed = true; logger.error("Failed to start 'npm install', Please make sure 'npm' is installed. {}", e.getMessage()); logger.debug("Failed to run 'npm install' command ", e); } if (npmInstallFailed) { // In case of error in 'npm install', delete and clone the repository to prevent wrong output success = StatusCode.PRE_STEP_FAILURE; scmConnector.deleteCloneDirectory(); pathToCloneRepoFiles = scmConnector.cloneRepository().getPath(); } } return new Pair<>(pathToCloneRepoFiles, success); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy