@@ -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,91 @@ 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+ "linux" , // Arch
158+ "minimal" , // openSUSE
159+ "openstack" , // Gentoo
160+ "server" , // Ubuntu
161+ "std" , // Alpine-Lima
162+ "stream" , // CentOS
163+ "uefi" , // Alpine
164+ "vm" , // openSUSE
165+ }
166+
167+ // imageTemplate checks if the locator specifies an image URL.
168+ // It will create a minimal template with the image URL and arch derived from the image name
169+ // and also set the default instance name to the image name, but stripped of generic tags.
170+ func imageTemplate (tmpl * Template , locator string ) bool {
171+ if ! imageURLRegex .MatchString (locator ) {
172+ return false
173+ }
174+
175+ var imageArch limayaml.Arch
176+ for keyword , arch := range archKeywords {
177+ pattern := fmt .Sprintf (`\b%s\b` , keyword )
178+ if regexp .MustCompile (pattern ).MatchString (locator ) {
179+ imageArch = arch
180+ break
181+ }
182+ }
183+ if imageArch == "" {
184+ imageArch = limayaml .NewArch (runtime .GOARCH )
185+ logrus .Warnf ("cannot determine image arch from URL %q; assuming %q" , locator , imageArch )
186+ }
187+ template := `arch: %q
188+ images:
189+ - location: %q
190+ arch: %q
191+ `
192+ tmpl .Bytes = []byte (fmt .Sprintf (template , imageArch , locator , imageArch ))
193+ tmpl .Name = InstNameFromImageURL (locator , imageArch )
194+ return true
195+ }
196+
197+ func InstNameFromImageURL (locator , imageArch string ) string {
198+ // We intentionally call both path.Base and filepath.Base in case we are running on Windows.
199+ name := strings .ToLower (filepath .Base (path .Base (locator )))
200+ // Remove file format and compression file types
201+ name = imageURLRegex .ReplaceAllString (name , "" )
202+ for _ , tag := range genericTags {
203+ re := regexp .MustCompile (fmt .Sprintf (`[-_.]%s\b` , tag ))
204+ name = re .ReplaceAllString (name , "" )
205+ }
206+ // The Alpine "nocloud_" prefix does not fit the genericTags pattern
207+ name = strings .TrimPrefix (name , "nocloud_" )
208+ // Remove imageArch as well if it is the native arch
209+ if limayaml .IsNativeArch (imageArch ) {
210+ re := regexp .MustCompile (fmt .Sprintf (`[-_.]%s\b` , imageArch ))
211+ name = re .ReplaceAllString (name , "" )
212+ }
213+ return name
214+ }
215+
124216func SeemsTemplateURL (arg string ) (bool , * url.URL ) {
125217 u , err := url .Parse (arg )
126218 if err != nil {
0 commit comments