Skip to content
Stjepan Bakrac edited this page May 22, 2020 · 3 revisions

Windower 5 allows registering multiple package repositories in addition to the primary (official) package source. All package sources are looked up when trying to install packages, and are also considered for updates. It solves one of the biggest issues of Windower 4, where there was no easy way to access unofficial addons, and even if people did that they would not update automatically.

To add a new package source, use the /pkg addsrc command. You can verify that it was added by using /pkg listsrc, where it should appear:

> /pkg addsrc https://raw.githubusercontent.com/z16/packages/master/
> /pkg listsrc
[package manager] listing sources...
[package manager] https://raw.githubusercontent.com/z16/packages/master/

Now you can install addons from that repository as if they were official addons:

> /install pv
> /load pv
pv loaded

To create a package source you need a publicly accessible URL where your addon folders reside. On the same URL there needs to be a packages.xml file containing information on the available packages. This file (and not the directory structure) is looked up to identify available packages.

The structure of the XML should look like this:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package>
    <name>pv</name> <!-- name of the package, must match the directory -->
    <version>2.2.0.0</version> <!-- version used to determine updates -->
    <type>addon</type> <!-- valid package types: addon, library, service -->
    <dependencies> <!-- dependent packages -->
      <dependency>entities</dependency>
      <dependency>lists</dependency>
      <dependency>packet_service</dependency>
      <dependency>packet</dependency>
      <dependency>resources</dependency>
      <dependency>settings</dependency>
    </dependencies>
    <files> <!-- list of included files, file size optional -->
      <file size="368">pv/manifest.xml</file>
      <file size="20996">pv/pv.lua</file>
    </files>
  </package>
  <!-- add more packages here -->
</packages>

The following is a sample PowerShell script to generate this XML structure. Note that the first line specifies the packages to include. This manual step is done intentionally, as there could be addons in the folder that are not meant for inclusion. If you remove the first line it will not perform this check and will treat all directories containing a manifest.xml file as a package and include it in the generated packages.xml file.

$includePackages = "pv", "v", "util"

$knownPackages = Get-ChildItem -Directory |
    Where-Object {
        if (Test-Path variable:local:includePackages) {
            $includePackages.Contains([System.IO.Path]::GetFileName($_))
        } else {
            Test-Path (Join-Path $_ "manifest.xml")
        }
    } |
    ForEach-Object {
        $_.Name
    } |
    Sort-Object

$xmlSettings = New-Object System.XMl.XmlWriterSettings
$xmlSettings.Indent = $true
$xmlSettings.IndentChars = "  "
$xmlSettings.NewLineChars = "`n"
$packagesWriter = [System.XMl.XmlWriter]::Create("packages.xml", $xmlSettings)

$packagesWriter.WriteStartDocument()
$packagesWriter.WriteStartElement("packages")

$knownPackages |
    ForEach-Object {
        $path = $_

        $manifest = Join-Path $path "manifest.xml"
        $package = ([xml](Get-Content $manifest)).package
        $version = $package.version |
            ForEach-Object {
                if (([string]$_) -match "^\d+(?:.\d+){1,3}") {
                    try {
                        [Version]($matches[0])
                    } catch {
                        [Version]::new()
                    }
                } else {
                    [Version]::new()
                }
            }

        $packagesWriter.WriteStartElement("package")
        $packagesWriter.WriteElementString("name", $package.name)
        $packagesWriter.WriteElementString("version", $package.version)
        $packagesWriter.WriteElementString("type", $package.type)

        $dependencies = $package.dependencies.dependency |
            Where-Object {
                if ($_.optional -is [string]) {
                    $c = $_.optional[0]
                    $c -eq "t" -or $c -eq "y" -or $c -eq "1"
                } else {
                    $true
                }
            } |
            ForEach-Object {
                if ($_ -is [Xml.XmlElement]) {
                    $_.'#text'
                } else {
                    $_
                }
            }

        if ($dependencies.Count -gt 0) {
            $packagesWriter.WriteStartElement("dependencies")
            $dependencies |
                ForEach-Object {
                    $packagesWriter.WriteElementString("dependency", $_)
                }
            $packagesWriter.WriteEndElement()
        }

        $packagesWriter.WriteStartElement("files")

        Get-ChildItem $path -Recurse -File |
            ForEach-Object {
                $relativePath = (Resolve-Path $_.FullName -Relative).Replace(".\", "")

                $packagesWriter.WriteStartElement('file')
                $packagesWriter.WriteAttributeString('size', $_.Length)
                $packagesWriter.WriteString($relativePath.Replace("\", "/"))
                $packagesWriter.WriteEndElement()
            }

        $packagesWriter.WriteEndElement()

        $packagesWriter.WriteEndElement()
    }

$packagesWriter.WriteEndElement()
$packagesWriter.WriteEndDocument()
$packagesWriter.Flush()
$packagesWriter.Close()
Clone this wiki locally