Search code examples
windowscmdpackage-managerswinget

Structure of winget source repositories


Microsoft announced and open-sourced winget, a package manager for Windows.

When entering winget source (after installing it), it can be seen that it supports adding sources.

winget source provides the following subcommands:

add     Add a new source
list    list current sources
update  updates current sources
remove  removes current sources
reset   resets sources

By entering winget source list, the default source is displayed (as long as the sources were not changed):

C:\Windows\System32>winget source list
Name   Arg
-----------------------------------------
winget https://winget.azureedge.net/cache

As sources can be added using winget source add, how can source repositories be created?

How does a repository has to be structured or is there just not enough documentation to answer this question?


I think this question is on-topic for Stack Overflow as the main reason to add sources is (in my point of view) to create alpha/beta channels for programs or similar.


Solution

  • winget 1.0 introduced a new REST API for custom repositories. The API and a reference implementation are provided by Microsoft at github.com/microsoft/winget-cli-restsource/. The reference implementation uses C# and allows self-hosting on Azure. Hosted offerings are also becoming available, such as https://winget.pro.

    Before winget 1.0, the structure of winget repositories looked roughly as follows:

    1. The remote repository should have a source.msix file. You may refer to the example at the default repository: https://winget.azureedge.net/cache/source.msix

    2. One can find details about MSIX itself on the Microsoft Docs website.

    3. Actually the source.msix is a zip package with contents structured in a pre-defined fashion (just rename it to source.zip and unpack):

      • Assets/
      • Public/
      • AppxBlockMap.xml
      • AppxManifest.xml
      • AppcSignature.p7x
      • [Content_Typex.xml]
    4. The main data file seems to be Public/index.db. It is an SQLite database containing information derived from Community Repo Manifests. It has a quite simple structure to understand.

    5. Another concern is the MSIX should be signed by the developer. One should change Windows settings in order winget to accept packages signed by third parties. See below for details.

    6. Note that winget doesn't accept an HTTP repository, it requires only the HTTPS one with a trusted certificate.

    7. The most interesting tables in index.db are manifest and pathparts. The first matches application's name, version, etc. to pathparts, and the latter points to the manifest YAML-file.

      For example: https://winget.azureedge.net/cache/manifests/RubyInstallerTeam/Ruby/e70d-2.7.2.yaml (a cache of github/winget-pkgs/manifests/RubyInstallerTeam/Ruby/2.7.2.yaml).

    8. winget uses this cached manifest for application installation.

    9. In order winget could add the third-party source repository (when the source.msix signed by third-party certificate) one should allow installing sideload apps.

    Windows Settings

    1. Summarizing the above the overall sequence seems to be the following:

      • Download the source.msix from the winget's default repo: https://winget.azureedge.net/cache/source.msix
      • Unpack it as a ZIP-package or using the MSIX Packaging Tool to get the index.db file from Public directory.
      • Edit this SQLite DB (I've used the DB Browser for SQLite for that) leaving only your application (tables ids, monikers, names, versions).
      • Set the path to YAML-manifest in pathparts table (one record per each path element). E.g. for /manifests/MyCompany/MyProduct/1.0.0.yaml the table should be like: pathparts table example
      • Edit the manifest table by adding the record that unites all related records.
      • Save the edited index.db, overwrite it in source.msix using the MSIX Packaging Tool, sign the MSIX with your own code-signing certificate.
      • Upload both the manifest (see Manifest Specification for details about manifest itself) and source.msix to your server (e.g. to myserver.net/repo/source.msix and myserver.net/repo/manifests/MyCompany/MyProduct/1.0.0.yaml).
      • Use:
      winget source add myrepo https://myserver.net/repo
      winget install MyProduct