diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs index 1018cbe34..2f0b35185 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs @@ -1,9 +1,12 @@ using System; +using System.IO; +using System.Linq; using System.Security.AccessControl; using System.Security.Principal; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Exceptions; +using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation; namespace NzbDrone.Common.EnvironmentInfo @@ -16,13 +19,20 @@ namespace NzbDrone.Common.EnvironmentInfo public class AppFolderFactory : IAppFolderFactory { private readonly IAppFolderInfo _appFolderInfo; + private readonly IStartupContext _startupContext; private readonly IDiskProvider _diskProvider; + private readonly IDiskTransferService _diskTransferService; private readonly Logger _logger; - public AppFolderFactory(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider) + public AppFolderFactory(IAppFolderInfo appFolderInfo, + IStartupContext startupContext, + IDiskProvider diskProvider, + IDiskTransferService diskTransferService) { _appFolderInfo = appFolderInfo; + _startupContext = startupContext; _diskProvider = diskProvider; + _diskTransferService = diskTransferService; _logger = NzbDroneLogger.GetLogger(this); } @@ -30,6 +40,7 @@ namespace NzbDrone.Common.EnvironmentInfo { try { + MigrateAppDataFolder(); _diskProvider.EnsureFolder(_appFolderInfo.AppDataFolder); } catch (UnauthorizedAccessException) @@ -60,5 +71,74 @@ namespace NzbDrone.Common.EnvironmentInfo _logger.Warn(ex, "Coudn't set app folder permission"); } } + + private void MigrateAppDataFolder() + { + try + { + var oldDbFile = Path.Combine(_appFolderInfo.AppDataFolder, "nzbdrone.db"); + + if (_startupContext.Args.ContainsKey(StartupContext.APPDATA)) + { + if (_diskProvider.FileExists(_appFolderInfo.GetDatabase())) return; + if (!_diskProvider.FileExists(oldDbFile)) return; + + _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase()); + CleanupSqLiteRollbackFiles(); + RemovePidFile(); + } + + if (_appFolderInfo.LegacyAppDataFolder.IsNullOrWhiteSpace()) return; + if (_diskProvider.FileExists(_appFolderInfo.GetDatabase()) || _diskProvider.FileExists(_appFolderInfo.GetConfigPath())) return; + if (!_diskProvider.FolderExists(_appFolderInfo.LegacyAppDataFolder)) return; + + // Delete the bin folder on Windows + var binFolder = Path.Combine(_appFolderInfo.LegacyAppDataFolder, "bin"); + + if (OsInfo.IsWindows && _diskProvider.FolderExists(binFolder)) + { + _diskProvider.DeleteFolder(binFolder, true); + } + + // Transfer other files and folders (with copy so a backup is maintained) + _diskTransferService.TransferFolder(_appFolderInfo.LegacyAppDataFolder, _appFolderInfo.AppDataFolder, TransferMode.Copy); + + // Rename the DB file + if (_diskProvider.FileExists(oldDbFile)) + { + _diskProvider.MoveFile(oldDbFile, _appFolderInfo.GetDatabase()); + } + + // Remove SQLite rollback files + CleanupSqLiteRollbackFiles(); + + // Remove Old PID file + RemovePidFile(); + + // Delete the old files after everything has been copied + _diskProvider.DeleteFolder(_appFolderInfo.LegacyAppDataFolder, true); + } + catch (Exception ex) + { + _logger.Debug(ex, ex.Message); + throw new SonarrStartupException("Unable to migrate AppData folder from {0} to {1}. Migrate manually", _appFolderInfo.LegacyAppDataFolder, _appFolderInfo.AppDataFolder); + } + } + + private void CleanupSqLiteRollbackFiles() + { + _diskProvider.GetFiles(_appFolderInfo.AppDataFolder, SearchOption.TopDirectoryOnly) + .Where(f => Path.GetFileName(f).StartsWith("nzbdrone.db")) + .ToList() + .ForEach(_diskProvider.DeleteFile); + } + + private void RemovePidFile() + { + if (OsInfo.IsNotWindows) + { + _diskProvider.DeleteFile(Path.Combine(_appFolderInfo.AppDataFolder, "sonarr.pid")); + } + } } } diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs index b93d9f870..331c7ee25 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Reflection; using NLog; @@ -9,6 +9,7 @@ namespace NzbDrone.Common.EnvironmentInfo public interface IAppFolderInfo { string AppDataFolder { get; } + string LegacyAppDataFolder { get; } string TempFolder { get; } string StartUpFolder { get; } } @@ -17,7 +18,6 @@ namespace NzbDrone.Common.EnvironmentInfo { private readonly Environment.SpecialFolder DATA_SPECIAL_FOLDER = Environment.SpecialFolder.CommonApplicationData; - private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(AppFolderInfo)); public AppFolderInfo(IStartupContext startupContext) @@ -34,7 +34,8 @@ namespace NzbDrone.Common.EnvironmentInfo } else { - AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "NzbDrone"); + AppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "Sonarr"); + LegacyAppDataFolder = Path.Combine(Environment.GetFolderPath(DATA_SPECIAL_FOLDER, Environment.SpecialFolderOption.None), "NzbDrone"); } StartUpFolder = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName; @@ -42,9 +43,8 @@ namespace NzbDrone.Common.EnvironmentInfo } public string AppDataFolder { get; } - + public string LegacyAppDataFolder { get; } public string StartUpFolder { get; } - public string TempFolder { get; } } -} \ No newline at end of file +}