psconfluencepublisher/PSConfluencePublisher/Manifest.psm1
2023-08-06 04:19:36 +02:00

361 lines
8.7 KiB
PowerShell
Executable file

#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"
$script:schema = Get-Content (
Join-Path $PSScriptRoot 'manifest.schema.json'
) | Out-String
function Get-Manifest
{
<#
.SYNOPSIS
Load the archive manifest
.EXAMPLE
Get-Manifest 'manifest.json'
#>
Param(
# filesystem location of manifest
[Parameter(Mandatory)] [string] $File
)
Process
{
try
{
$raw = Get-Content $File | Out-String
}
catch
{
Write-Debug $_
$raw = '{"pages":{}, "attachments": {}}'
}
$raw | Test-JSON -Schema $script:schema | Out-Null
$data = $raw | ConvertFrom-JSON
}
}
function Set-Manifest
{
<#
.SYNOPSIS
Dump the archive manifest
.EXAMPLE
Set-Manifest 'manifest.json'
#>
Param(
# manifest object
[Parameter(Mandatory)] [PSObject] $Manifest,
# filesystem location of manifest
[Parameter(Mandatory)] [string] $File,
# create a backup first
[Parameter()] [bool] $Backup = $false
)
Process
{
$raw = $Manifest | ConvertTo-JSON
$raw | Test-JSON -Schema $script:schema
if ($Backup)
{
$baseDir = Split-Path $File
$baseName = "$(Split-Path -Leaf $File).bck"
#FIXME: this should be handled without an explicit condition
if ($baseDir)
{
$path = Join-Path $baseDir $baseName
}
else
{
$path = $baseName
}
Copy-Item -Path $File -Destination $path
}
Set-Content -Path $File -Value $raw
}
}
function New-AncestralPageGenerationCache {
<#
.SYNOPSIS
Calculate the numeric ancestral generation of a page
.DESCRIPTION
The Get-AncestralPageGeneration calculates a numeric ancestral
generation of a page, which is used for sorting.
The index required as input can be retrieved through the
New-PagesManifestIndex function.
.EXAMPLES
$generation = Get-AncestralPageGeneration `
-Title 'foobar4' `
-Manifest @() `
-Index @{}
#>
Param(
# Pages manifest
[Parameter(Mandatory)] [Array] $Manifest,
# Title of page to calculate generation of
[Parameter()] [String] $Title,
# Index for lookup of page metadata manifest item position
[Parameter()] [Collections.Hashtable] $Index
)
Begin
{
$cache = @{}
If (-Not $Index)
{
Write-Debug "rebuilding index"
$Index = ,$Manifest | New-PagesManifestIndex
}
}
Process
{
ForEach ($pageMeta in $Manifest)
{
$generation = 0
$pageMeta = $Title ? $Manifest[$Index.$Title] : $pageMeta
$ancestor = $pageMeta.AncestorTitle
$pageMeta_ = $pageMeta
While ($ancestor)
{
$generation += 1
$pageMeta_ = $Manifest[$Index."$($pageMeta_.AncestorTitle)"]
$ancestor = $pageMeta_.AncestorTitle
}
$cache[$pageMeta.Title] = $generation
if ($Title) {Break}
}
}
End {$cache}
}
function Optimize-PagesManifest
{
<#
.SYNOPSIS
Sort Pages Manifest in accordance with the pages ancestry
.DESCRIPTION
The Optimize-PagesManifest function sorts a Pages manifest in
accordance with the pages ancestry. This makes sure that an ancestor
is already published, before its descendant is published.
The sorting is done with a quick-sort algorithm, using the Hoare
partitioning scheme.
Older/lower ancestral generations take precedence over
higher/younger ones. Syblings within a generation are treated
as LIFO, where the youngest (last) has precedence over the oldest
(fist).
.EXAMPLE
$manifest Optimize-PagesManifest -Manifest ,@()
or
$manifest = ,@() | Optimize-PagesManifest
.NOTES
whichever system generates the manifest should already output the
array in the correct order, however it is not wise to depend upon
this.
#>
Param(
# Manifest to sort
[Parameter(Mandatory)] [Array] $Manifest,
# Left partition border
[Parameter(Mandatory)] [Int] $Lo,
# Right partition border
[Parameter(Mandatory)] [Int] $Hi,
# Cache for storing the numeric ancestral generation of pages
[Parameter(Mandatory)] [Collections.Hashtable] $GenerationCache
)
Process
{
$pivotPageMeta = $Manifest[($Lo + $Hi) / 2]
$pivot = $generationCache[$pivotPageMeta.Title]
# left index
$i = $Lo
# right index
$j = $Hi
While($i -le $j)
{
# Move the left index to the right at least once and while
# the element at the left index is less than the pivot
While (
$generationCache."$($Manifest[$i].Title)" -lt $pivot `
-And `
$i -lt $Hi
)
{
$i += 1
}
# Move the right index to the left at least once and while
# element at the right index is greater than the pivot
While (
$generationCache."$($Manifest[$j].Title)" -gt $pivot `
-And `
$j -gt $Lo
)
{
$j -= 1
}
If ($i -le $j)
{
$tmp = $Manifest[$i]
$Manifest[$i] = $Manifest[$j]
$Manifest[$j] = $tmp
$i += 1
$j -= 1
}
If ($Lo -lt $j)
{
Optimize-PagesManifest `
-Manifest $Manifest `
-Lo $Lo`
-Hi $j `
-GenerationCache $GenerationCache
}
If ($i -lt $Hi)
{
Optimize-PagesManifest `
-Manifest $Manifest `
-Lo $i `
-Hi $Hi `
-GenerationCache $GenerationCache
}
}
}
}
function New-PagesManifestIndex
{
<#
.SYNOPSIS
Create an index of pages from a manifest
.DESCRIPTION
The New-PageIndex function builds a page index from a manifest
for faster lookup of page metadata. The title of a page is used for
indexing, since a page title is unique within a Confluence space.
.INPUTS
Manifest
.OUTPUTS
Returns a Hashtable, where the key of each key-value pair is the
page title and attachment name, and the value is the index of the
array item within the Attachments porition of the manifest.
.EXAMPLE
New-PageIndex -Manifest @{}
#>
Param(
[Parameter(Mandatory, ValueFromPipeline)] [Array] $Manifest
)
Process
{
$index = @{}
For($i = 0; $i -lt $Manifest.Count; $i += 1)
{
$index[$Manifest[$i].Title] = $i
}
$index
}
}
function New-AttachmentsManifestIndex
{
<#
.SYNOPSIS
Create an index of page container attachments from a manifest
.DESCRIPTION
The New-AttachmentIndex function builds an attachment index from a
manifest for faster lookup of attachment metadata. The title of
the container page, including the attachment name a is used for
indexing, since attachment names are unique within a container page.
.INPUTS
Manifest
.OUTPUTS
Returns a Hashtable, where the key of each key-value pair is the
interpolation of the container page title and attachment name, and
the value is the index of the array item within the Attachments
porition of the manifest.
.EXAMPLE
New-AttachmentIndex -Manifest @{}
#>
Param(
#manifest
[Parameter(Mandatory, ValueFromPipeline)] [Array] $Manifest
)
Process
{
$index = @{}
For($i = 0; $i -lt $Manifest.Count; $i += 1)
{
$key = "$($Manifest[$i].ContainerPageTitle):" + `
"$($Manifest[$i].Name)"
$index[$key] = $i
}
$index
}
}