From 72b0d60f3a9675f4fcafe7280a70b3e124dfd13c Mon Sep 17 00:00:00 2001 From: FrigaT Date: Fri, 12 Dec 2025 09:23:48 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ReleaseUpdater/ReleaseProvider.cs | 4 +- ReleaseUpdater/ReleaseUpdaterFacade.cs | 150 +++++++++++-------------- ReleaseUpdater/SemVerService.cs | 4 +- Updater.Test/Program.cs | 17 ++- Updater.Test/Tools/Updater.exe | Bin 227263 -> 232383 bytes Updater.Test/Updater.Test.csproj | 1 + Updater/Core/SafeFileInstaller.cs | 8 +- Updater/Core/UpdaterApp.cs | 3 + Updater/Properties/launchSettings.json | 8 ++ Updater/Updater.csproj | 2 +- 10 files changed, 103 insertions(+), 94 deletions(-) create mode 100644 Updater/Properties/launchSettings.json diff --git a/ReleaseUpdater/ReleaseProvider.cs b/ReleaseUpdater/ReleaseProvider.cs index 00a7f88..3fe117c 100644 --- a/ReleaseUpdater/ReleaseProvider.cs +++ b/ReleaseUpdater/ReleaseProvider.cs @@ -17,7 +17,7 @@ public sealed class ReleaseProvider /// Токен авторизации (если требуется). /// Список релизов. - public async Task> GetReleasesAsync(string apiUrl, string? token = null) + public async Task> GetReleasesAsync(Uri apiUrl, string? token = null) { using var client = CreateClient(token); using var resp = await client.GetAsync(apiUrl); @@ -38,7 +38,7 @@ public sealed class ReleaseProvider /// Токен авторизации (если требуется). /// Информация о релизе или null. - public async Task FindReleaseAsync(string apiUrl, string? versionOrLatest, string? token = null) + public async Task FindReleaseAsync(Uri apiUrl, string? versionOrLatest, string? token = null) { var all = await GetReleasesAsync(apiUrl, token); if (string.IsNullOrWhiteSpace(versionOrLatest) || versionOrLatest.Equals("latest", StringComparison.OrdinalIgnoreCase)) diff --git a/ReleaseUpdater/ReleaseUpdaterFacade.cs b/ReleaseUpdater/ReleaseUpdaterFacade.cs index 1736d7a..7249d96 100644 --- a/ReleaseUpdater/ReleaseUpdaterFacade.cs +++ b/ReleaseUpdater/ReleaseUpdaterFacade.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.IO.Compression; +using System.Reflection; namespace ReleaseUpdater; @@ -14,16 +15,16 @@ public static class ReleaseUpdaterFacade /// public static event Action? BeforeInstall; - /// - /// Событие вызывается после успешной установки новой версии. - /// - public static event Action? AfterInstall; - /// /// Событие вызывается при ошибке обновления. /// public static event Action? UpdateFailed; + /// + /// Событие вызывается, если текущая версия совпадает с требуемой. + /// + public static event Action? AlreadyUp; + /// /// Получает список доступных версий из Gitea. /// @@ -34,45 +35,27 @@ public static class ReleaseUpdaterFacade return releases.Select(r => r.TagName).ToList(); } - /// - /// Обновление без Updater.exe: скачивание, распаковка и перезапуск прямо из DLL. - /// - public static async Task UpdateInlineAsync( - string apiUrl, string? token, string installPath, string appExe, string versionOrLatest = "latest") - { - try - { - var provider = new ReleaseProvider(); - var release = await provider.FindReleaseAsync(apiUrl, versionOrLatest, token) - ?? throw new Exception("Release not found"); - - var asset = release.Assets.FirstOrDefault(a => a.Name.EndsWith(".zip")) - ?? throw new Exception("No zip asset found"); - - var downloader = new HttpAssetDownloader(); - var zipPath = await downloader.DownloadAssetAsync(asset.DownloadUrl, token); - - BeforeInstall?.Invoke(); - - ZipFile.ExtractToDirectory(zipPath, installPath, true); - - AfterInstall?.Invoke(); - - Process.Start(Path.Combine(installPath, appExe)); - Environment.Exit(0); - } - catch (Exception ex) - { - UpdateFailed?.Invoke(ex); - RestartCurrent(installPath, appExe); - } - } - /// /// Обновление через внешний Updater.exe. /// - public static async Task UpdateWithExternalAsync( - string apiUrl, string? token, string installPath, string appExe, string versionOrLatest = "latest", string? updaterExePath = null, bool exitCurrentApp = false, string? tempUpdaterDirectory = null) + /// API github/gitea release + /// Token авторизации + /// Путь для установки приложения + /// Наименование файла приложения + /// Папка для временного хранилища zip архива + /// Путь к updater.exe + /// Тэг с версией / "latest" + /// Маска наименовая ассета обновления. В маске может содержаться {version} + public static async Task UpdateAsync( + Uri apiUrl, + string? token, + string installPath, + string appExeName, + string tempDirectory, + string updaterExePath, + string versionOrLatest = "latest", + string? assetMask = null + ) { try { @@ -80,32 +63,42 @@ public static class ReleaseUpdaterFacade var release = await provider.FindReleaseAsync(apiUrl, versionOrLatest, token) ?? throw new Exception("Release not found"); - var asset = release.Assets.FirstOrDefault(a => a.Name.EndsWith(".zip")) - ?? throw new Exception("No zip asset found"); + + var currentVersion = GetCurrentVersion(); // реализуй сам + + + if (SemVerService.Compare(release.TagName, currentVersion) > 0) + { + AlreadyUp?.Invoke(currentVersion); + return; + } + + // Маска: myapp-{version}.zip + string? mask = assetMask?.Replace("{version}", release.TagName); + + var asset = release.Assets.FirstOrDefault(a => + mask != null + ? a.Name.Equals(mask, StringComparison.OrdinalIgnoreCase) + : a.Name.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) + ) ?? throw new Exception("No matching asset found"); string tempNumber = $"{Guid.NewGuid():N}"; var tempUpdaterName = $"updater_{tempNumber}.exe"; - if (updaterExePath == null) updaterExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater.exe"); - - if (string.IsNullOrWhiteSpace(tempUpdaterDirectory)) + if (string.IsNullOrWhiteSpace(tempDirectory)) { - tempUpdaterDirectory = Path.GetDirectoryName(updaterExePath); - tempUpdaterDirectory = Path.Combine(tempUpdaterDirectory!, "tempUpdater"); + tempDirectory = Path.GetTempPath(); + } + else if (!Directory.Exists(tempDirectory)) + { + Directory.CreateDirectory(tempDirectory); } - if (!Directory.Exists(tempUpdaterDirectory)) - { - Directory.CreateDirectory(tempUpdaterDirectory); - } - - var tempUpdaterPath = Path.Combine(tempUpdaterDirectory, tempUpdaterName!); - + var tempUpdaterPath = Path.Combine(tempDirectory, tempUpdaterName); var downloader = new HttpAssetDownloader(); - var zipPath = await downloader.DownloadAssetAsync(asset.DownloadUrl, token, Path.Combine(tempUpdaterDirectory, $"updater_{tempNumber}.zip")); + var zipPath = await downloader.DownloadAssetAsync(asset.DownloadUrl, token, Path.Combine(tempDirectory, $"updater_{tempNumber}.zip")); - BeforeInstall?.Invoke(); File.Copy(updaterExePath, tempUpdaterPath); @@ -118,17 +111,16 @@ public static class ReleaseUpdaterFacade { ZipPath = zipPath, InstallPath = installPath, - AppExe = appExe, + AppExe = appExeName, }; - if (exitCurrentApp) - { - int pid = Process.GetCurrentProcess().Id; - updaterOptions.WaitProcess = pid; - } + int pid = Process.GetCurrentProcess().Id; + updaterOptions.WaitProcess = pid; var args = ArgumentsToolkit.ArgumentsParser.ToArguments(updaterOptions, true); + BeforeInstall?.Invoke(); + var process = Process.Start(new ProcessStartInfo { FileName = tempUpdaterPath, @@ -137,36 +129,24 @@ public static class ReleaseUpdaterFacade WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory }); - if (exitCurrentApp) { Environment.Exit(0); } - - process?.WaitForExit(); - - if (process?.ExitCode == 0) - AfterInstall?.Invoke(); - else - throw new Exception($"Updater.exe завершился с кодом {process?.ExitCode}"); - Environment.Exit(0); } catch (Exception ex) { UpdateFailed?.Invoke(ex); - RestartCurrent(installPath, appExe); } } - private static void RestartCurrent(string installPath, string appExe) + /// + /// Получение текущей версии приложения + /// + /// + public static string GetCurrentVersion() { - var currentApp = Path.Combine(installPath, appExe); - if (File.Exists(currentApp)) - { - Process.Start(new ProcessStartInfo - { - FileName = currentApp, - UseShellExecute = true, - WorkingDirectory = installPath - }); - } + var entryAssembly = Assembly.GetEntryAssembly(); + var attr = entryAssembly?.GetCustomAttribute(); + return attr?.InformationalVersion + ?? entryAssembly?.GetName().Version?.ToString().Split("+")[0] + ?? "unknown"; } - } diff --git a/ReleaseUpdater/SemVerService.cs b/ReleaseUpdater/SemVerService.cs index 50ca57a..1db374b 100644 --- a/ReleaseUpdater/SemVerService.cs +++ b/ReleaseUpdater/SemVerService.cs @@ -11,7 +11,7 @@ public sealed class SemVerService /// Строка версии (например, "3.5.2"). /// Результат парсинга. /// true, если парсинг успешен. - public bool TryParse(string version, out Version parsed) + public static bool TryParse(string version, out Version parsed) { var v = version.Trim().TrimStart('v'); return Version.TryParse(Normalize(v), out parsed); @@ -34,7 +34,7 @@ public sealed class SemVerService /// Первая версия. /// Вторая версия. /// -1 если v1 < v2, 0 если равны, 1 если v1 > v2. - public int Compare(string v1, string v2) + public static int Compare(string v1, string v2) { TryParse(v1, out var a); TryParse(v2, out var b); diff --git a/Updater.Test/Program.cs b/Updater.Test/Program.cs index ff6c6f7..61bda39 100644 --- a/Updater.Test/Program.cs +++ b/Updater.Test/Program.cs @@ -14,7 +14,22 @@ internal class Program var url = "https://git.frigat.duckdns.org/api/v1/repos/automacon/RetailUpdatesBot/releases"; var APIKey = "0552a77699d7506711946fc71cc6635515726bd1"; //токен - await ReleaseUpdaterFacade.UpdateWithExternalAsync(url, APIKey, installPath, appExe, "latest", updaterPath, true); + SemVerService.TryParse("v0.1.2", out var v1); + Console.WriteLine($"v0.1.2 - {v1}"); + SemVerService.TryParse(ReleaseUpdaterFacade.GetCurrentVersion(), out var v2); + Console.WriteLine($"{ReleaseUpdaterFacade.GetCurrentVersion()} - {v2}"); + Console.WriteLine(SemVerService.Compare("v0.1.2", ReleaseUpdaterFacade.GetCurrentVersion())); + + await ReleaseUpdaterFacade.UpdateAsync( + apiUrl: url, + token: APIKey, + installPath: installPath, + appExeName: appExe, + tempDirectory: Path.Combine(updaterPath, "Tools", "Temp"), + updaterExePath: updaterPath, + versionOrLatest: "latest", + assetMask: "RetailUpdatesBot-{version}.zip" + ); Console.ReadKey(); } diff --git a/Updater.Test/Tools/Updater.exe b/Updater.Test/Tools/Updater.exe index 8b30a80c516fa09180b1267b5646197e0543be96..2d822dc78fa727e7f29f776284bdb84a2c7c02b0 100644 GIT binary patch delta 16224 zcmeHud3;pW-S_XDbLZZf$z+(Bkc1_`B#5C}{*mJo3g zQDkco7p_}d5V6&2#WlDfpcad@HK5oktyZnI4_cS!d(PZIuzmV|K7HQ4f4z4; z_j`Za`JLZc?z#7#bLQ|zk%vw90mj%DH*vOsyYxq{X5*OCr4!K&oXEcES$_SqoOM6T z`TP-VYxkg$e8zC?0~?W9K7;qSeF>`5?3%$d957c0H=mlp>)BZ|ekLEzpXTP!?L21U zB#I$MB^0Dp_|?;DYNJ-z$7<=?1g%6X*2aOFs1<5Onx6`_4DB+|nc8@5ET}wfmS(zL zBGcS4lP_SI=I>_msbU@tFvpbg_%!LZiQ1`!8fY0UhigCGi!+nbagGHw#nRQ#Jacv_ zFA;^*&wRU1!#SgOWDI}VA(>Y#Xw$J9V&Mm`WAdURy?X&q% zw?{T!5l%bK1oPNzK2g7FB+-ai(>;e*vnVq-hsTEc6FK#-^?^isYc%L!3}8UA5sbyv zWe*O(B>=6{9vlRW(tUbhFo^tTrR$5bIB7RTS{QmqB#}03WNhnD$=iMQmf=KA0R-su z*~4i9=q4#p3|w_l6NraF5H+KFjbMT~bS{r8MndOXXC@_uefk{3;$j2RtIyH0_d-fX zU!RVapIuZ0;?0h^ye5Rgu%SFK0x6S+ia?^gPH8y}LlH;<6P8>NK>avdKD;0f22=to z;kfXXi;bvSEjcP(qaUCWP!g}u0;6E+)C0-5q`6xD4j+1J3YZPHn2gXw-XYWY*svj1 z{H&#z_0|cq1yJe~A8VO=Q5LQZ2WrEn>ObtEB?Jqt14HUrMt9kV>y_#{*e@tac zJ~&;_3TROiULKBxCG&3=-kFl8tHMWcLzUbm?5f<6j&MOVuhv@-O%|lsnPfP^(d*&p zkDPJpsk*MBe+%`&JTkz+G-+`-z`^O9aF?lr#|9>tFIDmZb{Mf6(M!z_DtRC@0nLkX z*=k-k%yqHr@e5t=+s(`Vv3Yq1I+-SdMW`@6h$__2OmXoJj4N8pLU^)URS9)40$M$Q zfkfw_4lqbo47mtSR9GTyT+j}TJiSi_&pS}BnjW?a!liy@a+GE{R}H28bMODk`Jl)% z)AfM)#(eIIyd-z?lleTZEZp$D(GHG0LylyUJwT3^{pZmX+3G}hQ2z&Ma+v;t;s>(? zN&n9kFYht)ss(&RNDWZbvj0LYlL$;gem-hBd{L(L%GAxQ21mMh(}z1qs-dBAkyLdP zXOaLr8EkUzU^auR!BzyP$nv1I^<*;VCW^$uY*gm(tBLmD>X-D~ww8v~%jCnBj-aFT zVB8vBF_&(LA_7apr&dfykhBNL@F+rK;Y4P#XVGx;coiQK z>d;VKICOfSAJ%mW3W;B``}KbGKE^$r^7)%Wr%LgVrqeB4VuGR{RrDN%L4^(_Pf+v= zOj@2$K5sB~g1!u%oiv+F!%Zp1c}U`EXGrtWD&u}+x!Wc)eovF8=a@7dt(%5U9_6A0 zuLe5(8Coa3Z8MD+TC61FXs0%ao}?EMVl3OK4W(&7ojwy1|H~Fcs(G5k0w%Esw2xwK zGRLoxHl$OuT`B^~G*vl$E}TFgU?fmJyF=C*UIygBWaq;De7*LOtypmkT$gPplboO~ zaBu5j&Y-<$obP~>wHW5QVJSJg(zV-mh7{{iY=fnAk#xF3In~jIl6zKh2K7^1f#U2G zrMP7(Ll@r81T5i@ijisnRd!Zscd^P&!;ttgNj$3XG%%jN6#H2yeCfqD{az?uvpoR3 znI5u?blPcqj7{^)8rVgNsYTPSto0{+LZV#ZYDGrrLhS zToivHiB?C~k%_OgxaX&T77jHBdbBSQKM6c3SyMzQPJQOaN&j8`#A$f%{! zTT~2M2bRO8n0;5g1N<+;1J_54KOj|^rm^Yl?__5(V>g@4UNho==k?(%m8R)=ESnxR zx?mZt9R)68Q=yf)WU!ZwP$_F>$58rnxZ4lXY<7e#X17tXb`WJvRCrKGdKcc9gak+#zlY$U$zHi*%Mp;CNaOETP@Nne;Q@TzUn#kaW1Hr9r@zG*V1fu4`2`wTiA+ zc%8z1O8%U}cN7XH0~&6j3@cQkm=Y$LT1D3?dXu6zDS98ZC=6AQbatK&Co-Bk_zW$wBB{p*@OYq;+6>(><@ zFDw0eky$-f_^%vdIDOgCzUj=YvME={#O>B`$GF`*!U)TxbA-d( z+-2wp#N}(Y`!m;N`6+( z*qWM*oZ7nVtjxNanz1?AId$3T>0|S=YihDH>NB&JX6I&P;8QM&k$X;kV|`6)eMM7U zO`?G-JJ*~{D7np($=8MCax9JGbUeJi>7;c7lO=AD;* zdzx5Txx8~$;ruIJ$p7j$hX#3!UW1q2nt1c-Ej+>FdHDM~U-{56^B#8BmT`^RezU1s zB%8Z~JjZXT{=U>w!R4Z_qLyB{ePZGt7d|<42Bt+eo9-sQI@*J~?1mzu&I@-R=>I=c z^?#bF@?D$=lapaY{z=_8w(`}yJAD%GWcRG)`tDA?MGKC2^~3HRoqUO4qWhywd=&Sr z-gv+~v~gY8;k(~^>HBMDeNT=GgS$&M^G24F)!P+iugppro4K^UcFB_LtemGex<^2XNWWagN^yPhx8Cd601ZI*B0<(_-@9y|MB`l@LUy!nCt zvnw~gX&%_Zm-#JeUYaG9_9f4B|7c?2)mOCT-PhHfyOqypj^2JCy3K8TGG|%cr+4rP zY<3nNMq@E&w-hsXwX_63IoBs=_m-#`zg%D*=JIkO%f-t`x|-?Bg^ir!OGm1u(B#2K z4X&A#BWL__;r{4ZUc_$tn8$Uq8~F8}gqwctcpeq1jyqhPP!|vubv;1y8GG>I7V(RFU81iI_!3cEY-Q3SI%pXWD z-F)(HK4g&eJv-KQ`WZaqxKD&5=%+c5+b4G;w{&yxes!6=pQj=3AMEF`{lj@%De-zp zq9;dc;v5+7l)E?0Kkw&5%(MHst)C1>W^n+OCwlV2E)r#+nA%dB>y#$n9Ci<%!7{p6 z+{0fMEWLZ&eS8jQ^UUww&;9+sMmC21c1-?YEJ}&OVZ=Dj?zVHJOmgX^}r$s(xO^o!!}A3ws8a}L)9ZI;bJ4D4)@yjOHuxM>CUUS3`WA% zD`6R249Kg2IGi$AO%&lwt+2QnGvfgs70UP8+J+;&oRv6%5JPD9Mg$u{TDkxpD$d|)v;R+dQYZ*I zCZkx^g(`s~&;-fF;8T*I^0{JS12PXdv-S0I(as*bz-2eS*D&GpufF-FB@wynS2rU? zVp?p{)p#yCzt%Ce;%se`vQDW9;C@b-tg=hSYdr40dN!w<;f|8CuR48!D+=RnMT6>2 zoo~b>wWg(JXnKdFf~X%ob+}Ek=0`t8_m4F_5Au`=WstY7l^HmYfyX!gM8v7*|~!4aEM`nqARZbPP0e58z&lHERy=5z*2V zzND*KxROWfM)URqye_2rvrlv=Z(4^;9Yl6=LaPJc(az)qOs^{fg3exnA|U9Jf*HK^ z8eBI@#u}|gw{8N{d976Uj$j-5vA}f@w2VUWKyQ|G{21A7uJ3D?BlyMo#^l*hOneni z@?mldaUH<*(MZsJCeP~pMA^6#<>c9|371Zu{TTdu!~E4lJXx+es7W)lml}PYxFTmY zgrgGGaE}2&O|T&wlJ>aQ@NpGBZMdR^m5k_KL+a4Hl&{xD==f}x=&_YY^rKCfz0j%5 zHWr_q+w~;7PEXsCLb&|NCYg4HyA@U`b&jH+)1)?DIciZj!X}+IxK6^+c}?O$UE*m? z%73EdjY^*4kZB(#sr{o%YIixRB6a$$Atf)_PZ}X7eS`@!C;3|GI0b9lNIPjNg;ix1J$EEmix%Creax}MF(Yn7ch z*>i#K=n`L7*bd9e&P__b5OfBOa}{DzdptiY7#-r$^?v?)kwb|rS;U~6gN05NS{CMq z=R2kV7dmEX<$gp+o9(xY4^Yt10*n2rVyi9gb-Pq9x41^u4z9`KY{q%cXnmL)kQA{P zAv|j7MrkjiD?WWew;Y-NLUHf0QIV@PgHBsqZe*Kgr$2@+nCgi4FMUj%glfU@9+RdK z*881K&KV= zykocPMV3PEhjn&C?9fu^6N~eRUEsd3xH0HKsl@Scm)&c;xJ^r?2#Z^V{**>h7PsDh zo0dj#k_*u>nq_=|y$s8h@_E+JwMQFGuPJV~{g%jkv@vwn;XzJj zV=-1|^DJ(f<8!Tqo)2@O0jUw6(Im=}i&%6M7L9DSNi<7wo9)l)g?uv2SKKE1OL_sD zOx2cdwyT|{&~i(+$hDhIp=L`r#dR;6O6_4z-7!;XhvIgr{HD^amM$c3r>V3@v70dY znJK2y;XVnc(F>NY5zp~y2$IpO!sFp|94P2Ly9bjOTbajWqZmVK$7>QRE+D7jO8!qJ zAdk%z-l8}p9E$|usFQ`1Oi*RL9nVE($-~+({tz!fjDCfO5T{px zm(t5r>3^hbZZtTw$$~4N$YlwIo$f<6jNZiC7o&rC@xY{*OIGsJN*)eT1}A7@1jox) zIAdJ}G+kA7JG7SuSFN(FFxNfBQ_#+G%|f>JK%iW+kUc#^VZOp*h0_(zR#>I5MqvXm znwo(OYZgfngRy8JaTm~!$FTG)C24pCk@RdP{XaxoL>6#sC~`biu|w$i_bPP*=o!?^ zMj5lwdGUmeEe9=#aLN_Ok1>>*zM5+K$D#L)uN46F;Qg zK}Ui6=r}TaoKCS=?HQ!Xiuf5lLAONy5;#?y#DYpv1Qv5n(ChrH!uJq_9CXgHmBwdE z@;Md-K6e?cKL!;qi&J!*qDLrtge5-|k;Fz|s7Yd5*-qDJb`GvR81?4kE%6g}o=;>2 zs(1w?Z^#0Yx9mf7W5gXHHpx=Rd$Uv}m`5M$N7?68jfdt|_LIoh8RJWBr<9}L!+urd zhrpMNPnm&P9E${Q&vvXD&bPAP@x`_~^8s$sijf{(o5W52l zL-Fi6<8g?Z93NoORaV-~B;83z4soY?W4Tkkz1*pWqPyXGrWnW{cFh*|TeK~5hsft# zyGLwg3ycRuF~3tgEapM`Ga;+GN2IEN=Bb){RJ|QNN+J1r^r(70Dpl&IEtIcHJ5=55 zP_-f}`ESC9cUcc6j3R*?_swX~(V*>UYl-O;4a}xNz&siTET9pkjjsx zrMbZEAtZ>$LeE^_cF-dfJrYYrjm9WN%k`&mHo5*(0vt?BfWv7eFoo^~X3=B7@mL?1 z%TK#>x%~74AeNti3l-MVhkCa1R-|$%R#<`{Lb*l>6jitZH_>#XS}AH2)~Xn5m9`ez zIYy_FcPZSXaIeBgV3TVcRrFbf=M=uLkYPb8TJtkm;&^;N0Mjgr?Yx>m`%lw^~_&>p4O zs}%c`=!lXWRg&kF#1s_=-ycQqL< z*;K8B)TKz_B%4%JE4owR9$PCUdlY>{(MJ@0Rw3!i1!it?4Zos`6kVj~YK5Ij(y8b@ zir%B>BMQ&zA?bn)iJBp^_Zu?aYG9S7;WIJU7@@GpE^VsqGP7z$cPhG5(R&mgQFvBi zwL^N?qi`WTKyP9RvYc(?>%_x&%E_G~I<|5cb14e_o9I^}#zu5l;cx7c?qq|24r3@V zO-lgY?vj`+Mgk`&%iERZ5F-_m8ke-6;mWX?{8_#&bRU0;zsLKF%fu#eN_-@=PGo}v z4^Hc7#`95q(OUf1;+#@mDmx>?yTs1W{-R7SwX4HZmGHQb1A>pRfQ3yqIHf3wGMQ8c z)YU`l=tCIy$MZ5Q@4&TPZrh>XvhUL{zLQG$3v`kn$9WRxpQurMgr$3dkwqN^C5^$= z^@Ss-pfG>&;_SugR4^}C+_G%Vs`}M!t%XY<##l@FP693Hs=p|8r#(QdxZ6G&)x`#MkJ>a?zr^6DV&?K~$byP?6wBF+u0n7X~4 z@0$<5$|uKv#(Y(%Pb_18#;|qj8b=1V8}u#lIz5o@_ztCcbD z<(4zIp~O+-^fR|5i@d}jyv{tx!+F>_)|su6z{^k?%AC#%&ajf}n}<5gMlITv7hg8- zkI2$4lw3)N5|=fQtrL$!6QOwA?J{iM1w(ur?cVR0<6h^P{j9(Y(&WOh+iZND|G{p^ zVj{V@@Yj5(w!q{4PWQ%N<3axKE}j*f;`hf=Sg{B9{$mr4u5i>@z%ez8C; zy7t>V;a#(0(d}hV9QyNbI!-5;4{qUkrY9(D=9b^^v7;^ZSC;w>xZPM^Ip^ok+_bs; ziCdmZ9%wB$$(t-|q4`n17{n77nl)SbC^P*{{-WuAi+A>2gL{ilmuqn6&R}isKe`4t zmGNogyS+E?zeT8(%inJIp6cH5G5^5DgxUTTPs9S|55MC34bRSVk1TrU;M+y_9Y1`> zS9Jrg>7Hj3h5Ua}{R7OihG^2}e#ss-=h;QM=aET|T($g;_{;bG^y3!~K5*=iT)@mV zi#TfeW4jpZ@72F!>1E1q{Q1ETzZe%&Q1DQod$L1Jzho)XDH2hQCaQ6|c_vcWyWNpO z|Ib!vkzCXq(ak*KdXM&tcgOv*dxu|)lePImD*jL*x>=f-W%pce6kj`I-m8=E_*K-( z-)}qS>&8fT-fjn_g+nwCOD)PXOhP|7b_`4~GPi!y${6`tLg)4GGo`^6v z=Zo=vOMmPeOD|I%{Ob+3uU&Hemn)2)AL>4rFCO51`(uHKl>Kpkq3HO3P<;cs*+g-@ zJK;C4Zr?0#8F`%TT@#j%KI;kjmvr;KPOJ&nUcxAw2(|o)O3&exM3&gL%r97tLlncaf`H6n+zOX<%M{KrX zN3b*599G2>3*+EOE{tr!wOrDD7DnDcumL=#<-!O)I4~&<+S*m@0e?_43+IZYfpP_m z66ivBZ6OS|&crZAUD|6{dMDOWV3(vWb{o2)=qm|Cil-~RYvaynA0 z7t_NWHdAGSN>doE@EWZAGpu(>ybGT$y|clC!~{rsCxerO++ADam)Ev^eX8{KJfH$i8k{T3IkO-21Z zU~!4sEO3u2Znym~Ex=U&q277p4pa)}R}k&P?)c< zSmAVqvlUh;tWnsYuo)Olp>|vtW;{B?VC>$McpFg1w_k_wV^&1cetZ|rD z3R8Tmuv;(!oAczSUOR9w-3lCzITZP+_ckyKn;GS&-g#gNcEQO{y*q$&>Bqo@^cEW( zLL186iYxKAt0I*_u|oNgw}8u!yes*1WcC=ZR`ME!4Ul}rI~Cofa4RH@VvnNtD!dnx zUyCD(KC19IB$sJt6;1f0n~PQ65_u_7Otr#Jh4PJGzPf)0=vH`&OZsV14Kx*w!ZZ)j zbJS>lzf#nUs>jV@jUNzW*@=#;s|2X5;|-)voG(86);_?Gf6mj)&U7*0f7l23gDSC| zb&p&qMqz^TljB#WjlXru9kDOhr_aj#RP6&aH+)CLWn-fr8cn^>8Q9$?_W|1d*vKad z#NZYIb=r+USSjq}R$JdP{`Jn(brADiJidk*$I z)$>fx<4_y|{e=I-^*xV4{8&%7e_2D@@-<7aL9MO6#*bZd7d)KU?#C9oXL=5uxCW-r z^gMN9r@!Z6nNC{uJTcl_yhse3_`lmeH;7TR*|kPQ<9~PmxO>j@Y~e}Y+B4U^XOURR zW3CZ{|JM8d)`g}!j{*O@H~jwAjv>6=7v3~yy!gf64?8<9Ke+3awJ%0oJ5O$!Ya4Az z&-6;+ZS9@Q63XxT$$;^=VCD55Km(mM&l00^K>|L>x2S+jyZnJSv7e zPJw1#u|)iU-D!TljSpw*%^}+hpAZ}SxM$8{q6TmK==D*M0xzfrTPjC;C& zewOFUcdl#)S__lm^w;$6nsxkdZ1-~U3ClElR*RyDgmL}^wYe@K)hrH*1aonNxC(EE zZ#9VNA`8O5H;AF~eN?-|R7s2Sgwx!(LfB!yr%{xeudEQ*IkkJGNP;A?QA}`_1Y7FI zDF0^DO0lM|a+;M(IPukeRTE6*dgm%(yTqt8EI*JTG&6s-NbZ|vwE4tpQ5SZWZeAV~ zhfqXUlUN6lr%A+^w>OEx$_4fFN|r6lo4REFy4Jds(ivms&$yy?%#^ij=g!HW)RwWf zthjDU^Td_)(NSzTVC2|gEt_JdHH#$kaEq|%R&~o*%p)zrfw*KastwKZMpdO3qN!Xm2Y$yi z%w3(kYU#QKl`AH-!kGT6)S@EGbcC9SUNMaaaq%vj9_Wm%BI}Lwl$^8 zmadq#s-$7JCo7^n1Ro zzN-4pId!VOIyqoC4tyKAhcWi!R?e>Gn@o?dW3kq}V^s~0wVg?Xfd{`NC9Pe3TKz9wQh1Y$);eAjKxbGI_a>uc z|0Ll}k>@e~qc9X+w9OWhTE$(40#g10XTUF0{Zq3Txz;mHXW^wN9z+A z$y?Cn&4iVk_lgL&jr;Gt*beT+y=U`xNC9rubT?NG>+Eih^dA!;{LjK5);kESFBcG* zKHKWc0}-VOmlp8mOVXsdOsZg%?$W&l5P4O3Ffwcz$$F>W>@r`bcbQ|ogJI&*TzZJI z`U=4hxbv9JnxR{L>OP5$;H|QM{sU-?ip;U%C<|n`$u<842wfK65Ls=iA?ES{=r+S8 z;#5hEe;^y8f@2hI|A-23J2MXYEjLs0_$)!QjoEW~T;O6KZRzQ{>SF{qs}95X>oC5KjeDLoJBU;)Lf%9X!@M49z_z`W~ZB+iml> z#R3C%3vNflIgfh-CR|56?cwXldf6}CWBlSh_Ur4&{`orcR@_aR@L^!F={`hKKbB_a ztri)*tKg|Kcu@Nypw+z?9rPZ*i9EVqHkY>|RGKb)BcuUJ>BqcLTDZK5z7~%Djxnodx3~kC9bH1lLavbKNT`On5C8fS4SRT$-?VSF&3_YSCWh5Qd*j2Q`UF=}*^|G*`g)+tlZpc>QY(zB|0 zhoVG=Sqoh`Ep&qmu%jUF-#G@2=W2`;z7p9ZTsyr#8Lf@H&+vaB?5V4X<|BS@NqSm~ zzj4XDrLvoYajU$A;U;zZG_qiv21}`9rsJosTqQa?nEP@RmPvLQ;-BrUc3_+nkBL?Q80cBS5p3>4F;7vCUsT&p>n zPOV(xV1?5az8z2}i^4mUixKAGF!~y_jiykk*+C!b4?&Vl!!o3BI#qfN4!TQzC< zGLx1cn@Y_({T;N9rmsT9cR_2T8zGOOIZ84F9(vLi32Fy-V?YnFX1WiT$p%gaEyOjzRB{%j>lfy%ii-_%c9Krxlv5oSQgTg- zGgCLkeWl47EEJ`?0+VUCxc^s} zqCW)58q;pzt@LPEtJ84PJ~qxHBd~==YtJ!8$CD+uK2Ad%Ih|JADfWrxBp#r%VfHz& zg1Ef@=oC9?a^e>2p}0^%c{9r6uqogCwz@S#T(b5y;uSg$o1{|=PU<*pl0GrkggNOG z<3^bKL3@GODUf`zidR@S$_iI6l}`F=7hM#c3F~Bq-KnUz^s|L*+M6tfo(prgnD--= zrxhog{T}N<&OXv|Jsr|cutb{JH&pHyZ9k@JD+7v^rmwJGbiLwEG1)^8iGHe}3L7SO zid%~-_XU$JVRT5B*p2-fJMgaN^hX4Y(HGhOAkBMeT zCW}^TrvZA9zNC`@Z5@~>^9JfoRiXkY)m!KeGH5%B-3^Sw{j{CFrkz0Dv=7=D7;cN2OnUiYRGbp@Q6|>+H zu4fjE9yb8(v>E86+koBa4(7o!ri1sPrL>>*qpRozJ`m5>H*6rrn!f|%DH@VgN&=?S zEZ`t&1P-O;z!F*uoS@{>fPqrwNUom#lb}i$#Y8^wb=0~{mT+6-lujPl!Z)Hcm znAtBs!3dt@(E-iFm?_b0bLU38hckCE{<7R&ckgIdDYLlCT;;Cv2q$AwnM8>W%?2Ai zWGXzwEgp(?FJ|s4$eM97c{odm10!Wt_?F@*(mc2`U~j=w&n#vXlI~5>u7ErdbC+3U zNsC3#LK+~6%r>ShP{bjNI84MH4j{RM*P6`S;VOriJ7gh;L)e%_CjkS8><%|ehwk8Q zF0<9aUFFg48W`blH(;2OPF%t5<}AihQH{f7V_l7!6cRdR<*^VOCv1c6Lr)ZGKi(U3Okh zT~2;seZk!Py1Cg|+1YdRY8&!v@{A2Z9v`!9{FK{?l~-`wM2qp8iP`$hUdHpyB1V4+ z^h>>r)wlB$XYX@Mejm4_X~MRi#jUrWKe61f`$c~vr=90}!m5QaVHI4)&7Dx0ecrn5 zf~R%Fbx10t7>+f3N%UrfbaN4E!TI9xe=8Nkca(Iv*YhR(p^aSst*3%(+cxv-HCnLx z$Bs>#d97fq4Np&8x^~^7JHLWi zJI5{7Vcfw>@pkDrdKVwbretG~&PV1d8#yYOjjE$8pv+elATyPXcW?n@*%-ugpsB@Q z1LQK(RgVl<4(Pd%3<8%28d)%-xk41c{h{x85!-r}Cv>nK{5ogK`$do3-+7Z9rxZ^F zLrk!4>l|Qns*K%x_zcI)(JGFll%)fV2*HnW z6Pa9j$+T7fG2$&OjhI}yhVokdb2PbHv~9{TA|L0yS*DSLlUwEn`eR|DvQ`;peN(0} z|8brS^+ud5N*x2?5N`aa1+Zj&OgrkvfhU037)R^ zk>&+P+Y{WwvW$D4;PLSO%o9AZr}RE0)_(MPTvP5Ap*D2Wtf=qY6R0oKh<{R@N}uEd zQ2RYk^4RVdYnLT4ZzAzlp424RkcUz3J|bf~c;on!+|&&j8716<_=&d)LOw!G3Tv)a zn!!e|{d_#j>R7O!zbRN|$B<|ERL*)DH$KNb-A|()v*iwCJn)uGkJ4OP;SuA|bG&=t zIcWSYteah$52Ws$i0(!qRa1)dTe63ju0ci*m+3(%DqJs3UAk{Jj0Ud)6SDXH27Jbq zVP=l>ka)R=5iV0pDnwC89r>z>0=AeDLqg8{v1o-qUN*(-HKCbays6W@xVvnjdfb=S zQ}_lt-nFWv%c?4T3~JPd#Q=-4EWHYDqO3?P)k%N#lC!0kx{7VS21!S_tg&%R=StG< zw!0#{m@}ul?fzaeqc9(02raG%Un9t{&bt7#Z?-Y~dEPg$5Ohp-C1TR08&>ZkX@0Q> z>AAYw9vkPC)xe+b#ft%iD$!Yq>2mKdu*A-^Tg*2#j_mf!g$v47SAOO5;*<~7Fg7*+ zCWa?PrVDlY31_t4wX_V^$fol)Xf!P&Thm)5*Jb;vSD&pj8HnI=m zLB{*kwiKBVTN~^(-mAN>1x!SYJ$;&6;4W-KhFY_>#u~nZcsf#z?FV`9XlaTbMInKQ zE2NI4%Z#@V^7@6#QF?$|v?^~}t1RtX0T~91)|K*{f?Tg6AXwEYPy_^5OTl=)v=!$z z$%IFk&XFcx@Jn$qrsRo!BU+G%l*ygrI5#0P(>1wM(ThlC#bt75W%A|8o$JA$)r}!9 z@cxNtETN@@sL~kxZ1|xGY6ZN~Xnz4KE;m@*(wO9jUflAG(1)kKezVl!nh@8$5jrha z_@NdZ(T&E*v>wHne!=3UQvVi3wuwr=v>FBX`Q`fdM3sY?AR?rMp5Q9lft`0o>_ypQ0x!d?vSb$7^Z`QR`^x?Y6|JqR;_b?&2_EDnydVLW zRsK2Y0h3`b2NeK|2l$9$WztD1Pg)K8bkJ7CO}2$Nq?w?b7v_*y0@p9hxfM4w%tb4% zHO$2+?jK>F@rrvR%q0aB>kOMFtGw19pp>IWZwjJmXCp$@_f?iphb{Y|*+f5c!@d}I zb)nJ)Erz`r>4QR*R=ZzS;liXsHuPDNUffiI*?K4+G@YWUi~^Fy(}ap+un?6TULW9M z!6nln_C8CdzbO0-m-I@uSR~`&+YS7VJp#Oi?FBxpY{tMw*KO=cF(Ww3vKRP!UE;k8 zC&O|^aH5iDgU+T4frzIBQXae!xRp!St-ML-l%zcZ^jHr9ds|--6&|#T)?1py8T4mn zm|Lf~>M(b&Me62Z?ab}@BQQJ9lXUDVOVGKvm#v5caZyI6LoBV8E)DP48mai)MGR>_xs17f^xnPU~}z`qDD9aY>PtykG!W$E-~NM||9buFFF zg}GBa0^CnwE?~kfltIYgNH-Rjh|)4BBFyFEh8jRoVXoK`r4672#T}+N^BEdQ^A-0; z_HIN^Z6Lj?xNVkcksd9Rj)%Fi;IiraaJg^!V|)rG_}@WO{I@;7L!sL!yEJwd^Gh^+*-?R`Y<+{sg*aLDK`;dFAk1t{n-i_@vm9OiVI=o4LPHBDmDMdV0> zUM>mzv*>?S68NVUbyhDo+&J3KkxvMQZ`qaIp`V^Tsf81gq*HIHH>y(y1=Lna~wvmDU@O4B%3A39KkVT3RU^0a_Uw= zE`av(W~Cd0UgPP3uWd51Er-D#K$+N<_iVPpLWRW&%M?ygSf#K=VIwda>22v}6)+yj zTZvnM9=xukXDJyVGq|A3nDoDwej^3}#|9#YBFDKNcj+#rt^qxs8rgUH6uc~JBC$Ef z)@t>j$3`v$u8C+yu?Nko=tEkswb6D~p8z|fp^l=z@2zYer?-NN7!-k zJWBm&dkMMsX_2o36UBRU1T|usb%cJ;k1ITdM#$mgLzZj)K}pUdm)v1Dv+ndQcd-OT zCn&nNqI-wsYa*~9CW-B=(ms%#fNLj)uK{cr`;xuEN3mh5d&3Bi7HIkK?WHRs?hN1= zlwlc0@*$h33RKe5`XP26`^#dfeW)CL0sHjGZ-BR%{|k9U`P!9L{>&<= zA%bxiUty2r_4JM{gD;{ZcKO6hZ)waCxe7VM3Q zv?%0%7MY@*C7bg_F>lbuiArcE2^qR7k)ayb&YtCS@bQC;$E|9@a;uuK+^Qxl6P1k{ zGsca=jW_*9JXJ1w7<4pf3t@{{p0em>U@qMX98BAR!{{Dh5w>65xGOda59YnE18;yO z=0c#872R9W{b(V5uBRzl?lU}&mrfKt2aKnWfT{RIO71hHnB+dgK;Tds3M>g=TUBl} z!~&<$1mIN)@eP)qtK1c-YKj$>pb>lY63E{X*rK2p^lBxqQ7HE%UKe#rTL`%%#s_4xa&0qC_PSy(6j>T_Y8uPSJHr-mWBT74A^-`;>gA zk{nc$Lwqak*I!hU6G}@$T{4B$3WEv{Dm<<*;L%jO6dqJ~Qj@JClZt`DB88((QeLg- zpu!y{c{z3{`k^YBDKD}}n`(=!tXk1QMF$nVL*YS%#}yV?rH891@Cbc`ZKev=#(&~N z@o>n^e;vE?W{Og)aYNjU7s&MrcUmMpgKY)AtsB6=H@r07fgzI%RoEe-M(s zc4^0Q3ouoEF)R>X~hcle6H16&uiLJPtP4i-8AhoGQb^LHLA#csRt zBX{Fdk(;T6zetDpOZdHs-zU^xaHIWQ9%bx(m(Mej-{UuS?0b*j!aJsXzztK!nWKD? zFp5v`pE`zr%4505gBW2(C$PaG2B4c`XXifOTDQOaskhk|G52m6D|7Kfk{>}>xVsAb zRfKJyUD(ILX|KadBEbQ1@M+_tlRRjU*D>RSs^FyH2m8pvB=19>LibK1a&4 zmAET-R8khR1{bqAH_KfqSMYOV#OJ&;`JCJd!?kk<&oS&Fc^E#-F)PkhBzKt384rBU zAM19WajrWo*lSB7cRMp`Pw_q}CLTpm%%wKq+9RQfcB_-zhHHb9_DEybDPC#rYj#At zmodZk1@{E7O|^{4ov?%ibi)#PskFO28hd34b|<#ZP(Zmdc~G58V(>PYCtS7? zb+pBiM8=XYd6HJ?bj|G8{3YM;Z*PuF{+jh0GZZ#^%A`A))QA{h;>` z32k>h`o=#__wSxs_Rza)-}vJ-`)@O<&+z7fVd;iWDZDkjQakI>gCBnPr?0vf2253O z89sVd85hp*p4?Ss)NJQz#_c`Ca_nx*HynTC!LGY2f8%9xcjd%c?7I9%cUQ(To?F=A zs^EW*RC`jNJaGGKPi_)t?2H+!B1IqUOx+tP@KwRRPv8H^yF>3Ny6(*H&iys=(_UF_c-HttZ34{@4Mg)qcToZIG_J$WV(CHh4SF5b1Gd?uZ)u69W0GB<7}MB z^Mv)0MPWTkPWtp3--;jl_3mg&i=NR@+5_*su2JkM`XGu1qF81eOB9w4N21XGv+-2B zRlPfyM_lLBOs8rubZp8JLu52x9wrJAO*ULiwm6>}eD~z4>fe++|L(biD<<9N?Wisl zxBT1D^o|oxY4e`?&8c#uS|L=q2olEc!YNihyZ=E2Vy`h5Mg zd|MUahxZt{js4gVWHF(gzrk=Rk8$|P_u?k+e5zYIDWEkj__I9_A%P( zM32C6q~YX&q%PZpJX?;`^wP%WVzRb7EgzvK=3hzhI_#2NE6hop%Vzk0FlnJ^{ z;r*0Do!Q4fahYlD%s#%$<=2BX9_fC)iTd8v_uXVL`>TE8GCdReXn{ z?^C!7lEeIl88-dpMm(=wXrE2gdAq;)gEZHjQk=zv={wM4VCN5*s?a z3&ahqWfE4W4)v{$))P;M(Y`@MPYQjV^FQ^ePRDScSjc0^dGp!->YTl_ zqr=*@D5W-muUA9aRiFDLGu_wGL9<>E(UCbg`1;HFLTW1W_PVd<8?g{9KlZ&%)V z#ZM3HeSKE!&QCJJ1ECD%n9R`ZWpJjPy?Bi=-|(jl#~pk`|x=5h+7FDe9w}lnkSItw=HEw25mlvG}-6l!+XA95B#}We(pKX0H)JaRMpHm6>#7_V zt|e4>byw9$L%F`WU6?L2ni!JrDaO31aE<8Swah@{={2H0 zEtxe9V`eTcC>*yqXMXn533HnpDq6;6RgS9}U0J$p{?+3a=Qfv=jw-0lZJd(lE1ABs zDW_OAp^tH3y)fzFc+18Z2iFTL8YWv4nr>DERZK56$5)x%ysUY2`ohXpIc1Bcl{ZY9 zx}o~CN$SIUa_ox!HmL{RkeA(mbwMgW>ifY<*O>KZ(KEb!Nhq@ zGt;M*FJ3$$XXU7p@g+I)uBcTJ=@T(8lBm<7u#%2!oRp0;>O z?aJ(m%tckBbLLeR`13LgnpV{mESZwMa;bk>Wl3i9)y;)tN+vZepEA=owxzPZWkF+A zNq+r!--Ob_@iViQj$T?bv3^p1UBjeIW5BhduMxjNI8j%|2Kl{}j6tFttkz#OXHr$x zoR-CPGnXxyLGwe;_fMDssbe`;r^-viY)G!Y7zEij#C9T!2!E_Nuzt}ZT5i;C6oXjM z*tSs&u^ C20(uR diff --git a/Updater.Test/Updater.Test.csproj b/Updater.Test/Updater.Test.csproj index da8130a..1d8002e 100644 --- a/Updater.Test/Updater.Test.csproj +++ b/Updater.Test/Updater.Test.csproj @@ -5,6 +5,7 @@ net8.0 enable enable + 2.0.0 diff --git a/Updater/Core/SafeFileInstaller.cs b/Updater/Core/SafeFileInstaller.cs index 50edf60..7188952 100644 --- a/Updater/Core/SafeFileInstaller.cs +++ b/Updater/Core/SafeFileInstaller.cs @@ -23,12 +23,13 @@ public sealed class SafeFileInstaller : IInstaller var rel = Path.GetRelativePath(sourceDir, src); var dst = Path.Combine(installPath, rel); var dstDir = Path.GetDirectoryName(dst)!; - Directory.CreateDirectory(dstDir); + if (!Directory.Exists(dstDir)) Directory.CreateDirectory(dstDir); if (File.Exists(dst)) { var bkp = Path.Combine(backupDir, rel); - Directory.CreateDirectory(Path.GetDirectoryName(bkp)!); + var bkpDir = Path.GetDirectoryName(bkp); + if (!Directory.Exists(bkpDir)) Directory.CreateDirectory(bkpDir!); File.Copy(dst, bkp, overwrite: true); } @@ -63,7 +64,8 @@ public sealed class SafeFileInstaller : IInstaller { var rel = Path.GetRelativePath(backupDir, bkp); var dst = Path.Combine(installPath, rel); - Directory.CreateDirectory(Path.GetDirectoryName(dst)!); + var dstDir = Path.GetDirectoryName(dst); + if (!Directory.Exists(dstDir)) Directory.CreateDirectory(dstDir!); File.Copy(bkp, dst, overwrite: true); } } diff --git a/Updater/Core/UpdaterApp.cs b/Updater/Core/UpdaterApp.cs index b4de7c5..3ea853d 100644 --- a/Updater/Core/UpdaterApp.cs +++ b/Updater/Core/UpdaterApp.cs @@ -12,6 +12,7 @@ public sealed class UpdaterApp private readonly IInstaller _installer; private readonly IProcessManager _proc; + /// public UpdaterApp(ILogger log, IExtractor extractor, IInstaller installer, IProcessManager proc) { _log = log; @@ -34,6 +35,7 @@ public sealed class UpdaterApp { _log.Error($"Extraction failed: {ex.Message}"); Cleanup(tempExtractDir); + _proc.StartApp(opts.InstallPath, opts.AppExe, opts.RestartDelayMs); return ExitCodes.ExtractFailed; } @@ -45,6 +47,7 @@ public sealed class UpdaterApp { _log.Error($"Install failed: {ex.Message}"); Cleanup(tempExtractDir); + _proc.StartApp(opts.InstallPath, opts.AppExe, opts.RestartDelayMs); return ExitCodes.InstallFailed; } diff --git a/Updater/Properties/launchSettings.json b/Updater/Properties/launchSettings.json new file mode 100644 index 0000000..3b6b9cb --- /dev/null +++ b/Updater/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Updater": { + "commandName": "Project", + "commandLineArgs": "-z \"C:\\Job\\Projects\\FrigaT\\ReleaseUpdater\\Updater.Test\\bin\\Debug\\net8.0\\Tools\\tempUpdater\\updater_32f606dc1cda473ab953206927bf047b.zip\" -i \"C:\\Job\\Projects\\FrigaT\\ReleaseUpdater\\Updater.Test\\bin\\Debug\\net8.0\" -a \"RetailUpdatesBot.exe\" -rd \"500\" -ud \"500\" -wp \"31408\"" + } + } +} \ No newline at end of file diff --git a/Updater/Updater.csproj b/Updater/Updater.csproj index 67d8837..5e4e07e 100644 --- a/Updater/Updater.csproj +++ b/Updater/Updater.csproj @@ -6,7 +6,7 @@ enable enable true - 1.0.0 + 2.0.0 FrigaT FrigaT ReleaseUpdater