Source code for meta_package_manager.managers.yarn

# 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 json
import re
from functools import cached_property
from typing import Iterator

from extra_platforms import ALL_PLATFORMS

from meta_package_manager.base import Package, PackageManager
from meta_package_manager.capabilities import (
    search_capabilities,
    version_not_implemented,
)


[docs] class Yarn(PackageManager): name = "Node's yarn" homepage_url = "https://yarnpkg.com" platforms = ALL_PLATFORMS requirement = "1.20.0" """ .. code-block:: shell-session β–Ί yarn --version 1.22.11 """ @property def installed(self) -> Iterator[Package]: """Fetch installed packages. .. code-block:: shell-session β–Ί yarn global --json list --depth 0 {"type":"activityStart","data":{"id":0}} {"type":"activityTick","data":{"id":0,"name":"awesome-lint@^0.18.0"}} {"type":"activityTick","data":{"id":0,"name":"arrify@^2.0.1"}} {"type":"activityTick","data":{"id":0,"name":"case@^1.6.3"}} {"type":"activityTick","data":{"id":0,"name":"emoji-regex@^9.2.0"}} (...) {"type":"activityEnd","data":{"id":0}} {"type":"progressStart","data":{"id":0,"total":327}} {"type":"progressTick","data":{"id":0,"current":1}} {"type":"progressTick","data":{"id":0,"current":2}} {"type":"progressTick","data":{"id":0,"current":3}} {"type":"progressTick","data":{"id":0,"current":4}} {"type":"progressTick","data":{"id":0,"current":5}} (...) {"type":"progressFinish","data":{"id":0}} {"type":"info","data":"\"awesome-lint@0.18.0\" has binaries:"} {"type":"list","data":{"type":"bins-awesome-lint","items":["awesome-lint"]}} .. code-block:: shell-session β–Ί yarn global list --depth 0 yarn global v1.22.19 info "awesome-lint@0.18.0" has binaries: - awesome-lint ✨ Done in 0.13s. """ output = self.run_cli("global", "--json", "list", "--depth", "0") regexp = re.compile( r"^.+\"data\":\"\\\"(?P<package_id>\S+)" r"@(?P<version>\S+)\\\" has binaries:\"\}$", re.MULTILINE, ) for package_id, version in regexp.findall(output): yield self.package(id=package_id, installed_version=version) @cached_property def global_dir(self) -> str: """Locate the global directory. .. code-block:: shell-session β–Ί yarn global dir ~/.config/yarn/global """ return self.run_cli("global", "dir", force_exec=True).rstrip() @property def outdated(self) -> Iterator[Package]: """Fetch outdated packages. .. code-block:: shell-session β–Ί yarn --json outdated --cwd ~/.config/yarn/global | jq {"type":"warning","data":"package.json: No license field"} { "type": "info", "data": "Color legend : \n" " \"<red>\" : Major Update backward-incompatible updates \n" " \"<yellow>\" : Minor Update backward-compatible features \n" " \"<green>\" : Patch Update backward-compatible bug fixes" } { "type": "table", "data": { "head": [ "Package", "Current", "Wanted", "Latest", "Package Type", "URL" ], "body": [ [ "markdown", "0.4.0", "0.4.0", "0.5.0", "dependencies", "git://github.com/evilstreak/markdown-js.git" ] ] } } .. code-block:: shell-session β–Ί yarn outdated --cwd ~/.config/yarn/global yarn outdated v1.22.19 warning package.json: No license field info Color legend : "<red>" : Major Update backward-incompatible updates "<yellow>" : Minor Update backward-compatible features "<green>" : Patch Update backward-compatible bug fixes Package Current Wanted Latest Package Type URL markdown 0.4.0 0.4.0 0.5.0 dependencies git://github.com/.../md-js.git ✨ Done in 0.95s. """ output = self.run_cli("--json", "outdated", "--cwd", self.global_dir) if output: for line in output.splitlines(): if not line: continue obj = json.loads(line) if obj["type"] == "table": for package in obj["data"]["body"]: if package[2] == "linked": continue yield self.package( id=package[0], installed_version=package[1], latest_version=package[3], )
[docs] @search_capabilities(extended_support=False, exact_support=False) def search(self, query: str, extended: bool, exact: bool) -> Iterator[Package]: """Fetch matching packages. .. warning:: Yarn maintainers have `decided to not implement a dedicated search command <https://github.com/yarnpkg/yarn/issues/778#issuecomment-253146299>`_. Search is simulated by a direct call to ``yarn info``, and as a result only works for exact match. .. code-block:: shell-session β–Ί yarn --json info python | jq { "type": "inspect", "data": { "name": "python", "description": "Interact with python child process", "dist-tags": { "latest": "0.0.4" }, "versions": [ "0.0.0", "0.0.1", "0.0.2", "0.0.3", "0.0.4" ], "maintainers": [ { "name": "drderidder", "email": "drderidder@gmail.com" } ], "time": { "modified": "2017-09-16T05:26:13.151Z", "created": "2011-07-11T01:59:04.362Z", "0.0.0": "2011-07-11T01:59:05.137Z", "0.0.1": "2011-07-17T05:23:33.166Z", "0.0.2": "2011-07-20T03:42:50.379Z", "0.0.3": "2014-06-08T00:39:08.562Z", "0.0.4": "2015-01-25T02:48:07.820Z" }, "author": { "name": "Darren DeRidder" }, "repository": { "type": "git", "url": "git://github.com/73rhodes/node-python.git" }, "homepage": "https://github.com/73rhodes/node-python", "bugs": { "url": "https://github.com/73rhodes/node-python/issues" }, "readmeFilename": "README.md", "users": { "dewang-mistry": true, "goliatone": true, "sapanbhuta": true, "aditcmarix": true, "imlucas": true, "heyderpd": true, "ukuli": true, "chbardel": true, "asaupup": true, "nuwaio": true }, "version": "0.0.4", "main": "./lib/python.js", "engines": { "node": ">= 0.4.1" }, "gitHead": "69754aaa57658193916a1bf5fc391198098f74f6", "scripts": {}, "dist": { "shasum": "3094e898ef17a33aa9c3e973b3848a38e47d1818", "tarball": "https://registry.npmjs.org/python/-/python-1.tgz" }, "directories": {} } } """ output = self.run_cli("--json", "info", query) if output: result = json.loads(output) if result["type"] == "inspect": package = result["data"] yield self.package( id=package["name"], description=package["description"], latest_version=package["version"], )
@version_not_implemented def install(self, package_id: str, version: str | None = None) -> str: """Install one package. .. code-block:: shell-session β–Ί yarn global add awesome-lint yarn global v1.22.19 [1/4] πŸ” Resolving packages... [2/4] 🚚 Fetching packages... [3/4] πŸ”— Linking dependencies... [4/4] πŸ”¨ Building fresh packages... success Installed "awesome-lint@0.18.0" with binaries: - awesome-lint ✨ Done in 16.15s. """ return self.run_cli("global", "add", 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 β–Ί yarn global upgrade --latest yarn global v1.22.19 [1/4] πŸ” Resolving packages... [2/4] 🚚 Fetching packages... [3/4] πŸ”— Linking dependencies... [4/4] πŸ”¨ Rebuilding all packages... success Saved lockfile. success Saved 271 new dependencies. info Direct dependencies β”œβ”€ awesome-lint@0.18.0 └─ markdown@0.5.0 info All dependencies β”œβ”€ @babel/code-frame@7.18.6 β”œβ”€ @babel/helper-validator-identifier@7.18.6 β”œβ”€ @nodelib/fs.scandir@2.1.5 β”œβ”€ array-to-sentence@1.1.0 β”œβ”€ array-union@2.1.0 β”œβ”€ awesome-lint@0.18.0 β”œβ”€ fs.realpath@1.0.0 (...) └─ zwitch@1.0.5 ✨ Done in 19.89s. """ return self.build_cli("global", "upgrade", "--latest")
@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 β–Ί yarn global upgrade markdown --latest yarn global v1.22.19 [1/4] πŸ” Resolving packages... [2/4] 🚚 Fetching packages... [3/4] πŸ”— Linking dependencies... [4/4] πŸ”¨ Rebuilding all packages... success Saved lockfile. success Saved 2 new dependencies. info Direct dependencies └─ markdown@0.5.0 info All dependencies β”œβ”€ markdown@0.5.0 └─ nopt@2.1.2 ✨ Done in 1.77s. """ return self.build_cli("global", "upgrade", package_id, "--latest")
[docs] def remove(self, package_id: str) -> str: """Remove one package. .. code-block:: shell-session β–Ί yarn global remove awesome-lint yarn global v1.22.19 [1/2] πŸ—‘ Removing module awesome-lint... [2/2] πŸ”¨ Regenerating lockfile and installing missing dependencies... success Uninstalled packages. ✨ Done in 0.21s. """ return self.run_cli("global", "remove", package_id)
[docs] def cleanup(self) -> None: """Removes things we don't need anymore. See: https://yarnpkg.com/cli/cache/clean .. code-block:: shell-session β–Ί yarn cache clean --all yarn cache v1.22.19 success Cleared cache. ✨ Done in 0.35s. """ self.run_cli("cache", "clean", "--all")