Skip to content
Draft
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
1 change: 1 addition & 0 deletions src/Cli/Microsoft.DotNet.Cli.Utils/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public static class Constants
public const string Build = nameof(Build);
public const string ComputeRunArguments = nameof(ComputeRunArguments);
public const string ComputeAvailableDevices = nameof(ComputeAvailableDevices);
public const string DeployToDevice = nameof(DeployToDevice);
public const string CoreCompile = nameof(CoreCompile);

// MSBuild item metadata
Expand Down
3 changes: 3 additions & 0 deletions src/Cli/dotnet/Commands/CliCommandStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,9 @@ The default is to publish a framework-dependent application.</value>
<data name="RunCommandException" xml:space="preserve">
<value>The build failed. Fix the build errors and run again.</value>
</data>
<data name="RunCommandDeployFailed" xml:space="preserve">
<value>Deployment to device failed. Fix any deployment errors and run again.</value>
</data>
<data name="RunCommandExceptionCouldNotApplyLaunchSettings" xml:space="preserve">
<value>The launch profile "{0}" could not be applied.
{1}</value>
Expand Down
32 changes: 23 additions & 9 deletions src/Cli/dotnet/Commands/Run/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,20 @@ public int Execute()
FacadeLogger? logger = ProjectFileFullPath is not null
? LoggerUtility.DetermineBinlogger([.. MSBuildArgs.OtherMSBuildArgs], "dotnet-run")
: null;

// Create selector for project-based runs to handle framework/device selection and deploy
using var selector = ProjectFileFullPath is not null
? new RunCommandSelector(
ProjectFileFullPath,
CommonRunHelpers.GetGlobalPropertiesFromArgs(MSBuildArgs),
Interactive,
logger)
: null;

try
{
// Pre-run evaluation: Handle target framework and device selection for project-based scenarios
if (ProjectFileFullPath is not null && !TrySelectTargetFrameworkAndDeviceIfNeeded(logger))
if (selector is not null && !TrySelectTargetFrameworkAndDeviceIfNeeded(selector))
{
// If --list-devices was specified, this is a successful exit
return ListDevices ? 0 : 1;
Expand Down Expand Up @@ -194,6 +204,13 @@ public int Execute()
}
}

// Deploy step: Call DeployToDevice target if available
// This must run even with --no-build, as the user may have selected a different device
if (selector is not null && !selector.TryDeployToDevice())
{
throw new GracefulException(CliCommandStrings.RunCommandDeployFailed);
}

ICommand targetCommand = GetTargetCommand(projectFactory, cachedRunProperties, logger);
ApplyLaunchSettingsProfileToCommand(targetCommand, launchSettings);

Expand Down Expand Up @@ -228,11 +245,11 @@ public int Execute()
/// Uses a single RunCommandSelector instance for both operations, re-evaluating
/// the project after framework selection to get the correct device list.
/// </summary>
/// <param name="logger">Optional logger for MSBuild operations (device selection)</param>
/// <param name="selector">The selector to use for framework and device selection</param>
/// <returns>True if we can continue, false if we should exit</returns>
private bool TrySelectTargetFrameworkAndDeviceIfNeeded(FacadeLogger? logger)
private bool TrySelectTargetFrameworkAndDeviceIfNeeded(RunCommandSelector selector)
{
Debug.Assert(ProjectFileFullPath is not null);
Debug.Assert(selector is not null);

var globalProperties = CommonRunHelpers.GetGlobalPropertiesFromArgs(MSBuildArgs);

Expand All @@ -246,19 +263,16 @@ private bool TrySelectTargetFrameworkAndDeviceIfNeeded(FacadeLogger? logger)
}

// Optimization: If BOTH framework AND device are already specified (and we're not listing devices),
// we can skip both framework selection and device selection entirely
// we can skip device selection UI
bool hasFramework = globalProperties.TryGetValue("TargetFramework", out var existingFramework) && !string.IsNullOrWhiteSpace(existingFramework);
bool hasDevice = globalProperties.TryGetValue("Device", out var preSpecifiedDevice) && !string.IsNullOrWhiteSpace(preSpecifiedDevice);

if (!ListDevices && hasFramework && hasDevice)
{
// Both framework and device are pre-specified, no need to create selector or logger
// Both framework and device are pre-specified, skip device selection UI
return true;
}

// Create a single selector for both framework and device selection
using var selector = new RunCommandSelector(ProjectFileFullPath, globalProperties, Interactive, logger);

// Step 1: Select target framework if needed
if (!selector.TrySelectTargetFramework(out string? selectedFramework))
{
Expand Down
30 changes: 30 additions & 0 deletions src/Cli/dotnet/Commands/Run/RunCommandSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,34 @@ public bool TrySelectDevice(
return null;
}
}

/// <summary>
/// Attempts to deploy to a device by calling the DeployToDevice MSBuild target if it exists.
/// This reuses the already-loaded project instance for performance.
/// </summary>
/// <returns>True if deployment succeeded or was skipped (no target), false if deployment failed</returns>
public bool TryDeployToDevice()
{
if (!OpenProjectIfNeeded(out var projectInstance))
{
// Invalid project file
return false;
}

// Check if the DeployToDevice target exists in the project
if (!projectInstance.Targets.ContainsKey(Constants.DeployToDevice))
{
// Target doesn't exist, skip deploy step
return true;
}

// Build the DeployToDevice target
var buildResult = projectInstance.Build(
targets: [Constants.DeployToDevice],
loggers: _binaryLogger is null ? null : [_binaryLogger],
remoteLoggers: null,
out _);

return buildResult;
}
}
5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@
</ItemGroup>
</Target>

<!-- DeployToDevice target for testing deployment functionality -->
<Target Name="DeployToDevice">
<Message Text="DeployToDevice: Deployed to device $(Device) with RuntimeIdentifier $(RuntimeIdentifier)" Importance="high" />
</Target>

</Project>
Loading
Loading