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

org.spdx.tools.CompareSpdxDocs Maven / Gradle / Ivy

There is a newer version: 2.0.0-Alpha
Show newest version
/**
 * Copyright (c) 2013 Source Auditor Inc.
 * Copyright (c) 2013 Black Duck Software Inc.
 *
 *   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.spdx.tools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spdx.library.InvalidSPDXAnalysisException;
import org.spdx.library.model.SpdxDocument;
import org.spdx.spreadsheetstore.SpreadsheetException;
import org.spdx.tools.compare.MultiDocumentSpreadsheet;
import org.spdx.utility.compare.SpdxCompareException;
import org.spdx.utility.compare.SpdxComparer;

/**
 * Compares multiple SPDX documents and stores the results in a spreadsheet
 * Usage: CompareSpdxDoc output.xlsx doc1 doc2 doc3 ... docN
 * where output.xls is a file name for the output spreadsheet file
 * and docX are SPDX document files to compare or directories containing SPDX documents.  
 * Document files can be either in RDF/XML  or tag/value format
 *
 * @author Gary O'Neall
 *
 */
public class CompareSpdxDocs {
	static final int MIN_ARGS = 2;
	static final int MAX_ARGS = MultiDocumentSpreadsheet.MAX_DOCUMENTS + 1;
	static final int ERROR_STATUS = 1;
	static final Logger logger = LoggerFactory.getLogger(CompareSpdxDocs.class);


	/**
	 * @param args args[0] is the output Excel file name, all other args are SPDX document file names
	 */
	public static void main(String[] args) {
		if (args.length < MIN_ARGS) {
			System.out.println("Insufficient arguments");
			usage();
			System.exit(ERROR_STATUS);
		}
		if (args.length > MAX_ARGS) {
			System.out.println("Too many SPDX documents specified.  Must be less than "+String.valueOf(MAX_ARGS-1)+" document filenames");
			usage();
			System.exit(ERROR_STATUS);
		}
		try {
			onlineFunction(args);
		} catch (OnlineToolException e){
			System.out.println(e.getMessage());
			System.exit(ERROR_STATUS);
		}
	}

	/**
	 *
	 * @param args args[0] is the output Excel file name, all other args are SPDX document file names
	 * @throws OnlineToolException Exception caught by JPype and displayed to the user
	 */
	public static void onlineFunction(String[] args) throws OnlineToolException {
		// Arguments length( 14>=args length>=3 ) will checked in the Python Code
		File outputFile = new File(args[0]);
		// Output File name will be checked in the Python code for no clash, but if still found
		if (outputFile.exists()) {
			throw new OnlineToolException("Output file "+args[0]+" already exists. Change the name of the result file.");
		}
		List compareDocs = new ArrayList<>();
		List> verificationErrors = new ArrayList<>();
		List docNames = new ArrayList<>();
		for (int i = 1; i < args.length; i++) {
			try {
				addDocToComparer(compareDocs, args[i], docNames, verificationErrors);
			} catch (InvalidSPDXAnalysisException | IOException | InvalidFileNameException e) {
				throw new OnlineToolException("Error opening SPDX document "+args[i]+": "+e.getMessage());
			}
		}
		List normalizedDocNames = normalizeDocNames(docNames);
		MultiDocumentSpreadsheet outSheet = null;
		try {
			outSheet = new MultiDocumentSpreadsheet(outputFile, true, false);
			outSheet.importVerificationErrors(verificationErrors, normalizedDocNames);
			SpdxComparer comparer = new SpdxComparer();
			comparer.compare(compareDocs);
			outSheet.importCompareResults(comparer, normalizedDocNames);
		} catch (SpreadsheetException e) {
			throw new OnlineToolException("Unable to create output spreadsheet: "+e.getMessage());
		} catch (InvalidSPDXAnalysisException e) {
			throw new OnlineToolException("Invalid SPDX analysis: "+e.getMessage());
		} catch (SpdxCompareException e) {
			throw new OnlineToolException("Error comparing SPDX documents: "+e.getMessage());
		} finally {
			if (outSheet != null) {
				try {
					outSheet.close();
				} catch (SpreadsheetException e) {
					logger.warn("Warning - error closing spreadsheet: "+e.getMessage());
				}
			}
		}
	}
	
	

