container/init: handle unwrapped errors
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 34s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 1m59s
				
			
		
			
				
	
				Test / Hpkg (push) Successful in 3m32s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 3m54s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 5m16s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 2m12s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 1m29s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 34s
				
			Test / Sandbox (push) Successful in 1m59s
				
			Test / Hpkg (push) Successful in 3m32s
				
			Test / Sandbox (race detector) (push) Successful in 3m54s
				
			Test / Hakurei (race detector) (push) Successful in 5m16s
				
			Test / Hakurei (push) Successful in 2m12s
				
			Test / Flake checks (push) Successful in 1m29s
				
			This is much cleaner from both the return statement and the error handling. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									a462341a0a
								
							
						
					
					
						commit
						f24dd4ab8c
					
				| @ -6,6 +6,49 @@ import ( | ||||
| 	"syscall" | ||||
| ) | ||||
| 
 | ||||
| // messageFromError returns a printable error message for a supported concrete type. | ||||
| func messageFromError(err error) (string, bool) { | ||||
| 	if m, ok := messagePrefixP[MountError, *MountError]("cannot ", err); ok { | ||||
| 		return m, ok | ||||
| 	} | ||||
| 	if m, ok := messagePrefixP[os.PathError, *os.PathError]("cannot ", err); ok { | ||||
| 		return m, ok | ||||
| 	} | ||||
| 	if m, ok := messagePrefixP[AbsoluteError, *AbsoluteError]("", err); ok { | ||||
| 		return m, ok | ||||
| 	} | ||||
| 	if m, ok := messagePrefix[OpRepeatError]("", err); ok { | ||||
| 		return m, ok | ||||
| 	} | ||||
| 	if m, ok := messagePrefix[OpStateError]("", err); ok { | ||||
| 		return m, ok | ||||
| 	} | ||||
| 
 | ||||
| 	return zeroString, false | ||||
| } | ||||
| 
 | ||||
| // messagePrefix checks and prefixes the error message of a non-pointer error. | ||||
| // While this is usable for pointer errors, such use should be avoided as nil check is omitted. | ||||
| func messagePrefix[T error](prefix string, err error) (string, bool) { | ||||
| 	var targetError T | ||||
| 	if errors.As(err, &targetError) { | ||||
| 		return prefix + targetError.Error(), true | ||||
| 	} | ||||
| 	return zeroString, false | ||||
| } | ||||
| 
 | ||||
| // messagePrefixP checks and prefixes the error message of a pointer error. | ||||
| func messagePrefixP[V any, T interface { | ||||
| 	*V | ||||
| 	error | ||||
| }](prefix string, err error) (string, bool) { | ||||
| 	var targetError T | ||||
| 	if errors.As(err, &targetError) && targetError != nil { | ||||
| 		return prefix + targetError.Error(), true | ||||
| 	} | ||||
| 	return zeroString, false | ||||
| } | ||||
| 
 | ||||
| type MountError struct { | ||||
| 	Source, Target, Fstype string | ||||
| 
 | ||||
|  | ||||
| @ -8,6 +8,52 @@ import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestMessageFromError(t *testing.T) { | ||||
| 	testCases := []struct { | ||||
| 		name   string | ||||
| 		err    error | ||||
| 		want   string | ||||
| 		wantOk bool | ||||
| 	}{ | ||||
| 		{"mount", &MountError{ | ||||
| 			Source: SourceTmpfsEphemeral, | ||||
| 			Target: "/sysroot/tmp", | ||||
| 			Fstype: FstypeTmpfs, | ||||
| 			Flags:  syscall.MS_NOSUID | syscall.MS_NODEV, | ||||
| 			Data:   zeroString, | ||||
| 			Errno:  syscall.EINVAL, | ||||
| 		}, "cannot mount tmpfs on /sysroot/tmp: invalid argument", true}, | ||||
| 
 | ||||
| 		{"path", &os.PathError{ | ||||
| 			Op:   "mount", | ||||
| 			Path: "/sysroot", | ||||
| 			Err:  errUnique, | ||||
| 		}, "cannot mount /sysroot: unique error injected by the test suite", true}, | ||||
| 
 | ||||
| 		{"absolute", &AbsoluteError{"etc/mtab"}, | ||||
| 			`path "etc/mtab" is not absolute`, true}, | ||||
| 
 | ||||
| 		{"repeat", OpRepeatError("autoetc"), | ||||
| 			"autoetc is not repeatable", true}, | ||||
| 
 | ||||
| 		{"state", OpStateError("overlay"), | ||||
| 			"impossible overlay state reached", true}, | ||||
| 
 | ||||
| 		{"unsupported", errUnique, zeroString, false}, | ||||
| 	} | ||||
| 	for _, tc := range testCases { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			got, ok := messageFromError(tc.err) | ||||
| 			if got != tc.want { | ||||
| 				t.Errorf("messageFromError: %q, want %q", got, tc.want) | ||||
| 			} | ||||
| 			if ok != tc.wantOk { | ||||
| 				t.Errorf("messageFromError: ok = %v, want %v", ok, tc.wantOk) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestMountError(t *testing.T) { | ||||
| 	testCases := []struct { | ||||
| 		name  string | ||||
|  | ||||
| @ -184,10 +184,14 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV | ||||
| 		} | ||||
| 
 | ||||
| 		if err := op.early(state, k); err != nil { | ||||
| 			k.printBaseErr(err, | ||||
| 				fmt.Sprintf("cannot prepare op at index %d:", i)) | ||||
| 			k.beforeExit() | ||||
| 			k.exit(1) | ||||
| 			if m, ok := messageFromError(err); ok { | ||||
| 				k.fatal(m) | ||||
| 			} else { | ||||
| 				k.printBaseErr(err, | ||||
| 					fmt.Sprintf("cannot prepare op at index %d:", i)) | ||||
| 				k.beforeExit() | ||||
| 				k.exit(1) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -224,10 +228,14 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV | ||||
| 		// ops already checked during early setup | ||||
| 		k.verbosef("%s %s", op.prefix(), op) | ||||
| 		if err := op.apply(state, k); err != nil { | ||||
| 			k.printBaseErr(err, | ||||
| 				fmt.Sprintf("cannot apply op at index %d:", i)) | ||||
| 			k.beforeExit() | ||||
| 			k.exit(1) | ||||
| 			if m, ok := messageFromError(err); ok { | ||||
| 				k.fatal(m) | ||||
| 			} else { | ||||
| 				k.printBaseErr(err, | ||||
| 					fmt.Sprintf("cannot apply op at index %d:", i)) | ||||
| 				k.beforeExit() | ||||
| 				k.exit(1) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user