diff --git a/packaging/deb/postinst b/packaging/deb/postinst
index f92c16afa..3ef09330a 100755
--- a/packaging/deb/postinst
+++ b/packaging/deb/postinst
@@ -2,7 +2,7 @@
echo "This software may collect information about you and your use of the software, and send that to Microsoft."
echo "Please visit http://aka.ms/dotnet-cli-eula for more information."
-# Run 'dotnet new' as the user to trigger the first time experience to initialize the cache
+# Run 'dotnet new' to trigger the first time experience to initialize the cache
echo "Welcome to .NET Core!
---------------------
Learn more about .NET Core @ https://aka.ms/dotnet-docs. Use dotnet --help to see available commands or go to https://aka.ms/dotnet-cli-docs.
@@ -15,4 +15,4 @@ The data collected is anonymous and will be published in an aggregated form for
The .NET Core Tools telemetry feature is enabled by default. You can opt-out of the telemetry feature by setting an environment variable DOTNET_CLI_TELEMETRY_OPTOUT (for example, 'export' on macOS/Linux, 'set' on Windows) to true (for example, 'true', 1). You can read more about .NET Core tools telemetry at https://aka.ms/dotnet-cli-telemetry."
-su - $SUDO_USER -c "dotnet new > /dev/null 2>&1 || true"
+dotnet new > /dev/null 2>&1 || true
diff --git a/packaging/osx/clisdk/scripts/postinstall b/packaging/osx/clisdk/scripts/postinstall
index 54ea36c0d..4d69748e9 100755
--- a/packaging/osx/clisdk/scripts/postinstall
+++ b/packaging/osx/clisdk/scripts/postinstall
@@ -11,8 +11,7 @@ INSTALL_DESTINATION=$2
# A temporary fix for the permissions issue(s)
chmod -R 755 $INSTALL_DESTINATION
-# Run 'dotnet new' as user to trigger the first time experience to initialize the cache
-INSTALLER_USER=$(stat -f '%Su' $HOME)
-su - $INSTALLER_USER -c "$INSTALL_DESTINATION/dotnet new > /dev/null 2>&1 || true"
+# Run 'dotnet new' to trigger the first time experience to initialize the cache
+$INSTALL_DESTINATION/dotnet new > /dev/null 2>&1 || true
exit 0
diff --git a/src/Microsoft.DotNet.Configurer/CliFallbackFolderPathCalculator.cs b/src/Microsoft.DotNet.Configurer/CliFallbackFolderPathCalculator.cs
index 354d23ab4..8dece0fb7 100644
--- a/src/Microsoft.DotNet.Configurer/CliFallbackFolderPathCalculator.cs
+++ b/src/Microsoft.DotNet.Configurer/CliFallbackFolderPathCalculator.cs
@@ -12,16 +12,9 @@ namespace Microsoft.DotNet.Configurer
{
public class CliFallbackFolderPathCalculator
{
- public string CliFallbackFolderPath
- {
- get
- {
- string profileDir = Environment.GetEnvironmentVariable(
- RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "USERPROFILE" : "HOME");
-
- return Path.Combine(profileDir, ".dotnet", "NuGetFallbackFolder");
- }
- }
+ public string CliFallbackFolderPath =>
+ Environment.GetEnvironmentVariable("DOTNET_CLI_TEST_FALLBACKFOLDER") ??
+ Path.Combine(new DirectoryInfo(AppContext.BaseDirectory).Parent.FullName, "NuGetFallbackFolder");
public string NuGetUserSettingsDirectory =>
NuGetEnvironment.GetFolderPath(NuGetFolderPath.UserSettingsDirectory);
diff --git a/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs b/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs
index b2d6f4fd4..836462da3 100644
--- a/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs
+++ b/src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs
@@ -14,19 +14,22 @@ namespace Microsoft.DotNet.Configurer
private INuGetCachePrimer _nugetCachePrimer;
private INuGetCacheSentinel _nugetCacheSentinel;
private IFirstTimeUseNoticeSentinel _firstTimeUseNoticeSentinel;
+ private string _cliFallbackFolderPath;
public DotnetFirstTimeUseConfigurer(
INuGetCachePrimer nugetCachePrimer,
INuGetCacheSentinel nugetCacheSentinel,
IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel,
IEnvironmentProvider environmentProvider,
- IReporter reporter)
+ IReporter reporter,
+ string cliFallbackFolderPath)
{
_nugetCachePrimer = nugetCachePrimer;
_nugetCacheSentinel = nugetCacheSentinel;
_firstTimeUseNoticeSentinel = firstTimeUseNoticeSentinel;
_environmentProvider = environmentProvider;
_reporter = reporter;
+ _cliFallbackFolderPath = cliFallbackFolderPath;
}
public void Configure()
@@ -41,6 +44,10 @@ namespace Microsoft.DotNet.Configurer
PrintNugetCachePrimeMessage();
_nugetCachePrimer.PrimeCache();
}
+ else if (_nugetCacheSentinel.UnauthorizedAccess)
+ {
+ PrintUnauthorizedAccessMessage();
+ }
}
private bool ShouldPrintFirstTimeUseNotice()
@@ -55,14 +62,20 @@ namespace Microsoft.DotNet.Configurer
private void PrintFirstTimeUseNotice()
{
- string firstTimeUseWelcomeMessage = LocalizableStrings.FirstTimeWelcomeMessage;
-
_reporter.WriteLine();
- _reporter.WriteLine(firstTimeUseWelcomeMessage);
+ _reporter.WriteLine(LocalizableStrings.FirstTimeWelcomeMessage);
_firstTimeUseNoticeSentinel.CreateIfNotExists();
}
+ private void PrintUnauthorizedAccessMessage()
+ {
+ _reporter.WriteLine();
+ _reporter.WriteLine(string.Format(
+ LocalizableStrings.UnauthorizedAccessMessage,
+ _cliFallbackFolderPath));
+ }
+
private bool ShouldPrimeNugetCache()
{
return ShouldRunFirstRunExperience() &&
diff --git a/src/Microsoft.DotNet.Configurer/INuGetCacheSentinel.cs b/src/Microsoft.DotNet.Configurer/INuGetCacheSentinel.cs
index 0eaa8d91d..9564145e8 100644
--- a/src/Microsoft.DotNet.Configurer/INuGetCacheSentinel.cs
+++ b/src/Microsoft.DotNet.Configurer/INuGetCacheSentinel.cs
@@ -12,5 +12,7 @@ namespace Microsoft.DotNet.Configurer
bool Exists();
void CreateIfNotExists();
+
+ bool UnauthorizedAccess { get; }
}
}
diff --git a/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx b/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx
index 3a7ee20e6..57a874b2f 100644
--- a/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx
+++ b/src/Microsoft.DotNet.Configurer/LocalizableStrings.resx
@@ -136,4 +136,14 @@ A command is running to initially populate your local package cache, to improve
Failed to prime the NuGet cache. {0} failed with: {1}
+
+ Permission denied to modify the '{0}' folder.
+
+Here are some options to fix this error:
+---------------------
+1. Re-run this command with elevated access.
+2. Disabled the first run experience by setting the environment variable DOTNET_SKIP_FIRST_TIME_EXPERIENCE to true.
+3. Copy the .NET Core SDK to a non-protected location and use it from there.";
+
+
diff --git a/src/Microsoft.DotNet.Configurer/NuGetCachePrimer.cs b/src/Microsoft.DotNet.Configurer/NuGetCachePrimer.cs
index e69a4f96d..669d3be0d 100644
--- a/src/Microsoft.DotNet.Configurer/NuGetCachePrimer.cs
+++ b/src/Microsoft.DotNet.Configurer/NuGetCachePrimer.cs
@@ -61,10 +61,10 @@ namespace Microsoft.DotNet.Configurer
var nuGetFallbackFolder = _cliFallbackFolderPathCalculator.CliFallbackFolderPath;
- _nuGetConfig.AddCliFallbackFolder(nuGetFallbackFolder);
-
_nugetPackagesArchiver.ExtractArchive(nuGetFallbackFolder);
+ _nuGetConfig.AddCliFallbackFolder(nuGetFallbackFolder);
+
_nuGetCacheSentinel.CreateIfNotExists();
}
diff --git a/src/Microsoft.DotNet.Configurer/NuGetCacheSentinel.cs b/src/Microsoft.DotNet.Configurer/NuGetCacheSentinel.cs
index fccb50c1e..def087615 100644
--- a/src/Microsoft.DotNet.Configurer/NuGetCacheSentinel.cs
+++ b/src/Microsoft.DotNet.Configurer/NuGetCacheSentinel.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System;
using System.IO;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.EnvironmentAbstractions;
@@ -13,8 +14,12 @@ namespace Microsoft.DotNet.Configurer
public static readonly string SENTINEL = $"{Product.Version}.dotnetSentinel";
public static readonly string INPROGRESS_SENTINEL = $"{Product.Version}.inprogress.dotnetSentinel";
+ public bool UnauthorizedAccess { get; private set; }
+
private readonly IFile _file;
+ private readonly IDirectory _directory;
+
private string _nugetCachePath;
private string SentinelPath => Path.Combine(_nugetCachePath, SENTINEL);
@@ -23,14 +28,17 @@ namespace Microsoft.DotNet.Configurer
private Stream InProgressSentinel { get; set; }
public NuGetCacheSentinel(CliFallbackFolderPathCalculator cliFallbackFolderPathCalculator) :
- this(cliFallbackFolderPathCalculator.CliFallbackFolderPath, FileSystemWrapper.Default.File)
+ this(cliFallbackFolderPathCalculator.CliFallbackFolderPath,
+ FileSystemWrapper.Default.File,
+ FileSystemWrapper.Default.Directory)
{
}
- internal NuGetCacheSentinel(string nugetCachePath, IFile file)
+ internal NuGetCacheSentinel(string nugetCachePath, IFile file, IDirectory directory)
{
- _file = file;
_nugetCachePath = nugetCachePath;
+ _file = file;
+ _directory = directory;
SetInProgressSentinel();
}
@@ -62,9 +70,9 @@ namespace Microsoft.DotNet.Configurer
{
try
{
- if (!Directory.Exists(_nugetCachePath))
+ if (!_directory.Exists(_nugetCachePath))
{
- Directory.CreateDirectory(_nugetCachePath);
+ _directory.CreateDirectory(_nugetCachePath);
}
// open an exclusive handle to the in-progress sentinel and mark it for delete on close.
@@ -80,6 +88,10 @@ namespace Microsoft.DotNet.Configurer
1,
FileOptions.DeleteOnClose);
}
+ catch (UnauthorizedAccessException)
+ {
+ UnauthorizedAccess = true;
+ }
catch { }
}
diff --git a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.xlf b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.xlf
index 45687abde..64e3c6463 100644
--- a/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.xlf
+++ b/src/Microsoft.DotNet.Configurer/xlf/LocalizableStrings.xlf
@@ -25,4 +25,4 @@ A command is running to initially populate your local package cache, to improve