Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Here are some pointers to get started with Multipass.

| Task | Command |
|----|----|
| Find available images | `multipass find` |
| List available images | `multipass images` |
| Launch an instance with the current Ubuntu LTS | `multipass launch lts` |
| List existing instances | `multipass list` |
| Get info about an instance | `multipass info <instance-name>` |
Expand Down
4 changes: 2 additions & 2 deletions completions/bash/multipass
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ _multipass_complete()
fi
cmd="${COMP_WORDS[1]}"
prev_opts=false
multipass_cmds="authenticate transfer delete exec find help info launch list mount networks \
multipass_cmds="authenticate transfer delete exec images help info launch list mount networks \
purge recover restart restore shell snapshot start stop suspend unmount \
version get set clone alias aliases unalias"

Expand Down Expand Up @@ -267,7 +267,7 @@ _multipass_complete()
"stop")
_add_nonrepeating_args "--all --cancel --time"
;;
"find")
"images"|"find")
_add_nonrepeating_args "--show-unsupported --force-update --format"
;;
"unalias")
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
# the sphinx_reredirects extension will be disabled.

redirects = {
"reference/command-line-interface/find": "../images/",
"reference/command-line-interface/umount": "../unmount/",
}

Expand Down
4 changes: 2 additions & 2 deletions docs/explanation/image.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
(explanation-image)=
# Image

> See also: [`find`](/reference/command-line-interface/find), [`launch`](/reference/command-line-interface/launch)
> See also: [`images`](/reference/command-line-interface/images), [`launch`](/reference/command-line-interface/launch)

