/*
* SPDXVersion: SPDX-1.1
* Creator: Person: Nuno Brito (nuno.brito@triplecheck.de)
* Creator: Organization: TripleCheck (contact@triplecheck.de)
* Created: 2013-12-11T00:00:00Z
* LicenseName: NOASSERTION
* FileName: show.java
* FileType: SOURCE
* FileCopyrightText: <text> Copyright 2013 Nuno Brito, TripleCheck </text>
* FileComment: <text> The class that shows details about a given SPDX document
available on our archive our shows all the available SPDX documents when no
specific document is mentioned.
* </text>
*/
package spdx;
import GUI.swingUtils;
import definitions.Messages;
import definitions.is;
import java.io.File;
import www.Table;
import java.util.ArrayList;
import main.Graphs;
import script.Plugin;
import spdxlib.tools;
import spdxlib.FileInfo;
import spdxlib.SPDXfile;
import main.core;
import main.param;
import script.log;
import utils.html;
import www.WebRequest;
/**
*
* @author Nuno Brito, 11th of December 2013 in Darmstadt, Germany.
* nuno.brito@triplecheck.de | http://nunobrito.eu
*/
public class show extends Plugin{
String showSPDX = "showSPDX";
@Override
public void startup(){
// add our node to the tree right after the "Tools" node is added
log.hooks.addAction(Messages.RefreshSPDX, thisFile, "refreshCache");
}
/**
* Cache our front page to speed up loading time when clicked by end user
*/
void refreshCache(){
log.write(is.ACCEPTED, "Re-doing our cache again");
}
/**
* Shows a summary of details about the selected package
* @param request
*/
@Override
public void main(WebRequest request) {
int
counterFiles = 0,
counterCreators = 0,
counterLicensesDeclared = 0
;
// get some statistical data
for(Object object : core.products){
SPDXfile spdx = (SPDXfile) object;
counterFiles += spdx.fileSection.files.size();
counterCreators += spdx.creatorSection.people.size();
counterLicensesDeclared += doStatistics(spdx);
}
// calculate percentage of files with a license declared
// String percentage =
// " ("
// + (counterLicensesDeclared * 100)/counterFiles
// + "% in total)" + html.br;
String summary =
"<h2>"
//+ html.getCommonFolderIcon("wooden-box-label.png")
+ "SPDX summary"
+ "</h2>"
+ html._div
+ html.div(20)
//+ html.getCommonFolderIcon("documents-stack.png")
+ core.products.size() + " documents"
+ html.br
//+ " containing "
//+ html.getCommonFolderIcon("calculator.png")
+ counterLicensesDeclared + " files with declared licenses"
+ html.br
+ counterFiles + " files in total"
+ html.br
//+ percentage
//+ html.getCommonFolderIcon("stickman.png")
+ counterCreators + " reviewers" + html.br
+ html.br
;
// generate the nice graph
String[] titles = new String[]{"No license declared", "License declared"};
int noLicenses = counterFiles - counterLicensesDeclared;
int[] values = new int[]{noLicenses, counterLicensesDeclared};
// do the graph file
File graphFile = Graphs.generate(thisFolder, titles, values);
String[] header = new String[]{summary,
html.br
+ html.getIcon("chart.png", request)};
values = new int[]{270, 180};
summary = Table.alignedTable(header, values);
String result =
html.div(20)
+ summary
+ html.h2("List of documents")
+ listFilesSPDX(request)
//+ html.br
+ html._div
+ html.br
+ "";
// provide an answer
request.setAnswer(result);
}
/**
* List all the files that are on the disk
*/
private String listFilesSPDX(WebRequest request){
// String[] line = new String[]{"SPDX", "Last modified"};
// Table table = new Table(line);
String result = "";
// for(SPDXfile product : core.products){
// String lastModified = utils.time.getTimeFromLong
// (product.file.lastModified());
//
// line = new String[]{product.getId(), lastModified};
// table.add(line);
//// }
result = findFiles(core.getProductsFolder(), 25, request);
return result;
}
/**
* Find all files in a given folder and respective subfolders
* @param where A file object of the start folder
* @param maxDeep How deep is the crawl allowed to proceed
* @param request
* @return An array containing all the found files, returns null if none is
* found
*/
public String findFiles(File where, int maxDeep, WebRequest request){
File[] files = where.listFiles();
String result = "";
int[] sizes = new int[]{10,200};
if(files != null)
for (File file : files) {
if (file.isFile()){
String filePath = file.getAbsolutePath();
// we only want .spdx files
if(filePath.endsWith("spdx")){
// remove the local disk path with a generic one
String filteredPath = "."
+ file.getAbsolutePath().replace(core.getProductsFolder()
.getAbsolutePath(), "");
//filteredPath = filteredPath.replace(" ", "%20");
String fileLink = html.link(file.getName(),
"?x=summary&spdx="
+ filteredPath
+ "");
//System.err.println("MSG SH23 - " + fileLink);
result += Table.alignedTable(new String[]{
html.getIcon("document-text.png", request),
fileLink},
sizes);
}
}
else
if ( (file.isDirectory())
&&( maxDeep-1 > 0 ) ){
String folderName = file.getName();
// do the recursive crawling
String temp = findFiles(file, maxDeep-1, request);
// we don't need empty folders
if(temp.length() == 0){
continue;
}
String folderText = Table.alignedTable(new String[]{
html.getIcon("folder-horizontal-open.png", request),
folderName},
sizes);
String current =
html.div()
+ folderText
//+ html.br
+ html.div()
+ temp
+ html._div
+ html._div;
// add a pretty paragraph
if(maxDeep == 25){
current = html.br + current;
}
result += current;
}
}
return result;
}
/**
* Verifies if a given SPDX document exists inside our archive or or not
* @param spdxTarget The file inside the SPDX Archive
* @return null if the file does not exists, otherwise return a pointer
*/
private File getFile(String spdxTarget, WebRequest request){
if(spdxTarget == null){
request.setAnswer("No file specified");
return null;
}
// does this file exists?
File file = new File(core.getProductsFolder(), spdxTarget);
// this file needs to exist
if((file.exists() == false) || (file.isDirectory())){
request.setAnswer("Sorry, the file was not found: " + spdxTarget);
return null;
}
// all done
return file;
}
/**
* Shows the full text of an SPDX document
* @param request
*/
public void full(WebRequest request) {
// we need the "file" parameter to tell us what to detail
String spdxTarget = request.getParameter(param.spdx);
// does this file exists?
File file = getFile(spdxTarget, request);
if(file == null){
return;
}
// read the whole file
String result = utils.files.readAsString(file);
// output the file
request.setAnswer(result);
}
/**
* Show the summary for a given SPDX document
* @param request
*/
public void summary(WebRequest request) {
// we need the "file" parameter to tell us what to detail
String spdxTarget = request.getParameter(param.spdx);
// does this file exists?
File file = getFile(spdxTarget, request);
if(file == null){
return;
}
// String cache = (String) core.temp.get(showSPDX);
// if(cache != null){
// log.write(is.COMPLETED, "Using the cached version of show SPDX");
// request.setAnswer(cache);
// return;
// }
// get the SPDX file from the root node
SPDXfile spdx = new SPDXfile(file);
// compute some of our useful statistics about the SPDX document
int counterLicensesDeclared = doStatistics(spdx);
int counterFiles = spdx.fileSection.files.size();
// calculate percentage of files with a license declared
String percentage =
" ("
+ (counterLicensesDeclared * 100)/counterFiles
+ "% in total)" + html.br;
String searchEngines =
html.div(10)
+ html.linkToSearchGoogle(spdx.getId())
// + html.divider
// + html.linkToSearchAntepedia(node.id)
+ html.divider
+ html.linkToSearchGitHub(spdx.getId())
+ html._div
;
String evaluation = doEvaluation(spdx);
// prepare the answer
String result = ""
//swingUtils.getBreadcrumb(node)
+ html.div(20)
+ html.h2(spdx.getId())
//+ html.getCommonFolderIcon("documents-stack.png")
+ counterFiles + " files inside the package"
+ html.br
//+ html.getCommonFolderIcon("calculator.png")
+ counterLicensesDeclared + " files with declared licenses"
+ percentage
+ evaluation
+ html._div
+ html.div()
+ html.br
+ swingUtils.addIfNotEmpty(""
//html.getCommonFolderIcon("magnifier-zoom-fit.png")
+ "Look around the web"
, searchEngines)
+ html._div
+ html.div()
+ "<b>" + "Other actions" + "</b>" + html.br
+ html._div
+ html.div(20)
//+ html.getCommonFolderIcon("receipt--pencil.png")
+ html.link("Show full text",
"?x=full&"
+ param.spdx + "=" + spdxTarget)
+ html._div
+ html.br
//+ html.br
+ html.div()
+ "<b>" + "List files" + "</b>" + html.br
+ html._div
+ html.div(20)
//+ html.getCommonFolderIcon("folder-smiley-sad.png")
//+ html.linkScript("Without a license", thisFile, "showFilesWithoutLicense")
+ html.link("Without license specified", "?x=list&"
+ param.filter + "=nolicense&"
+ param.spdx + "=" + spdxTarget)
+ html.br
//+ html.getCommonFolderIcon("folder-smiley.png")
//+ html.linkScript("With a license reported", thisFile, "showFilesWithLicense")
+ html.link("With license", "?x=list&"
+ param.filter + "=withlicense&"
+ param.spdx + "=" + spdxTarget)
+ html._div
+ "";
// save our cache for next time
core.temp.put(showSPDX, result);
// write everything on our UI text area
request.setAnswer(result);
}
/**
* list some information according to a filter
* @param request
*/
public void list(WebRequest request) {
// we need the "file" parameter to tell us what to detail
String spdxTarget = request.getParameter(param.spdx);
// does this file exists?
File file = getFile(spdxTarget, request);
if(file == null){
return;
}
// get what we want to show
String thisFilter = request.getParameter(param.filter);
// value can't be empty
if(thisFilter == null){
request.setAnswer("No filter specified");
return;
}
// start the processing
SPDXfile spdx = new SPDXfile(file);
// create the place holder for the results
ArrayList<FileInfo> list = new ArrayList();
// get only the files without a declared license
if(thisFilter.equalsIgnoreCase(param.noLicense)){
// iterate through all files
for(FileInfo fileInfo : spdx.fileSection.files){
// if there is a license, no need to continue
if(tools.hasLicense(fileInfo)){
continue;
}
list.add(fileInfo);
}
}
// get the unlicensed files
if(thisFilter.equalsIgnoreCase(param.withLicense)){
// iterate through all files
for(FileInfo fileInfo : spdx.fileSection.files){
// if there is a license, no need to continue
if(tools.hasLicense(fileInfo)==false){
continue;
}
list.add(fileInfo);
}
}
// create the HTML data where our info will be placed
String[] columns = new String[]{"File name", "", "Path"};
Table table = new Table(columns);
// iterate through all files
for(FileInfo fileInfo : list){
// create a column with our file information
String[] column = new String[]{
// utils.text.shortText(fileInfo.toString(), 25),
// utils.text.shortText(fileInfo.tagFilePath.toString(), 30),
fileInfo.toString(),
html.link("Detail", "?x=specific&"
+ param.spdx + "=" + spdxTarget + "&"
+ param.file + "=" + fileInfo.getName()
),
fileInfo.tagFilePath.toString()
};
table.add(column);
}
// do the output that is displayed to the end-user
String result = "" //swingUtils.getBreadcrumb(node)
+ html.div(20)
+ html.h2(spdx.getId())
//+ this.doFileSummary(spdx)
+ doEvaluation(spdx)
+ "Showing " + list.size() + " files from a total of "
+ spdx.fileSection.files.size() + " files"
+ "" + html.br+ html.br
+ table.output()
+ html._div
;
request.setAnswer(result);
}
/**
* list some information according to a filter
* @param request
*/
public void specific(WebRequest request) {
// we need the "file" parameter to tell us what to detail
String spdxTarget = request.getParameter(param.spdx);
// does this file exists?
File spdxFile = getFile(spdxTarget, request);
if(spdxFile == null){
return;
}
// get what we want to show
String targetFile = request.getParameter(param.file);
// value can't be empty
if(targetFile == null){
request.setAnswer("No filter specified");
return;
}
// start the processing
SPDXfile spdx = new SPDXfile(spdxFile);
// go through all files inside the document
for(FileInfo file : spdx.fileSection.files){
// have we (finally) found a match?
if(targetFile.equals(file.getName())){
String result = getFileDetails(file);
request.setAnswer(result);
return;
}
}
request.setAnswer("Didn't found " + targetFile);
}
/**
* Show the specific file details about a given file name
* @param file
*/
private String getFileDetails(FileInfo file){
String googleTerm;
String filename = file.tagFileName.toString();
// get the file extension if available
//String extension = getFileExtension(filename);
try{
// we need to remove misleading terms from the filename
String filteredName = file.getName().toLowerCase();
filteredName = filteredName.replace(".tar.gz", "");
filteredName = filteredName.replace(".zip", "");
filteredName = filteredName.replace(".jar", "");
filteredName = filteredName.replace(".7z", "");
filteredName = filteredName.replace(".tar", "");
filteredName = filteredName.replace(".bz2", "");
// build up our google query
googleTerm = filteredName
+ " %22"
+ filename
+ "%22 "
//+ extension
;
} catch (Exception e){
return log.write(is.ERROR, "SFD01 - Error occurred when trying to build"
+ " a search keyword for google");
}
// do the introduction of this file with a breadcrumb
// String[] fields = node.getUID().split(">>");
// String breadCrumb =
// fields[4]
// + ">"
// + fields[3]
// + ">"
// + fields[1]
// ;
// add a short summary about the file
String summary = "";
if(file.tagFileSize != null){
summary += "This file is sized in " + file.tagFileSize.toString();
}
if(file.tagFileLOC != null){
summary += " and has " + file.tagFileLOC + " lines of code"
+ html.br + html.br;
}
if(spdxlib.tools.hasLicense(file)){
summary += "Applicable license(s): " + spdxlib.tools.getLicense(file);
}
// do the date creation
//TODO We need to archive file date information
//summary += "Created in " + file.;
String resultIntroduction = ""
+ html.h2(filename)
// + "<h2>"
// + breadCrumb
// + "</h2>"
+ html.div()
+ summary
+ html._div
// + html.br
;
// Add links to find more info on the Internet about the file name
String resultFilename =
html.div()
+ html.linkToSearchYandex("\"" + filename + "\"")
+ html.divider
+ html.linkToSearchGoogle(googleTerm)
// + html.divider
// + html.linkToSearchOhloh(file.tagFileName.toString())
+ html.divider
+ html.linkToSearchGitHub(file.tagFileName.toString())
+ html._div;
String resultSHA1 = "";
if(file.tagFileChecksumSHA1!= null){
resultSHA1 = file.tagFileChecksumSHA1.toString()
+ html.br
+ html.div()
+ html.linkSearch("Find duplicates", "SHA1: "
+ file.tagFileChecksumSHA1.toString())
+ html.divider
+ html.linkToSearchGoogle(
"%22"+ file.tagFileChecksumSHA1.toString() + "%22" )
+ html._div;
}
String resultSHA256 = "";
if(file.tagFileChecksumSHA256!= null){
resultSHA256 = file.tagFileChecksumSHA256.toString()
+ html.div()
// only possible when we have SHA256 hashes available
+ html.linkToSearchVirusTotal(file.tagFileChecksumSHA256.toString())
+ html._div;
}
String resultMD5 = "";
if(file.tagFileChecksumMD5!= null){
resultMD5 = file.tagFileChecksumMD5.toString()
+ html.div()
// We might be lucky and find an MD5 with info
+ html.linkToSearchGoogle(
"%22"+ file.tagFileChecksumMD5.toString() + "%22" )
+ html._div;
}
String resultSSDEEP = "";
if(file.tagFileChecksumSSDEEP!= null){
String text = file.tagFileChecksumSSDEEP.raw;
// remove the tag header
text = text.replace("FileChecksum: SSDEEP: ", "");
resultSSDEEP = text
+ html.div()
// only possible when we have SHA256 hashes available
+ html.linkSearch("Find similar files", "SSDEEP: "
+ text)
+ html._div;
}
String result = html.div()
+ resultIntroduction
+ html.br
+ swingUtils.addIfNotEmpty("SHA1", resultSHA1)
+ swingUtils.addIfNotEmpty("SHA256", resultSHA256)
+ swingUtils.addIfNotEmpty("MD5",resultMD5)
//+ html.br
+ swingUtils.addIfNotEmpty("SSDEEP", resultSSDEEP)
+ swingUtils.addIfNotEmpty("Look for \""
+filename
+"\" in search engines"
, resultFilename)
+ html._div
// + swingUtils.addSSDEEP("SSDEEP", file)
// + swingUtils.addIfNotEmpty("Copyright text",file.tagFileCopyrightText.toString())
;
/** missing to add:
* - File path
* - Applicable licenses (when available)
*/
return result;
}
// /**
// * This operation might take a while, so we first launch a menu asking
// * people to wait for a while and then launch a thread with the results
// */
// void showFilesWithoutLicense(){
// String inProgress = ""
// + html.div()
// + "<h2>"
// + html.getCommonFolderIcon("wand.png")
// + "In progress!</h2>"
// + ""
// + "We are creating a list, please wait.."
// + html.br
// + html._div;
// // update the text box
// core.studio.editorPane(is.contentHTML, false, 0, inProgress);
// Thread thread = new Thread(){
// @Override
// public void run(){
// processFilesWithoutLicense();
// }
// };
// thread.start();
// }
//
// /**
// * This operation might take a while, so we first launch a menu asking
// * people to wait for a while and then launch a thread with the results
// */
// void showFilesWithLicense(){
// String inProgress = ""
// + html.div()
// + "<h2>"
// + html.getCommonFolderIcon("wand.png")
// + "In progress!</h2>"
// + ""
// + "We are creating a list, please wait.."
// + html.br
// + html._div;
// // update the text box
// core.studio.editorPane(is.contentHTML, false, 0, inProgress);
// Thread thread = new Thread(){
// @Override
// public void run(){
// processFilesWithLicense();
// }
// };
// thread.start();
// }
//
//
//
//
// /**
// * Shows a list of files for the selected package that do not have a license
// */
// void processFilesWithoutLicense(){
//
// //node = swingUtils.getSelectedNode();
// node = (TreeNodeSPDX) core.temp.get("showPackageDetails");
// // no need to continue if there is nothing selected
// if(node == null){
// return;
// }
// // get the SPDX file from the root node
// SPDXfile spdx = (SPDXfile) node.getUserObject();
//
// // create the HTML data where our info will be placed
// String[] columns = new String[]{"File name", "Path", ""};
// Table table = new Table(columns);
//
//
// // iterate through all files
// for(FileInfo file : spdx.fileSection.files){
//
// // if there is a license, no need to continue
// if(tools.hasLicense(file)){
// continue;
// }
//
// // create a column with our file information
// String[] column = new String[]{
// utils.text.shortText(file.toString(), 25),
// utils.text.shortText(file.tagFilePath.toString(), 30),
// //file.tagFilePath.toString(),
// html.linkNode("details", ">> "
// + file.tagFileName.toString()
// + " >> Files >> "
// + node.id
// + " >> Products ")
// };
// table.add(column);
// }
//
// // do the output that is displayed to the end-user
// String result = swingUtils.getBreadcrumb(node)
// + html.div(20)
// + table.output()
// + html._div
// ;
//
// // write everything on our UI text area
// core.studio.editorPane(is.contentHTML, false, 0, result, false, null);
// }
//
// /**
// * Shows a list of files for the selected package that do not have a license
// */
// void processFilesWithLicense(){
//
// //node = swingUtils.getSelectedNode();
// node = (TreeNodeSPDX) core.temp.get("showPackageDetails");
// // no need to continue if there is nothing selected
// if(node == null){
// return;
// }
// // get the SPDX file from the root node
// SPDXfile spdx = (SPDXfile) node.getUserObject();
//
// // create the HTML data where our info will be placed
// String[] columns = new String[]{"File name", "Path", ""};
// Table table = new Table(columns);
//
//
// // iterate through all files
// for(FileInfo file : spdx.fileSection.files){
//
// // if there is a license, no need to continue
// if(tools.hasLicense(file) == false){
// continue;
// }
//
// // create a column with our file information
// String[] column = new String[]{
// utils.text.shortText(file.toString(), 25),
// utils.text.shortText(file.tagFilePath.toString(), 30),
// //file.tagFilePath.toString(),
// html.linkNode("details", ">> "
// + file.tagFileName.toString()
// + " >> Files >> "
// + node.id
// + " >> Products ")
// };
// table.add(column);
// }
//
// // do the output that is displayed to the end-user
// String result = swingUtils.getBreadcrumb(node)
// + html.div(20)
// + table.output()
// + html._div
// ;
//
// // write everything on our UI text area
// core.studio.editorPane(is.contentHTML, false, 0, result, false, null);
// }
//
//
// /**
// * Show the SPDX document on the text area
// */
// public void showSPDX(){
// node = swingUtils.getSelectedNode();
// // no need to continue if there is nothing selected
// if(node == null){
// return;
// }
// // get the SPDX file from the root node
// SPDXfile spdx = (SPDXfile) node.getUserObject();
//
//
// // write everything on our UI text area
// String content = spdx.rawText;
// core.studio.editorPane(is.contentText, true, 0, content);
// }
//
//
/**
* When given a SPDX object, provide some statistics
* about the number of licenses that are not declared
*/
int doStatistics(SPDXfile spdx){
int counterLicensesDeclared = 0;
// get the number of licenses declared
for(Object fileObject : spdx.fileSection.files){
FileInfo file = (FileInfo) fileObject;
// go deep into the license information
if(tools.hasLicense(file)){
counterLicensesDeclared++;
}
}
return counterLicensesDeclared;
}
/**
* Provides an evaluation if the SPDX file has quality or not
* @param spdx an object from where we will read all data
* @return A string used for the HTML output
*/
private String doEvaluation(SPDXfile spdx) {
String result = "";
Boolean hasSVNfiles = false;
ArrayList<FileInfo> list = spdx.fileSection.files;
for(FileInfo file : list){
if(file.tagFileName.toString().contains(".svn")){
hasSVNfiles = true;
break;
}
}
if(hasSVNfiles){
result = html.br
+ html.h2(""
//html.getCommonFolderIcon("exclamation.png")
+ "Suggestions"
+ "")
+ "Source code has SVN files that could be removed from the"
+ " distribution"
+ html.br
+ html.br
;
}
return result;
}
}