В Linux отключена попытка применить переменные
This commit is contained in:
@@ -77,8 +77,7 @@ dotnet run --project src/Sms.TaskTwo.Avalonia/Sms.TaskTwo.Avalonia.csproj
|
||||
### Linux
|
||||
|
||||
- Запись в `~/.config/environment.d/` (systemd `KEY=value`).
|
||||
- **Применить к сессии** (`ReloadEnvironment`): текущий процесс, `systemctl --user set-environment`, при наличии — `dbus-update-environment`.
|
||||
- Новые login-сессии могут потребовать перелогин — ограничение systemd.
|
||||
- **Применить к сессии** не поддерживается: переменные подхватываются после перезапуска login-сессии.
|
||||
|
||||
## Предположения (ТЗ)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics;
|
||||
using Sms.Environment;
|
||||
|
||||
namespace Sms.Environment.Linux;
|
||||
@@ -6,7 +5,6 @@ namespace Sms.Environment.Linux;
|
||||
public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
{
|
||||
private const string ManagedFileName = "99-sms-task-two.conf";
|
||||
private const int SystemctlBatchSize = 32;
|
||||
|
||||
private readonly string _managedFilePath;
|
||||
private readonly string _environmentDirectory;
|
||||
@@ -121,7 +119,6 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
}
|
||||
|
||||
System.Environment.SetEnvironmentVariable(name, null);
|
||||
TryRunSystemctl(["--user", "unset-environment", name], out _);
|
||||
}
|
||||
catch (Exception ex) when (ex is UnauthorizedAccessException or IOException)
|
||||
{
|
||||
@@ -131,141 +128,14 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
}
|
||||
}
|
||||
|
||||
public EnvironmentReloadResult ReloadEnvironment()
|
||||
public EnvironmentReloadResult ReloadEnvironment() =>
|
||||
new()
|
||||
{
|
||||
var variables = GetUserPersistedEnvironment();
|
||||
ApplyToCurrentProcess(variables);
|
||||
|
||||
if (variables.Count == 0)
|
||||
{
|
||||
return new EnvironmentReloadResult
|
||||
{
|
||||
Success = true,
|
||||
Message = "Пользовательских переменных для применения нет.",
|
||||
Success = false,
|
||||
Message =
|
||||
"Применение переменных к сессии в Linux не поддерживается. " +
|
||||
"Значения сохраняются в ~/.config/environment.d/ и подхватываются после перезапуска login-сессии.",
|
||||
};
|
||||
}
|
||||
|
||||
var messages = new List<string>();
|
||||
if (TryApplyViaSystemctl(variables, out var systemctlError))
|
||||
{
|
||||
messages.Add("systemd user manager обновлён (systemctl --user set-environment).");
|
||||
}
|
||||
else if (systemctlError is not null)
|
||||
{
|
||||
messages.Add($"systemctl: {systemctlError}");
|
||||
}
|
||||
|
||||
if (TryApplyViaDbusUpdateEnvironment(variables, out var dbusError))
|
||||
{
|
||||
messages.Add("D-Bus session обновлён (dbus-update-environment).");
|
||||
}
|
||||
else if (dbusError is not null)
|
||||
{
|
||||
messages.Add($"dbus-update-environment: {dbusError}");
|
||||
}
|
||||
|
||||
var processApplied = messages.Count > 0 || variables.Count > 0;
|
||||
return new EnvironmentReloadResult
|
||||
{
|
||||
Success = processApplied,
|
||||
Message = processApplied
|
||||
? $"Применено {variables.Count} переменных к текущему процессу. {string.Join(' ', messages)}"
|
||||
: "Не удалось применить переменные к сессии.",
|
||||
};
|
||||
}
|
||||
|
||||
private static void ApplyToCurrentProcess(IReadOnlyDictionary<string, string> variables)
|
||||
{
|
||||
foreach (var pair in variables)
|
||||
{
|
||||
System.Environment.SetEnvironmentVariable(pair.Key, pair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryApplyViaSystemctl(
|
||||
IReadOnlyDictionary<string, string> variables,
|
||||
out string? errorMessage)
|
||||
{
|
||||
errorMessage = null;
|
||||
var pairs = variables.ToList();
|
||||
for (var offset = 0; offset < pairs.Count; offset += SystemctlBatchSize)
|
||||
{
|
||||
var arguments = new List<string> { "--user", "set-environment" };
|
||||
foreach (var pair in pairs.Skip(offset).Take(SystemctlBatchSize))
|
||||
{
|
||||
arguments.Add($"{pair.Key}={pair.Value}");
|
||||
}
|
||||
|
||||
if (!TryRunSystemctl(arguments, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryApplyViaDbusUpdateEnvironment(
|
||||
IReadOnlyDictionary<string, string> variables,
|
||||
out string? errorMessage)
|
||||
{
|
||||
var arguments = new List<string>();
|
||||
foreach (var pair in variables)
|
||||
{
|
||||
arguments.Add($"{pair.Key}={pair.Value}");
|
||||
}
|
||||
|
||||
return TryRunCommand("dbus-update-environment", arguments, out errorMessage);
|
||||
}
|
||||
|
||||
private static bool TryRunSystemctl(IReadOnlyList<string> arguments, out string? errorMessage) =>
|
||||
TryRunCommand("systemctl", arguments, out errorMessage);
|
||||
|
||||
private static bool TryRunCommand(
|
||||
string fileName,
|
||||
IReadOnlyList<string> arguments,
|
||||
out string? errorMessage)
|
||||
{
|
||||
errorMessage = null;
|
||||
try
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
};
|
||||
foreach (var argument in arguments)
|
||||
{
|
||||
startInfo.ArgumentList.Add(argument);
|
||||
}
|
||||
|
||||
using var process = Process.Start(startInfo);
|
||||
if (process is null)
|
||||
{
|
||||
errorMessage = "не удалось запустить процесс";
|
||||
return false;
|
||||
}
|
||||
|
||||
var stderr = process.StandardError.ReadToEnd();
|
||||
process.WaitForExit(5000);
|
||||
if (process.ExitCode == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
errorMessage = string.IsNullOrWhiteSpace(stderr)
|
||||
? $"код выхода {process.ExitCode}"
|
||||
: stderr.Trim();
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, string> LoadManagedFile()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user