Skip to content

Commit

Permalink
Rework on build tasks
Browse files Browse the repository at this point in the history
- Remove dependency of local nanoFirmawareFlasher.
- Replace with calls to nanoff dotnet tool.
- Add installer step to extension activation.
- Fix all calls to nanoff.
- General improvements in all Dotnet class API: calling msbuild, generating outputs, calling nanoff to deploy and flash.
- Update repo readme and developer instructions.
- Update AZDO yaml to remove the build tasks and everything related with nanoff local copy.
  • Loading branch information
josesimoes committed Jun 19, 2024
1 parent 2acf752 commit 60f2b93
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 124 deletions.
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
[submodule "nanoFirmwareFlasher"]
path = nanoFirmwareFlasher
url = https://github.com/nanoframework/nanoFirmwareFlasher.git
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ Then select the type of project you want to add.

You will need to make sure you'll have the following elements installed:

- [.NET 6.0](https://dotnet.microsoft.com/download/dotnet)
- [.NET 8.0](https://dotnet.microsoft.com/download/dotnet)
- [nuget CLI](https://www.nuget.org/downloads)
- [Visual Studio build tools](https://visualstudio.microsoft.com/en/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) on Windows, `mono-complete` on [Linux/macOS](https://www.mono-project.com/docs/getting-started/install/)

> **Note:** Do not use the `mono-complete` package provided by your Linux distribution
> as it may not include `msbuild` which is required for this extension to work.
>
>
> Instead install the `mono-complete` package provided by the Mono Project.
> The [preview](https://www.mono-project.com/download/preview/) version is recommended
> as the [stable](https://www.mono-project.com/download/stable/) version is outdated.
Expand All @@ -94,11 +95,6 @@ This extension will **not** allow you to debug the device. Debug is only availab

This extension will work on any Mac version (x64 or M1), works only on Linux x64 and Windows x64. Other 32 bits OS or ARM platforms are not supported.

## Install path issues

:warning: That are know issues running commands for STM32 devices when the user path contains diacritic characters. This causes issues with with STM32 Cube Programmer which is used by `nanoff` a dependency of the extension.
Note that if you're not using the extension with with STM32 devices, this limitation does not apply.

## Developing for the VS Code extension

Documentation about development for the extension can be found [here](instalation.md).
Expand Down
13 changes: 0 additions & 13 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,10 @@ steps:
# need this here in order to persist GitHub credentials
- checkout: self
persistCredentials: true
submodules: true

- pwsh: scripts/build.ps1
displayName: Download and build dependencies for .NET nanoFramework

- task: DotNetCoreCLI@2
condition: succeeded()
displayName: Build nanoff
inputs:
command: 'build'
projects: '$(Build.SourcesDirectory)/nanoFirmwareFlasher/nanoFirmwareFlasher.Tool/nanoFirmwareFlasher.Tool.csproj'
arguments: '-o $(Build.SourcesDirectory)/dist/utils/nanoFirmwareFlasher /p:DefineConstants=VS_CODE_EXTENSION_BUILD /p:RestoreLockedMode=false /p:VSCodeExtensionBuild=True'

- script: chmod -R +x $(Build.SourcesDirectory)/dist/utils/
displayName: Adding executable rights to utils folder
condition: succeeded()

- task: DeleteFiles@1
displayName: Remove source folders
condition: succeeded()
Expand Down
17 changes: 9 additions & 8 deletions installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The following packages/tools/frameworks are required:

- [node](https://nodejs.org/en/) (> v12)
- [npm](https://www.npmjs.com/)
- [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [nbgv](https://github.com/dotnet/nerdbank.gitversioning)
- .NET 4.7.2 on Windows, [mono-complete](https://www.mono-project.com/docs/getting-started/install/) on Linux/macOS
- PowerShell core (`pwsh`) for Linux/macOS
Expand All @@ -27,15 +27,16 @@ The following packages/tools/frameworks are required:
- Run `npm install`
- Run `pwsh scripts/build.ps1` (on Linux & MacOS) or `./scripts/build.ps1` in Windows PowerShell
- Open in Visual Studio Code (`code .`)
- Press <kbd>F5</kbd> to debug

## Updating the dependencies
## Debugging extension

The extension depends on a .NET **nanoFramework** tool: [nanoFirmwareFlasher](https://github.com/nanoframework/nanoFirmwareFlasher). This is made available as git sub-module in the respective folder. To it manually, you have to `cd` into the folder and use the following git command to update to the desired tag. For example to update `nanoFirmwareFlasher` to version `v2.0.3`.
- Press <kbd>F5</kbd> to debug
- Set breakpoints at will
- Move to the new VS Code instance window
- Load a directory with a project or go to Command Palette and choose one of the nanoFramework commands

```cmd
cd nanoFirmwareFlasher
git checkout tags/v2.0.3
```
## Updating the dependencies

The extension depends on .NET **nanoFramework** msbuild components providade by the [VS extension](https://github.com/nanoframework/vs-extension).
To update to a new version go to the [build.ps1](scripts\build.ps1) and set the `$vsExtensionVersion` variable to the desired Git tag.
Make sure to commit these update changes in a individual commit to the upstream repository.
1 change: 0 additions & 1 deletion nanoFirmwareFlasher
Submodule nanoFirmwareFlasher deleted from 62262d
50 changes: 1 addition & 49 deletions scripts/build.ps1
Original file line number Diff line number Diff line change
@@ -1,28 +1,4 @@
function BuildDotnet ($solution, $dotnetBuild, $outputDirectory)
{
Write-Host "Building $solution..."

# create folder
$outFolder = (New-Item -Name "$outputDirectory/utils/$solution" -ItemType Directory -Force).ToString()

# unpack in folder
Get-ChildItem "$solution.sln" -Recurse | ForEach-Object {
nuget restore $PSItem.FullName -UseLockFile

if ($dotnetBuild)
{
Write-Host "Building with dotnet"
dotnet build $PSItem.FullName -o $outFolder
}
else
{
Write-Host "Building with msbuild"
msbuild $PSItem.FullName /p:OutDir=$outFolder
}
}
}

# only need these modules if not running on Azure Pipeline
# only need these modules if not running on Azure Pipeline
if(-Not $env:TF_BUILD)
{
"Installing VSSetup PS1 module" | Write-Host
Expand All @@ -39,16 +15,6 @@ if(-Not $env:TF_BUILD)
## Defining variables
$outputDirectory = "dist"

## Setup nanoFirmwareFlasher
$solution = "nanoFirmwareFlasher"

# skip build if running on Azure Pipeline
if(-Not $env:TF_BUILD)
{
"Setup build for $solution" | Write-Host
BuildDotnet $solution $true $outputDirectory
}

## Setup nanoFrameworkSDK
$extName = "VS2022ext"
$vsExtensionVersion = "v2022.3.0.86"
Expand Down Expand Up @@ -82,18 +48,4 @@ Remove-Item "$extName.zip"
Remove-Item $extName -Recurse -Force

# Copy the packages.config file
$ScriptDirectory = Get-ChildItem -Path $PSScriptRoot
Copy-Item (Join-Path $PSScriptRoot packages.config) (Join-Path $outputDirectory utils) -Force

## Setup nuget
$nugetFolder = (New-Item -Name "$outputDirectory/utils/nuget" -ItemType Directory -Force).ToString()

"Downloading nuget CLI..." | Write-Host

Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -Out "$nugetFolder/nuget.exe"

if ((-Not $env:TF_BUILD) -And ($IsMacOS -Or $IsLinux))
{
Write-Output "Adding executable rights to utils folder on Unix"
chmod -R +x ./$outputDirectory/utils/
}
155 changes: 124 additions & 31 deletions src/dotnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

import * as path from "path";
import * as os from 'os';

import { Executor } from "./executor";
import * as cp from 'child_process';
import * as vscode from 'vscode';

export class Dotnet {
/**
Expand All @@ -18,14 +19,14 @@ export class Dotnet {
public static build(fileUri: string, toolPath: String) {
if (fileUri) {
// using dynamicly-solved MSBuild.exe when ran from win32
if(os.platform() === "win32") {
Executor.runInTerminal('$path = & "${env:ProgramFiles(x86)}\\microsoft visual studio\\installer\\vswhere.exe" -products * -latest -prerelease -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\MSBuild.exe | select-object -first 1; ' +
if (os.platform() === "win32") {
Executor.runInTerminal('$path = & "${env:ProgramFiles(x86)}\\microsoft visual studio\\installer\\vswhere.exe" -products * -latest -prerelease -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\amd64\\MSBuild.exe | select-object -first 1; ' +
toolPath + '/nuget/nuget.exe restore "' + fileUri + '"; ' +
'& $path "' + fileUri + '" -p:NanoFrameworkProjectSystemPath=' + toolPath + '\\nanoFramework\\v1.0\\');
'& $path "' + fileUri + '" -p:platform="Any CPU" -p:NanoFrameworkProjectSystemPath=' + toolPath + '\\nanoFramework\\v1.0\\' + ' -verbosity:minimal');
}
// using msbuild (comes with mono-complete) on unix
else {
Executor.runInTerminal(`nuget restore "${fileUri}" && msbuild "${fileUri}" -p:NanoFrameworkProjectSystemPath=${toolPath}/nanoFramework/v1.0/`);
Executor.runInTerminal(`nuget restore "${fileUri}" && msbuild "${fileUri}" -p:platform="Any CPU" -p:NanoFrameworkProjectSystemPath=${toolPath}/nanoFramework/v1.0/ -verbosity:minimal`);
}
}
}
Expand All @@ -36,44 +37,136 @@ export class Dotnet {
* @param serialPath path to connected nanoFramework device (e.g. COM4 or /dev/tty.usbserial*)
* @param toolPath absolute path to root of nanoFramework extension
*/
public static deploy(fileUri: string, serialPath: string, toolPath: String) {
public static async deploy(fileUri: string, serialPath: string, toolPath: String) {
if (fileUri) {
const outputDir = path.dirname(fileUri) + '/OutputDir/';
const cliBuildArgumentsLinux = `/p:NanoFrameworkProjectSystemPath=${toolPath}/nanoFramework/v1.0/ /p:OutDir=${outputDir}`;
const cliBuildArgumentsWindows = `/p:NanoFrameworkProjectSystemPath=`+ toolPath + `\\nanoFramework\\v1.0\\ /p:OutDir=${outputDir}`;
const cliDeployArgumentsLinux = `${toolPath}/nanoFirmwareFlasher/nanoff.dll --nanodevice --deploy --serialport ${serialPath} --image ${outputDir}`;
const cliDeployArgumentsWindows = toolPath + `\\nanoFirmwareFlasher\\nanoff.exe --nanodevice --deploy --serialport ${serialPath} --image ${outputDir}`;
const cliBuildArgumentsLinux = `-p:platform="Any CPU" /p:NanoFrameworkProjectSystemPath=${toolPath}/nanoFramework/v1.0/ -verbosity:minimal /p:OutDir=${outputDir}`;
const cliBuildArgumentsWindows = `-p:platform="Any CPU" /p:NanoFrameworkProjectSystemPath=` + toolPath + `\\nanoFramework\\v1.0\\ -verbosity:minimal /p:OutDir=${outputDir}`;

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This string concatenation which depends on
library input
is later used in a
shell command
.
This string concatenation which depends on
library input
is later used in a
shell command
.
const cliDeployArguments = `nanoff --nanodevice --deploy --serialport ${serialPath} --image ${outputDir}`;
var binaryFile;

if(os.platform() === "win32") {
Executor.runInTerminal('$path = & "${env:ProgramFiles(x86)}\\microsoft visual studio\\installer\\vswhere.exe" -products * -latest -prerelease -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\MSBuild.exe | select-object -first 1; ' +
toolPath + '/nuget/nuget.exe restore "' + fileUri + '"; ' +
'& $path ' + fileUri + ' ' + cliBuildArgumentsWindows + '; '+
cliDeployArgumentsWindows);
if (os.platform() === "win32") {
// run nuget restore and call msbuild
Executor.runInTerminal('$path = & "${env:ProgramFiles(x86)}\\microsoft visual studio\\installer\\vswhere.exe" -products * -latest -prerelease -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\amd64\\MSBuild.exe | select-object -first 1; ' +
'nuget restore "' + fileUri + '"; ' +
'& $path ' + fileUri + ' ' + cliBuildArgumentsWindows);

// grab the binary file name
binaryFile = await executeMSBuildAndFindBinaryFile(fileUri, cliBuildArgumentsWindows);
}
else {
// run nuget restore and call msbuild
Executor.runInTerminal(`nuget restore "${fileUri}" && \
msbuild "${fileUri}" ${cliBuildArgumentsLinux} && \
dotnet ${cliDeployArgumentsLinux}`);
}
}
}
msbuild "${fileUri}" ${cliBuildArgumentsLinux}`);

// grab the binary file name
binaryFile = await executeMSBuildAndFindBinaryFile(fileUri, cliBuildArgumentsWindows);
}

// deploy the binary file to the selected device
Executor.runInTerminal(cliDeployArguments + binaryFile);
}
}

/**
* Flashes the selected device to new firmware using nanoFirmwareFlasher
* @param toolPath absolute path to root of nanoFramework extension
* @param cliArguments CLI arguments passed to nanoff
*/
public static flash(toolPath: String, cliArguments: String) {
if(toolPath && cliArguments) {
if(os.platform() === "win32") {
Executor.runInTerminal(`${toolPath}\\nanoFirmwareFlasher\\nanoff.exe --update ${cliArguments}`);
}
else
{
Executor.runInTerminal(`dotnet ${toolPath}/nanoFirmwareFlasher/nanoff.dll --update ${cliArguments}`);
}
public static flash(cliArguments: String) {
if (cliArguments) {
Executor.runInTerminal(`nanoff --update ${cliArguments}`);
}
}
}
}

/**
* Function to run the build again and grab the binary file name
* @param fileUri absolute path to *.sln
* @param cliBuildArguments CLI arguments passed to msbuild
* @returns binary file name
* @throws Error if the binary file name is not found in the build output
* @throws Error if the MSBuild path is not found
* @throws Error if the MSBuild command fails
* @throws Error if the executable name is not found in the build output
*/
function executeMSBuildAndFindBinaryFile(fileUri: string, cliBuildArguments: string): Promise<string> {
return new Promise(async (resolve, reject) => {

if (os.platform() === "win32") {

// Command to find MSBuild
const findMSBuildCmd = `"${process.env['ProgramFiles(x86)']}\\microsoft visual studio\\installer\\vswhere.exe" -products * -latest -prerelease -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\amd64\\MSBuild.exe`;

// First execution to find MSBuild path
cp.exec(findMSBuildCmd, (error, stdout, stderr) => {
if (error) {
vscode.window.showErrorMessage(`Error finding MSBuild: ${error}`);
reject(error);
return;
}

// Split the output by new lines to get an array of paths
const paths = stdout.split(/\r?\n/);

// Select the first non-empty path as the MSBuild path
const msBuildPath = paths.find(path => path.trim() !== '');

if (!msBuildPath) {
vscode.window.showErrorMessage('MSBuild path not found.');
reject(new Error('MSBuild path not found.'));
return;
}

// Construct MSBuild command using the found path
const buildCmd = `"${msBuildPath}" ${fileUri} ${cliBuildArguments}`;

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This string concatenation which depends on
library input
is later used in a
shell command
.

// Second execution to run MSBuild
cp.exec(buildCmd, (error, stdout, stderr) => {
if (error) {
vscode.window.showErrorMessage(`Error rebuilding: ${error}`);
reject(error);
return;
}
// Parse stdout to find the binary file name
const lines = stdout.split('\n');
const exeLine = lines.find(line => line.trim().endsWith('.exe'));
if (exeLine) {
const exeName = path.basename(exeLine.trim());
// Rename the executable from .exe to .bin
const binName = exeName.replace('.exe', '.bin');
// Resolve the promise with the binary file name
resolve(binName);
} else {
vscode.window.showErrorMessage('Executable name not found in build output.');
reject(new Error('Executable name not found in build output.'));
}
});
});
} else {
// For non-Windows platforms, we can directly call msbuild
const buildCmd = `msbuild "${fileUri}" ${cliBuildArguments}`;

Check warning

Code scanning / CodeQL

Unsafe shell command constructed from library input Medium

This string concatenation which depends on
library input
is later used in a
shell command
.

// Second execution to run MSBuild
cp.exec(buildCmd, (error, stdout, stderr) => {
if (error) {
vscode.window.showErrorMessage(`Error rebuilding: ${error}`);
reject(error);
return;
}
// Parse stdout to find the binary file name
const lines = stdout.split('\n');
const exeLine = lines.find(line => line.trim().endsWith('.exe'));
if (exeLine) {
const exeName = path.basename(exeLine.trim());
// Rename the executable from .exe to .bin
const binName = exeName.replace('.exe', '.bin');
// Resolve the promise with the binary file name
resolve(binName);
} else {
vscode.window.showErrorMessage('Executable name not found in build output.');
reject(new Error('Executable name not found in build output.'));
}
});
}
});
}
Loading

0 comments on commit 60f2b93

Please sign in to comment.