Skip to content

Commit b3d33df

Browse files
committed
Рефакторинг и фиксы ИИ-ревью
1 parent e1e35dd commit b3d33df

1 file changed

Lines changed: 155 additions & 86 deletions

File tree

install/ovm.iss

Lines changed: 155 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -45,121 +45,190 @@ Source: "..\ovm.exe"; DestDir: "{app}"; Flags: ignoreversion
4545
const
4646
EnvironmentKey = 'Environment';
4747
48-
function NeedsAddPath(Param: string): boolean;
48+
// Удаляет завершающий обратный слеш из пути, если он есть
49+
function NormalizePath(Path: string): string;
50+
begin
51+
Result := Path;
52+
if (Length(Result) > 0) and (Result[Length(Result)] = '\') then
53+
Result := Copy(Result, 1, Length(Result) - 1);
54+
end;
55+
56+
// Проверяет, существует ли путь в переменной PATH
57+
// Учитывает варианты с завершающим слешем и без него
58+
function PathExistsInEnv(Path: string): Boolean;
4959
var
50-
OrigPath: string;
51-
ParamExpanded: string;
60+
EnvPath: string;
61+
NormalizedPath: string;
62+
SearchIn: string;
5263
begin
53-
ParamExpanded := ExpandConstant(Param);
54-
// Normalize: remove trailing backslash
55-
if (Length(ParamExpanded) > 0) and (ParamExpanded[Length(ParamExpanded)] = '\') then
56-
ParamExpanded := Copy(ParamExpanded, 1, Length(ParamExpanded) - 1);
64+
Result := False;
65+
66+
// Нормализуем ВХОДНОЙ путь для единообразия
67+
NormalizedPath := NormalizePath(Path);
68+
69+
// Получаем PATH из реестра (НЕ нормализуем — там могут быть пути с backslash)
70+
if not RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', EnvPath) then
71+
exit;
72+
73+
// Добавляем разделители по краям для корректного поиска подстроки
74+
SearchIn := ';' + Uppercase(EnvPath) + ';';
75+
76+
// Ищем путь в EnvPath в двух вариантах:
77+
// 1. Без trailing backslash (C:\MyApp)
78+
// 2. С trailing backslash (C:\MyApp\) — на случай, если так записано в реестре
79+
if Pos(';' + Uppercase(NormalizedPath) + ';', SearchIn) > 0 then
80+
Result := True
81+
else if Pos(';' + Uppercase(NormalizedPath) + '\;', SearchIn) > 0 then
82+
Result := True;
83+
end;
5784
58-
if not RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', OrigPath) then
85+
// Добавляет путь в переменную окружения PATH
86+
// Возвращает True при успешном добавлении
87+
function AddToPath(Path: string): Boolean;
88+
var
89+
EnvPath: string;
90+
NewPath: string;
91+
NormalizedPath: string;
92+
begin
93+
Result := False;
94+
NormalizedPath := NormalizePath(Path);
95+
96+
// Проверяем, есть ли путь уже в PATH
97+
if PathExistsInEnv(NormalizedPath) then
5998
begin
99+
Log('Путь уже существует в PATH: ' + NormalizedPath);
60100
Result := True;
61101
exit;
62102
end;
63-
// Check if our path already exists in PATH (case insensitive)
64-
// Check without trailing backslash
65-
Result := Pos(';' + Uppercase(ParamExpanded) + ';', ';' + Uppercase(OrigPath) + ';') = 0;
66-
// Also check with trailing backslash variant
67-
if Result = True then
68-
Result := Pos(';' + Uppercase(ParamExpanded) + '\' + ';', ';' + Uppercase(OrigPath) + ';') = 0;
103+
104+
// Получаем текущее значение PATH
105+
if RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', EnvPath) then
106+
begin
107+
// Добавляем разделитель, если PATH не заканчивается на него
108+
if Length(EnvPath) = 0 then
109+
NewPath := NormalizedPath
110+
else if EnvPath[Length(EnvPath)] = ';' then
111+
NewPath := EnvPath + NormalizedPath
112+
else
113+
NewPath := EnvPath + ';' + NormalizedPath;
114+
end
115+
else
116+
begin
117+
// PATH не существует, создаём новый
118+
NewPath := NormalizedPath;
119+
end;
120+
121+
// Записываем обновлённый PATH в реестр
122+
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', NewPath) then
123+
begin
124+
Log('Добавлено в PATH: ' + NormalizedPath);
125+
Result := True;
126+
end
127+
else
128+
Log('Ошибка при добавлении в PATH: ' + NormalizedPath);
69129
end;
70130
71-
procedure CurStepChanged(CurStep: TSetupStep);
131+
// Удаляет путь из переменной окружения PATH
132+
// Использует TStringList для парсинга и ручную сборку строки для записи,
133+
// чтобы избежать проблемы с кавычками вокруг путей с пробелами
134+
function RemoveFromPath(Path: string): Boolean;
72135
var
73-
OrigPath: string;
136+
EnvPath: string;
74137
NewPath: string;
75-
AppPath: string;
138+
NormalizedPath: string;
139+
PathList: TStringList;
140+
PathItem: string;
141+
NormalizedItem: string;
142+
i: Integer;
143+
Removed: Boolean;
76144
begin
77-
if CurStep = ssPostInstall then
145+
Result := False;
146+
Removed := False;
147+
NormalizedPath := NormalizePath(Path);
148+
149+
// Получаем текущее значение PATH
150+
if not RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', EnvPath) then
78151
begin
79-
AppPath := ExpandConstant('{app}');
80-
if NeedsAddPath(AppPath) then
152+
Log('PATH не найден в реестре');
153+
exit;
154+
end;
155+
156+
PathList := TStringList.Create;
157+
try
158+
// Разбираем PATH на элементы
159+
PathList.Delimiter := ';';
160+
PathList.StrictDelimiter := True;
161+
PathList.DelimitedText := EnvPath;
162+
163+
// Удаляем наш путь и пустые элементы
164+
for i := PathList.Count - 1 downto 0 do
81165
begin
82-
if RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', OrigPath) then
166+
PathItem := PathList[i];
167+
168+
// Удаляем пустые элементы (защита от ";;" в PATH)
169+
if Trim(PathItem) = '' then
83170
begin
84-
// Add semicolon separator if PATH doesn't already end with one
85-
if (Length(OrigPath) > 0) and (OrigPath[Length(OrigPath)] = ';') then
86-
NewPath := OrigPath + AppPath
87-
else
88-
NewPath := OrigPath + ';' + AppPath;
89-
90-
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', NewPath) then
91-
Log('Added to PATH: ' + AppPath)
92-
else
93-
Log('Failed to add to PATH');
94-
end
95-
else
171+
PathList.Delete(i);
172+
Continue;
173+
end;
174+
175+
// Нормализуем для сравнения (убираем завершающий слеш)
176+
NormalizedItem := NormalizePath(PathItem);
177+
178+
// Сравниваем без учёта регистра
179+
if Uppercase(NormalizedItem) = Uppercase(NormalizedPath) then
96180
begin
97-
// PATH doesn't exist, create it
98-
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', AppPath) then
99-
Log('Created PATH with: ' + AppPath)
100-
else
101-
Log('Failed to create PATH');
181+
Log('Удалено из PATH: ' + PathItem);
182+
PathList.Delete(i);
183+
Removed := True;
102184
end;
185+
end;
186+
187+
// Собираем строку вручную, чтобы избежать добавления кавычек
188+
// (TStringList.DelimitedText добавляет кавычки к путям с пробелами)
189+
NewPath := '';
190+
for i := 0 to PathList.Count - 1 do
191+
begin
192+
if i > 0 then
193+
NewPath := NewPath + ';';
194+
NewPath := NewPath + PathList[i];
195+
end;
196+
197+
// Записываем обновлённый PATH в реестр
198+
if RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', NewPath) then
199+
begin
200+
if Removed then
201+
Log('PATH успешно обновлён')
202+
else
203+
Log('Путь не найден в PATH: ' + NormalizedPath);
204+
Result := True;
103205
end
104206
else
105-
Log('Path already in PATH, skipping');
207+
Log('Ошибка при обновлении PATH');
208+
finally
209+
PathList.Free;
210+
end;
211+
end;
212+
213+
procedure CurStepChanged(CurStep: TSetupStep);
214+
var
215+
AppPath: string;
216+
begin
217+
if CurStep = ssPostInstall then
218+
begin
219+
AppPath := ExpandConstant('{app}');
220+
AddToPath(AppPath);
106221
end;
107222
end;
108223
109224
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
110225
var
111-
OrigPath: string;
112-
NewPath: string;
113226
AppPath: string;
114-
PathList: TStringList;
115-
PathItem: string;
116-
i: Integer;
117227
begin
118228
if CurUninstallStep = usPostUninstall then
119229
begin
120230
AppPath := ExpandConstant('{app}');
121-
// Normalize: remove trailing backslash
122-
if (Length(AppPath) > 0) and (AppPath[Length(AppPath)] = '\') then
123-
AppPath := Copy(AppPath, 1, Length(AppPath) - 1);
124-
125-
if RegQueryStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', OrigPath) then
126-
begin
127-
PathList := TStringList.Create;
128-
try
129-
PathList.Delimiter := ';';
130-
PathList.StrictDelimiter := True;
131-
PathList.DelimitedText := OrigPath;
132-
133-
// Remove our path from the list (both with and without trailing backslash)
134-
// Also remove empty entries to avoid ";;" in PATH
135-
for i := PathList.Count - 1 downto 0 do
136-
begin
137-
PathItem := PathList[i];
138-
139-
// Remove empty entries
140-
if Trim(PathItem) = '' then
141-
begin
142-
PathList.Delete(i);
143-
Continue;
144-
end;
145-
146-
// Normalize by removing trailing backslash for comparison
147-
if (Length(PathItem) > 0) and (PathItem[Length(PathItem)] = '\') then
148-
PathItem := Copy(PathItem, 1, Length(PathItem) - 1);
149-
150-
if Uppercase(PathItem) = Uppercase(AppPath) then
151-
begin
152-
Log('Removed from PATH: ' + PathList[i]);
153-
PathList.Delete(i);
154-
end;
155-
end;
156-
157-
NewPath := PathList.DelimitedText;
158-
RegWriteStringValue(HKEY_CURRENT_USER, EnvironmentKey, 'Path', NewPath);
159-
finally
160-
PathList.Free;
161-
end;
162-
end;
231+
RemoveFromPath(AppPath);
163232
end;
164233
end;
165234

0 commit comments

Comments
 (0)