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.

Virtual Packages in Universal Package Feeds

view on GitHub

A Virtual Package is a special type of Universal Package that contains no content (i.e. application files, components, metadata files, etc.). It's simply a package manifest file (i.e. upack.json) with instructions on where to download the content.

When you upload a Virtual Package to a feed, it will appear and function as an ordinary universal package in most cases. When a user or client downloads the package from the feed, ProGet will transparently assemble the package file.

Creating Virtual Packages

A Virtual Package is JSON-based Universal Package Manifest file with an additional content property that describes the package's content (i.e. what files will be placed in the packages/ folder in the package file).

For example, the following Virtual Package simply combines two other universal packages into one:

# HDARS.Combined-1.3.9.vpack
{
 "name": "HDARS.Combined",
 "version": "1.3.9",
 "contents": [ "HDARS.Web:1.3.9", "HDARS.API:1.3.9"  ]
}

ProGet will assemble the HDARS.Combined package file by taking the contents from the referenced packages (i.e. files under package/ in the package file) and adding them to the packages/ folder in the new package file.

HDARS.Web-1.3.9HDARS.API-1.3.9HDARS.Combined-1.3.9v
upack.json
package/index.htm
package/logo.gif
upack.json
package/cgi-bin/api.py
upack.json
package/index.htm
package/logo.gif
package/cgi-bin/api.py

Note that the manifest files (upack.json) from the referenced packages are not used. The new manifest file (upack.json) will contain all of the same properties as the virtual package file, except the contents property:

# upack.json
{
 "name": "HDARS.Combined",
 "version": "1.3.9"
}

Using Virtual Paths

By default, ProGet will assemble referenced resources into the new package's content root (i.e. packages/). You can specify a subfolder by using a Virtual Content Object with a targetPath property.

For example, consider this virtual package that's assembled from 4 packages:

# ErpProduct.Initech-2.2.1.vpack
{
 "name": "ErpProduct.Initech",
 "version": "2.2.1",
 "contents": [
   "ErpProduct.Core:2.2.1",
   {
    "source": "Plugins.Initech:2.0.1",
    "targetPath": "custom/plugin"
   },
   {
    "source": "Plugins.SalesPipeline:2.1.0",
    "targetPath": "custom/plugin"
   },
   {
    "source": "Plugins.Workflows:2.1.0",
    "targetPath": "custom/plugin"
   }
  ]
}

The ErpProduct.Core:2.2.1 package is specified as a string, but the other three packages are specified as objects with a source and targetPath. As such, those packages' contents will be written to the package/{targetPath}/ folder instead of package/.

Assuming that each of those packages had a single file, the assembled package might look like this:

package/erp.core.exe
package/custom/plugins/initech.dll
package/custom/plugins/salespipeline.dll
package/custom/plugins/workflows.dll
upack.json

Using Files and Assets

In addition to packages, content from an asset directory or files from a url.

{
 "group": "initrode/vendors/abl",
 "name": "ABLast.AstDist",
 "version": "2.2.1",
 "contents": [
   {
    "virtualPath": "vendors/common/ast",
    "source": "initrode/vendors/abl/ABlast:2.2.1:ab60bf74fc8147ca41bd53bdb1defc3aae35bc91"
   },
   {
    "virtualPath": "common/logo/logo.png",
    "source": { 
       "url": "http://proget/endpoints/customer-assets/content/ast-logo.png"
    }
   },
   {
    "virtualPath": "common/logo/logo.png",
    "source": { 
       "feed": "customer-assets",
       "asset": "logos/ast-logo.png"
    }
   }
  ]
}

Metacontents

By default, ProGet will assemble package contents to the packages/ folder in the new package file. However, if you specify items in the metaContents folder, they will instead be written to the root folder in the package file.

Usecases for Virtual Packages

There are two main use cases for virtual packages:

Usecase: Bundling Multiple Packages

There are several cases where you may want to bundle a number of packages into a single, logical package.

This can be easily solved with a virtual package that "bundles" a specific version of the base application (CrmAppBase) and the client customization (InitechApp) into a single, logical package (Initech.crm).

When you deliver the package, it will be exactly what is needed. However, you can easily see from the metadata which versions/components were used to assemble the package.

Usecase: Logical Packaging of External Files

Another way to use Virtual Packages is to reference known external files.

You can also bundle these files together with your regular package contents by bundling them.

Assembling Virtual Package Contents

When assembling a virtual package, ProGet uses the following logic:

  1. The contents array is enumerated, and each resource is assessed as follows:

    1. If it's a file resource: the contents are downloaded, verified (if a hash is specified), and written to the target virtual path. A directory is created if it doesn't exist, and a file is ignored if it already exists.
    2. If it's a package resource: the current package feed is queried for the specified package (including hash). The contents are then extracted to the target virtual path, ignoring any existing files.
  2. The metaContents array is enumerated; each resource is assessed as follows:

    1. If the virtualPath is upack.json or within the packages directory: the operation fails
    2. If it's a file resource: the contents are downloaded, verified (if a hash is specified), and written to the target virtual path. A directory is created if it doesn't exist, and a file is ignored if it already exists.
    3. If it's a package resource: the current feed is queried for the specified package (including hash). The contents are then extracted to the target virtual path, ignoring any existing files.
  3. If any error occurs during assembly, then the entire operation fails.

Depending on the size of the referenced files and packages, package assembly may be resource-intensive and time-consuming. However, ProGet will save assembled packages to the feed's package store using a .constructed extension and will use this file for subsequent requests.

Specifications & Data Objects

Additional Manifest File Properties

Property Format
contentsR An array of at least one item, containing any of the following:
string - a package identification string
string - an absolute URL to an HTTP or HTTPS file resource
object - virtual content object

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

Virtual Content Object

This object describes a remote file or folder within either the root of the content (package/) or package root (/) folder, depending on whether it's within the contents or metaContents property.

PropertyFormat
typeA string of either virtualDirectory or virtualFile that describes the content to be added. The default value is virtualDirectory, and is used only in the case of missing property. All other values (including null or empty) are invalid.
virtualPathA string of a path to a file or folder within either the root of the content (package/) or package root (/) folder, depending on whether the object is within the contents or metaContents property.

A missing property, or null, empty, or "/" string means the root within that path.

When used in metaContent, a value of upack.json is invalid, as the manifest can never be virtualized. A value that begins with package/ is also invalid for metaContent.
sourceOne of the following values:

Package Source Object

This object describes where either a virtualFile or virtualFolder (as specified by the parent object) can be found.

Property Format
group A string of the referenced package group. When not specified, the empty group is used.
nameR A string of the referenced package name.
versionR A string of the referenced package version.
hash A SHA-1 hash string of file contents
packagePath A string containing the path within the package file (i.e. under the / directory of the archive file) the content can be found. A missing property or null value will default to package/.

File Source Object

This object describes where a virtualFile can be found.

Property Format
urlR A string of an absolute HTTP/HTTPS resource where file contents can be found
hash A SHA-1 hash string of file contents