Table of Contents

Private registries

In this guide we focus on how you can create and publish your own NuGet packages on an on-premises NuGet server.

Upload NuGet Package


  1. Save your PLC as a .library, either with CI/CD or manually in the TwinCAT IDE, make sure to set the following properties for your library

    • Company: Name of your company, in Twinpack we refer to this as 'distributor name'
    • Title: Name of your library as it should be seen in the TwinCAT Library Repository.
    • Version: Version number in the format x.y.z or x.y.z.w, see Versions
  2. Pack the library with twinpack nuget pack. It reads the properties above straight out of the library file and writes one .nupkg per library, so there is no .nuspec to write and keep in sync:

    twinpack.exe nuget pack
    

    This only writes files, it does not upload anything. Useful flags:

    Flag Purpose
    --target TwinCAT target the library is placed under in the package, defaults to TC3.1
    --output-directory Where the .nupkg files are written, defaults to .Zeugwerk/nupkg
    --compiled Pack .compiled-library files and add the tp-compiled-library tag
    --project-url, --license, --license-file, --icon-file Catalog metadata that has no equivalent in the TwinCAT project properties
    --without-config, --library-path Pack loose .library files in a folder, without a config.json

    To pack a whole solution at once, including its applications, use zkmake nuget pack.

  3. Push the packages to your NuGet server:

    nuget.exe push .Zeugwerk\nupkg\MyPlcLibrary.1.0.0.nupkg -Source https://your-nuget-server -ApiKey your-api-key
    

Versions

A TwinCAT library version has 3 or 4 numbers (x.y.z or x.y.z.w). A NuGet package version can additionally have a prerelease, e.g. 1.0.0-feat-ci. NuGet supports all 4 numbers, so twinpack nuget pack writes the library version into the nuspec unchanged:

Library version in TwinCAT Packed as On the server this is
1.2.3 1.2.3 a release
1.2.3.4 1.2.3.4 a release
1.2.3.0 1.2.3 a release
1.2.3-feat-ci 1.2.3-feat-ci a prerelease
1.2.3.4-feat-ci 1.2.3.4-feat-ci a prerelease
1.2.3.0-feat-ci 1.2.3-feat-ci a prerelease

The only number NuGet changes is a 4th number of 0, which it normalizes away. That is lossless: 1.2.3 and 1.2.3.0 are the same version to NuGet, so a lookup for either one finds the package. It also keeps a released library a release rather than a prerelease, which matters because a consumer asking for the latest stable version would not resolve a prerelease.

Twinpack reads the following forms when it looks for a package:

NuGet package version Twinpack reads it as Version referenced in TwinCAT
1.2.3 1.2.3 1.2.3
1.2.3.4 1.2.3.4 1.2.3.4
1.2.3-feat-ci 1.2.3-feat-ci 1.2.3
1.2.3.4-feat-ci 1.2.3.4-feat-ci 1.2.3.4
1.2.3-4 1.2.3.4 1.2.3.4
1.2.3-feat-ci.4 1.2.3.4-feat-ci 1.2.3.4
  • A 3 number version is left as it is. TwinCAT accepts 3 number library versions and registers them under exactly that string, so padding 1.2.3 to 1.2.3.0 would produce a version no installed library can be matched against.
  • Because 1.2.3.0 is published as 1.2.3, a package version alone cannot say whether the library inside is 1.2.3 or 1.2.3.0. Twinpack settles that against the libraries actually installed rather than by guessing from the version string.
  • The prerelease is never passed to TwinCAT, because a TwinCAT library version only consists of numbers. The library in the package should have the numeric version from the last column.
  • The last two rows are a superseded convention that moved the 4th number into the prerelease. Twinpack still reads them so that packages published that way keep working, but nothing produces them any more. A prerelease that ends with . and a number is therefore read as the 4th number, e.g. 1.0.0-beta.2 is referenced as 1.0.0.2 in TwinCAT.

Writing the nuspec yourself

