# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import annotations
import re
from typing import Iterator
from extra_platforms import MACOS
from meta_package_manager.base import Package, PackageManager
from meta_package_manager.capabilities import (
search_capabilities,
version_not_implemented,
)
[docs]
class MAS(PackageManager):
name = "Mac AppStore"
homepage_url = "https://github.com/argon/mas"
platforms = MACOS
requirement = "1.8.7"
"""`1.8.7 <https://github.com/mas-cli/mas/releases/tag/v1.8.7>`_ is fixing the
``mas search`` command.
"""
version_cli_options = ("version",)
"""
.. code-block:: shell-session
► mas version
1.8.3
"""
@property
def installed(self) -> Iterator[Package]:
"""Fetch installed packages.
.. code-block:: shell-session
► mas list
1569813296 1Password for Safari (2.3.5)
1295203466 Microsoft Remote Desktop (10.7.6)
409183694 Keynote (12.0)
1408727408 com.adriangranados.wifiexplorerlite (1.5.5)
409203825 Numbers (12.0)
"""
output = self.run_cli("list")
regexp = re.compile(
r"""
(?P<package_id>\d+)
\s+
(?P<package_name>.+?)
\s+
\(
(?P<version>\S+)
\)
""",
re.MULTILINE | re.VERBOSE,
)
for package_id, package_name, version in regexp.findall(output):
yield self.package(
id=package_id,
name=package_name,
installed_version=version,
)
@property
def outdated(self) -> Iterator[Package]:
"""Fetch outdated packages.
.. code-block:: shell-session
► mas outdated
409183694 Keynote (11.0 -> 12.0)
1176895641 Spark (2.11.20 -> 2.11.21)
"""
output = self.run_cli("outdated")
regexp = re.compile(
r"""
(?P<package_id>\d+)
\s+
(?P<package_name>.+?)
\s+
\(
(?P<installed_version>\S+)
\s+->\s+
(?P<latest_version>\S+)
\)
""",
re.MULTILINE | re.VERBOSE,
)
for (
package_id,
package_name,
installed_version,
latest_version,
) in regexp.findall(output):
yield self.package(
id=package_id,
name=package_name,
installed_version=installed_version,
latest_version=latest_version,
)
[docs]
@search_capabilities(extended_support=False, exact_support=False)
def search(self, query: str, extended: bool, exact: bool) -> Iterator[Package]:
"""Fetch matching packages.
.. caution::
Search does not support extended or exact matching. So we returns the best
subset of results and let
:py:meth:`meta_package_manager.base.PackageManager.refiltered_search` refine
them.
.. code-block:: shell-session
► mas search python
689176796 Python Runner (1.3)
630736088 Learning Python (1.0)
945397020 Run Python (1.0)
1164498373 PythonGames (1.0)
1400050251 Pythonic (1.0.0)
"""
output = self.run_cli("search", query)
regexp = re.compile(
r"""
(?P<package_id>\d+)
\s+
(?P<package_name>.+?)
\s+
\(
(?P<version>\S+)
\)
""",
re.MULTILINE | re.VERBOSE,
)
for package_id, package_name, version in regexp.findall(output):
yield self.package(id=package_id, name=package_name, latest_version=version)
@version_not_implemented
def install(self, package_id: str, version: str | None = None) -> str:
"""Install one package.
.. code-block:: shell-session
► mas install 945397020
"""
return self.run_cli("install", package_id)
[docs]
def upgrade_all_cli(self) -> tuple[str, ...]:
"""Generates the CLI to upgrade all packages (default) or only the one provided
as parameter.
.. code-block:: shell-session
► mas upgrade
"""
return self.build_cli("upgrade")
@version_not_implemented
def upgrade_one_cli(
self,
package_id: str,
version: str | None = None,
) -> tuple[str, ...]:
"""Generates the CLI to upgrade all packages (default) or only the one provided
as parameter.
.. code-block:: shell-session
► mas upgrade 945397020
"""
return self.build_cli("upgrade", package_id)
[docs]
def remove(self, package_id: str) -> str:
"""Removes a package.
.. code-block:: shell-session
► sudo mas uninstall 1494051017
Password:
Deleted '/Applications/SimpleLogin.app' to '/Users/kde/.Trash/SimpleLogin.app'
"""
return self.run_cli("uninstall", package_id, sudo=True)