@@ -21,6 +21,7 @@ internal sealed class DockerCli : ILocalRegistry
21
21
22
22
private readonly ILogger _logger ;
23
23
private string ? _commandPath ;
24
+ private string ? _fullCommandPath ;
24
25
25
26
public DockerCli ( string ? command , ILoggerFactory logger )
26
27
{
@@ -38,13 +39,8 @@ public DockerCli(string? command, ILoggerFactory logger)
38
39
public DockerCli ( ILoggerFactory loggerFactory ) : this ( null , loggerFactory )
39
40
{ }
40
41
41
- private static string ? FindFullPathFromPath ( string ? command )
42
+ private static string FindFullPathFromPath ( string command )
42
43
{
43
- if ( string . IsNullOrEmpty ( command ) )
44
- {
45
- return command ;
46
- }
47
-
48
44
foreach ( string directory in ( Environment . GetEnvironmentVariable ( "PATH" ) ?? string . Empty ) . Split ( Path . PathSeparator ) )
49
45
{
50
46
string fullPath = Path . Combine ( directory , command + FileNameSuffixes . CurrentPlatform . Exe ) ;
@@ -57,19 +53,32 @@ public DockerCli(ILoggerFactory loggerFactory) : this(null, loggerFactory)
57
53
return command ;
58
54
}
59
55
60
- public async Task LoadAsync ( BuiltImage image , ImageReference sourceReference , ImageReference destinationReference , CancellationToken cancellationToken )
56
+ private async ValueTask < string > FindFullCommandPath ( CancellationToken cancellationToken )
61
57
{
62
- cancellationToken . ThrowIfCancellationRequested ( ) ;
63
- string dockerPath = FindFullPathFromPath ( "docker" ) ?? "docker" ;
58
+ if ( _fullCommandPath != null )
59
+ {
60
+ return _fullCommandPath ;
61
+ }
64
62
65
- string ? commandPath = await GetCommandPathAsync ( cancellationToken ) ;
66
- if ( commandPath is null )
63
+ string ? command = await GetCommandAsync ( cancellationToken ) ;
64
+ if ( command is null )
67
65
{
68
66
throw new NotImplementedException ( Resource . FormatString ( Strings . DockerProcessCreationFailed , Commands ) ) ;
69
67
}
70
68
69
+ _fullCommandPath = FindFullPathFromPath ( command ) ;
70
+
71
+ return _fullCommandPath ;
72
+ }
73
+
74
+ public async Task LoadAsync ( BuiltImage image , ImageReference sourceReference , ImageReference destinationReference , CancellationToken cancellationToken )
75
+ {
76
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
77
+
78
+ string commandPath = await FindFullCommandPath ( cancellationToken ) ;
79
+
71
80
// call `docker load` and get it ready to receive input
72
- ProcessStartInfo loadInfo = new ( dockerPath , $ "load") ;
81
+ ProcessStartInfo loadInfo = new ( commandPath , $ "load") ;
73
82
loadInfo . RedirectStandardInput = true ;
74
83
loadInfo . RedirectStandardOutput = true ;
75
84
loadInfo . RedirectStandardError = true ;
@@ -102,20 +111,20 @@ public async Task LoadAsync(BuiltImage image, ImageReference sourceReference, Im
102
111
public async Task < bool > IsAvailableAsync ( CancellationToken cancellationToken )
103
112
{
104
113
bool commandPathWasUnknown = this . _commandPath is null ; // avoid running the version command twice.
105
- string ? commandPath = await GetCommandPathAsync ( cancellationToken ) ;
106
- if ( commandPath is null )
114
+ string ? command = await GetCommandAsync ( cancellationToken ) ;
115
+ if ( command is null )
107
116
{
108
117
_logger . LogError ( $ "Cannot find { Commands } executable.") ;
109
118
return false ;
110
119
}
111
120
112
121
try
113
122
{
114
- switch ( commandPath )
123
+ switch ( command )
115
124
{
116
125
case DockerCommand :
117
126
{
118
- JsonDocument config = GetConfig ( ) ;
127
+ JsonDocument config = GetDockerConfig ( ) ;
119
128
120
129
if ( ! config . RootElement . TryGetProperty ( "ServerErrors" , out JsonElement errorProperty ) )
121
130
{
@@ -136,7 +145,7 @@ public async Task<bool> IsAvailableAsync(CancellationToken cancellationToken)
136
145
case PodmanCommand :
137
146
return commandPathWasUnknown || await TryRunVersionCommandAsync ( PodmanCommand , cancellationToken ) ;
138
147
default :
139
- throw new NotImplementedException ( $ "{ commandPath } is an unknown command.") ;
148
+ throw new NotImplementedException ( $ "{ command } is an unknown command.") ;
140
149
}
141
150
}
142
151
catch ( Exception ex )
@@ -152,16 +161,16 @@ public bool IsAvailable()
152
161
=> IsAvailableAsync ( default ) . GetAwaiter ( ) . GetResult ( ) ;
153
162
154
163
public string ? GetCommand ( )
155
- => GetCommandPathAsync ( default ) . GetAwaiter ( ) . GetResult ( ) ;
164
+ => GetCommandAsync ( default ) . GetAwaiter ( ) . GetResult ( ) ;
156
165
157
166
/// <summary>
158
167
/// Gets docker configuration.
159
168
/// </summary>
160
169
/// <param name="sync">when <see langword="true"/>, the method is executed synchronously.</param>
161
170
/// <exception cref="DockerLoadException">when failed to retrieve docker configuration.</exception>
162
- internal static JsonDocument GetConfig ( )
171
+ internal static JsonDocument GetDockerConfig ( )
163
172
{
164
- string dockerPath = FindFullPathFromPath ( "docker" ) ?? "docker" ;
173
+ string dockerPath = FindFullPathFromPath ( "docker" ) ;
165
174
Process proc = new ( )
166
175
{
167
176
StartInfo = new ProcessStartInfo ( dockerPath , "info --format=\" {{json .}}\" " )
@@ -265,7 +274,7 @@ private static async Task WriteImageToStreamAsync(BuiltImage image, ImageReferen
265
274
}
266
275
}
267
276
268
- private async ValueTask < string ? > GetCommandPathAsync ( CancellationToken cancellationToken )
277
+ private async ValueTask < string ? > GetCommandAsync ( CancellationToken cancellationToken )
269
278
{
270
279
if ( _commandPath != null )
271
280
{
@@ -306,7 +315,7 @@ private static bool IsPodmanAlias()
306
315
// or if it is a podman script in a trenchcoat.
307
316
try
308
317
{
309
- var dockerinfo = GetConfig ( ) . RootElement ;
318
+ var dockerinfo = GetDockerConfig ( ) . RootElement ;
310
319
// Docker's info output has a 'DockerRootDir' top-level property string that is a good marker,
311
320
// while Podman has a 'host' top-level property object with a 'buildahVersion' subproperty
312
321
var hasdockerProperty =
0 commit comments