mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add backup settings for the Hosts File Editor to allow users to customize the existing hardcoded logic. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] **Closes:** #37666 - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [x] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: https://github.com/MicrosoftDocs/windows-dev-docs/pull/5342 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <img width="707" alt="image" src="https://github.com/user-attachments/assets/e114431e-60e0-4b8c-bba7-df23f7af0182" /> <img width="707" alt="image" src="https://github.com/user-attachments/assets/a02b591e-eb46-4964-bee7-548ec175b3aa" /> <img width="707" alt="image" src="https://github.com/user-attachments/assets/6eb0ff21-74fa-4229-8832-df2df877b5cd" /> <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed - Backup on: verified that backup isn't executed - Backups off: Verified that only one backup is executed - Verified that backup is located in the expected path - Auto delete is set to "never": verified that no backups are deleted - Auto delete is set to "based on count": verified that backups are deleted according to count value - Auto delete is set to "based on age and count": verified that backups are deleted according to days and count values - Verified that files without the backup pattern aren't deleted - There is also adequate test coverage for these scenarios 🚀 --------- Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
113 lines
3.4 KiB
C#
113 lines
3.4 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO.Abstractions;
|
|
using System.Linq;
|
|
using HostsUILib.Settings;
|
|
|
|
namespace HostsUILib.Helpers
|
|
{
|
|
public class BackupManager : IBackupManager
|
|
{
|
|
private const string BackupSuffix = "_PowerToysBackup_";
|
|
private readonly IFileSystem _fileSystem;
|
|
private readonly IUserSettings _userSettings;
|
|
private bool _backupDone;
|
|
|
|
public BackupManager(IFileSystem fileSystem, IUserSettings userSettings)
|
|
{
|
|
_fileSystem = fileSystem;
|
|
_userSettings = userSettings;
|
|
}
|
|
|
|
public void Create(string hostsFilePath)
|
|
{
|
|
if (_backupDone || !_userSettings.BackupHosts || !_fileSystem.File.Exists(hostsFilePath))
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (!_fileSystem.Directory.Exists(_userSettings.BackupPath))
|
|
{
|
|
_fileSystem.Directory.CreateDirectory(_userSettings.BackupPath);
|
|
}
|
|
|
|
var backupPath = _fileSystem.Path.Combine(_userSettings.BackupPath, $"hosts{BackupSuffix}{DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture)}");
|
|
|
|
_fileSystem.File.Copy(hostsFilePath, backupPath);
|
|
_backupDone = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LoggerInstance.Logger.LogError("Backup failed", ex);
|
|
}
|
|
}
|
|
|
|
public void Delete()
|
|
{
|
|
switch (_userSettings.DeleteBackupsMode)
|
|
{
|
|
case HostsDeleteBackupMode.Count:
|
|
DeleteByCount(_userSettings.DeleteBackupsCount);
|
|
break;
|
|
case HostsDeleteBackupMode.Age:
|
|
DeleteByAge(_userSettings.DeleteBackupsDays, _userSettings.DeleteBackupsCount);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void DeleteByCount(int count)
|
|
{
|
|
if (count < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var backups = GetAll().OrderByDescending(f => f.CreationTime).Skip(count).ToArray();
|
|
DeleteAll(backups);
|
|
}
|
|
|
|
public void DeleteByAge(int days, int count)
|
|
{
|
|
if (days < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var backupsEnumerable = GetAll();
|
|
|
|
if (count > 0)
|
|
{
|
|
backupsEnumerable = backupsEnumerable.OrderByDescending(f => f.CreationTime).Skip(count);
|
|
}
|
|
|
|
var backups = backupsEnumerable.Where(f => f.CreationTime < DateTime.Now.AddDays(-days)).ToArray();
|
|
DeleteAll(backups);
|
|
}
|
|
|
|
private IEnumerable<IFileInfo> GetAll()
|
|
{
|
|
if (!_fileSystem.Directory.Exists(_userSettings.BackupPath))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return _fileSystem.Directory.GetFiles(_userSettings.BackupPath, $"*{BackupSuffix}*").Select(_fileSystem.FileInfo.New);
|
|
}
|
|
|
|
private void DeleteAll(IFileInfo[] files)
|
|
{
|
|
foreach (var f in files)
|
|
{
|
|
_fileSystem.File.Delete(f.FullName);
|
|
}
|
|
}
|
|
}
|
|
}
|