We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
update homebrew formula to newest microk8s version (1.27) and ubuntu version (22.04)- otherwise Mac Users can't use it. 
#### Summary
The latest present formula on homebrew  as of June 2023 point to ubuntu version 18.04 and microk8s version 1.26. This makes it near to impossible for mac users to use it.

#### Why is this important?
Lot has changed since that time. The instructions do not work in the present day, leading to newbies like myself wasting precious time, assuming the fault is theirs :)

#### Are you interested in contributing to this feature?
yep definitely.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `installer/common/definitions.py`
Content:
```
1 MAX_CHARACTERS_WRAP: int = 120
2 command_descriptions = {
3     "add-node": "Adds a node to a cluster",
4     "ambassador": "Ambassador API Gateway and Ingress",
5     "cilium": "The cilium client",
6     "config": "Print the kubeconfig",
7     "ctr": "The containerd client",
8     "dashboard-proxy": "Enable the Kubernetes dashboard and proxy to host",
9     "dbctl": "Backup and restore the Kubernetes datastore",
10     "disable": "Disables running add-ons",
11     "enable": "Enables useful add-ons",
12     "helm": "The helm client",
13     "helm3": "The helm3 client",
14     "inspect": "Checks the cluster and gathers logs",
15     "istioctl": "The istio client",
16     "join": "Joins this instance as a node to a cluster",
17     "kubectl": "The kubernetes client",
18     "leave": "Disconnects this node from any cluster it has joined",
19     "linkerd": "The linkerd client",
20     "refresh-certs": "Refresh the CA certificates in this deployment",
21     "remove-node": "Removes a node from the cluster",
22     "reset": "Cleans the cluster from all workloads",
23     "start": "Starts the kubernetes cluster",
24     "status": "Displays the status of the cluster",
25     "stop": "Stops the kubernetes cluster",
26 }
27 DEFAULT_CORES: int = 2
28 DEFAULT_MEMORY_GB: int = 4
29 DEFAULT_DISK_GB: int = 50
30 DEFAULT_ASSUME: bool = False
31 DEFAULT_CHANNEL: str = "1.26/stable"
32 DEFAULT_IMAGE: str = "18.04"
33 
34 MIN_CORES: int = 2
35 MIN_MEMORY_GB: int = 2
36 MIN_DISK_GB: int = 10
37
```

