Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Nuget support #58

Merged
merged 18 commits into from
Sep 1, 2020
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as Collections from 'typescript-collections';
import * as vscode from 'vscode';
import { ComponentDetails } from 'xray-client-js';
import { DependenciesTreeNode } from '../dependenciesTreeNode';
import { TreesManager } from '../../treesManager';
import { GeneralInfo } from '../../../types/generalInfo';
import { NugetUtils } from '../../../utils/nugetUtils';

export class NugetTreeNode extends DependenciesTreeNode {
private static readonly COMPONENT_PREFIX: string = 'nuget://';

constructor(
private _workspaceFolder: string,
private _componentsToScan: Collections.Set<ComponentDetails>,
private _treesManager: TreesManager,
parent?: DependenciesTreeNode
) {
super(new GeneralInfo('', '', _workspaceFolder, ''), vscode.TreeItemCollapsibleState.Expanded, parent, '');
}

public async refreshDependencies(quickScan: boolean, project: any) {
this.generalInfo = new GeneralInfo(project.name, '', this._workspaceFolder, NugetUtils.PKG_TYPE);
this.label = project.name;
this.populateDependenciesTree(this, project.dependencies, quickScan);
}

private populateDependenciesTree(dependenciesTreeNode: DependenciesTreeNode, dependencies: any, quickScan: boolean) {
if (!dependencies) {
return;
}
for (let key in dependencies) {
let dependency: any = dependencies[key];
let nameVersionTuple: string[] = this.getNameVersionTuple(dependency.id);
let name: string = nameVersionTuple[0];
let version: string = nameVersionTuple[1];
if (version) {
let childDependencies: any = dependency.dependencies;
let generalInfo: GeneralInfo = new GeneralInfo(name, version, '', NugetUtils.PKG_TYPE);
let treeCollapsibleState: vscode.TreeItemCollapsibleState = childDependencies
? vscode.TreeItemCollapsibleState.Collapsed
: vscode.TreeItemCollapsibleState.None;
let child: DependenciesTreeNode = new DependenciesTreeNode(generalInfo, treeCollapsibleState, dependenciesTreeNode, '');
if (!quickScan || !this._treesManager.scanCacheManager.validateOrDelete(dependency.id)) {
this._componentsToScan.add(new ComponentDetails(NugetTreeNode.COMPONENT_PREFIX + dependency.id));
}
this.populateDependenciesTree(child, childDependencies, quickScan);
}
}
}

private getNameVersionTuple(value: string): string[] {
let split: string[] = value.split(':');
return [split[0], split[1]];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PypiUtils } from '../../utils/pypiUtils';
import { DependenciesTreeNode } from './dependenciesTreeNode';
import { TreesManager } from '../treesManager';
import { MavenUtils } from '../../utils/mavenUtils';
import { NugetUtils } from '../../utils/nugetUtils';

export class DependenciesTreesFactory {
public static async createDependenciesTrees(
Expand All @@ -22,6 +23,7 @@ export class DependenciesTreesFactory {
await NpmUtils.createDependenciesTrees(workspaceFolders, componentsToScan, treesManager, parent, quickScan);
await PypiUtils.createDependenciesTrees(workspaceFolders, componentsToScan, treesManager, parent, quickScan);
await MavenUtils.createMavenDependenciesTrees(workspaceFolders, componentsToScan, treesManager, parent, quickScan);
await NugetUtils.createDependenciesTrees(workspaceFolders, componentsToScan, treesManager, parent, quickScan);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export class DependenciesTreeNode extends vscode.TreeItem {
super(_generalInfo.artifactId, collapsibleState);
this._topIssue = new Issue('', Severity.Normal, '', '');
this.iconPath = IconsPaths.NORMAL_SEVERITY;
this.contextValue = contextValue || ContextKeys.SHOW_IN_PROJECT_DESC_ENABLED;
if (contextValue === undefined) {
this.contextValue = ContextKeys.SHOW_IN_PROJECT_DESC_ENABLED;
}
if (_parent) {
_parent.children.push(this);
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/utils/nugetDepsTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ScanUtils } from './scanUtils';
import * as path from 'path';


// TODO TO BE REPLACED WITH PACKAGE
export class NugetDepsTree {
public static buildTree(slnFilePath: string): string {
return ScanUtils.executeCmd('jfrog rt nuget-deps-tree', path.dirname(slnFilePath)).toString();
}
}
90 changes: 90 additions & 0 deletions src/main/utils/nugetUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as path from 'path';
import * as Collections from 'typescript-collections';
import * as vscode from 'vscode';
import { ComponentDetails } from 'xray-client-js';
import { DependenciesTreeNode } from '../treeDataProviders/dependenciesTree/dependenciesTreeNode';
import { NugetTreeNode } from '../treeDataProviders/dependenciesTree/dependenciesRoot/nugetTree';
import { TreesManager } from '../treeDataProviders/treesManager';
import { ScanUtils } from './scanUtils';
import { LogManager } from '../log/logManager';
import { NugetDepsTree } from './nugetDepsTree';

export class NugetUtils {
public static readonly PKG_TYPE: string = 'nuget';

/**
* Find .sln files in workspaces.
* @param workspaceFolders - Base workspace folders to search
* @param logManager - Log manager
*/
public static async locateSolutions(workspaceFolders: vscode.WorkspaceFolder[], logManager: LogManager): Promise<Collections.Set<vscode.Uri>> {
let solutions: Collections.Set<vscode.Uri> = new Collections.Set();
for (let workspace of workspaceFolders) {
logManager.logMessage('Locating *.sln files in workspace "' + workspace.name + '".', 'INFO');
let wsSolutions: vscode.Uri[] = await vscode.workspace.findFiles(
{ base: workspace.uri.fsPath, pattern: '**/*.sln' },
ScanUtils.getScanExcludePattern(workspace)
);
wsSolutions.forEach(solution => solutions.add(solution));
}
return Promise.resolve(solutions);
}

/**
* @param workspaceFolders - Base workspace folders
* @param componentsToScan - Set of nuget components to populate during the tree building. We'll use this set later on, while scanning the packages with Xray.
* @param scanCacheManager - Scan cache manager
* @param parent - The base tree node
* @param quickScan - True to allow using the scan cache
*/
public static async createDependenciesTrees(
workspaceFolders: vscode.WorkspaceFolder[],
componentsToScan: Collections.Set<ComponentDetails>,
treesManager: TreesManager,
parent: DependenciesTreeNode,
quickScan: boolean
): Promise<NugetTreeNode[]> {
let solutions: Collections.Set<vscode.Uri> = await NugetUtils.locateSolutions(workspaceFolders, treesManager.logManager);
if (solutions.isEmpty()) {
treesManager.logManager.logMessage('No *.sln files found in workspaces.', 'DEBUG');
return [];
}

treesManager.logManager.logMessage('Solution files to scan: [' + solutions.toString() + ']', 'DEBUG');
let nugetTreeNodes: NugetTreeNode[] = [];
for (let solution of solutions.toArray()) {
let tree: any = await NugetUtils.getProjects(solution.fsPath, treesManager.logManager, quickScan);
if (!tree) {
continue;
}
for (let project of tree.projects) {
let dependenciesTreeNode: NugetTreeNode = new NugetTreeNode(path.dirname(solution.fsPath), componentsToScan, treesManager, parent);
dependenciesTreeNode.refreshDependencies(quickScan, project);
nugetTreeNodes.push(dependenciesTreeNode);
}
}
return nugetTreeNodes;

}

private static async getProjects(slnFilePath: string, logManager: LogManager, quickScan: boolean) : Promise<any> {
let nugetList: any;
try {
nugetList = JSON.parse(NugetDepsTree.buildTree(slnFilePath));
} catch (error) {
logManager.logError(error, !quickScan);
logManager.logMessage('Failed building tree for solution "' + slnFilePath + '", due to the above error. Skipping to next solution... ', 'INFO');
return null;
}

if (!nugetList.projects) {
logManager.logError(new Error('No projects found for solution "' + slnFilePath + '".'), !quickScan);
logManager.logMessage(
'Possible cause: The solution needs to be restored. Restore it by running "nuget restore ' + slnFilePath + '.',
RobiNino marked this conversation as resolved.
Show resolved Hide resolved
'INFO'
);
return null;
}
return nugetList;
}
}