22using UniGetUI . Core . SettingsEngine ;
33using UniGetUI . Core . Tools ;
44using UniGetUI . PackageEngine . Enums ;
5+ using YamlDotNet . Serialization . ObjectGraphVisitors ;
56
67namespace UniGetUI . PackageOperations ;
78
8- public abstract class AbstractOperation : IDisposable
9+ public abstract partial class AbstractOperation : IDisposable
910{
10- public static class RetryMode
11- {
12- public const string NoRetry = "" ;
13- public const string Retry = "Retry" ;
14- public const string Retry_AsAdmin = "RetryAsAdmin" ;
15- public const string Retry_Interactive = "RetryInteractive" ;
16- public const string Retry_SkipIntegrity = "RetryNoHashCheck" ;
17- }
18-
19- public class OperationMetadata
20- {
21- /// <summary>
22- /// Installation of X
23- /// </summary>
24- public string Title = "" ;
25-
26- /// <summary>
27- /// X is being installed/upated/removed
28- /// </summary>
29- public string Status = "" ;
30-
31- /// <summary>
32- /// X was installed
33- /// </summary>
34- public string SuccessTitle = "" ;
35-
36- /// <summary>
37- /// X has been installed successfully
38- /// </summary>
39- public string SuccessMessage = "" ;
40-
41- /// <summary>
42- /// X could not be installed.
43- /// </summary>
44- public string FailureTitle = "" ;
45-
46- /// <summary>
47- /// X Could not be installed
48- /// </summary>
49- public string FailureMessage = "" ;
50-
51- /// <summary>
52- /// Starting operation X with options Y
53- /// </summary>
54- public string OperationInformation = "" ;
55-
56- public readonly string Identifier ;
57-
58- public OperationMetadata ( )
59- {
60- Identifier = new Random ( ) . NextInt64 ( 1000000 , 9999999 ) . ToString ( ) ;
61- }
62- }
63-
6411 public readonly OperationMetadata Metadata = new ( ) ;
65- public static readonly List < AbstractOperation > OperationQueue = [ ] ;
6612
6713 public event EventHandler < OperationStatus > ? StatusChanged ;
6814 public event EventHandler < EventArgs > ? CancelRequested ;
@@ -72,38 +18,12 @@ public OperationMetadata()
7218 public event EventHandler < EventArgs > ? Enqueued ;
7319 public event EventHandler < EventArgs > ? OperationSucceeded ;
7420 public event EventHandler < EventArgs > ? OperationFailed ;
75-
76- public static int MAX_OPERATIONS ;
77-
7821 public event EventHandler < BadgeCollection > ? BadgesChanged ;
7922
80- public class BadgeCollection
81- {
82- public readonly bool AsAdministrator ;
83- public readonly bool Interactive ;
84- public readonly bool SkipHashCheck ;
85- public readonly string ? Scope ;
86-
87- public BadgeCollection ( bool admin , bool interactive , bool skiphash , string ? scope )
88- {
89- AsAdministrator = admin ;
90- Interactive = interactive ;
91- SkipHashCheck = skiphash ;
92- Scope = scope ;
93- }
94- }
95- public void ApplyCapabilities ( bool admin , bool interactive , bool skiphash , string ? scope )
96- {
97- BadgesChanged ? . Invoke ( this , new BadgeCollection ( admin , interactive , skiphash , scope ) ) ;
98- }
99-
100- public enum LineType
101- {
102- VerboseDetails ,
103- ProgressIndicator ,
104- Information ,
105- Error
106- }
23+ public bool Started { get ; private set ; }
24+ protected bool QUEUE_ENABLED ;
25+ protected bool FORCE_HOLD_QUEUE ;
26+ private bool IsInnerOperation = false ;
10727
10828 private readonly List < ( string , LineType ) > LogList = [ ] ;
10929 private OperationStatus _status = OperationStatus . InQueue ;
@@ -113,20 +33,23 @@ public OperationStatus Status
11333 set { _status = value ; StatusChanged ? . Invoke ( this , value ) ; }
11434 }
11535
116- public bool Started { get ; private set ; }
117- protected bool QUEUE_ENABLED ;
118- protected bool FORCE_HOLD_QUEUE ;
36+ public void ApplyCapabilities ( bool admin , bool interactive , bool skiphash , string ? scope )
37+ {
38+ BadgesChanged ? . Invoke ( this , new BadgeCollection ( admin , interactive , skiphash , scope ) ) ;
39+ }
11940
120- private readonly AbstractOperation ? requirement ;
41+ // private readonly AbstractOperation? requirement;
42+ private readonly IReadOnlyList < InnerOperation > PreOperations = [ ] ;
43+ private readonly IReadOnlyList < InnerOperation > PostOperations = [ ] ;
12144
122- public AbstractOperation ( bool queue_enabled , AbstractOperation ? req )
45+ public AbstractOperation (
46+ bool queue_enabled ,
47+ IReadOnlyList < InnerOperation > ? preOps = null ,
48+ IReadOnlyList < InnerOperation > ? postOps = null )
12349 {
12450 QUEUE_ENABLED = queue_enabled ;
125- if ( req is not null )
126- {
127- requirement = req ;
128- QUEUE_ENABLED = false ;
129- }
51+ if ( preOps is not null ) PreOperations = preOps ;
52+ if ( postOps is not null ) PostOperations = postOps ;
13053
13154 Status = OperationStatus . InQueue ;
13255 Line ( "Please wait..." , LineType . ProgressIndicator ) ;
@@ -202,20 +125,9 @@ public async Task MainThread()
202125
203126 Enqueued ? . Invoke ( this , EventArgs . Empty ) ;
204127
205- if ( requirement != null )
206- { // OPERATION REQUIREMENT HANDLER
207- Logger . Info ( $ "Operation { Metadata . Title } is waiting for requirement operation { requirement . Metadata . Title } ") ;
208- Line ( CoreTools . Translate ( "Waiting for {0} to complete..." , requirement . Metadata . Title ) , LineType . ProgressIndicator ) ;
209- {
210- while ( requirement . Status is OperationStatus . Running or OperationStatus . InQueue )
211- {
212- await Task . Delay ( 100 ) ;
213- if ( SKIP_QUEUE ) break ;
214- }
215- }
216- }
217- else if ( QUEUE_ENABLED )
218- { // QUEUE HANDLER
128+ if ( QUEUE_ENABLED && ! IsInnerOperation )
129+ {
130+ // QUEUE HANDLER
219131 SKIP_QUEUE = false ;
220132 OperationQueue . Add ( this ) ;
221133 int lastPos = - 2 ;
@@ -238,61 +150,8 @@ public async Task MainThread()
238150 }
239151 // END QUEUE HANDLER
240152
241- // BEGIN ACTUAL OPERATION
242- OperationVeredict result ;
243- Line ( CoreTools . Translate ( "Starting operation..." ) , LineType . ProgressIndicator ) ;
244- if ( Status is OperationStatus . InQueue ) Status = OperationStatus . Running ;
245-
246- do
247- {
248- OperationStarting ? . Invoke ( this , EventArgs . Empty ) ;
249-
250- try
251- {
252- // Check if the operation was canceled
253- if ( Status is OperationStatus . Canceled )
254- {
255- result = OperationVeredict . Canceled ;
256- break ;
257- }
258-
259- if ( requirement is not null )
260- {
261- if ( requirement . Status is OperationStatus . Failed )
262- {
263- Line ( CoreTools . Translate ( "{0} has failed, that was a requirement for {1} to be run" , requirement . Metadata . Title , Metadata . Title ) , LineType . Error ) ;
264- result = OperationVeredict . Failure ;
265- break ;
266- }
267-
268- if ( requirement . Status is OperationStatus . Canceled )
269- {
270- Line ( CoreTools . Translate ( "The user has canceled {0}, that was a requirement for {1} to be run" , requirement . Metadata . Title , Metadata . Title ) , LineType . Error ) ;
271- result = OperationVeredict . Canceled ;
272- break ;
273- }
274- }
275-
276- Task < OperationVeredict > op = PerformOperation ( ) ;
277- while ( Status != OperationStatus . Canceled && ! op . IsCompleted ) await Task . Delay ( 100 ) ;
278-
279- if ( Status is OperationStatus . Canceled ) result = OperationVeredict . Canceled ;
280- else result = op . GetAwaiter ( ) . GetResult ( ) ;
281- }
282- catch ( Exception e )
283- {
284- result = OperationVeredict . Failure ;
285- Logger . Error ( e ) ;
286- foreach ( string l in e . ToString ( ) . Split ( "\n " ) )
287- {
288- Line ( l , LineType . Error ) ;
289- }
290- }
291- } while ( result == OperationVeredict . AutoRetry ) ;
292-
293-
153+ var result = await _runOperation ( ) ;
294154 while ( OperationQueue . Remove ( this ) ) ;
295- // END OPERATION
296155
297156 if ( result == OperationVeredict . Success )
298157 {
@@ -352,6 +211,91 @@ public async Task MainThread()
352211 }
353212 }
354213
214+ private async Task < OperationVeredict > _runOperation ( )
215+ {
216+ OperationVeredict result ;
217+
218+ // Process preoperations
219+ int i = 0 , count = PreOperations . Count ;
220+ if ( count > 0 ) Line ( "" , LineType . VerboseDetails ) ;
221+ foreach ( var preReq in PreOperations )
222+ {
223+ i ++ ;
224+ Line ( CoreTools . Translate ( $ "Running PreOperation ({ i } /{ count } )...") , LineType . Information ) ;
225+ preReq . Operation . LogLineAdded += ( _ , line ) => Line ( line . Item1 , line . Item2 ) ;
226+ await preReq . Operation . MainThread ( ) ;
227+ if ( preReq . Operation . Status is not OperationStatus . Succeeded && preReq . MustSucceed )
228+ {
229+ Line (
230+ CoreTools . Translate ( $ "PreOperation { i } out of { count } failed, and was tagged as necessary. Aborting...") ,
231+ LineType . Error ) ;
232+ return OperationVeredict . Failure ;
233+ }
234+ Line ( CoreTools . Translate ( $ "PreOperation { i } out of { count } finished with result { preReq . Operation . Status } ") , LineType . Information ) ;
235+ Line ( "--------------------------------" , LineType . Information ) ;
236+ Line ( "" , LineType . VerboseDetails ) ;
237+ }
238+
239+ // BEGIN ACTUAL OPERATION
240+ Line ( CoreTools . Translate ( "Starting operation..." ) , LineType . Information ) ;
241+ if ( Status is OperationStatus . InQueue ) Status = OperationStatus . Running ;
242+
243+ do
244+ {
245+ OperationStarting ? . Invoke ( this , EventArgs . Empty ) ;
246+
247+ try
248+ {
249+ // Check if the operation was canceled
250+ if ( Status is OperationStatus . Canceled )
251+ {
252+ result = OperationVeredict . Canceled ;
253+ break ;
254+ }
255+
256+ Task < OperationVeredict > op = PerformOperation ( ) ;
257+ while ( Status != OperationStatus . Canceled && ! op . IsCompleted ) await Task . Delay ( 100 ) ;
258+
259+ if ( Status is OperationStatus . Canceled ) result = OperationVeredict . Canceled ;
260+ else result = op . GetAwaiter ( ) . GetResult ( ) ;
261+ }
262+ catch ( Exception e )
263+ {
264+ result = OperationVeredict . Failure ;
265+ Logger . Error ( e ) ;
266+ foreach ( string l in e . ToString ( ) . Split ( "\n " ) )
267+ {
268+ Line ( l , LineType . Error ) ;
269+ }
270+ }
271+ } while ( result is OperationVeredict . AutoRetry ) ;
272+
273+ if ( result is not OperationVeredict . Success )
274+ return result ;
275+
276+ // Process postoperations
277+ i = 0 ; count = PostOperations . Count ;
278+ foreach ( var postReq in PostOperations )
279+ {
280+ i ++ ;
281+ Line ( "--------------------------------" , LineType . Information ) ;
282+ Line ( "" , LineType . VerboseDetails ) ;
283+ Line ( CoreTools . Translate ( $ "Running PostOperation ({ i } /{ count } )...") , LineType . Information ) ;
284+ postReq . Operation . LogLineAdded += ( _ , line ) => Line ( line . Item1 , line . Item2 ) ;
285+ await postReq . Operation . MainThread ( ) ;
286+ if ( postReq . Operation . Status is not OperationStatus . Succeeded && postReq . MustSucceed )
287+ {
288+ Line (
289+ CoreTools . Translate ( $ "PostOperation { i } out of { count } failed, and was tagged as necessary. Aborting...") ,
290+ LineType . Error ) ;
291+ return OperationVeredict . Failure ;
292+ }
293+ Line ( CoreTools . Translate ( $ "PostOperation { i } out of { count } finished with result { postReq . Operation . Status } ") , LineType . Information ) ;
294+ }
295+
296+ return result ;
297+ }
298+
355299 private bool SKIP_QUEUE ;
356300
357301 public void SkipQueue ( )
0 commit comments