@@ -12,11 +12,14 @@ import (
1212 "os"
1313 "path"
1414 "path/filepath"
15+ "regexp"
16+ "runtime"
1517 "strings"
1618 "unicode"
1719
1820 "github.com/containerd/containerd/identifiers"
1921 "github.com/lima-vm/lima/pkg/ioutilx"
22+ "github.com/lima-vm/lima/pkg/limayaml"
2023 "github.com/lima-vm/lima/pkg/templatestore"
2124 "github.com/sirupsen/logrus"
2225)
@@ -30,6 +33,10 @@ func Read(ctx context.Context, name, locator string) (*Template, error) {
3033 Locator : locator ,
3134 }
3235
36+ if imageTemplate (tmpl , locator ) {
37+ return tmpl , nil
38+ }
39+
3340 isTemplateURL , templateURL := SeemsTemplateURL (locator )
3441 switch {
3542 case isTemplateURL :
@@ -121,6 +128,88 @@ func Read(ctx context.Context, name, locator string) (*Template, error) {
121128 return tmpl , nil
122129}
123130
131+ // Locators with an image file format extension, optionally followed by a compression method.
132+ // This regex is also used to remove the file format suffix from the instance name.
133+ var imageURLRegex = regexp .MustCompile (`\.(img|qcow2|raw|iso)(\.(gz|xz|bz2|zstd))?$` )
134+
135+ // Image architecture will be guessed based on the presence of arch keywords.
136+ var archKeywords = map [string ]limayaml.Arch {
137+ "aarch64" : limayaml .AARCH64 ,
138+ "amd64" : limayaml .X8664 ,
139+ "arm64" : limayaml .AARCH64 ,
140+ "armhf" : limayaml .ARMV7L ,
141+ "armv7l" : limayaml .ARMV7L ,
142+ "riscv64" : limayaml .RISCV64 ,
143+ "x86_64" : limayaml .X8664 ,
144+ }
145+
146+ // These generic tags will be stripped from an image name before turning it into an instance name.
147+ var genericTags = []string {
148+ "base" , // Fedora, Rocky
149+ "cloud" , // Fedora, openSUSE
150+ "cloudimg" , // Ubuntu, Arch
151+ "cloudinit" , // Alpine
152+ "default" , // Gentoo
153+ "generic" , // Fedora
154+ "genericcloud" , // CentOS, Debian, Rocky, Alma
155+ "kvm" , // Oracle
156+ "latest" , // Gentoo, CentOS, Rocky, Alma
157+ "minimal" , // openSUSE
158+ "openstack" , // Gentoo
159+ "server" , // Ubuntu
160+ "std" , // Alpine-Lima
161+ "stream" , // CentOS
162+ "uefi" , // Alpine
163+ "vm" , // openSUSE
164+ }
165+
166+ // imageTemplate checks if the locator specifies an image URL.
167+ // It will create a minimal template with the image URL and arch derived from the image name
168+ // and also set the default instance name to the image name, but stripped of generic tags.
169+ func imageTemplate (tmpl * Template , locator string ) bool {
170+ if ! imageURLRegex .MatchString (locator ) {
171+ return false
172+ }
173+
174+ var imageArch limayaml.Arch
175+ for keyword , arch := range archKeywords {
176+ pattern := fmt .Sprintf (`\b%s\b` , keyword )
177+ if regexp .MustCompile (pattern ).MatchString (locator ) {
178+ imageArch = arch
179+ break
180+ }
181+ }
182+ if imageArch == "" {
183+ imageArch = limayaml .NewArch (runtime .GOARCH )
184+ logrus .Warnf ("cannot determine image arch from URL %q; assuming %q" , locator , imageArch )
185+ }
186+ template := `
187+ arch: %q
188+ images:
189+ - location: %q
190+ arch: %q
191+ `
192+ tmpl .Bytes = []byte (fmt .Sprintf (template , imageArch , locator , imageArch ))
193+
194+ // Make up instance name from image name.
195+ // We intentionally call both path.Base and filepath.Base in case we are running on Windows.
196+ tmpl .Name = strings .ToLower (filepath .Base (path .Base (locator )))
197+ // Remove file format and compression file types
198+ tmpl .Name = imageURLRegex .ReplaceAllString (tmpl .Name , "" )
199+ for _ , tag := range genericTags {
200+ re := regexp .MustCompile (fmt .Sprintf (`[-_.]%s\b` , tag ))
201+ tmpl .Name = re .ReplaceAllString (tmpl .Name , "" )
202+ }
203+ // The Alpine "nocloud_" prefix does not fit the genericTags pattern
204+ tmpl .Name = strings .TrimPrefix (tmpl .Name , "nocloud_" )
205+ // Remove imageArch as well if it is the native arch
206+ if limayaml .IsNativeArch (imageArch ) {
207+ re := regexp .MustCompile (fmt .Sprintf (`[-_.]%s\b` , imageArch ))
208+ tmpl .Name = re .ReplaceAllString (tmpl .Name , "" )
209+ }
210+ return true
211+ }
212+
124213func SeemsTemplateURL (arg string ) (bool , * url.URL ) {
125214 u , err := url .Parse (arg )
126215 if err != nil {
0 commit comments