Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 3 additions & 3 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,20 +434,20 @@ All commands support these global options:

Winapp creates a directory to cache files that can be shared between multiple projects.

By default, winapp creates a directory at `$UserProfile/.winappglobal` as the global cache directory.
By default, winapp creates a directory at `$UserProfile/.winapp` as the global cache directory.

To use a different location, set the `WINAPP_CLI_CACHE_DIRECTORY` environment variable.

In **cmd**:
```cmd
REM Set a custom location for winapp's global cache
set WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winappglobal
set WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winapp
```

In **Powershell** and **pwsh**:
```pwsh
# Set a custom location for winapp's global cache
$env:WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winappglobal
$env:WINAPP_CLI_CACHE_DIRECTORY=d:\temp\.winapp
```

Winapp will create this directory automatically when you run commands like `init` or `restore`.
7 changes: 3 additions & 4 deletions src/winapp-CLI/WinApp.Cli.Tests/BaseCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public abstract class BaseCommandTests(bool configPaths = true)
{
private protected DirectoryInfo _tempDirectory = null!;
private protected DirectoryInfo _testWinappDirectory = null!;
private protected DirectoryInfo _testGlobalDirectory = null!;
private protected DirectoryInfo _testCacheDirectory = null!;
private protected IConfigService _configService = null!;
private protected IBuildToolsService _buildToolsService = null!;

Expand Down Expand Up @@ -57,10 +57,9 @@ public void SetupBase()
_configService = GetRequiredService<IConfigService>();
_configService.ConfigPath = new FileInfo(Path.Combine(_tempDirectory.FullName, "winapp.yaml"));

_testGlobalDirectory = _tempDirectory.CreateSubdirectory(".winappglobal");

var directoryService = GetRequiredService<IWinappDirectoryService>();
directoryService.SetCacheDirectoryForTesting(_testGlobalDirectory);
_testCacheDirectory = _tempDirectory.CreateSubdirectory(".winappcache");
directoryService.SetCacheDirectoryForTesting(_testCacheDirectory);
_buildToolsService = GetRequiredService<IBuildToolsService>();
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/winapp-CLI/WinApp.Cli.Tests/BuildToolsServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void BuildToolsService_WithTestCacheDirectory_UsesOverriddenDirectory()
Assert.IsNull(result);

// Additional verification: Create a fake bin directory structure and verify it's found
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand All @@ -40,7 +40,7 @@ public void BuildToolsService_WithTestCacheDirectory_UsesOverriddenDirectory()
public void GetBuildToolPath_WithNonExistentTool_ReturnsNull()
{
// Arrange - Create package structure but without the requested tool
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand All @@ -59,7 +59,7 @@ public void GetBuildToolPath_WithNonExistentTool_ReturnsNull()
public void GetBuildToolPath_WithMultipleVersions_ReturnsLatestVersion()
{
// Arrange - Create multiple package versions
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");

// Create older version
var olderPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.22000.1");
Expand All @@ -86,7 +86,7 @@ public void GetBuildToolPath_WithMultipleVersions_ReturnsLatestVersion()
public void GetBuildToolPath_WithPinnedVersion_ReturnsPinnedVersion()
{
// Arrange - Create multiple package versions
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");

// Create older version
var olderPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.22000.1742");
Expand Down Expand Up @@ -122,7 +122,7 @@ public void GetBuildToolPath_WithPinnedVersion_ReturnsPinnedVersion()
public void GetBuildToolPath_WithMultipleArchitectures_ReturnsCorrectArchitecture()
{
// Arrange - Create package with multiple architectures
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binVersionDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0");

Expand All @@ -149,7 +149,7 @@ public void GetBuildToolPath_WithMultipleArchitectures_ReturnsCorrectArchitectur
public async Task RunBuildToolAsync_WithValidTool_ReturnsOutput()
{
// Arrange - Create a fake tool that outputs to stdout
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand Down Expand Up @@ -198,7 +198,7 @@ public async Task EnsureBuildToolsAsync_WithNoExistingPackage_ShouldAttemptInsta
public async Task EnsureBuildToolsAsync_WithExistingPackage_ReturnsExistingPath()
{
// Arrange - Create existing package structure
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand All @@ -214,7 +214,7 @@ public async Task EnsureBuildToolsAsync_WithExistingPackage_ReturnsExistingPath(
public async Task EnsureBuildToolsAsync_WithForceLatest_ShouldAttemptReinstallation()
{
// Arrange - Create existing package structure
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand All @@ -231,7 +231,7 @@ public async Task EnsureBuildToolsAsync_WithForceLatest_ShouldAttemptReinstallat
public async Task EnsureBuildToolAvailableAsync_WithExistingTool_ReturnsToolPath()
{
// Arrange - Create package structure with a tool
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand All @@ -250,7 +250,7 @@ public async Task EnsureBuildToolAvailableAsync_WithExistingTool_ReturnsToolPath
public async Task EnsureBuildToolAvailableAsync_WithToolNameWithoutExtension_AddsExtensionAndReturnsPath()
{
// Arrange - Create package structure with a tool
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand Down Expand Up @@ -297,7 +297,7 @@ public async Task EnsureBuildToolAvailableAsync_WithNoExistingPackageAndInstallS
public async Task EnsureBuildToolAvailableAsync_WithNonExistentTool_ThrowsFileNotFoundException()
{
// Arrange - Create package structure but without the requested tool
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand Down Expand Up @@ -340,7 +340,7 @@ public async Task RunBuildToolAsync_WithNoExistingPackage_AutoInstallsAndRuns()
public async Task RunBuildToolAsync_WithExistingTool_RunsDirectly()
{
// Arrange - Create package structure with a working batch file
var packagesDir = Path.Combine(_testGlobalDirectory.FullName, "packages");
var packagesDir = Path.Combine(_testCacheDirectory.FullName, "packages");
var buildToolsPackageDir = Path.Combine(packagesDir, "Microsoft.Windows.SDK.BuildTools.10.0.26100.1");
var binDir = Path.Combine(buildToolsPackageDir, "bin", "10.0.26100.0", "x64");
Directory.CreateDirectory(binDir);
Expand Down
5 changes: 5 additions & 0 deletions src/winapp-CLI/WinApp.Cli.Tests/SignCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
namespace WinApp.Cli.Tests;

[TestClass]
[DoNotParallelize] // Locally sometimes ExportCertificateFromStore fails with:
// Initialization method WinApp.Cli.Tests.SignCommandTests.Setup threw exception.
// System.InvalidOperationException: Failed to export certificate from store: No valid certificate
// found in store with subject: CN=WinappTestPublisher ---> System.InvalidOperationException:
// No valid certificate found in store with subject: CN=WinappTestPublisher.
public class SignCommandTests : BaseCommandTests
{
private FileInfo _testExecutablePath = null!;
Expand Down
30 changes: 21 additions & 9 deletions src/winapp-CLI/WinApp.Cli.Tests/WinappDirectoryServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void GetGlobalWinappDirectory_WithoutOverride_ReturnsDefaultDirectory()
var result = directoryService.GetGlobalWinappDirectory();

// Assert
var expectedDefaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".winappglobal");
var expectedDefaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".winapp");
Assert.AreEqual(expectedDefaultPath, result.FullName);
}

Expand Down Expand Up @@ -170,25 +170,37 @@ public void GetLocalWinappDirectory_WithNullBaseDirectory_UsesCurrentDirectory()
}

[TestMethod]
public void GetLocalWinappDirectory_WhenLocalAndGlobalAreSame_ReturnsLocalWinappDirectory()
public void GetLocalWinappDirectory_WhenGlobalIsInParentDir_DontReturnGlobalAsLocal()
{
// Directory structure:
// topDir/
// .winapp/ <- expected result - should find this one
// appDir/
// .winapp/ <- global (set as cache dir) - should skip
// winapp.yaml
// subdir/ <- search from here

// Arrange - Create a .winapp directory and winapp.yaml in the same location
var localWinappDir = _tempDirectory.CreateSubdirectory(".winapp");
var winappYamlPath = Path.Combine(_tempDirectory.FullName, "winapp.yaml");
var topDir = _tempDirectory.CreateSubdirectory("topDir");
var topWinAppDir = topDir.CreateSubdirectory(".winapp");

var appDir = topDir.CreateSubdirectory("appDir");
var localWinappDir = appDir.CreateSubdirectory(".winapp");
var winappYamlPath = Path.Combine(appDir.FullName, "winapp.yaml");
File.WriteAllText(winappYamlPath, "# test winapp.yaml");

// Set the global directory to be the same as the local directory
// Set the appDir/.winapp as the global cache directory
var directoryService = GetRequiredService<IWinappDirectoryService>();
directoryService.SetCacheDirectoryForTesting(localWinappDir);

// Create a subdirectory to search from (so we test walking up the tree)
var subDir = _tempDirectory.CreateSubdirectory("subdir");
var subDir = appDir.CreateSubdirectory("subdir");

// Act - Search for local .winapp from subdirectory
var result = directoryService.GetLocalWinappDirectory(subDir);

// Assert - Should find the local .winapp (which is also the global one) because winapp.yaml exists
Assert.AreEqual(localWinappDir.FullName, result.FullName,
"Should return the .winapp directory when winapp.yaml exists, even if it's also the global directory");
// Assert - Should find the topDir .winapp because we skip the appDir/.winapp since it's set as global cache dir
Assert.AreEqual(topWinAppDir.FullName, result.FullName,
"Should return the top .winapp directory when local and global are the same");
}
}
11 changes: 5 additions & 6 deletions src/winapp-CLI/WinApp.Cli/Commands/GetWinappPathCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ static GetWinappPathCommand()
{
GlobalOption = new Option<bool>("--global")
{
Description = "Get the global .winappglobal directory instead of local .winapp"
Description = "Get the global .winapp directory instead of local"
};
}

public GetWinappPathCommand() : base("get-winapp-path", "Get the path to the .winapp directory (local) or .winappglobal directory (global)")
public GetWinappPathCommand() : base("get-winapp-path", "Get the path to the .winapp directory (local by default, global with --global)")
{
Options.Add(GlobalOption);
}
Expand All @@ -39,7 +39,7 @@ public override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken

if (global)
{
// Get the global .winappglobal directory
// Get the global .winapp directory
winappDir = winappDirectoryService.GetGlobalWinappDirectory();
directoryType = "Global";
}
Expand All @@ -53,7 +53,7 @@ public override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken
// For global directories, check if they exist
if (global && !winappDir.Exists)
{
logger.LogError("{UISymbol} {DirectoryType} .winappglobal directory not found: {WinappDir}", UiSymbols.Error, directoryType, winappDir);
logger.LogError("{UISymbol} {DirectoryType} .winapp directory not found: {WinappDir}", UiSymbols.Error, directoryType, winappDir);
logger.LogError(" Make sure to run 'winapp init' first");
return Task.FromResult(1);
}
Expand All @@ -62,8 +62,7 @@ public override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken
logger.LogInformation("{WinappDir}", winappDir);

var status = winappDir.Exists ? "exists" : "does not exist";
var dirName = global ? ".winappglobal" : ".winapp";
logger.LogDebug("{UISymbol} {DirectoryType} {DirName} directory: {WinappDir} ({Status})", UiSymbols.Folder, directoryType, dirName, winappDir, status);
logger.LogDebug("{UISymbol} {DirectoryType} .winapp directory: {WinappDir} ({Status})", UiSymbols.Folder, directoryType, winappDir, status);

return Task.FromResult(0);
}
Expand Down
24 changes: 11 additions & 13 deletions src/winapp-CLI/WinApp.Cli/Services/WinappDirectoryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,29 @@ public DirectoryInfo GetGlobalWinappDirectory()
}

var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var winappDir = Path.Combine(userProfile, ".winappglobal");
var winappDir = Path.Combine(userProfile, ".winapp");
return new DirectoryInfo(winappDir);
}

public DirectoryInfo GetLocalWinappDirectory(DirectoryInfo? baseDirectory = null)
{
baseDirectory ??= new DirectoryInfo(currentDirectoryProvider.GetCurrentDirectory());

DirectoryInfo globalWinappDirectory = GetGlobalWinappDirectory();

var originalBaseDir = new DirectoryInfo(baseDirectory.FullName);
var dir = originalBaseDir;
while (dir != null)
{
var winappDirectory = Path.Combine(dir.FullName, ".winapp");
if (Directory.Exists(winappDirectory))
if (Directory.Exists(winappDirectory))
{
// Does this dir have a "packages" subdirectory? If so, it's probably the old global dir
bool hasPackagesSubdir = Directory.Exists(Path.Combine(winappDirectory, "packages"));
if (hasPackagesSubdir)
bool isGlobalWinAppDir =
string.Equals(winappDirectory, globalWinappDirectory.FullName, StringComparison.OrdinalIgnoreCase);
if (isGlobalWinAppDir)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(
$"Warning: Found .winapp folder in UserProfile directory: {winappDirectory}. " +
"The global winapp folder is now named .winappglobal. " +
"Please remove the .winapp folder from your UserProfile directory or rename to .winappglobal.");
Console.ResetColor();
// We don't currently allow the global winapp directory to be used as a local winapp directory,
// so continue searching upwards.
}
else
{
Expand All @@ -70,5 +68,5 @@ public DirectoryInfo GetLocalWinappDirectory(DirectoryInfo? baseDirectory = null
}

return new DirectoryInfo(Path.Combine(originalBaseDir.FullName, ".winapp"));
}
}
}
}
6 changes: 3 additions & 3 deletions src/winapp-npm/winapp-path-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ function getWinappPath(isGlobal = false) {
}

/**
* Get the path to the global .winappglobal directory
* @returns {string} The full path to the global .winappglobal directory
* @throws {Error} If the global .winappglobal directory is not found
* Get the path to the global .winapp directory
* @returns {string} The full path to the global .winapp directory
* @throws {Error} If the global .winapp directory is not found
*/
function getGlobalWinappPath() {
return getWinappPath(true);
Expand Down