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