Path: `installer/vm_providers/_multipass/_windows.py`
Content:
```
1 # -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2 #
3 # Copyright (C) 2018 Canonical Ltd
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 3 as
7 # published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 import logging
18 import os.path
19 import requests
20 import shutil
21 import simplejson
22 import subprocess
23 import sys
24 import tempfile
25 
26 from progressbar import AnimatedMarker, Bar, Percentage, ProgressBar, UnknownLength
27 
28 from common.file_utils import calculate_sha3_384, is_dumb_terminal
29 from vm_providers.errors import (
30     ProviderMultipassDownloadFailed,
31     ProviderMultipassInstallationFailed,
32 )
33 
34 if sys.platform == "win32":
35     import winreg
36 
37 
38 logger = logging.getLogger(__name__)
39 
40 
41 _MULTIPASS_RELEASES_API_URL = "https://api.github.com/repos/canonical/multipass/releases"
42 _MULTIPASS_DL_VERSION = "1.11.1"
43 _MULTIPASS_DL_NAME = "multipass-{version}+win-win64.exe".format(version=_MULTIPASS_DL_VERSION)
44 
45 # Download multipass installer and calculate hash:
46 #   python3 -c "from installer.common.file_utils import calculate_sha3_384; print(calculate_sha3_384('$HOME/Downloads/multipass-1.11.1+win-win64.exe'))"  # noqa: E501
47 _MULTIPASS_DL_SHA3_384 = "7691383eb0f4def0f9e2b5c77f04424756a63f222b3500bdc8fb25bf4725f1c0ce3bd0cb0b7cff7f79d8f489e199225b"  # noqa: E501
48 
49 
50 def windows_reload_multipass_path_env():
51     """Update PATH to include installed Multipass, if not already set."""
52 
53     assert sys.platform == "win32"
54 
55     key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment")
56 
57     paths = os.environ["PATH"].split(";")
58 
59     # Drop empty placeholder for trailing comma, if present.
60     if paths[-1] == "":
61         del paths[-1]
62 
63     reg_user_path, _ = winreg.QueryValueEx(key, "Path")
64     for path in reg_user_path.split(";"):
65         if path not in paths and "Multipass" in path:
66             paths.append(path)
67 
68     # Restore path with trailing comma.
69     os.environ["PATH"] = ";".join(paths) + ";"
70 
71 
72 def _run_installer(installer_path: str, echoer):
73     """Execute multipass installer."""
74 
75     echoer.info("Installing Multipass...")
76 
77     # Multipass requires administrative privileges to install, which requires
78     # the use of `runas` functionality. Some of the options included:
79     # (1) https://stackoverflow.com/a/34216774
80     # (2) ShellExecuteW and wait on installer by attempting to delete it.
81     # Windows would prevent us from deleting installer with a PermissionError:
82     # PermissionError: [WinError 32] The process cannot access the file because
83     # it is being used by another process: <path>
84     # (3) Use PowerShell's "Start-Process" with RunAs verb as shown below.
85     # None of the options are quite ideal, but #3 will do.
86     cmd = """
87     & {{
88         try {{
89             $Output = Start-Process -FilePath {path!r} -Args /S -Verb RunAs -Wait -PassThru
90         }} catch {{
91             [Environment]::Exit(1)
92         }}
93       }}
94     """.format(
95         path=installer_path
96     )
97 
98     try:
99         subprocess.check_call(["powershell.exe", "-Command", cmd])
100     except subprocess.CalledProcessError:
101         raise ProviderMultipassInstallationFailed("error launching installer")
102 
103     # Reload path environment to see if we can find multipass now.
104     windows_reload_multipass_path_env()
105 
106     if not shutil.which("multipass.exe"):
107         # Installation failed.
108         raise ProviderMultipassInstallationFailed("installation did not complete successfully")
109 
110     echoer.info("Multipass installation completed successfully.")
111 
112 
113 def _requests_exception_hint(e: requests.RequestException) -> str:
114     # Use the __doc__ description to give the user a hint. It seems to be a
115     # a decent option over trying to enumerate all of possible types.
116     if e.__doc__:
117         split_lines = e.__doc__.splitlines()
118         if split_lines:
119             return e.__doc__.splitlines()[0].decode().strip()
120 
121     # Should never get here.
122     return "unknown download error"
123 
124 
125 def _fetch_installer_url() -> str:
126     """Verify version set is a valid
127     ref in GitHub and return the full
128     URL.
129     """
130 
131     try:
132         resp = requests.get(_MULTIPASS_RELEASES_API_URL)
133     except requests.RequestException as e:
134         raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))
135 
136     try:
137         data = resp.json()
138     except simplejson.JSONDecodeError:
139         raise ProviderMultipassDownloadFailed(
140             "failed to fetch valid release data from {}".format(_MULTIPASS_RELEASES_API_URL)
141         )
142 
143     for assets in data:
144         for asset in assets.get("assets", list()):
145             # Find matching name.
146             if asset.get("name") != _MULTIPASS_DL_NAME:
147                 continue
148 
149             return asset.get("browser_download_url")
150 
151     # Something changed we don't know about - we will simply categorize
152     # all possible events as an updated version we do not yet know about.
153     raise ProviderMultipassDownloadFailed("ref specified is not a valid ref in GitHub")
154 
155 
156 def _download_multipass(dl_dir: str, echoer) -> str:
157     """Creates temporary Downloads installer to temp directory."""
158 
159     dl_url = _fetch_installer_url()
160     dl_basename = os.path.basename(dl_url)
161     dl_path = os.path.join(dl_dir, dl_basename)
162 
163     echoer.info("Downloading Multipass installer...\n{} -> {}".format(dl_url, dl_path))
164 
165     try:
166         request = requests.get(dl_url, stream=True, allow_redirects=True)
167         request.raise_for_status()
168         download_requests_stream(request, dl_path)
169     except requests.RequestException as e:
170         raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))
171 
172     digest = calculate_sha3_384(dl_path)
173     if digest != _MULTIPASS_DL_SHA3_384:
174         raise ProviderMultipassDownloadFailed(
175             "download failed verification (expected={} but found={})".format(
176                 _MULTIPASS_DL_SHA3_384, digest
177             )
178         )
179 
180     echoer.info("Verified installer successfully...")
181     return dl_path
182 
183 
184 def windows_install_multipass(echoer) -> None:
185     """Download and install multipass."""
186 
187     assert sys.platform == "win32"
188 
189     dl_dir = tempfile.mkdtemp()
190     dl_path = _download_multipass(dl_dir, echoer)
191     _run_installer(dl_path, echoer)
192 
193     # Cleanup.
194     shutil.rmtree(dl_dir)
195 
196 
197 def _init_progress_bar(total_length, destination, message=None):
198     if not message:
199         message = "Downloading {!r}".format(os.path.basename(destination))
200 
201     valid_length = total_length and total_length > 0
202 
203     if valid_length and is_dumb_terminal():
204         widgets = [message, " ", Percentage()]
205         maxval = total_length
206     elif valid_length and not is_dumb_terminal():
207         widgets = [message, Bar(marker="=", left="[", right="]"), " ", Percentage()]
208         maxval = total_length
209     elif not valid_length and is_dumb_terminal():
210         widgets = [message]
211         maxval = UnknownLength
212     else:
213         widgets = [message, AnimatedMarker()]
214         maxval = UnknownLength
215 
216     return ProgressBar(widgets=widgets, maxval=maxval)
217 
218 
219 def download_requests_stream(request_stream, destination, message=None, total_read=0):
220     """This is a facility to download a request with nice progress bars."""
221 
222     # Doing len(request_stream.content) may defeat the purpose of a
223     # progress bar
224     total_length = 0
225     if not request_stream.headers.get("Content-Encoding", ""):
226         total_length = int(request_stream.headers.get("Content-Length", "0"))
227         # Content-Length in the case of resuming will be
228         # Content-Length - total_read so we add back up to have the feel of
229         # resuming
230         if os.path.exists(destination):
231             total_length += total_read
232 
233     progress_bar = _init_progress_bar(total_length, destination, message)
234     progress_bar.start()
235 
236     if os.path.exists(destination):
237         mode = "ab"
238     else:
239         mode = "wb"
240     with open(destination, mode) as destination_file:
241         for buf in request_stream.iter_content(1024):
242             destination_file.write(buf)
243             if not is_dumb_terminal():
244                 total_read += len(buf)
245                 progress_bar.update(total_read)
246     progress_bar.finish()
247
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/installer/common/definitions.py b/installer/common/definitions.py
--- a/installer/common/definitions.py
+++ b/installer/common/definitions.py
@@ -28,8 +28,8 @@
 DEFAULT_MEMORY_GB: int = 4
 DEFAULT_DISK_GB: int = 50
 DEFAULT_ASSUME: bool = False
-DEFAULT_CHANNEL: str = "1.26/stable"
-DEFAULT_IMAGE: str = "18.04"
+DEFAULT_CHANNEL: str = "1.27/stable"
+DEFAULT_IMAGE: str = "22.04"
 
 MIN_CORES: int = 2
 MIN_MEMORY_GB: int = 2
diff --git a/installer/vm_providers/_multipass/_windows.py b/installer/vm_providers/_multipass/_windows.py
--- a/installer/vm_providers/_multipass/_windows.py
+++ b/installer/vm_providers/_multipass/_windows.py
@@ -39,12 +39,12 @@
 
 
 _MULTIPASS_RELEASES_API_URL = "https://api.github.com/repos/canonical/multipass/releases"
-_MULTIPASS_DL_VERSION = "1.11.1"
+_MULTIPASS_DL_VERSION = "1.12.0"
 _MULTIPASS_DL_NAME = "multipass-{version}+win-win64.exe".format(version=_MULTIPASS_DL_VERSION)
 
 # Download multipass installer and calculate hash:
 #   python3 -c "from installer.common.file_utils import calculate_sha3_384; print(calculate_sha3_384('$HOME/Downloads/multipass-1.11.1+win-win64.exe'))"  # noqa: E501
-_MULTIPASS_DL_SHA3_384 = "7691383eb0f4def0f9e2b5c77f04424756a63f222b3500bdc8fb25bf4725f1c0ce3bd0cb0b7cff7f79d8f489e199225b"  # noqa: E501
+_MULTIPASS_DL_SHA3_384 = "ddba66059052a67fa6a363729b75aca374591bc5a2531c938dd70d63f683c22108d5c2ab77025b818b31f69103228eee"  # noqa: E501
 
 
 def windows_reload_multipass_path_env():

{"golden_diff": "diff --git a/installer/common/definitions.py b/installer/common/definitions.py\n--- a/installer/common/definitions.py\n+++ b/installer/common/definitions.py\n@@ -28,8 +28,8 @@\n DEFAULT_MEMORY_GB: int = 4\n DEFAULT_DISK_GB: int = 50\n DEFAULT_ASSUME: bool = False\n-DEFAULT_CHANNEL: str = \"1.26/stable\"\n-DEFAULT_IMAGE: str = \"18.04\"\n+DEFAULT_CHANNEL: str = \"1.27/stable\"\n+DEFAULT_IMAGE: str = \"22.04\"\n \n MIN_CORES: int = 2\n MIN_MEMORY_GB: int = 2\ndiff --git a/installer/vm_providers/_multipass/_windows.py b/installer/vm_providers/_multipass/_windows.py\n--- a/installer/vm_providers/_multipass/_windows.py\n+++ b/installer/vm_providers/_multipass/_windows.py\n@@ -39,12 +39,12 @@\n \n \n _MULTIPASS_RELEASES_API_URL = \"https://api.github.com/repos/canonical/multipass/releases\"\n-_MULTIPASS_DL_VERSION = \"1.11.1\"\n+_MULTIPASS_DL_VERSION = \"1.12.0\"\n _MULTIPASS_DL_NAME = \"multipass-{version}+win-win64.exe\".format(version=_MULTIPASS_DL_VERSION)\n \n # Download multipass installer and calculate hash:\n #   python3 -c \"from installer.common.file_utils import calculate_sha3_384; print(calculate_sha3_384('$HOME/Downloads/multipass-1.11.1+win-win64.exe'))\"  # noqa: E501\n-_MULTIPASS_DL_SHA3_384 = \"7691383eb0f4def0f9e2b5c77f04424756a63f222b3500bdc8fb25bf4725f1c0ce3bd0cb0b7cff7f79d8f489e199225b\"  # noqa: E501\n+_MULTIPASS_DL_SHA3_384 = \"ddba66059052a67fa6a363729b75aca374591bc5a2531c938dd70d63f683c22108d5c2ab77025b818b31f69103228eee\"  # noqa: E501\n \n \n def windows_reload_multipass_path_env():\n", "issue": "update homebrew formula to newest microk8s version (1.27) and ubuntu version (22.04)- otherwise Mac Users can't use it. \n#### Summary\r\nThe latest present formula on homebrew  as of June 2023 point to ubuntu version 18.04 and microk8s version 1.26. This makes it near to impossible for mac users to use it.\r\n\r\n#### Why is this important?\r\nLot has changed since that time. The instructions do not work in the present day, leading to newbies like myself wasting precious time, assuming the fault is theirs :)\r\n\r\n#### Are you interested in contributing to this feature?\r\nyep definitely.\r\n\n", "before_files": [{"content": "MAX_CHARACTERS_WRAP: int = 120\ncommand_descriptions = {\n    \"add-node\": \"Adds a node to a cluster\",\n    \"ambassador\": \"Ambassador API Gateway and Ingress\",\n    \"cilium\": \"The cilium client\",\n    \"config\": \"Print the kubeconfig\",\n    \"ctr\": \"The containerd client\",\n    \"dashboard-proxy\": \"Enable the Kubernetes dashboard and proxy to host\",\n    \"dbctl\": \"Backup and restore the Kubernetes datastore\",\n    \"disable\": \"Disables running add-ons\",\n    \"enable\": \"Enables useful add-ons\",\n    \"helm\": \"The helm client\",\n    \"helm3\": \"The helm3 client\",\n    \"inspect\": \"Checks the cluster and gathers logs\",\n    \"istioctl\": \"The istio client\",\n    \"join\": \"Joins this instance as a node to a cluster\",\n    \"kubectl\": \"The kubernetes client\",\n    \"leave\": \"Disconnects this node from any cluster it has joined\",\n    \"linkerd\": \"The linkerd client\",\n    \"refresh-certs\": \"Refresh the CA certificates in this deployment\",\n    \"remove-node\": \"Removes a node from the cluster\",\n    \"reset\": \"Cleans the cluster from all workloads\",\n    \"start\": \"Starts the kubernetes cluster\",\n    \"status\": \"Displays the status of the cluster\",\n    \"stop\": \"Stops the kubernetes cluster\",\n}\nDEFAULT_CORES: int = 2\nDEFAULT_MEMORY_GB: int = 4\nDEFAULT_DISK_GB: int = 50\nDEFAULT_ASSUME: bool = False\nDEFAULT_CHANNEL: str = \"1.26/stable\"\nDEFAULT_IMAGE: str = \"18.04\"\n\nMIN_CORES: int = 2\nMIN_MEMORY_GB: int = 2\nMIN_DISK_GB: int = 10\n", "path": "installer/common/definitions.py"}, {"content": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 3 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nimport logging\nimport os.path\nimport requests\nimport shutil\nimport simplejson\nimport subprocess\nimport sys\nimport tempfile\n\nfrom progressbar import AnimatedMarker, Bar, Percentage, ProgressBar, UnknownLength\n\nfrom common.file_utils import calculate_sha3_384, is_dumb_terminal\nfrom vm_providers.errors import (\n    ProviderMultipassDownloadFailed,\n    ProviderMultipassInstallationFailed,\n)\n\nif sys.platform == \"win32\":\n    import winreg\n\n\nlogger = logging.getLogger(__name__)\n\n\n_MULTIPASS_RELEASES_API_URL = \"https://api.github.com/repos/canonical/multipass/releases\"\n_MULTIPASS_DL_VERSION = \"1.11.1\"\n_MULTIPASS_DL_NAME = \"multipass-{version}+win-win64.exe\".format(version=_MULTIPASS_DL_VERSION)\n\n# Download multipass installer and calculate hash:\n#   python3 -c \"from installer.common.file_utils import calculate_sha3_384; print(calculate_sha3_384('$HOME/Downloads/multipass-1.11.1+win-win64.exe'))\"  # noqa: E501\n_MULTIPASS_DL_SHA3_384 = \"7691383eb0f4def0f9e2b5c77f04424756a63f222b3500bdc8fb25bf4725f1c0ce3bd0cb0b7cff7f79d8f489e199225b\"  # noqa: E501\n\n\ndef windows_reload_multipass_path_env():\n    \"\"\"Update PATH to include installed Multipass, if not already set.\"\"\"\n\n    assert sys.platform == \"win32\"\n\n    key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, \"Environment\")\n\n    paths = os.environ[\"PATH\"].split(\";\")\n\n    # Drop empty placeholder for trailing comma, if present.\n    if paths[-1] == \"\":\n        del paths[-1]\n\n    reg_user_path, _ = winreg.QueryValueEx(key, \"Path\")\n    for path in reg_user_path.split(\";\"):\n        if path not in paths and \"Multipass\" in path:\n            paths.append(path)\n\n    # Restore path with trailing comma.\n    os.environ[\"PATH\"] = \";\".join(paths) + \";\"\n\n\ndef _run_installer(installer_path: str, echoer):\n    \"\"\"Execute multipass installer.\"\"\"\n\n    echoer.info(\"Installing Multipass...\")\n\n    # Multipass requires administrative privileges to install, which requires\n    # the use of `runas` functionality. Some of the options included:\n    # (1) https://stackoverflow.com/a/34216774\n    # (2) ShellExecuteW and wait on installer by attempting to delete it.\n    # Windows would prevent us from deleting installer with a PermissionError:\n    # PermissionError: [WinError 32] The process cannot access the file because\n    # it is being used by another process: <path>\n    # (3) Use PowerShell's \"Start-Process\" with RunAs verb as shown below.\n    # None of the options are quite ideal, but #3 will do.\n    cmd = \"\"\"\n    & {{\n        try {{\n            $Output = Start-Process -FilePath {path!r} -Args /S -Verb RunAs -Wait -PassThru\n        }} catch {{\n            [Environment]::Exit(1)\n        }}\n      }}\n    \"\"\".format(\n        path=installer_path\n    )\n\n    try:\n        subprocess.check_call([\"powershell.exe\", \"-Command\", cmd])\n    except subprocess.CalledProcessError:\n        raise ProviderMultipassInstallationFailed(\"error launching installer\")\n\n    # Reload path environment to see if we can find multipass now.\n    windows_reload_multipass_path_env()\n\n    if not shutil.which(\"multipass.exe\"):\n        # Installation failed.\n        raise ProviderMultipassInstallationFailed(\"installation did not complete successfully\")\n\n    echoer.info(\"Multipass installation completed successfully.\")\n\n\ndef _requests_exception_hint(e: requests.RequestException) -> str:\n    # Use the __doc__ description to give the user a hint. It seems to be a\n    # a decent option over trying to enumerate all of possible types.\n    if e.__doc__:\n        split_lines = e.__doc__.splitlines()\n        if split_lines:\n            return e.__doc__.splitlines()[0].decode().strip()\n\n    # Should never get here.\n    return \"unknown download error\"\n\n\ndef _fetch_installer_url() -> str:\n    \"\"\"Verify version set is a valid\n    ref in GitHub and return the full\n    URL.\n    \"\"\"\n\n    try:\n        resp = requests.get(_MULTIPASS_RELEASES_API_URL)\n    except requests.RequestException as e:\n        raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))\n\n    try:\n        data = resp.json()\n    except simplejson.JSONDecodeError:\n        raise ProviderMultipassDownloadFailed(\n            \"failed to fetch valid release data from {}\".format(_MULTIPASS_RELEASES_API_URL)\n        )\n\n    for assets in data:\n        for asset in assets.get(\"assets\", list()):\n            # Find matching name.\n            if asset.get(\"name\") != _MULTIPASS_DL_NAME:\n                continue\n\n            return asset.get(\"browser_download_url\")\n\n    # Something changed we don't know about - we will simply categorize\n    # all possible events as an updated version we do not yet know about.\n    raise ProviderMultipassDownloadFailed(\"ref specified is not a valid ref in GitHub\")\n\n\ndef _download_multipass(dl_dir: str, echoer) -> str:\n    \"\"\"Creates temporary Downloads installer to temp directory.\"\"\"\n\n    dl_url = _fetch_installer_url()\n    dl_basename = os.path.basename(dl_url)\n    dl_path = os.path.join(dl_dir, dl_basename)\n\n    echoer.info(\"Downloading Multipass installer...\\n{} -> {}\".format(dl_url, dl_path))\n\n    try:\n        request = requests.get(dl_url, stream=True, allow_redirects=True)\n        request.raise_for_status()\n        download_requests_stream(request, dl_path)\n    except requests.RequestException as e:\n        raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))\n\n    digest = calculate_sha3_384(dl_path)\n    if digest != _MULTIPASS_DL_SHA3_384:\n        raise ProviderMultipassDownloadFailed(\n            \"download failed verification (expected={} but found={})\".format(\n                _MULTIPASS_DL_SHA3_384, digest\n            )\n        )\n\n    echoer.info(\"Verified installer successfully...\")\n    return dl_path\n\n\ndef windows_install_multipass(echoer) -> None:\n    \"\"\"Download and install multipass.\"\"\"\n\n    assert sys.platform == \"win32\"\n\n    dl_dir = tempfile.mkdtemp()\n    dl_path = _download_multipass(dl_dir, echoer)\n    _run_installer(dl_path, echoer)\n\n    # Cleanup.\n    shutil.rmtree(dl_dir)\n\n\ndef _init_progress_bar(total_length, destination, message=None):\n    if not message:\n        message = \"Downloading {!r}\".format(os.path.basename(destination))\n\n    valid_length = total_length and total_length > 0\n\n    if valid_length and is_dumb_terminal():\n        widgets = [message, \" \", Percentage()]\n        maxval = total_length\n    elif valid_length and not is_dumb_terminal():\n        widgets = [message, Bar(marker=\"=\", left=\"[\", right=\"]\"), \" \", Percentage()]\n        maxval = total_length\n    elif not valid_length and is_dumb_terminal():\n        widgets = [message]\n        maxval = UnknownLength\n    else:\n        widgets = [message, AnimatedMarker()]\n        maxval = UnknownLength\n\n    return ProgressBar(widgets=widgets, maxval=maxval)\n\n\ndef download_requests_stream(request_stream, destination, message=None, total_read=0):\n    \"\"\"This is a facility to download a request with nice progress bars.\"\"\"\n\n    # Doing len(request_stream.content) may defeat the purpose of a\n    # progress bar\n    total_length = 0\n    if not request_stream.headers.get(\"Content-Encoding\", \"\"):\n        total_length = int(request_stream.headers.get(\"Content-Length\", \"0\"))\n        # Content-Length in the case of resuming will be\n        # Content-Length - total_read so we add back up to have the feel of\n        # resuming\n        if os.path.exists(destination):\n            total_length += total_read\n\n    progress_bar = _init_progress_bar(total_length, destination, message)\n    progress_bar.start()\n\n    if os.path.exists(destination):\n        mode = \"ab\"\n    else:\n        mode = \"wb\"\n    with open(destination, mode) as destination_file:\n        for buf in request_stream.iter_content(1024):\n            destination_file.write(buf)\n            if not is_dumb_terminal():\n                total_read += len(buf)\n                progress_bar.update(total_read)\n    progress_bar.finish()\n", "path": "installer/vm_providers/_multipass/_windows.py"}], "after_files": [{"content": "MAX_CHARACTERS_WRAP: int = 120\ncommand_descriptions = {\n    \"add-node\": \"Adds a node to a cluster\",\n    \"ambassador\": \"Ambassador API Gateway and Ingress\",\n    \"cilium\": \"The cilium client\",\n    \"config\": \"Print the kubeconfig\",\n    \"ctr\": \"The containerd client\",\n    \"dashboard-proxy\": \"Enable the Kubernetes dashboard and proxy to host\",\n    \"dbctl\": \"Backup and restore the Kubernetes datastore\",\n    \"disable\": \"Disables running add-ons\",\n    \"enable\": \"Enables useful add-ons\",\n    \"helm\": \"The helm client\",\n    \"helm3\": \"The helm3 client\",\n    \"inspect\": \"Checks the cluster and gathers logs\",\n    \"istioctl\": \"The istio client\",\n    \"join\": \"Joins this instance as a node to a cluster\",\n    \"kubectl\": \"The kubernetes client\",\n    \"leave\": \"Disconnects this node from any cluster it has joined\",\n    \"linkerd\": \"The linkerd client\",\n    \"refresh-certs\": \"Refresh the CA certificates in this deployment\",\n    \"remove-node\": \"Removes a node from the cluster\",\n    \"reset\": \"Cleans the cluster from all workloads\",\n    \"start\": \"Starts the kubernetes cluster\",\n    \"status\": \"Displays the status of the cluster\",\n    \"stop\": \"Stops the kubernetes cluster\",\n}\nDEFAULT_CORES: int = 2\nDEFAULT_MEMORY_GB: int = 4\nDEFAULT_DISK_GB: int = 50\nDEFAULT_ASSUME: bool = False\nDEFAULT_CHANNEL: str = \"1.27/stable\"\nDEFAULT_IMAGE: str = \"22.04\"\n\nMIN_CORES: int = 2\nMIN_MEMORY_GB: int = 2\nMIN_DISK_GB: int = 10\n", "path": "installer/common/definitions.py"}, {"content": "# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-\n#\n# Copyright (C) 2018 Canonical Ltd\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License version 3 as\n# published by the Free Software Foundation.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nimport logging\nimport os.path\nimport requests\nimport shutil\nimport simplejson\nimport subprocess\nimport sys\nimport tempfile\n\nfrom progressbar import AnimatedMarker, Bar, Percentage, ProgressBar, UnknownLength\n\nfrom common.file_utils import calculate_sha3_384, is_dumb_terminal\nfrom vm_providers.errors import (\n    ProviderMultipassDownloadFailed,\n    ProviderMultipassInstallationFailed,\n)\n\nif sys.platform == \"win32\":\n    import winreg\n\n\nlogger = logging.getLogger(__name__)\n\n\n_MULTIPASS_RELEASES_API_URL = \"https://api.github.com/repos/canonical/multipass/releases\"\n_MULTIPASS_DL_VERSION = \"1.12.0\"\n_MULTIPASS_DL_NAME = \"multipass-{version}+win-win64.exe\".format(version=_MULTIPASS_DL_VERSION)\n\n# Download multipass installer and calculate hash:\n#   python3 -c \"from installer.common.file_utils import calculate_sha3_384; print(calculate_sha3_384('$HOME/Downloads/multipass-1.11.1+win-win64.exe'))\"  # noqa: E501\n_MULTIPASS_DL_SHA3_384 = \"ddba66059052a67fa6a363729b75aca374591bc5a2531c938dd70d63f683c22108d5c2ab77025b818b31f69103228eee\"  # noqa: E501\n\n\ndef windows_reload_multipass_path_env():\n    \"\"\"Update PATH to include installed Multipass, if not already set.\"\"\"\n\n    assert sys.platform == \"win32\"\n\n    key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, \"Environment\")\n\n    paths = os.environ[\"PATH\"].split(\";\")\n\n    # Drop empty placeholder for trailing comma, if present.\n    if paths[-1] == \"\":\n        del paths[-1]\n\n    reg_user_path, _ = winreg.QueryValueEx(key, \"Path\")\n    for path in reg_user_path.split(\";\"):\n        if path not in paths and \"Multipass\" in path:\n            paths.append(path)\n\n    # Restore path with trailing comma.\n    os.environ[\"PATH\"] = \";\".join(paths) + \";\"\n\n\ndef _run_installer(installer_path: str, echoer):\n    \"\"\"Execute multipass installer.\"\"\"\n\n    echoer.info(\"Installing Multipass...\")\n\n    # Multipass requires administrative privileges to install, which requires\n    # the use of `runas` functionality. Some of the options included:\n    # (1) https://stackoverflow.com/a/34216774\n    # (2) ShellExecuteW and wait on installer by attempting to delete it.\n    # Windows would prevent us from deleting installer with a PermissionError:\n    # PermissionError: [WinError 32] The process cannot access the file because\n    # it is being used by another process: <path>\n    # (3) Use PowerShell's \"Start-Process\" with RunAs verb as shown below.\n    # None of the options are quite ideal, but #3 will do.\n    cmd = \"\"\"\n    & {{\n        try {{\n            $Output = Start-Process -FilePath {path!r} -Args /S -Verb RunAs -Wait -PassThru\n        }} catch {{\n            [Environment]::Exit(1)\n        }}\n      }}\n    \"\"\".format(\n        path=installer_path\n    )\n\n    try:\n        subprocess.check_call([\"powershell.exe\", \"-Command\", cmd])\n    except subprocess.CalledProcessError:\n        raise ProviderMultipassInstallationFailed(\"error launching installer\")\n\n    # Reload path environment to see if we can find multipass now.\n    windows_reload_multipass_path_env()\n\n    if not shutil.which(\"multipass.exe\"):\n        # Installation failed.\n        raise ProviderMultipassInstallationFailed(\"installation did not complete successfully\")\n\n    echoer.info(\"Multipass installation completed successfully.\")\n\n\ndef _requests_exception_hint(e: requests.RequestException) -> str:\n    # Use the __doc__ description to give the user a hint. It seems to be a\n    # a decent option over trying to enumerate all of possible types.\n    if e.__doc__:\n        split_lines = e.__doc__.splitlines()\n        if split_lines:\n            return e.__doc__.splitlines()[0].decode().strip()\n\n    # Should never get here.\n    return \"unknown download error\"\n\n\ndef _fetch_installer_url() -> str:\n    \"\"\"Verify version set is a valid\n    ref in GitHub and return the full\n    URL.\n    \"\"\"\n\n    try:\n        resp = requests.get(_MULTIPASS_RELEASES_API_URL)\n    except requests.RequestException as e:\n        raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))\n\n    try:\n        data = resp.json()\n    except simplejson.JSONDecodeError:\n        raise ProviderMultipassDownloadFailed(\n            \"failed to fetch valid release data from {}\".format(_MULTIPASS_RELEASES_API_URL)\n        )\n\n    for assets in data:\n        for asset in assets.get(\"assets\", list()):\n            # Find matching name.\n            if asset.get(\"name\") != _MULTIPASS_DL_NAME:\n                continue\n\n            return asset.get(\"browser_download_url\")\n\n    # Something changed we don't know about - we will simply categorize\n    # all possible events as an updated version we do not yet know about.\n    raise ProviderMultipassDownloadFailed(\"ref specified is not a valid ref in GitHub\")\n\n\ndef _download_multipass(dl_dir: str, echoer) -> str:\n    \"\"\"Creates temporary Downloads installer to temp directory.\"\"\"\n\n    dl_url = _fetch_installer_url()\n    dl_basename = os.path.basename(dl_url)\n    dl_path = os.path.join(dl_dir, dl_basename)\n\n    echoer.info(\"Downloading Multipass installer...\\n{} -> {}\".format(dl_url, dl_path))\n\n    try:\n        request = requests.get(dl_url, stream=True, allow_redirects=True)\n        request.raise_for_status()\n        download_requests_stream(request, dl_path)\n    except requests.RequestException as e:\n        raise ProviderMultipassDownloadFailed(_requests_exception_hint(e))\n\n    digest = calculate_sha3_384(dl_path)\n    if digest != _MULTIPASS_DL_SHA3_384:\n        raise ProviderMultipassDownloadFailed(\n            \"download failed verification (expected={} but found={})\".format(\n                _MULTIPASS_DL_SHA3_384, digest\n            )\n        )\n\n    echoer.info(\"Verified installer successfully...\")\n    return dl_path\n\n\ndef windows_install_multipass(echoer) -> None:\n    \"\"\"Download and install multipass.\"\"\"\n\n    assert sys.platform == \"win32\"\n\n    dl_dir = tempfile.mkdtemp()\n    dl_path = _download_multipass(dl_dir, echoer)\n    _run_installer(dl_path, echoer)\n\n    # Cleanup.\n    shutil.rmtree(dl_dir)\n\n\ndef _init_progress_bar(total_length, destination, message=None):\n    if not message:\n        message = \"Downloading {!r}\".format(os.path.basename(destination))\n\n    valid_length = total_length and total_length > 0\n\n    if valid_length and is_dumb_terminal():\n        widgets = [message, \" \", Percentage()]\n        maxval = total_length\n    elif valid_length and not is_dumb_terminal():\n        widgets = [message, Bar(marker=\"=\", left=\"[\", right=\"]\"), \" \", Percentage()]\n        maxval = total_length\n    elif not valid_length and is_dumb_terminal():\n        widgets = [message]\n        maxval = UnknownLength\n    else:\n        widgets = [message, AnimatedMarker()]\n        maxval = UnknownLength\n\n    return ProgressBar(widgets=widgets, maxval=maxval)\n\n\ndef download_requests_stream(request_stream, destination, message=None, total_read=0):\n    \"\"\"This is a facility to download a request with nice progress bars.\"\"\"\n\n    # Doing len(request_stream.content) may defeat the purpose of a\n    # progress bar\n    total_length = 0\n    if not request_stream.headers.get(\"Content-Encoding\", \"\"):\n        total_length = int(request_stream.headers.get(\"Content-Length\", \"0\"))\n        # Content-Length in the case of resuming will be\n        # Content-Length - total_read so we add back up to have the feel of\n        # resuming\n        if os.path.exists(destination):\n            total_length += total_read\n\n    progress_bar = _init_progress_bar(total_length, destination, message)\n    progress_bar.start()\n\n    if os.path.exists(destination):\n        mode = \"ab\"\n    else:\n        mode = \"wb\"\n    with open(destination, mode) as destination_file:\n        for buf in request_stream.iter_content(1024):\n            destination_file.write(buf)\n            if not is_dumb_terminal():\n                total_read += len(buf)\n                progress_bar.update(total_read)\n    progress_bar.finish()\n", "path": "installer/vm_providers/_multipass/_windows.py"}]}