Internet Explorer is no longer supported. Many things will still work, but your experience will be degraded and some things won't function. Please use a modern browser such as Edge, Chrome, or Firefox.

Universal Packages

view on GitHub

A Universal Package is a file that contains other files such as programs, configurations, application components, plugins, libraries, or any other kind of content. It also contains a manifest file that uniquely identifies the package with a name/version and optionally describes its contents.

Unlike other packaging formats (NuGet, Rpm, etc.), Universal Packages were not designed for a specific use case (.NET libraries, Linux applications, etc.) and were designed to be as simple to use as possible.

You can create Universal Packages manually by hand or by using one of the free and open Universal Packaging Tools.

Universal Package Format

There isn't much to a universal package file; there are just two requirements:

  1. is a ZIP archive format with a .upack file extension
  2. has a manifest file in the root directory named upack.json with a few required fields

For example, a very basic Universal Package for my-app version 1.3.9 might look like this:

Files my-app-1.3.9.upackContent of upack.json
upack.json
packages/my-app.config
packages/my-app.exe
packages/my-app.dll
{
 "name": "my-app",
 "version": "1.3.9"
}

You could create this package file manually or using the pgutil CLI tool. For example:

$ pgutil upack create --name=my-app --version=1.3.9 --source-directory=.\package-files\my-app --target-directory=.\universal-packages

Alternatively, if you have already created a upack.json manifest for your Universal Package, you can specify this instead:

$ pgutil upack create --manifest=.\package-files\my-app\upack.json --source-directory=.\package-files\my-app --target-directory=.\universal-packages

That command will package the .\my-app folder into the my-app-1.3.9.upack ZIP archive file. See the Universal Feeds & Packages page to learn more.

Package Content and Metacontent

Files contained in the package/ folder within a Universal Package ZIP archive are referred to as content. When you "install" or "unpackage" a Universal Package to a folder on disk, that folder will only contain the files from the ZIP archive's package/ folder.

You can use the upack install pgutil command to install a package from a ProGet feed. For example:

$ pgutil upack install --package=my-app --version=1.3.9 --feed=universal --target=.\my-app

That command will basically do the opposite of the create command and write the content files to the .\my-app folder.

Installing packages will also create an entry in the Universal Package Registry. This is a local system that tracks and manages installed Universal Packages, creating a record of the packages metadata.

All other files within a Universal Package (including upack.json) are referred to as metacontent. For most use cases, you will never need to use or access metacontent, but it might come in handy for advanced scenarios like embedding installation scripts, build logs, Software Bill of Material (SBOM) files, etc.

Manifest (upack.json) Specification

The upack.json file is a JSON object with the following properties:

Required or Implicit Properties

Property Format
group A string of 0 to 250 characters: numbers (0-9), upper- and lower-case letters (a-Z), dashes (-), periods (.), forward-slashes (/), and underscores (_); may not start or end with a forward-slash; if not specified, the group name will be considered an empty string.
nameR A string of 1 to 50 characters: numbers (0-9), upper- and lower-case letters (a-Z), dashes (-), periods (.), and underscores (_).
versionR A string representing a SemVer2 Semantic Version; is a three-part, dot-separated specification.

Additional Descriptive Properties (Optional)

Property Format
title A string of no more than 50 characters.
projectUrl A string of an absolute URL where more about the package can be found
icon A string of an absolute URL pointing to an image to be displayed in a UI (at both 64px and 128px); if package:// is used as the protocol, it references a package in the image within the package instead
description A string containing any number of characters; will be formatted as Markdown in the UI.
shortDescription A string containing up to 1000 characters; is a short summary that will be displayed instead of the description in lists and is not Markdown-formatted.
tags An array of strings, each being 1 to 50 characters: numbers (0-9), upper- and lower-case letters (a-Z), dashes (-), periods (.), and underscores (_). Tags may not start with a number and must be unique within the array.
dependencies An array of dependency specifier strings, each of which may be formatted as follows:
• «package-name»  
• «group»/«package-name»
• «group»:«package-name»
• «group»/«package-name»:«version-range»
• «group»:«package-name»:«version-range»
• «group»:«package-name»:«version-range»:«sha1-hash»

«version-range» can be one of these:
• Not specified (or *) to indicate the latest version
• SemVer2 Version Number
• Range of version numbers specified with interval notation, such as 
• [1.0.0,2.0.0) to mean every version between 1.0.0 and 2.0.0 (but not 2)
• [3.0.0,] to mean every version after 3.0.0

Audit-based Properties (Optional)

Property Format
createdDate A string representing the UTC date when the package was first created, in ISO 8601 format (yyyy-MM-ddThh:mm:ssZ)
createdReason A string describing the reason or purpose of the creation

For example, BuildMaster uses {Application Name} {Release Number} #{Package Number} (ID{Execution-Number})
createdUsing A string describing the mechanism the package was created with; there are no format restrictions, but we recommend treating it like a User Agent string and including the tool name and version

