You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							71 lines
						
					
					
						
							1.6 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							71 lines
						
					
					
						
							1.6 KiB
						
					
					
				| package shell | |
| 
 | |
| import ( | |
| 	"errors" | |
| 	"sync" | |
| ) | |
| 
 | |
| var ( | |
| 	// Default maximum parallelization/concurrency for commands supporting it. | |
| 	DefaultMaxParallelization = 10 | |
| ) | |
| 
 | |
| // ErrorWaitGroup implements a goroutine wait group which aggregates errors, if any. | |
| type ErrorWaitGroup struct { | |
| 	maxConcurrency int | |
| 	wg             *sync.WaitGroup | |
| 	wgSem          chan bool | |
| 	errors         []error | |
| 	errorsMu       sync.Mutex | |
| } | |
| 
 | |
| type ErrorWaitGroupTask func() error | |
| 
 | |
| func NewErrorWaitGroup(maxConcurrency int) *ErrorWaitGroup { | |
| 	if maxConcurrency <= 0 { | |
| 		// no concurrency = one task at the time | |
| 		maxConcurrency = 1 | |
| 	} | |
| 	return &ErrorWaitGroup{ | |
| 		maxConcurrency: maxConcurrency, | |
| 		wg:             &sync.WaitGroup{}, | |
| 		wgSem:          make(chan bool, maxConcurrency), | |
| 	} | |
| } | |
| 
 | |
| // Reset restarts an ErrorWaitGroup, keeping original settings. Errors and pending goroutines, if any, are flushed. | |
| func (ewg *ErrorWaitGroup) Reset() { | |
| 	close(ewg.wgSem) | |
| 
 | |
| 	ewg.wg = &sync.WaitGroup{} | |
| 	ewg.wgSem = make(chan bool, ewg.maxConcurrency) | |
| 	ewg.errors = nil | |
| } | |
| 
 | |
| // Add queues an ErrorWaitGroupTask to be executed as a goroutine. | |
| func (ewg *ErrorWaitGroup) Add(f ErrorWaitGroupTask) { | |
| 	if ewg.maxConcurrency <= 1 { | |
| 		// keep run order deterministic when parallelization is off | |
| 		ewg.errors = append(ewg.errors, f()) | |
| 		return | |
| 	} | |
| 
 | |
| 	ewg.wg.Add(1) | |
| 	go func() { | |
| 		ewg.wgSem <- true | |
| 
 | |
| 		err := f() | |
| 		ewg.errorsMu.Lock() | |
| 		ewg.errors = append(ewg.errors, err) | |
| 		ewg.errorsMu.Unlock() | |
| 
 | |
| 		<-ewg.wgSem | |
| 		ewg.wg.Done() | |
| 	}() | |
| } | |
| 
 | |
| // Wait sleeps until all ErrorWaitGroupTasks are completed, then returns errors for them. | |
| func (ewg *ErrorWaitGroup) Wait() error { | |
| 	ewg.wg.Wait() | |
| 	return errors.Join(ewg.errors...) | |
| }
 |