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

Scan per build config #373

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions client/src/__tests__/unit-tests/driver/scanner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ describe('BitBakeProjectScanner', () => {
}, BITBAKE_TIMEOUT)

it('can get the bitbake version', async () => {
const version = bitBakeProjectScanner.scanResult._bitbakeVersion
const version = bitBakeProjectScanner.activeScanResult._bitbakeVersion
expect(version).toMatch(/^[\d.]+$/);
})

it('can get a list of layers', async () => {
const layers = bitBakeProjectScanner.scanResult._layers
const layers = bitBakeProjectScanner.activeScanResult._layers
// poky provides the "core", "yocto" and "yoctobsp" layers
expect(layers.length).toBeGreaterThan(2)
expect(layers).toEqual(
Expand All @@ -94,7 +94,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get a list of recipes', async () => {
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
expect(recipes.length).toBeGreaterThan(100)
expect(recipes).toEqual(
expect.arrayContaining([
Expand All @@ -108,7 +108,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can detected skipped recipes', async () => {
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
// systemd is skipped in the poky distribution, because systemV is used instead
const systemdRecipe = recipes.find((recipe) => recipe.name === 'systemd')
expect(systemdRecipe).toEqual(
Expand All @@ -121,7 +121,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get recipes appends', async () => {
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
const busyboxRecipe = recipes.find((recipe) => recipe.name === 'busybox')
expect(busyboxRecipe).toEqual(
expect.objectContaining(
Expand All @@ -137,7 +137,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get recipes paths', async () => {
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
const busyboxRecipe = recipes.find((recipe) => recipe.name === 'busybox')
expect(busyboxRecipe).toEqual(
expect.objectContaining({
Expand All @@ -150,7 +150,7 @@ describe('BitBakeProjectScanner', () => {

it('can get tricky recipes paths', async () => {
// These recipes change their PN and require the recipesWithoutPaths code
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
const gccSourceRecipe = recipes.find((recipe) => recipe.name.includes('gcc-source-'))
expect(gccSourceRecipe).toEqual(
expect.objectContaining({
Expand Down Expand Up @@ -178,7 +178,7 @@ describe('BitBakeProjectScanner', () => {
})

it('respects PREFERRED_VERSION', async () => {
const recipes = bitBakeProjectScanner.scanResult._recipes
const recipes = bitBakeProjectScanner.activeScanResult._recipes
const fixtureVersionRecipe = recipes.find((recipe) => recipe.name === 'fixture-version')
expect(fixtureVersionRecipe).toEqual(
expect.objectContaining({
Expand All @@ -191,7 +191,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get a list of classes', async () => {
const classes = bitBakeProjectScanner.scanResult._classes
const classes = bitBakeProjectScanner.activeScanResult._classes
expect(classes.length).toBeGreaterThan(50)
expect(classes).toEqual(
expect.arrayContaining([
Expand All @@ -205,7 +205,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get a list of overrides', async () => {
const overrides = bitBakeProjectScanner.scanResult._overrides
const overrides = bitBakeProjectScanner.activeScanResult._overrides
expect(overrides.length).toBeGreaterThan(5)
expect(overrides).toEqual(
expect.arrayContaining([
Expand All @@ -215,7 +215,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get a list of conf files', async () => {
const confFiles = bitBakeProjectScanner.scanResult._confFiles
const confFiles = bitBakeProjectScanner.activeScanResult._confFiles
expect(confFiles.length).toBeGreaterThan(0)
expect(confFiles).toEqual(
expect.arrayContaining(
Expand All @@ -233,7 +233,7 @@ describe('BitBakeProjectScanner', () => {
})

it('can get a list of devtool workspaces', async () => {
const devtoolWorkspaces = bitBakeProjectScanner.scanResult._workspaces
const devtoolWorkspaces = bitBakeProjectScanner.activeScanResult._workspaces
expect(devtoolWorkspaces.length).toBeGreaterThan(0)
expect(devtoolWorkspaces).toEqual(
expect.arrayContaining([
Expand Down
4 changes: 2 additions & 2 deletions client/src/__tests__/unit-tests/ui/bitbake-commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('Devtool ide-sdk command', () => {
pathToBitbakeFolder: '',
sdkImage: 'core-image-minimal'
}
jest.spyOn(bitBakeProjectScanner, 'scanResult', 'get').mockReturnValue({'_bitbakeVersion': '1.0.0'} as BitbakeScanResult)
jest.spyOn(bitBakeProjectScanner, 'activeScanResult', 'get').mockReturnValue({'_bitbakeVersion': '1.0.0'} as BitbakeScanResult)
const ideSDKCommand = mockExtensionContext(bitBakeProjectScanner)

jest.spyOn(BitbakeTerminal, 'runBitbakeTerminalCustomCommand').mockReturnValue(undefined as unknown as Promise<IPty>)
Expand All @@ -78,7 +78,7 @@ describe('Devtool ide-sdk command', () => {
sdkImage: 'core-image-minimal',
sshTarget: 'root@192.168.0.3'
}
jest.spyOn(bitBakeProjectScanner, 'scanResult', 'get').mockReturnValue({'_bitbakeVersion': '3.0.0'} as BitbakeScanResult)
jest.spyOn(bitBakeProjectScanner, 'activeScanResult', 'get').mockReturnValue({'_bitbakeVersion': '3.0.0'} as BitbakeScanResult)
const ideSDKCommand = mockExtensionContext(bitBakeProjectScanner)

const commandSpy = jest.spyOn(BitbakeTerminal, 'runBitbakeTerminalCustomCommand').mockReturnValue(undefined as unknown as Promise<IPty>)
Expand Down
123 changes: 74 additions & 49 deletions client/src/driver/BitBakeProjectScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,22 @@ import * as vscode from 'vscode'

import { logger } from '../lib/src/utils/OutputLogger'

import type {
BitbakeScanResult,
DevtoolWorkspaceInfo,
ElementInfo,
LayerInfo,
import {
SCAN_RESULT_VERSION,
type BitbakeScanResult,
type DevtoolWorkspaceInfo,
type ElementInfo,
type LayerInfo,
} from '../lib/src/types/BitbakeScanResult'

import { type BitbakeDriver } from './BitbakeDriver'
import { type LanguageClient } from 'vscode-languageclient/node'
import fs from 'fs'
import { runBitbakeTerminalCustomCommand } from '../ui/BitbakeTerminal'
import { bitbakeESDKMode } from './BitbakeESDK'
import { finishProcessExecution } from '../utils/ProcessUtils'
import { extractRecipeName, extractRecipeVersion } from '../lib/src/utils/files'
import { NotificationMethod } from '../lib/src/types/notifications'

interface ScannStatus {
interface ScanStatus {
scanIsRunning: boolean
scanIsPending: boolean
}
Expand All @@ -46,9 +45,9 @@ export class BitBakeProjectScanner {
private readonly _confFileExtension: string = 'conf'
onChange: EventEmitter = new EventEmitter()

private _bitbakeScanResult: BitbakeScanResult = { _classes: [], _includes: [], _layers: [], _overrides: [], _recipes: [], _workspaces: [], _confFiles: [], _bitbakeVersion: '' }
/// The scan results stored per activeBuildConfiguration
private _bitbakeScanResults: { [key: string]: BitbakeScanResult } = {}
private readonly _bitbakeDriver: BitbakeDriver
private _languageClient: LanguageClient | undefined

/// These attributes map bind mounts of the workDir to the host system if a docker container commandWrapper is used (-v).
private containerMountPoint: string | undefined
Expand All @@ -58,27 +57,54 @@ export class BitBakeProjectScanner {
this._bitbakeDriver = bitbakeDriver
}

setClient (languageClient: LanguageClient): void {
this._languageClient = languageClient
}

private readonly _scanStatus: ScannStatus = {
private _scanStatus: ScanStatus = {
scanIsRunning: false,
scanIsPending: false
}

get scanResult (): BitbakeScanResult {
return this._bitbakeScanResult
}

set scanResult (scanResult: BitbakeScanResult) {
this._bitbakeScanResult = scanResult
get activeScanResult (): BitbakeScanResult {
const activeBuildConfiguration = this._bitbakeDriver.activeBuildConfiguration
if (this._bitbakeScanResults[activeBuildConfiguration] === undefined) {
this._bitbakeScanResults[activeBuildConfiguration] = {
_classes: [],
_includes: [],
_layers: [],
_overrides: [],
_recipes: [],
_workspaces: [],
_confFiles: [],
_bitbakeVersion: ''
}
}
return this._bitbakeScanResults[activeBuildConfiguration]
}

get bitbakeDriver (): BitbakeDriver {
return this._bitbakeDriver
}

public saveCacheResult(memento: vscode.Memento): Thenable<void> {
const ret = memento.update('bitbake.ScanResults', this._bitbakeScanResults).then(() => {
logger.debug('BitBake scan result saved to workspace state')
})
void memento.update('bitbake.ScanResultVersion', SCAN_RESULT_VERSION).then(() => {
logger.debug('BitBake scan result version saved to workspace state')
})
return ret
}

public restoreCacheResult(memento: vscode.Memento) : void {
const scanResult = memento.get('bitbake.ScanResults') as { [key: string]: BitbakeScanResult }
const scanResultVersion = memento.get('bitbake.ScanResultVersion') as number
if (scanResult !== undefined && scanResultVersion === SCAN_RESULT_VERSION) {
this._bitbakeScanResults = scanResult
logger.debug('BitBake scan result restored from workspace state')
// No need to emit onChange, because this is called during the initialization, when nothing is listening
} else {
logger.debug('No valid BitBake scan result found in workspace state: ' + scanResultVersion + '!=' + SCAN_RESULT_VERSION)
}
}

public needsContainerPathsResolution (): boolean {
return this.containerMountPoint !== undefined
}
Expand All @@ -87,7 +113,7 @@ export class BitBakeProjectScanner {
async rescanDevtoolWorkspaces (): Promise<void> {
logger.info('request rescanDevtoolWorkspaces')
await this.scanDevtoolWorkspaces()
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this._bitbakeScanResult)
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this.activeScanResult)
}

async rescanProject (): Promise<void> {
Expand Down Expand Up @@ -115,11 +141,10 @@ export class BitBakeProjectScanner {
logger.info('scan ready')
this.printScanStatistic()

void this._languageClient?.sendNotification(NotificationMethod.ScanComplete, this._bitbakeScanResult)
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this._bitbakeScanResult)
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this.activeScanResult)
} catch (error) {
logger.error(`scanning of project is aborted: ${error}`)
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this._bitbakeScanResult)
this.onChange.emit(BitBakeProjectScanner.EventType.SCAN_COMPLETE, this.activeScanResult)
}

this._scanStatus.scanIsRunning = false
Expand Down Expand Up @@ -178,25 +203,25 @@ export class BitBakeProjectScanner {
private printScanStatistic (): void {
logger.info('Scan results:')
logger.info('******************************************************************')
logger.info(`Layer: ${this._bitbakeScanResult._layers.length}`)
logger.info(`Recipes: ${this._bitbakeScanResult._recipes.length}`)
logger.info(`Inc-Files: ${this._bitbakeScanResult._includes.length}`)
logger.info(`bbclass: ${this._bitbakeScanResult._classes.length}`)
logger.info(`conf Files: ${this._bitbakeScanResult._confFiles.length}`)
logger.info(`overrides: ${this._bitbakeScanResult._overrides.length}`)
logger.info(`Devtool-workspaces: ${this._bitbakeScanResult._workspaces.length}`)
logger.info(`Layer: ${this.activeScanResult._layers.length}`)
logger.info(`Recipes: ${this.activeScanResult._recipes.length}`)
logger.info(`Inc-Files: ${this.activeScanResult._includes.length}`)
logger.info(`bbclass: ${this.activeScanResult._classes.length}`)
logger.info(`conf Files: ${this.activeScanResult._confFiles.length}`)
logger.info(`overrides: ${this.activeScanResult._overrides.length}`)
logger.info(`Devtool-workspaces: ${this.activeScanResult._workspaces.length}`)
}

private scanForClasses (): void {
this._bitbakeScanResult._classes = this.searchFiles(this._classFileExtension)
this.activeScanResult._classes = this.searchFiles(this._classFileExtension)
}

private scanForIncludeFiles (): void {
this._bitbakeScanResult._includes = this.searchFiles(this._includeFileExtension)
this.activeScanResult._includes = this.searchFiles(this._includeFileExtension)
}

private scanForConfFiles (): void {
this._bitbakeScanResult._confFiles = this.searchFiles(this._confFileExtension)
this.activeScanResult._confFiles = this.searchFiles(this._confFileExtension)
}

private scanBitbakeVersion(): void {
Expand All @@ -211,11 +236,11 @@ export class BitBakeProjectScanner {
}
logger.info('Bitbake version: ' + match[1])

this._bitbakeScanResult._bitbakeVersion = match[1]
this.activeScanResult._bitbakeVersion = match[1]
}

public async scanAvailableLayers (): Promise<void> {
this._bitbakeScanResult._layers = new Array < LayerInfo >()
this.activeScanResult._layers = new Array < LayerInfo >()
this.containerMountPoint = undefined

const output = await this.executeBitBakeCommand('bitbake-layers show-layers')
Expand All @@ -237,7 +262,7 @@ export class BitBakeProjectScanner {
}

if ((layerElement.name !== undefined) && (layerElement.path !== undefined) && (layerElement.priority !== undefined)) {
this._bitbakeScanResult._layers.push(layerElement as LayerInfo)
this.activeScanResult._layers.push(layerElement as LayerInfo)
}
}
}
Expand Down Expand Up @@ -302,7 +327,7 @@ You should adjust your docker volumes to use the same URIs as those present on y
private searchFiles (pattern: string): ElementInfo[] {
const elements: ElementInfo[] = new Array < ElementInfo >()

for (const layer of this._bitbakeScanResult._layers) {
for (const layer of this.activeScanResult._layers) {
try {
const files = find.fileSync(new RegExp(`.${pattern}$`), layer.path)
for (const file of files) {
Expand All @@ -327,7 +352,7 @@ You should adjust your docker volumes to use the same URIs as those present on y
}

async scanForRecipes (): Promise<void> {
this._bitbakeScanResult._recipes = new Array < ElementInfo >()
this.activeScanResult._recipes = new Array < ElementInfo >()

const output = await this.executeBitBakeCommand('bitbake-layers show-recipes')
const splittedOutput = output.split(/\r?\n/g)
Expand Down Expand Up @@ -380,7 +405,7 @@ You should adjust your docker volumes to use the same URIs as those present on y
Here 'meta' is used to refer to the layer instead of 'core'. So in such case we need to compare
the basename of the path found in 'show-layers' with the layer name found in this function.
*/
const layerInfo = this._bitbakeScanResult._layers.find((layer) => {
const layerInfo = this.activeScanResult._layers.find((layer) => {
return layer.name === layerName || path.parse(layer.path).name === layerName
})

Expand All @@ -392,7 +417,7 @@ You should adjust your docker volumes to use the same URIs as those present on y
skipped
}

this._bitbakeScanResult._recipes.push(element)
this.activeScanResult._recipes.push(element)
}

await this.scanForRecipesPath()
Expand All @@ -401,16 +426,16 @@ You should adjust your docker volumes to use the same URIs as those present on y
async scanOverrides (): Promise<void> {
const output = await this.executeBitBakeCommand('bitbake-getvar OVERRIDES')
const outerReg = /\nOVERRIDES="(.*)"\r?\n/
this._bitbakeScanResult._overrides = output.match(outerReg)?.[1].split(':') ?? []
this.activeScanResult._overrides = output.match(outerReg)?.[1].split(':') ?? []
}

public async scanDevtoolWorkspaces (): Promise<void> {
this._bitbakeScanResult._workspaces = new Array < DevtoolWorkspaceInfo >()
this.activeScanResult._workspaces = new Array < DevtoolWorkspaceInfo >()
const output = await this.executeBitBakeCommand('devtool status')
const regex = /^([^\s]+):\s([^\s]+)(?:\s\([^\s]+\))?$/gm
let match
while ((match = regex.exec(output)) !== null) {
this._bitbakeScanResult._workspaces.push({ name: match[1], path: match[2] })
this.activeScanResult._workspaces.push({ name: match[1], path: match[2] })
}
}

Expand Down Expand Up @@ -444,12 +469,12 @@ You should adjust your docker volumes to use the same URIs as those present on y

// Sort by decreasing length to avoid partial matches
filenames.sort((a, b) => b.length - a.length)
this._bitbakeScanResult._recipes.sort((a, b) => b.name.length - a.name.length)
await this.assignRecipesPaths(filenames, this._bitbakeScanResult._recipes, (a: string, b: string) => a === b)
this.activeScanResult._recipes.sort((a, b) => b.name.length - a.name.length)
await this.assignRecipesPaths(filenames, this.activeScanResult._recipes, (a: string, b: string) => a === b)

// Some recipes change their PN like gcc-source -> gcc-source-13.2
// We allow the recipe to be found by just including part of the name
const recipesWithoutPaths = this._bitbakeScanResult._recipes.filter((recipe) => recipe.path === undefined)
const recipesWithoutPaths = this.activeScanResult._recipes.filter((recipe) => recipe.path === undefined)
await this.assignRecipesPaths(filenames, recipesWithoutPaths, (a: string, b: string) => a.includes(b))
}

Expand Down Expand Up @@ -486,7 +511,7 @@ You should adjust your docker volumes to use the same URIs as those present on y
const recipeName: string = fullRecipeNameAsArray[0].split('.')[0]
const recipeVersion: string | undefined = fullRecipeNameAsArray[1]?.split('.bb')[0]

const recipe: ElementInfo | undefined = this._bitbakeScanResult._recipes.find((obj: ElementInfo): boolean => {
const recipe: ElementInfo | undefined = this.activeScanResult._recipes.find((obj: ElementInfo): boolean => {
return obj.name === recipeName
})

Expand Down
Loading
Loading