	/**
	 * Adds all SPDX documents found in the file or directory to the compareDocs list
	 * @param compareDocs
	 * @param filePath
	 * @param verificationErrors
	 * @throws InvalidFileNameException 
	 * @throws IOException 
	 * @throws InvalidSPDXAnalysisException 
	 */
	private static void addDocToComparer(List compareDocs,
			String filePath, List docNames, List> verificationErrors) throws InvalidSPDXAnalysisException, IOException, InvalidFileNameException {
		File spdxDocOrDir = new File(filePath);
		if (!spdxDocOrDir.exists()) {
			throw new FileNotFoundException("File "+filePath+" not found");
		}
		if (spdxDocOrDir.isFile()) {
			SpdxDocument doc = SpdxToolsHelper.deserializeDocument(spdxDocOrDir);
			for (SpdxDocument otherDocs:compareDocs) {
				if (otherDocs.getDocumentUri().equals(doc.getDocumentUri())) {
					// Duplicate document URI
					throw new InvalidSPDXAnalysisException("Duplicate document namespace "+doc.getDocumentUri()+".  Document namespaces must be unique per specification and for a valid comparison.");
				}
			}
			compareDocs.add(doc);
			List warnings = doc.verify();
			if (!warnings.isEmpty()) {
				System.out.println("Verification errors were found in "+filePath.trim()+".  See verification errors sheet for details.");
			}
			verificationErrors.add(warnings);
			docNames.add(filePath);
		} else if (spdxDocOrDir.isDirectory()) {
			for (File file:spdxDocOrDir.listFiles()) {
				try {
					addDocToComparer(compareDocs, file.getPath(), docNames, verificationErrors);
				} catch (InvalidSPDXAnalysisException | IOException | InvalidFileNameException e) {
					System.out.println("Error deserializing "+file+".  Skipping.");
					continue;
				}
			}
		}
	}

	/**
	 * Converts the URI's or file paths to a list of document names by
	 * removing the common string prefixes
     * @param uriFilePaths Un-normalized file paths or URIs
     * @return List of normalized doc names
     */
    private static List normalizeDocNames(List uriFilePaths) {
        List docNames = new ArrayList<>();
        if (uriFilePaths.size() < 1) {
        	return docNames;
        }
        int commonPrefixIndex = uriFilePaths.get(0).length();
        // first find the minimum index length
        for (int i = 1; i < uriFilePaths.size(); i++) {
            if (uriFilePaths.get(i).length() < commonPrefixIndex) {
                commonPrefixIndex = uriFilePaths.get(i).length();
            }
        }
        // look for the smallest common substring
        for (int i = 1; i < uriFilePaths.size(); i++) {
            for (int j = 0; j < commonPrefixIndex; j++) {
                if (uriFilePaths.get(i-1).charAt(j) != uriFilePaths.get(i).charAt(j)) {
                    commonPrefixIndex = j;
                    break;
                }
            }
        }
        // Back up looking for the first path separator
        for (int i = commonPrefixIndex; i >= 0; i--) {
        	if (uriFilePaths.get(0).charAt(i) == '/' || uriFilePaths.get(0).charAt(i) == '\\') {
        		commonPrefixIndex = i+1;
        		break;
        	}
        }
        for (String uriFilePath:uriFilePaths) {
            docNames.add(uriFilePath.substring(commonPrefixIndex).replace("\\", "/"));
        }
        return docNames;
    }

    /**
	 *
	 */
	private static void usage() {
		System.out.println("Usage: CompareMultipleSpdxDoc output.xls doc1 doc2 ... docN");
		System.out.println("where output.xls is a file name for the output spreadsheet file");
		System.out.println("and doc1 through docN are file names of valid SPDX documents ");
		System.out.println("in either tag/value or RDF/XML format");
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy