# 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
from extra_platforms import BSD, LINUX_LIKE, MACOS, WINDOWS
from ..capabilities import search_capabilities, version_not_implemented
from ..manager import PackageManager
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterator
from ..package import Package
[docs]
class APM(PackageManager):
"""Atom's package manager, from the sunset Atom editor.
apm installed packages and themes for GitHub's Atom editor, exposing an
npm-style CLI whose queries mpm parses from ``--json`` output.
Atom was `sunset on December 15, 2022
<https://github.blog/2022-06-08-sunsetting-atom/>`_, so apm is flagged
deprecated here. mpm keeps the wrapper while doing so stays cheap: the
community fork `atom-community/apm <https://github.com/atom-community/apm>`_
has been floated but never produced a usable drop-in, and per the project's
stability policy a deprecated manager may be dropped without notice once it
becomes a burden to maintain.
"""
deprecated = True
deprecation_url = "https://github.blog/2022-06-08-sunsetting-atom/"
"""GitHub announced the end of the project for December 15, 2022.
Source: https://github.blog/2022-06-08-sunsetting-atom/
There is a tentative community fork being discussed. See:
https://github.com/atom-community/apm
In the mean time, as long as no apm alternative is useable, it is safe to tag this
manager as deprecated.
"""
name = "Atom apm"
homepage_url = "https://atom.io/packages"
platforms = BSD, LINUX_LIKE, MACOS, WINDOWS
requirement = ">=1.0.0"
version_regexes = (r"apm\s+(?P<version>\S+)",)
"""
.. code-block:: shell-session
$ apm --version
apm 2.6.2
npm 6.14.13
node 12.14.1 x64
atom 1.58.0
python 2.7.16
git 2.33.0
"""
@property
def installed(self) -> Iterator[Package]:
"""Fetch installed packages.
.. code-block:: shell-session
$ apm list --json
{
"core": [
{
"name": "background-tips",
"version": "0.26.1",
"description": "Displays tips about Atom in the background."
}
],
"user": [
{
"name": "file-icons",
"version": "2.0.9",
"description": "Assign file extension icons"
}
]
}
"""
output = self.run_cli("list", "--json", must_succeed=True)
data = self.parse_json(output)
if data:
for package_list in data.values():
for pkg in package_list:
yield self.package(
id=pkg["name"],
description=pkg["description"],
installed_version=pkg["version"],
)
@property
def outdated(self) -> Iterator[Package]:
"""Fetch outdated packages.
.. code-block:: shell-session
$ apm outdated --compatible --json
[
{
"name": "file-icons",
"version": "2.0.9",
"latestVersion": "2.0.10",
"description": "Assign file extension icons"
}
]
"""
output = self.run_cli("outdated", "--compatible", "--json", must_succeed=True)
data = self.parse_json(output)
if data:
for pkg in data:
yield self.package(
id=pkg["name"],
description=pkg["description"],
installed_version=pkg["version"],
latest_version=pkg["latestVersion"],
)
[docs]
@search_capabilities(exact_support=False)
def search(self, query: str, extended: bool, exact: bool) -> Iterator[Package]:
"""Fetch matching packages.
.. caution::
Search does not supports exact matching.
.. code-block:: shell-session
$ apm search --json python | jq
[
{
"name": "atom-python-run",
"main": "./lib/atom-python-run.js",
"version": "0.7.3",
"description": "Run a python source file.",
"keywords": [
"python"
],
"repository": "https://github.com/foreshadow/atom-python-run",
"license": "MIT",
"engines": {
"atom": ">=1.0.0 <2.0.0"
},
"dependencies": {},
"readme": "Blah blah",
"downloads": 41379,
"stargazers_count": 16
},
{
"name": "build-python",
"version": "0.6.3",
"description": "Atom Build provider for python/python3",
"repository": "https://github.com/idleberg/atom-build-python",
"license": "MIT",
"keywords": [
"buildprovider",
"compile",
"python",
"python3",
"linter",
"lint"
],
"main": "lib/provider.js",
"engines": {
"atom": ">=1.0.0 <2.0.0"
},
"providedServices": {
"builder": {
"description": "Compiles Python",
"versions": {
"2.0.0": "provideBuilder"
}
}
},
"package-deps": [
"build"
],
"dependencies": {
"atom-package-deps": "^4.3.1"
},
"devDependencies": {
"babel-eslint": "^7.1.1",
"coffeelint-stylish": "^0.1.2",
"eslint": "^3.13.1",
"eslint-config-atom-build": "^4.0.0",
"gulp": "github:gulpjs/gulp#4.0",
"gulp-coffeelint": "^0.6.0",
"gulp-debug": "^3.0.0",
"gulp-jshint": "^2.0.4",
"gulp-jsonlint": "^1.2.0",
"gulp-lesshint": "^2.1.0",
"jshint": "^2.9.4"
},
"scripts": {
"test": "gulp lint"
},
"readme": "Blah blah",
"downloads": 2838,
"stargazers_count": 0
},
(...)
]
.. code-block:: shell-session
$ apm search --no-description --json python | jq
"""
search_args = []
if not extended:
search_args.append("--no-description")
output = self.run_cli("search", search_args, "--json", query, must_succeed=True)
data = self.parse_json(output)
if data:
for pkg in data:
yield self.package(
id=pkg["name"],
description=pkg["description"],
latest_version=pkg["version"],
)
[docs]
@version_not_implemented
def install(self, package_id: str, version: str | None = None) -> str:
"""Install one package.
.. code-block:: shell-session
$ apm install image-view
The image-view package is bundled with Atom and should not be explicitly
installed. You can run `apm uninstall image-view` to uninstall it and then
the version bundled with Atom will be used.
Installing image-view to /Users/kde/.atom/packages β
"""
return self.run_cli("install", package_id)
[docs]
def upgrade_all_cli(self) -> tuple[str, ...]:
"""Generates the CLI to upgrade all outdated packages.
.. code-block:: shell-session
$ apm update --no-confirm
"""
return self.build_cli("update", "--no-confirm")
[docs]
@version_not_implemented
def upgrade_one_cli(
self,
package_id: str,
version: str | None = None,
) -> tuple[str, ...]:
"""Generates the CLI to upgrade the provided package.
.. code-block:: shell-session
$ apm update --no-confirm image-view
"""
return self.build_cli("update", "--no-confirm", package_id)
[docs]
def remove(self, package_id: str) -> str:
"""Remove one package.
.. code-block:: shell-session
$ apm uninstall image-view
"""
return self.run_cli("uninstall", package_id)
[docs]
def cleanup(self) -> None:
"""Removes things we don't need anymore.
.. code-block:: shell-session
$ apm clean
"""
self.run_cli("clean")