Skip to content

Conversation

jandubois
Copy link
Member

@jandubois jandubois commented Aug 30, 2025

The template reader will attempt to call limactl-url-$SCHEME to rewrite a custom URL as either a local filename, or a URL with a supported scheme like https.

This change allows us to experiment with custom schemes, like the one requested in #3930.

Example implementation for the github: scheme is at the end. You can use:

github:ORG/REPO
github:ORG/REPO/DIR/
github:ORG/REPO/DIR/FILE
github:ORG/REPO/DIR/FILE@BRANCH

FILE defaults to lima, and files without an extension will have .yaml appended.

The default branch is determined by the GitHub API if no BRANCH is specified.

limactl tmpl copy github:lima-vm/lima/templates/fedora-42 -
minimumLimaVersion: 1.1.0

base:
- template://_images/fedora-42
- template://_default/mounts

This implementation has a few differences to the one requested in #3930:

  • uses default branch instead of hard-coded master
  • uses lima.yaml instead of templates/default.yaml as the default file

I believe this implementation is more versatile, but we can discuss this below. The plugin format makes it easy to experiment.

Here is a minimalistic my: scheme to fetch default templates from the Lima repo:

cat ~/bin/limactl-url-my
#!/bin/bash
echo "https://raw.githubusercontent.com/lima-vm/lima/master/templates/$1.yaml"limactl tmpl copy my:opensuse-leap -
minimumLimaVersion: 1.1.0

base:
- template://_images/opensuse-leap
- template://_default/mounts

And here is limactl-url-github. Which should become a builtin scheme (implemented in Go) once we agree on the specific semantics:

#!/bin/bash

