-
Notifications
You must be signed in to change notification settings - Fork 253
Description
Did you search for prior issues before submitting a new issue?
Yes:
- None of the existing issues matching "appdata" were relevant.
- Ditto for "roaming".
- This particular issue was almost touched-on in Do we need to write logs to
~/.azcopydirectory? #221 - though that issue is now closed.
Which version of the AzCopy was used?
Note: The version is visible when running AzCopy without any argument
v10.16.2
Which platform are you using? (ex: Windows, Mac, Linux)
Windows 10, Windows 11
What command did you run?
(Any command)
What problem was encountered?
- AzCopy uses
C:\Users\Me\.azcopy\for its local-only data.- ...which gets copied around the network when Roaming Profiles are enabled. Not good.
- Using the user-profile root means seldom-used directories start to pile-up in the navigation sidebar.
- This behaviour violates Microsoft's own guidelines and requirements for software targeting Windows:
- I'll divert your attention towards the Windows 10 Certification requirements for Windows Desktop Apps (emphasis mine):
-
Your app’s data that is exclusive to a specific user and that is not to be shared with other users of the computer, must be stored in
Users\<username>\AppData
- Finally, the comments in
init_windows.goandplatdiff_windows.godescribe using "local appdata" even though this is presently not the case:
azure-storage-azcopy/testSuite/cmd/platdiff_windows.go
Lines 10 to 13 in ffcdb9e
| // GetAzCopyAppPath returns the path of Azcopy in local appdata. | |
| func GetAzCopyAppPath() string { | |
| userProfile := common.GetEnvironmentVariable(common.EEnvironmentVariable.UserDir()) | |
| azcopyAppDataFolder := path.Join(userProfile, ".azcopy") |
azure-storage-azcopy/common/init_windows.go
Lines 28 to 31 in ffcdb9e
| // getAzCopyAppPath returns the path of Azcopy in local appdata. | |
| func getAzCopyAppPath() string { | |
| userProfile := GetEnvironmentVariable(EEnvironmentVariable.UserDir()) | |
| azcopyAppDataFolder := strings.ReplaceAll(path.Join(userProfile, ".azcopy"), "/", `\`) |
How can we reproduce the problem in the simplest way?
Just use azcopy as normal.
Have you found a mitigation/solution?
Yes:
-
In
common/environment.goaddLocalDataDir()which usesLOCALAPPDATAon Windows:func (EnvironmentVariable) LocalDataDir() EnvironmentVariable { // Only used internally, not listed in the environment variables. return EnvironmentVariable{ Name: Iff(runtime.GOOS == "windows", "LOCALAPPDATA", "HOME"), } }
-
In
common/init_windows.go, useLocalDataDirinstead ofUserDir:// getAzCopyAppPath returns the path of Azcopy in local AppData. // e.g. C:\Users\billg\AppData\Local\AzCopy func getAzCopyAppPath() string { localAppData := GetEnvironmentVariable(EEnvironmentVariable.LocalDataDir()) azcopyLocalAppDataFolder := strings.ReplaceAll(path.Join(localAppData , "AzCopy"), "/", `\`) return azcopyLocalAppDataFolder }
-
However, it does make sense to continue using
.azcopyif it's already in use, so an alternative approach might be:// getAzCopyAppPath returns the path of Azcopy in local AppData. // e.g. C:\Users\billg\AppData\Local\AzCopy func getAzCopyAppPath() string { userProfile := GetEnvironmentVariable(EEnvironmentVariable.UserDir()) userProfileDotAzCopy := strings.ReplaceAll(path.Join(userProfile, ".azcopy"), "/", `\`) if err := os.Mkdir(azcopyAppDataFolder, os.ModeDir); err != nil { if os.IsExist(err) { return userProfileDotAzCopy } } localAppData := GetEnvironmentVariable(EEnvironmentVariable.LocalDataDir()) azcopyLocalAppDataFolder := strings.ReplaceAll(path.Join(localAppData , "AzCopy"), "/", `\`) return azcopyLocalAppDataFolder }
-
-
In
platdiff_windows.go, similarly useLocalDataDirinstead ofUserDir:// GetAzCopyAppPath returns the path of AzCopy in local appdata // e.g. C:\Users\billg\AppData\Local\AzCopy func GetAzCopyAppPath() string { localAppData := common.GetEnvironmentVariable(common.EEnvironmentVariable.LocalDataDir()) azcopyLocalAppDataFolder := path.Join(localAppData , "AzCopy") if err := os.Mkdir(azcopyAppDataFolder, os.ModeDir); err != nil && !os.IsExist(err) { return "" } return azcopyAppDataFolder }
I'm happy to submit this as a PR if everyone's happy with it.