Multipass uses **images** (short for [disk images](https://en.wikipedia.org/wiki/Disk_image) or [system images](https://en.wikipedia.org/wiki/System_image)) tuned for cloud usage to spin up VMs.

You can use `multipass find` to view a list of the available images. These images are obtained from different sources, such as:
You can use `multipass images` to view a list of the available images. These images are obtained from different sources, such as:
* Ubuntu Cloud Images: https://cloud-images.ubuntu.com/
* Ubuntu CD Images: https://cdimages.ubuntu.com/

Expand Down
4 changes: 2 additions & 2 deletions docs/how-to-guides/manage-instances/create-an-instance.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ Mounts: --

## Create an instance with a specific image

> See also: [`find`](reference-command-line-interface-find), [`launch <image>`](reference-command-line-interface-launch), [`info`](reference-command-line-interface-info)
> See also: [`images`](reference-command-line-interface-images), [`launch <image>`](reference-command-line-interface-launch), [`info`](reference-command-line-interface-info)

To find out which images are available, run `multipass find`. Here's a sample output:
To find out which images are available, run `multipass images`. Here's a sample output:

```{code-block} text
Image Aliases Version Description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ When successful, you should see Multipass's instances in VirtualBox

This can be caused by a known Qt bug (see issue [#1714](https://github.com/canonical/multipass/issues/1714) on our GitHub).

A workaround to resolve this issue is to run the command `multipass find --force-update`, which forces downloading the image information from the network. As a result, if the download is successful, the `network-cache` will be overwritten.
A workaround to resolve this issue is to run the command `multipass images --force-update`, which forces downloading the image information from the network. As a result, if the download is successful, the `network-cache` will be overwritten.

Alternatively, try deleting the `network-cache` folder and restart the Multipass service:

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<!--Welcome to the *Multipass Guide!*

Multipass is a mini-cloud on your workstation using native hypervisors of all the supported plaforms (Windows, macOS and Linux), it will give you an Ubuntu command line in just a click ("Open shell") or a simple `multipass shell` command, or even a keyboard shortcut. Find what images are available with `multipass find` and create new instances with `multipass launch`.
Multipass is a mini-cloud on your workstation using native hypervisors of all the supported plaforms (Windows, macOS and Linux), it will give you an Ubuntu command line in just a click ("Open shell") or a simple `multipass shell` command, or even a keyboard shortcut. Find what images are available with `multipass images` and create new instances with `multipass launch`.

You can initialise instances through [cloud-init](https://cloudinit.readthedocs.io/en/latest/) as you normally would on all the clouds Ubuntu is supported on, just pass the configuration to `multipass launch --cloud-init`.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(reference-command-line-interface-find)=
# find
(reference-command-line-interface-images)=
# images

The `multipass find` command without any argument lists the images Multipass can use to run instances with [`launch`](/reference/command-line-interface/launch) on your system and associated version information. For example:
The `multipass images` command without any argument lists the images Multipass can use to run instances with [`launch`](/reference/command-line-interface/launch) on your system and associated version information. For example:

```{code-block} text
Image Aliases Version Description
Expand Down Expand Up @@ -37,7 +37,7 @@ The list of available images is updated periodically. The option `--force-update

The option `--show-unsupported` includes old Ubuntu images, which were available at some point but are not supported anymore. This means that some features of Multipass might not work on these images and no user support is given. However, they are still available for testing.

The command also supports searching through available images. For example, `multipass find resolute` returns:
The command also supports searching through available images. For example, `multipass images resolute` returns:

```{code-block} text
Image Aliases Version Description
Expand All @@ -47,10 +47,10 @@ resolute 20260720 Ubuntu 26.04 LTS

---

The full `multipass help find` output explains the available options:
The full `multipass help images` output explains the available options:

```{code-block} text
Usage: multipass find [options] [<remote:>][<string>]
Usage: multipass images [options] [<remote:>][<string>]
Lists available images matching <string> for creating instances from.
With no search string, lists all aliases for supported releases.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/command-line-interface/launch.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ You can then shell into an instance by its name:
multipass shell relishing-lionfish
```

The only, optional, positional argument is the image to launch an instance from. See [`find`](/reference/command-line-interface/find) for how to find information on the available images.
The only, optional, positional argument is the image to launch an instance from. See [`images`](/reference/command-line-interface/images) for how to find information on the available images.

It's also possible to provide a full URL to the image (use `file://` for an image available on the host running `multipassd`).

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/gui-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ as well as a {ref}`gui-client-tray-icon` menu.
(gui-client-catalogue-tab)=
## Catalogue tab

Here you can browse the available Ubuntu images. The output is equivalent to the one given by `multipass find --only-images`.
Here you can browse the available Ubuntu, Debian and Fedora images.

```{figure} /images/gui-client/multipass-gui-catalogue-tab.png
:width: 720px
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,10 @@ In Multipass, an instance with the name "primary" is privileged. That is, it ser

## Create a customised instance

Multipass has a great feature to help you get started with creating customised instances. Open a terminal and run the `multipass find` command. The result shows a list of all images you can currently launch through Multipass.
Multipass has a great feature to help you get started with creating customised instances. Open a terminal and run the `multipass images` command. The result shows a list of all images you can currently launch through Multipass.

```{code-block} text
$ multipass find
$ multipass images
Image Aliases Version Description
22.04 jammy 20260515 Ubuntu 22.04 LTS
24.04 noble 20260518 Ubuntu 24.04 LTS
Expand Down
1 change: 1 addition & 0 deletions include/multipass/cli/argparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class ArgParser
QString value(const QString& option) const;
QStringList values(const QCommandLineOption& option) const;

QString commandName() const;
QStringList positionalArguments() const;

QStringList unknownOptionNames() const;
Expand Down
2 changes: 1 addition & 1 deletion include/multipass/cli/csv_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class CSVFormatter final : public Formatter
std::string format(const InfoReply& info) const override;
std::string format(const ListReply& list) const override;
std::string format(const NetworksReply& list) const override;
std::string format(const FindReply& list) const override;
std::string format(const ImagesReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
Expand Down
11 changes: 2 additions & 9 deletions include/multipass/cli/dispatch_rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <multipass/cli/return_codes.h>
#include <multipass/format.h>
#include <multipass/reply_concepts.h>
#include <multipass/user_messages/driver_deprecation_warning.h>
#include <multipass/utils.h>

#include <QLocalSocket>
Expand Down Expand Up @@ -81,14 +82,6 @@ auto adapt_failure_handler(FailureCallable& on_failure,
};
}

// TODO@deprecations remove
inline bool is_repeated_deprecation_warning(const std::string& log_line)
{
static const std::regex warning{R"(^\*\*\* Warning! The \S+ driver is deprecated)"};
static bool warned = false;
return std::regex_search(log_line, warning) && std::exchange(warned, true);
}

} // namespace detail

template <typename RpcFunc,
Expand Down Expand Up @@ -122,7 +115,7 @@ ReturnCodeVariant dispatch_rpc_stream(Rpc::StubInterface* stub,
{
// TODO@deprecations remove
if constexpr (LogReply<ReplyType>)
if (detail::is_repeated_deprecation_warning(reply.log_line()))
if (is_repeated_driver_deprecation_warning(reply.log_line()))
reply.clear_log_line();

streaming_callback(reply, client.get());
Expand Down
2 changes: 1 addition & 1 deletion include/multipass/cli/formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Formatter : private DisabledCopyMove
virtual std::string format(const InfoReply& reply) const = 0;
virtual std::string format(const ListReply& reply) const = 0;
virtual std::string format(const NetworksReply& reply) const = 0;
virtual std::string format(const FindReply& reply) const = 0;
virtual std::string format(const ImagesReply& reply) const = 0;
virtual std::string format(const VersionReply& reply,
const std::string& client_version) const = 0;
virtual std::string format(const AliasDict& aliases) const = 0;
Expand Down
2 changes: 1 addition & 1 deletion include/multipass/cli/json_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class JsonFormatter final : public Formatter
std::string format(const InfoReply& info) const override;
std::string format(const ListReply& list) const override;
std::string format(const NetworksReply& list) const override;
std::string format(const FindReply& list) const override;
std::string format(const ImagesReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
Expand Down
2 changes: 1 addition & 1 deletion include/multipass/cli/table_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class TableFormatter final : public Formatter
std::string format(const InfoReply& info) const override;
std::string format(const ListReply& list) const override;
std::string format(const NetworksReply& list) const override;
std::string format(const FindReply& list) const override;
std::string format(const ImagesReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
Expand Down
2 changes: 1 addition & 1 deletion include/multipass/cli/yaml_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class YamlFormatter final : public Formatter
std::string format(const InfoReply& info) const override;
std::string format(const ListReply& list) const override;
std::string format(const NetworksReply& list) const override;
std::string format(const FindReply& list) const override;
std::string format(const ImagesReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
Expand Down
37 changes: 37 additions & 0 deletions include/multipass/user_messages/deprecation_warning.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
* SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include <fmt/format.h>
#include <string>
Comment thread
Copilot marked this conversation as resolved.
#include <utility>

namespace multipass
{

template <typename DeprecatedFeature, typename AdviceMessage>
std::string make_deprecation_warning(DeprecatedFeature&& deprecated_feature, AdviceMessage&& advice)
Comment thread
Laefy marked this conversation as resolved.
{
return fmt::format(
"*** Warning: {} is deprecated and will be removed in an upcoming release. ***\n\n"
"{}\n\n",
std::forward<DeprecatedFeature>(deprecated_feature),
std::forward<AdviceMessage>(advice));
}

} // namespace multipass
68 changes: 68 additions & 0 deletions include/multipass/user_messages/driver_deprecation_warning.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
* SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include "deprecation_warning.h"

#include <fmt/format.h>
#include <regex>
#include <string>
#include <utility>

namespace multipass
{

// TODO@deprecations remove
inline bool is_repeated_driver_deprecation_warning(const std::string& log_line)
{
static const std::regex warning{R"(^\*\*\* Warning: the \S+ driver is deprecated)"};
Comment thread
ricab marked this conversation as resolved.
static bool warned = false;
return std::regex_search(log_line, warning) && std::exchange(warned, true);
}

template <typename DeprecatedDriverName,
typename RecommendedDriverName,
typename RecommendedDriverId>
std::string make_driver_deprecation_warning(DeprecatedDriverName&& deprecated_name,
RecommendedDriverName&& recommended_name,
RecommendedDriverId&& recommended_id,
bool migrationful)
{
const auto deprecated_feature = fmt::format(
"the {} driver",
std::forward<DeprecatedDriverName>(deprecated_name));

constexpr auto migrationless_advice =
"We recommend switching to the new {0} driver as soon as possible (multipass set "
"local.driver={1}). Your instances will not be destroyed but they will be unreachable from "
"the new driver. You can switch back to the old driver for now, but you will need to "
"manually recreate any instances you want to keep in the next release.";

constexpr auto migrationful_advice =
"When you are ready to have your instances migrated, please stop them (multipass stop "
"--all) and switch to the new {0} driver (multipass set local.driver={1}).";

const auto deprecation_advice = fmt::format(
fmt::runtime(migrationful ? migrationful_advice : migrationless_advice),
std::forward<RecommendedDriverName>(recommended_name),
std::forward<RecommendedDriverId>(recommended_id));

return make_deprecation_warning(deprecated_feature, deprecation_advice);
}

} // namespace multipass
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ add_subdirectory(settings)
add_subdirectory(simplestreams)
add_subdirectory(ssh)
add_subdirectory(sshfs_mount)
add_subdirectory(user_messages)
add_subdirectory(utils)
add_subdirectory(xz_decoder)
15 changes: 11 additions & 4 deletions src/client/cli/argparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ auto max_command_string_length(const std::vector<cmd::Command::UPtr>& commands)
auto string_len_compare = [](const cmd::Command::UPtr& a, const cmd::Command::UPtr& b) {
return a->name().length() < b->name().length();
};
const auto& max_elem =
*std::max_element(commands.begin(), commands.end(), string_len_compare);
const auto& max_elem = *std::max_element(commands.begin(),
commands.end(),
string_len_compare);
ret = max_elem->name().length();
}

Expand Down Expand Up @@ -158,8 +159,8 @@ mp::ParseCode mp::ArgParser::parse(const std::optional<mp::AliasDict>& aliases)
}

const QString requested_command = parser.isSet(version_option)
? QStringLiteral("version")
: parser.positionalArguments().first();
? QStringLiteral("version")
: parser.positionalArguments().first();

chosen_command = findCommand(requested_command);

Expand Down Expand Up @@ -372,6 +373,12 @@ QStringList mp::ArgParser::values(const QCommandLineOption& option) const
return parser.values(option);
}

QString mp::ArgParser::commandName() const
{
const auto& args = parser.positionalArguments();
return args.isEmpty() ? QString() : args.first();
}

QStringList mp::ArgParser::positionalArguments() const
{
// Remove the first "command" positional argument, if there, so calling Command sees just the
Expand Down
Loading
Loading