В Linux отключена попытка применить переменные
This commit is contained in:
@@ -77,8 +77,7 @@ dotnet run --project src/Sms.TaskTwo.Avalonia/Sms.TaskTwo.Avalonia.csproj
|
|||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
- Запись в `~/.config/environment.d/` (systemd `KEY=value`).
|
- Запись в `~/.config/environment.d/` (systemd `KEY=value`).
|
||||||
- **Применить к сессии** (`ReloadEnvironment`): текущий процесс, `systemctl --user set-environment`, при наличии — `dbus-update-environment`.
|
- **Применить к сессии** не поддерживается: переменные подхватываются после перезапуска login-сессии.
|
||||||
- Новые login-сессии могут потребовать перелогин — ограничение systemd.
|
|
||||||
|
|
||||||
## Предположения (ТЗ)
|
## Предположения (ТЗ)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using Sms.Environment;
|
using Sms.Environment;
|
||||||
|
|
||||||
namespace Sms.Environment.Linux;
|
namespace Sms.Environment.Linux;
|
||||||
@@ -6,7 +5,6 @@ namespace Sms.Environment.Linux;
|
|||||||
public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||||
{
|
{
|
||||||
private const string ManagedFileName = "99-sms-task-two.conf";
|
private const string ManagedFileName = "99-sms-task-two.conf";
|
||||||
private const int SystemctlBatchSize = 32;
|
|
||||||
|
|
||||||
private readonly string _managedFilePath;
|
private readonly string _managedFilePath;
|
||||||
private readonly string _environmentDirectory;
|
private readonly string _environmentDirectory;
|
||||||
@@ -121,7 +119,6 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
|||||||
}
|
}
|
||||||
|
|
||||||
System.Environment.SetEnvironmentVariable(name, null);
|
System.Environment.SetEnvironmentVariable(name, null);
|
||||||
TryRunSystemctl(["--user", "unset-environment", name], out _);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (ex is UnauthorizedAccessException or IOException)
|
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();
|
Success = false,
|
||||||
ApplyToCurrentProcess(variables);
|
Message =
|
||||||
|
"Применение переменных к сессии в Linux не поддерживается. " +
|
||||||
if (variables.Count == 0)
|
"Значения сохраняются в ~/.config/environment.d/ и подхватываются после перезапуска login-сессии.",
|
||||||
{
|
|
||||||
return new EnvironmentReloadResult
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Message = "Пользовательских переменных для применения нет.",
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
private Dictionary<string, string> LoadManagedFile()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user