⠕ Universal Package Manager - Python, Node.js, Ruby, Emacs Lisp.
⠕ Universal Package Manager - Python, Node.js, Ruby, Emacs Lisp.
UPM is the Universal Package Manager. It allows you to manage packages for any (supported) programming language through the same interface following the principle of least astonishment. At Repl.it, we use UPM to provide deep package manager integration for many different programming languages using the same infrastructure.
UPM does not implement package management itself. Instead, it runs a package manager for you. The value added is:
pip search flask doesn't return
Flask in the search resultslist --depth=0, neither of which is
exactly what you wantIn other words, UPM eliminates the need to remember a huge collection of language-specific package manager quirks and weirdness, and adds a few nifty extra features like dependency guessing and machine-parseable specfile and lockfile listing.
upm add, upm remove, upm lock, upm install, upm listupm search, upm infoupm guess| core | index | guess | |
|---|---|---|---|
| python-python3-uv | yes | yes | yes |
| python-python3-pip | yes | yes | yes |
| python-python3-poetry | yes | yes | yes |
| nodejs-yarn | yes | yes | yes |
| nodejs-pnpm | yes | yes | yes |
| nodejs-npm | yes | yes | yes |
| ruby-bundler | yes | yes | |
| elisp-cask | yes | yes | yes |
| dart-pub.dev | yes | yes | |
| rlang | yes | yes | |
| java | yes | yes | |
| rust | yes | yes | |
| dotnet | yes | yes | |
| php | yes | yes |
You have many options. UPM is a single binary with no dependencies, so you can install it anywhere. Tarballs are available on the releases page. Read on for instructions on installing via a package manager.
Available on Homebrew in a custom tap.
$ brew install replit/tap/upm.deb packages are available on the releases page.
.rpm packages are available on the releases page.
Soon to be available on the Arch User
Repository. Right now, you can clone this
repository and install with makepkg using the PKGBUILD in
packaging/aur.
Available on Scoop in the main bucket.
$ scoop install upmSoon to be available on the Snap Store. Right now, .snap packages are available on the releases page.
You can try out UPM right away in a Docker image based on Ubuntu that has all the supported languages and package managers already installed.
$ docker run -it --rm replco/upmAdditional tags are also available. replco/upm:full is the same as
the above, while replco/upm:light just has the UPM binary installed
to /usr/local/bin and none of the languages or package managers
installed. If you want to run a specific tagged release, rather than
the latest development snapshot, use e.g. replco/upm:1.0,
replco/upm:1.0-full, or replco/upm:1.0-light.
Let's create a new Python project:
$ mkdir ~/python
$ cd ~/pythonWe'll start by adding Flask as a dependency. UPM will handle setting up the project for us:
$ upm -l python add flask
--> python3 -m poetry init --no-interaction
This command will guide you through creating your pyproject.toml config.
--> python3 -m poetry add flask
Creating virtualenv python-py3.7 in /root/.cache/pypoetry/virtualenvs
Using version ^1.1 for flask
Updating dependencies
Resolving dependencies... (0.6s)
Writing lock file
Package operations: 6 installs, 0 updates, 0 removals
- Installing markupsafe (1.1.1)
- Installing click (7.0)
- Installing itsdangerous (1.1.0)
- Installing jinja2 (2.10.1)
- Installing werkzeug (0.15.4)
- Installing flask (1.1.1)UPM operates on a specfile and lockfile for each project. The
specfile says what your project's dependencies are in a human-readable
format, while the lockfile specifies exact versions for everything,
including transitive dependencies. For Python, the specfile is
pyproject.toml and the lockfile is poetry.lock:
$ ls
poetry.lock pyproject.tomlWe don't have to read them ourselves, because UPM can handle that. Notice that UPM is now aware that our project uses Python, because of the files that were created:
$ upm list
name spec
----- ----
flask ^1.1
$ upm list -a
name version
------------ -------
click 7.0
flask 1.1.1
itsdangerous 1.1.0
jinja2 2.10.1
markupsafe 1.1.1
werkzeug 0.15.4Let's search for another dependency to add:
$ upm search nose
--> python3 -c '' nose
Name Description Version
----------------- ---------------------------------------------------------------------- -------
nose nose extends unittest to make testing easier 1.3.7
nose-detecthttp A nose plugin to detect tests making http calls. 1.1.0
nose-picker nose plugin that picks a subset of your unit tests 0.5.5
nose-progressive A testrunner with a progress bar and smarter tracebacks 1.5.2
nose-unittest UNKNOWN 0.1.1
nose-blockage Raise errors when communicating outside of tests 0.1.2
nose-watcher A nose plugin to watch for changes within the local directory. 0.1.3
nose-bisect A Nose plugin which allows bisection of test failures. 0.1.0
nose-printlog Print log to console in nose tests 0.2.0
nose-json A JSON report plugin for Nose. 0.2.4
nose-faulthandler Nose plugin. Activates faulthandler module for test runs. 0.1
nose-knows 0.2
nose-pagerduty PagerDuty alert plugin for nose 0.2.0
nose-logpertest Logging nose plugin to create log per test 0.0.1
nose-bleed A progressive coverage plugin for Nose. 0.5.1
nose-numpyseterr Nose plugin to set how floating-point errors are handled by numpy 0.1
nose-skipreq nose plugin that will skip Google API RequestError exceptions. 2.0
nose-selecttests Specify whitelist of keywords for tests to be run by nose 0.5
nose-pacman A testrunner with a pacman progress bar 0.1.0
nose-switch Add special switches in code, based on options set when running tests. 0.1.5We can get more information about a package like this:
$ upm info nose
--> python3 -c '' nose
Name: nose
Description: nose extends unittest to make testing easier
Version: 1.3.7
Homepage: http://readthedocs.org/docs/nose/
Author: Jason Pellerin
License: GNU LGPLFor piping into other programs, the search and info commands can
also output JSON:
$ upm info nose --format=json | jq
--> python3 -c '' nose
{
"name": "nose",
"description": "nose extends unittest to make testing easier",
"version": "1.3.7",
"homepageURL": "http://readthedocs.org/docs/nose/",
"author": "Jason Pellerin ",
"license": "GNU LGPL"
}UPM can also look at your project's source code and guess what packages need to be installed. We use this on Repl.it to help developers get started faster. To see it in action, we'll need some source code:
$ git clone https://github.com/replit/play.git ~/play
$ cd ~/play
$ upm add --guess
--> python3 -c '' ''
--> python3 -m poetry init --no-interaction
This command will guide you through creating your pyproject.toml config.
--> python3 -m poetry add pygame pymunk setuptools
Creating virtualenv play-py3.7 in /root/.cache/pypoetry/virtualenvs
Using version ^1.9 for pygame
Using version ^5.5 for pymunk
Using version ^41.0 for setuptools
Updating dependencies
Resolving dependencies... (1.4s)
Writing lock file
Package operations: 4 installs, 0 updates, 0 removals
- Installing pycparser (2.19)
- Installing cffi (1.12.3)
- Installing pygame (1.9.6)
- Installing pymunk (5.5.0)You can also just get the list of guessed dependencies, if you want.
The -a flag lists all guessed dependencies, even the ones already
added to the specfile:
$ upm guess -a
pygame
pymunk
setuptoolsAll of this might seem a bit too simple to justify a new tool, but the real power of UPM is that it works exactly the same for every programming language:
$ upm -l nodejs info express
Name: express
Description: Fast, unopinionated, minimalist web framework
Version: 4.17.1
Homepage: http://expressjs.com/
Source code: git+https://github.com/expressjs/express.git
Bug tracker: https://github.com/expressjs/express/issues
Author: TJ Holowaychuk
License: MIT
$ upm -l ruby info jekyll
--> ruby -e '' jekyll
Name: jekyll
Description: Jekyll is a simple, blog aware, static site generator.
Version: 3.8.6
Homepage: https://github.com/jekyll/jekyll
Documentation: http://jekyllrb.com
Source code: https://github.com/jekyll/jekyll
Bug tracker: https://github.com/jekyll/jekyll/issues
Author: Tom Preston-Werner
License: MIT
Dependencies: addressable, colorator, em-websocket, i18n, jekyll-sass-converter, jekyll-watch, kramdown, liquid, mercenary, pathutil, rouge, safe_yaml
$ upm -l elisp info elnode
--> emacs -Q --batch --eval '' /tmp/elpa552971126 info elnode
Name: elnode
Description: The Emacs webserver.
Version: 20190702.1509
Dependencies: web, dash, noflet, s, creole, fakir, db, kvThat includes adding and removing packages, listing the specfile and lockfile, searching package indices, and guessing project dependencies. UPM knows all the best practices for each language so that you don't have to!
Explore the command-line interface at your leisure:
$ upm --help
Usage:
upm [command]
Available CommandsNo open issues yet, or sync has not completed.