@@ -5,11 +5,13 @@ package limatmpl
5
5
6
6
import (
7
7
"context"
8
+ "errors"
8
9
"fmt"
9
10
"io"
10
11
"net/http"
11
12
"net/url"
12
13
"os"
14
+ "os/exec"
13
15
"path"
14
16
"path/filepath"
15
17
"regexp"
@@ -22,18 +24,23 @@ import (
22
24
"github.com/lima-vm/lima/v2/pkg/ioutilx"
23
25
"github.com/lima-vm/lima/v2/pkg/limatype"
24
26
"github.com/lima-vm/lima/v2/pkg/limayaml"
27
+ "github.com/lima-vm/lima/v2/pkg/plugins"
25
28
"github.com/lima-vm/lima/v2/pkg/templatestore"
26
29
)
27
30
28
31
const yBytesLimit = 4 * 1024 * 1024 // 4MiB
29
32
30
33
func Read (ctx context.Context , name , locator string ) (* Template , error ) {
31
- var err error
32
34
tmpl := & Template {
33
35
Name : name ,
34
36
Locator : locator ,
35
37
}
36
38
39
+ locator , err := TransformCustomURL (ctx , locator )
40
+ if err != nil {
41
+ return nil , err
42
+ }
43
+
37
44
if imageTemplate (tmpl , locator ) {
38
45
return tmpl , nil
39
46
}
@@ -241,7 +248,10 @@ func SeemsTemplateURL(arg string) (isTemplate bool, templateName string) {
241
248
return false , ""
242
249
}
243
250
if u .Scheme == "template" {
244
- return true , path .Join (u .Host , u .Path )
251
+ if u .Opaque == "" {
252
+ return true , path .Join (u .Host , u .Path )
253
+ }
254
+ return true , u .Opaque
245
255
}
246
256
return false , ""
247
257
}
@@ -285,3 +295,55 @@ func InstNameFromYAMLPath(yamlPath string) (string, error) {
285
295
}
286
296
return s , nil
287
297
}
298
+
299
+ func TransformCustomURL (ctx context.Context , locator string ) (string , error ) {
300
+ u , err := url .Parse (locator )
301
+ if err != nil || len (u .Scheme ) <= 1 {
302
+ return locator , nil
303
+ }
304
+
305
+ if u .Scheme == "template" {
306
+ if u .Opaque != "" {
307
+ return locator , nil
308
+ }
309
+ // Fix malformed "template://" URLs.
310
+ newLocator := "template:" + path .Join (u .Host , u .Path )
311
+ logrus .Warnf ("Template locator %q should be written %q" , locator , newLocator )
312
+ return newLocator , nil
313
+ }
314
+
315
+ plugin , err := plugins .Find ("url-" + u .Scheme )
316
+ if err != nil {
317
+ return "" , err
318
+ }
319
+ if plugin == nil {
320
+ return locator , nil
321
+ }
322
+
323
+ currentPath := os .Getenv ("PATH" )
324
+ defer os .Setenv ("PATH" , currentPath )
325
+ err = plugins .UpdatePath ()
326
+ if err != nil {
327
+ return "" , err
328
+ }
329
+
330
+ cmd := exec .CommandContext (ctx , plugin .Path , strings .TrimPrefix (u .String (), u .Scheme + ":" ))
331
+ cmd .Env = os .Environ ()
332
+
333
+ stdout , err := cmd .Output ()
334
+ if err != nil {
335
+ var exitErr * exec.ExitError
336
+ if errors .As (err , & exitErr ) {
337
+ stderrMsg := string (exitErr .Stderr )
338
+ if stderrMsg != "" {
339
+ return "" , fmt .Errorf ("command %q failed: %s" , cmd .String (), strings .TrimSpace (stderrMsg ))
340
+ }
341
+ }
342
+ return "" , fmt .Errorf ("command %q failed: %w" , cmd .String (), err )
343
+ }
344
+ newLocator := strings .TrimSpace (string (stdout ))
345
+ if newLocator != locator {
346
+ logrus .Debugf ("Custom locator %q replaced with %q" , locator , newLocator )
347
+ }
348
+ return newLocator , nil
349
+ }
0 commit comments