twinpack nuget pack covers the layout and metadata described here. This section documents what it produces, for the case that you want to build the package with nuget pack and a hand-written .nuspec instead.

  1. In the same folder as you saved the library file, create a .nuspec file with the following content (adapt to match your specific library). The filename should match the name of the library, i.e. for the library file MyPlcLibrary.library, the nuspec file should be called MyPlcLibrary.nuspec

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
        <metadata>
            <id>MyPlcLibrary</id>
            <version>1.0.0.0</version>
            <title>MyPlcLibrary</title>
            <icon>logo.png</icon>
            <iconUrl>https://myhost.me/icon.png</iconUrl>
            <authors>MyCompany</authors>
            <description>MyPlcLibrary is an awesome library</description>
            <copyright>MyCompany</copyright>
            <tags>library</tags>
            <dependencies>
                <dependency id="Dependency1" version="1.1.2" />
            </dependencies>
        </metadata>
        <files>
            <file src="MyPlcLibrary.library" target="TC3.1" />
            <file src="logo.png" target="" />
        </files>
    </package>
    
    • authors must match the company of your PLC library (as set in the TwinCAT properties)
    • id and title must match the title of your PLC library (as set in the TwinCAT properties), see FAQ if your title contains spaces.
    • version must match the version of your PLC library (as set in the TwinCAT properties), optionally with a prerelease, see Versions
    • In tags you can put any additional tags you like, but the tag library must be included. If you are distributing a compiled-library (e.g. MyLibrary.compiled-library) in addition to the library tag, the tp-compiled-library tag has to be set (e.g. <tags>library tp-compiled-library</tags>)
    • In files, the .library file must be set
    • icon is optional and can be used to provide an icon that is shown in the Twinpack Catalog instead of an autogenerated icon (using icon is supported since Twinpack 1.2).
    • iconUrl is optional and can be used to provide an icon, which is shown in the Twinpack Catalog instead of an autogenerated icon. This property is ignored if icon is used.
    • dependencies is optional and contains any number of elements that identify other packages upon which the top-level package depends. The attributes for each are id and version. A dependency does not have to be on the same NuGet server, Twinpack looks for it in all configured repositories, e.g. on twinpack.dev.
    • Other properties in the .nuspec file are optional
  2. Use nuget to package and push the NuGet package to your NuGet server, assuming nuget.exe is in your path environment variable and you navigated to the folder containing your .library file, this can be done with

    nuget.exe pack
    nuget.exe push MyPlcLibrary.1.0.0.nupkg -Source https://your-nuget-server -ApiKey your-api-key
    

Use NuGet package

In order to use the NuGet package you just uploaded to your server

  1. Open Twinpack in the TwinCAT IDE
  2. On the right, top corner click on Configure to add your NuGet Server as a repository for Twinpack
  3. If your repository requires authentication, you have to login. Click on the Login button and enter your personal Username and Password. If your Twinpack server only supports apikeys, leave the Username empty and put the ApiKey into the Password field.
  4. The repository configuration is saved by clicking Ok on the Package servers modal.
  5. You can now search and install the package(s) available on your NuGet server.

Example: Local Repository

The example below demonstrates how to create NuGet packages and host them in a local repository. It shows how to configure .nuspec files for publishing to a NuGet server. The demo publishes to a local folder, but the same approach applies to any NuGet repository.

  1. Download and extract this zip-archive

  2. The archive contains precompiled library files, but you can also open the included TwinCAT solution to build these files yourself.

  3. Open a command prompt, navigate to the extracted folder, and run the following commands to create the NuGet packages and “host” them locally:

    nuget pack CoreLib.nuspec
    nuget pack Utilities.nuspec
    nuget push CoreLib.1.1.2.nupkg -Source E:\LocalRepo
    nuget push Utilities.1.2.3.nupkg -Source E:\LocalRepo
    
  4. Open the included solution and open the Twinpack catalog for the Application PLC.

  5. Add the local repository to your Twinpack Source Repositories (see screenshot).

  6. You can now add the UtilitiesLib package to your application.


FAQ

I have spaces in the title of my library, but NuGet doesn't allow spaces

Even though NuGet Servers have a restriction regarding spaces, it is still possible to host this library on your NuGet repository with Twinpack. In the nuspec file

  • in <id>, replace the spaces in the title of your library with dots (.) or underscores (_) and use this as your package id, e.g. <id>My.Library.With.Spaces</id>
  • in <title>, use the title of your library with spaces, e.g. <title>My Library With Spaces</title>