For example, BuildMaster uses BuildMaster/5.6.11
createdBy A string describing the person or service that performed the installation

For example, BuildMaster uses the user who triggered the deployment or SYSTEM if it was a triggered/scheduled deployment
repackageHistory An array containing package identification strings or objects with the following properties:

idR - a package identification string
date - A string representing the UTC date when the package was repackaged, in ISO 8601 format (yyyy-MM-ddThh:mm:ssZ)
reason - A string describing the reason or purpose of the repackaging
using - A string describing the mechanism the package was repackaged with; there are no format restrictions, but we recommend treating it like a User Agent string and including the tool name and version
by - A string describing the person or service that performed the repackage
url - A string where more information about the repackaging can be found, typically to logs within the tool that performed it

A package identification string is a 3- or 4-part string, formatted as follows:
• «group»/«package-name»:«version»
• «group»/«package-name»:«version»:«sha1-hash»

You may include other properties in the object, but it is recommended to prefix the names with an underscore (_).

An R denotes a required property.

Additional Metadata

This object may contain additional properties as needed. However, if you need to add additional metadata, it's strongly recommended that you prefix these properties with an underscore (_)... just on the off-chance that a property you add will exist in a future version of the specification, or is returned in other metadata queries.

Example Manifest Files (upack.json)

Using Extended Fields

The following manifest adds a group (which is a part of the package's identifier) and two custom properties (_sourceRoot, _deployTarget). Note how they are prefixed with an underscore to avoid future naming conflicts.

{
 "group": "virtudyne/simdesk",
 "name": "var-index-service",
 "version": "5.3.9",
 "_sourceRoot": "$/global/vindex/branches/v5-hotfix"
 "_deployTarget": "/var/vsimdesk/vindex"
}

Full/Complete Manifest

The following manifest uses just about every property available; note how the description is markdown formatted.

{
 "group": "initrode/vendors/abl",
 "name": "ABLast",
 "version": "2.2.1",
 "title": "ast distribution files for ABL",
 "icon": "package://ablast.svg",
 "description": "This contains [ast distro](http://initrode-net.local/ast) files specific to ABL",
 "dependencies": [ "initrode/vendors-common:ast-common:2.0.0" ],
 "createdDate": "2017-11-09T04:03:01Z",
 "createdReason": "ABLast v2.2.1 #18 (ID8843) ",
 "createdUsing": "BuildMaster/5.6.11",
 "createdBy": "THoven"
}

Inedo Extensions (Plugins) Manifest

The following is the manifest for our AWS extension (i.e. Plugin) package which uses array-based custom properties. You can also see that this particular manifest was repackaged as part of a CI/CD process.

{
  "group": "inedox",
  "name": "AWS",
  "version": "3.1.0",
  "title": "Amazon AWS",
  "description": "Contains a ProGet Package Store backed by Amazon S3, and operations for working with S3 storage in Otter and BuildMaster.",
  "icon": "https://inedo.com/den/logos/AWS.png",
  "_inedoSdkVersion": "3.1.0",
  "_inedoProducts": [ "BuildMaster", "Otter", "ProGet" ],
  "_targetFrameworks": [ "net452", "net6.0", "net8.0" ],
  "repackageHistory": [
    {
      "id": "inedox:AWS:3.1.0-CI.2",
      "using": "ProGet/24.0.17"
    },
    {
      "id": "inedox:AWS:3.1.0-RC.2",
      "using": "ProGet/24.0.17"
    }
  ]
}

Universal Package Tools

The main tool used to create and manage Universal Packages and installations is the pgutil CLI tool. This will require some minor configuration to use, and offers several commands:

  • upack create: Will create a Universal Package at a specified location
  • upack install: Will "Install" or "unpack" a Universal Package to a specified location
  • upack list: Will list all installed Universal Packages
  • upack update: Will update the installation with another version from a specified Universal Package feed
  • upack remove: Will uninstall the specified Universal Package

You can learn more about how to use these commands on the Universal Feeds & Packages page.

Deprecated & Older Tools

Over the years, users have gotten more comfortable using Command-line tools. As such, we decided to abandon some of the earlier Universal Package tools we created.

Although we do not maintain these tools anymore, you may find them useful. If you think we should revive/rebuild them, just let us know.

UPack Command-line Interface

upack is a cross-platform command-line tool for creating and installing universal packages; you can also see which packages are installed on a machine.

Inedo.UPack

Inedo.UPack is aAremote feed on ProGet.

Universal Package Explorer

A Windows desktop application that allows you to easily create, view, and publish universal packages. You can load a .upack file from disk or directly from a ProGet universal feed.

Push to ProGet Visual Studio Extension

Allows you to publish universal packages directly from Visual Studio.

ProGet Jenkins Plugin

Integrates ProGet with Jenkins allowing Jenkins jobs to create and upload, or download and extract, universal packages. It still works, but it's no longer actively maintained.