Overview Demonstration videos Interesting features To do
Pog is an in-development package manager for Windows, written for PowerShell Core. Unlike most existing Windows package managers, which delegate to existing program installers, Pog manages the whole package installation process end-to-end, preferring installation from package archives instead. The packages are encapsulated by redirecting their default data directories to a package-local directory, This also provides first-class support for portable packages, which can be moved between machines without reinstallation.
First, the .zip archive containing Pog is unzipped and Pog/setup.cmd
is started, which creates the necessary directories inside the Pog
directory, downloads the current package repository and adds Pog to $env:PATH
and $env:PSModulePath
(these are the only two changes outside the package directory during installation).
Then, we can open PowerShell and start installing and using Pog packages. Binaries are immediately available as commands, and start menu shortcuts can be exported with a single command. While the packages are installing in the background, I open a few of the package manifests for illustration.
The latest version of Nim (1.6.10) is already installed and available. Then, I install an older version into a separate directory (the -TargetName
parameter) and allow it to override the nim
command. Now, when I run nim --version
, the old version starts instead. This is repeated with another older version.
Now, 3 different versions of Nim are installed. To switch between the versions, I use the Enable-Pog
cmdlet, which redirects the nim
command to the selected version. In the future, I plan to add automatic renaming of the exported commands, but explicit control is still useful for tools which expect a binary named nim
, and not e.g. nim-1.6.0
.
Usage of multiple versions is possible, because each package is encapsulated and bundles all of its dependencies (as is a good custom on Windows). This grows the install size, but solves a lot of ugly issues without having to go all Nix-like.
Similar example to the one above, this time with a GUI program, where different versions can be launched by launching the exported shortcut inside the package directory. Similarly to commands, I plan to add automatic shortcut renaming so that all the shortcuts can be automatically exported to start menu with different suffixes.
Pog has a single package repository (for now), and possibly multiple installation directories, with the first one being the default one.
Package is installed in 4 steps: 1) the repository manifest is copied to the package directory, 2) the package archive is downloaded and extracted into the ./app
subdirectory of the package, 3) the package is enabled (creating necessary directories, exposing available commands and shortcuts,...), 4) exposed commands are exported to a directory on PATH
, exposed shortcuts are copied to the start menu.
The package manifest is a PowerShell data file (roughly equivalent to JSON with nicer syntax and support for code blocks), with a few metadata properties, an Install
key containing information about the archive source and an Enable
key, which is a script block, which uses a set of provided functions to declaratively describe the internal setup and external interface of the package.
Most of the exported entry points of each package (shortcuts or console commands) are wrappers, which configure environment variables, working directory and extra arguments before calling the actual program. Even when no extra configuration is needed, most programs load DLLs and other dependencies from the app directory, so symlinks are not usable.
Pog provides a stub executable, which can be configured to setup the environment and then invoke the real target. This considerably simplifies creating portable packages and allows the package author to describe the necessary parameters directly in the package manifest.
For example, the exported go
command from the go-lang
package is configured like this, Pog takes care of resolving paths and actually generating the stub:
xxxxxxxxxx
81Export-Command "go" "./app/bin/go.exe" -Environment @{
2 GOROOT = "./app"
3 GOBIN = "./data/go-bin"
4 GOENV = "./config/goenv"
5 GOCACHE = "./cache/build-cache"
6 GOMODCACHE = "./cache/mod-cache"
7 GOPATH = "%GOPATH%", "./data/packages"
8}
All dynamically-linked C++ applications on Windows use the MSVC runtime libraries, which are typically provided by installing the vcredist.exe
package from MS. Pog bundles the latest versions of the redistributable libraries, and packages can then request to have the libraries added to their %PATH%
. The following example is taken from the Alacritty
package:
xxxxxxxxxx
31Export-Shortcut "Alacritty" "./app/Alacritty.exe" `
2 -Arguments @("--config-file", (Resolve-Path "./config/alacritty.yml")) `
3 -VcRedist
This list is by no means complete, it's just a list of features I'd like to see added before Pog is oficially released.
Currently, when multiple packages export the same command, the most recently registered package overrides the other options. Collisions between different packages are not too common, but Pog supports installing multiple versions of the same package, where a collision is likely.
Ideally, collisions for multiple installed versions would be resolved by suffixing the binary name with the package version and installed package name. Additionally, the user should have control (similarly to the update-alternatives
command in Debian-based Linux distributions) over which package provides the default unsuffixed command.
Pog has the potential to simplify management and sharing of DIY tools and projects, which are not developed as a standard package and registered in the package repository. Pog should be able to keep track of and manage packages outside the registered package roots.
Pog currently supports "manifest generators" – scripts which scrape the source website for the package and automatically generate manifests for newly released versions. However, the support is very low-level and there's no unified interface. Given that a large portion of the currently supported packages is downloaded from Github and Sourceforge, a lot of code duplication between generators could be avoided by providing a higher-level interface.
Currently, Pog requires the package repository to be available locally, similarly to most package managers. I'd prefer if Pog could work directly with an online repository, with an optional local cache, which would free the user from having to manually refresh the local copy to see if there are any updates.
Currently, pinning an app to taskbar pins the actual executed binary, and next time the program is started from the taskbar icon, it forgets all arguments and environment variables passed by the wrapper.
Allow the app to declare supported file types in the manifest. TODO: should we actually register the associations during installation, or only when user explicitly requests the association?