if [ $# -ne 1 ]; then
    echo "Usage: $0 [github:]ORG/REPO[/PATH][@BRANCH]" >&2
    exit 1
fi

input="$1"

# Remove optional github: prefix
if [[ "$input" == github:* ]]; then
    input="${input#github:}"
fi

# Check for explicit branch specification with @ at the end
branch=""
if [[ "$input" == *@* ]]; then
    # Split on last @ to get branch
    branch="${input##*@}"
    input="${input%@*}"
fi

# Split the input into components
IFS='/' read -ra PARTS <<< "$input"

if [ ${#PARTS[@]} -lt 2 ]; then
    echo "Error: Input must be at least ORG/REPO" >&2
    exit 1
fi

org="${PARTS[0]}"
repo="${PARTS[1]}"

# Extract path (everything after ORG/REPO)
if [ ${#PARTS[@]} -gt 2 ]; then
    path=""
    for ((i=2; i<${#PARTS[@]}; i++)); do
        if [ -n "$path" ]; then
            path="$path/"
        fi
        path="$path${PARTS[i]}"
    done
else
    path="lima"
fi

# If path ends with /, it's a directory, so append lima
if [[ "$path" == */ ]]; then
    path="${path}lima"
fi

# If the filename (last component) has no extension, add .yaml
filename="${path##*/}"
if [[ "$filename" != *.* ]]; then
    path="$path.yaml"
fi

# Query default branch if no branch was specified
if [ -z "$branch" ]; then
    branch=$(gh repo view "$org/$repo" --json defaultBranchRef --jq '.defaultBranchRef.name' 2>/dev/null)
    if [ $? -ne 0 ] || [ -z "$branch" ]; then
        echo "Error: Failed to get default branch for $org/$repo. Make sure the repository exists and you have access." >&2
        exit 1
    fi
fi

echo "https://raw.githubusercontent.com/$org/$repo/$branch/$path"

@jandubois
Copy link
Member Author

jandubois commented Aug 30, 2025

I just realized that the limactl-url prefix makes the names overlap with regular plugin names. Not sure if that is an issue or a feature:

limactl url-github lima-vm/lima
https://raw.githubusercontent.com/lima-vm/lima/master/lima.yamllimactl url-my default
https://raw.githubusercontent.com/lima-vm/lima/master/templates/default.yaml

If we don't want this, then we need to use a longer prefix for plugins, like limactl-plugin-*. Which does not match what other commands like git or kubectl do, so I would prefer to keep it as it is. Or I guess we could use lima-url-* as a prefix for url schemes. 🤷 I think I'm fine with the overlap.

@jandubois
Copy link
Member Author

I've just tested, and you can use tags or commit ids instead of branch names too. These all work:

limactl tmpl copy github:lima-vm/lima/examples/[email protected] -limactl tmpl copy github:lima-vm/lima/examples/opensuse@74e2fda81 -

@msgilligan
Copy link
Contributor

This looks great!

a few differences to the one requested in #3930

I did say "something like" in the request to leave room for improvement!

@jandubois
Copy link
Member Author

I've updated the PR by refactoring the code to run subcommands with the limactl directory first on the PATH and also added a limactl template url CUSTOM_URL command (mostly for integration tests later):

❯ l tmpl url github:lima-vm/lima
https://raw.githubusercontent.com/lima-vm/lima/master/lima.yaml

@AkihiroSuda AkihiroSuda added this to the v2.0.0 milestone Sep 1, 2025
@AkihiroSuda
Copy link
Member

What is the remaining task to merge this PR? CI?

@jandubois
Copy link
Member Author

What is the remaining task to merge this PR? CI?

I was planning to move to template:default style templates (and translate the existing form with a warning to the new format), but also to move the github: scheme to be builtin, implemented in Go. I was hoping to get some feedback if the semantics of the bash prototype seem correct to everyone.

Either or both could happen in separate PRs to keep the PR easier to review.

@jandubois
Copy link
Member Author

I was planning to move to template:default style templates (and translate the existing form with a warning to the new format), but also to move the github: scheme to be builtin, implemented in Go. I was hoping to get some feedback if the semantics of the bash prototype seem correct to everyone.

I think it will be best to create separate PRs for further changes, to keep things easy for review.

I've made one more change in this PR: I've appended /usr/local/libexec/lima to the end of the PATH, so we look for plugins in the same directory we use to store external drivers. This is based on discussion in #3744 (comment).

I've noticed that we also use LIMA_DRIVERS_PATH and LIMA_TEMPLATES_PATH to define additional search locations for drivers and templates. And we look in $LIMA_HOME/_templates for templates as well. I feel like this is getting out of hand and don't want to add similar mechanisms for plugins, at least not yet. Let me know if you think otherwise.

@jandubois jandubois force-pushed the custom-url-schemes branch 2 times, most recently from 5a1ab38 to 6032d5f Compare September 4, 2025 23:59
@jandubois jandubois marked this pull request as ready for review September 5, 2025 01:19
if err != nil || cmd == rootCmd {
// Function calls os.Exit() if it found and executed the plugin
runExternalPlugin(rootCmd.Context(), args[0], args[1:])
_ = executil.WithExecutablePath(func() error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ignore err?

return err
}

func newTemplateURLCommand() *cobra.Command {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs docs and tests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is also modifying the same logic that #3973 is currently changing.

And tests should be implemented using BATS from #3969.

I'm turning this back unto "Draft" until these 3 PRs have landed because it will likely need serious refactoring by then.

@jandubois jandubois marked this pull request as draft September 5, 2025 23:19
@jandubois
Copy link
Member Author

jandubois commented Sep 7, 2025

I just created another URL scheme for testing: instance: to reference the template of an already created instance:

#!/bin/bash
echo "${LIMA_HOME:-$HOME/.lima}/$1/lima.yaml"

With this you can create another instance with identical config like this (but unlike the clone command you start with a fresh disk):

limactl create -y --name clone instance:default

And of course it works all the usual places: limactl tmpl validate instance:clone or limactl tmpl copy instance:default - etc.

Not sure though if it is useful enough to be builtin.

@AkihiroSuda
Copy link
Member

instance:

This is quite confusing; limactl start instance:NAME should just mean starting an instance named NAME (i.e., limactl start NAME)

@jandubois
Copy link
Member Author

instance:

This is quite confusing; limactl start instance:NAME should just mean starting an instance named NAME (i.e., limactl start NAME)

Yeah, let's not include it in Lima. I think the only scheme we want to have builtin is github.

@AkihiroSuda
Copy link
Member

Needs rebase

@jandubois
Copy link
Member Author

github:ORG/REPO
github:ORG/REPO/DIR/
github:ORG/REPO/DIR/FILE
github:ORG/REPO/DIR/FILE@BRANCH

Extension ideas:

  • github:ORG is the same as github:ORG/lima.yaml or github:ORG/ORG if lima.yaml repo doesn't exist
  • github:ORG// is the same as github:ORG, but you can now append a DIR, FILE, and BRANCH: github:mylongprojectname//templates/lima.yaml

@jandubois jandubois force-pushed the custom-url-schemes branch 3 times, most recently from 5dde020 to 5d72cc0 Compare September 26, 2025 07:02
@jandubois jandubois marked this pull request as ready for review September 26, 2025 07:25
@jandubois
Copy link
Member Author

I think this PR is ready for review.

Still missing, but could be done in several separate PRs:

  • Implement builtin github: scheme in Go
  • Switch to template: scheme, but keep template:// working for backwards compatibility
  • Add BATS tests for plugins in general and url-* plugins in particular
  • Explain url-* plugins in the docs

Also fix the global option processing so that they are
not passed on to the plugin commands.

Signed-off-by: Jan Dubois <[email protected]>
@jandubois jandubois force-pushed the custom-url-schemes branch 2 times, most recently from d306d12 to 97a9d84 Compare September 28, 2025 20:20
The template reader will attempt to call `limactl-url-$SCHEME` to
rewrite a custom URL as either a local filename, or a URL with a
supported URL like https.

Signed-off-by: Jan Dubois <[email protected]>
@jandubois
Copy link
Member Author

Still missing, but could be done in several separate PRs:

  • Switch to template: scheme, but keep template:// working for backwards compatibility

I've made that change as well now (in a separate commit), but I think this PR is getting too big. Can we get this reviewed and merged, and do the remaining tasks in separate PRs?

README.md Outdated
To run containers with Docker:
```bash
limactl start template://docker
limactl start template:docker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old form should be kept until people actually begin using v2

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of disagree. The website should document the released version, but the README.md should correspond to the state of the branch.

Otherwise we could also not close issues until their PRs have been included in a new release, which would make the whole workflow really awkward.

I'll revert for now, but after 2.0 we should rethink our workflow, and also figure out how to have a version of the docs for the last release, and a different version for the head of master.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless to our intention, people will just refer to the README in the default branch and will continue opening "I followed README but it doesn't work" issues when the content conflicts with the latest release, so we have to care about them

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless to our intention, people will just refer to the README in the default branch

I think the way to deal with that is to remove end-user instructions from the README and point them to the docs. There is no reason to repeat usage documentation in it.


README

Lima is Linux Machines running in a VM...

How to install and use?

Please read the [Documentation] and follow the [Installation] instructions.

Community channels

  • New releases on GitHub
  • GitHub Discussions and Issues
  • Slack
  • Community meetings (maybe?)
  • Social media (if we start posting there)

Developing Lima

Required tools and their version

How to build

How to run tests

License

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still prefer to keep the "TLDR" abstract in README.md.
First comers do not want to access the website when they do not even know what it is all about.

The old style template://name URLs are malformed because they do not
contain a valid AUTHORITY (host name), but treat the host name as part
of the path. They are still fully supported, but will emit a warning.

Signed-off-by: Jan Dubois <[email protected]>
Copy link
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@AkihiroSuda AkihiroSuda merged commit 70a3f13 into lima-vm:master Sep 29, 2025
61 of 63 checks passed
@jandubois jandubois deleted the custom-url-schemes branch September 29, 2025 23:06
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
@AkihiroSuda
Copy link
Member

On the second thought, a locator plugin should return the YAML contents, not HTTPS URL, so as to support non-HTTP and non-local remotes

jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 4, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
jandubois added a commit to jandubois/lima that referenced this pull request Oct 5, 2025
This is a reimplementation of the bash code in
lima-vm#3937 (comment)

Signed-off-by: Jan Dubois <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants