Tools/Sync.ps1
|
<#
SPDX-License-Identifier: MIT Copyright (c) 2026 Leon McClatchey, Linktech Engineering LLC Package: VSCode-Updater Author: Leon McClatchey Company: Linktech Engineering LLC Created: 2026-04-23 Modified: 2026-05-20 File: Sync.ps1 Version: 1.0.1 Description: Deterministically synchronize the repo version of VSCode-Updater into the user's installed PowerShell module path. #> <# .SYNOPSIS Synchronizes the VSCode-Updater module from repo → module folder. .DESCRIPTION This script performs a deterministic sync by validating: - Module folder existence - File count drift - Hash drift - Timestamp drift - Version drift If ANY mismatch is detected, a full sync is performed. #> Write-Host "=== VSCode-Updater Sync ===" # ===================================================================== # Resolve Paths # ===================================================================== # Repo root = parent of Tools\ $ScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path $RepoRoot = "C:\Users\ldmcc\Nextcloud\Projects\Scripts\PowerShell\VSCode-Updater" # The module lives directly in the repo root (not nested) $RepoModule = $RepoRoot $LoadedModule = Get-Module VSCode-Updater -ListAvailable | Select-Object -First 1 if ($LoadedModule) { # Use the versioned module folder directly $ModuleRoot = $LoadedModule.ModuleBase } else { # First-time install $ModuleRoot = Join-Path $HOME 'Documents\PowerShell\Modules\VSCode-Updater' } Write-Host "Repo: $RepoModule" Write-Host "Module: $ModuleRoot" # Ensure module folder exists if (-not (Test-Path $ModuleRoot)) { New-Item -ItemType Directory -Force -Path $ModuleRoot | Out-Null } # ===================================================================== # Logging Setup # ===================================================================== $LogRoot = Join-Path $RepoRoot "Logs" if (-not (Test-Path $LogRoot)) { New-Item -ItemType Directory -Force -Path $LogRoot | Out-Null } $LogFile = Join-Path $LogRoot "Sync.log" function Write-SyncLog { param([string]$Message) $ts = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") Add-Content -Path $LogFile -Value "$ts $Message" } Write-SyncLog "===============================================================" Write-SyncLog "VSCode-Updater Sync Started" Write-SyncLog "Repo: $RepoModule" Write-SyncLog "Module: $ModuleRoot" Write-SyncLog "===============================================================" # ===================================================================== # Drift Detection (Simple + Deterministic) # ===================================================================== $repoFiles = Get-ChildItem -Path $RepoModule -Recurse -File $moduleFiles = Get-ChildItem -Path $ModuleRoot -Recurse -File -ErrorAction SilentlyContinue $repoCount = $repoFiles.Count $moduleCount = $moduleFiles.Count if ($repoCount -ne $moduleCount) { Write-Host "File count mismatch — syncing." Write-SyncLog "File count mismatch — performing FULL SYNC." $DoFullSync = $true } else { # Compare LastWriteTime for drift detection $drift = $false foreach ($file in $repoFiles) { $relative = $file.FullName.Substring($RepoModule.Length).TrimStart('\') $target = Join-Path $ModuleRoot $relative if (-not (Test-Path $target)) { $drift = $true break } $repoTime = $file.LastWriteTimeUtc $moduleTime = (Get-Item $target).LastWriteTimeUtc if ($repoTime -ne $moduleTime) { $drift = $true break } } if ($drift) { Write-Host "Drift detected — syncing." Write-SyncLog "Drift detected — performing FULL SYNC." $DoFullSync = $true } else { Write-Host "No drift detected — module is up to date." Write-SyncLog "No drift detected — module is up to date." Write-SyncLog "===============================================================" return } } # ===================================================================== # Incremental Sync (only changed files) # ===================================================================== Write-Host "Performing SYNC..." Write-SyncLog "Performing SYNC..." $ModuleItems = @( "VSCode-Updater.psm1", "VSCode-Updater.psd1", "Private", "Public" ) # Remove orphaned files in module folder $moduleExisting = Get-ChildItem -Path $ModuleRoot -Recurse -File -ErrorAction SilentlyContinue foreach ($file in $moduleExisting) { $relative = $file.FullName.Substring($ModuleRoot.Length).TrimStart('\') $source = Join-Path $RepoRoot $relative if (-not (Test-Path $source)) { Write-SyncLog "Removing orphaned file: $relative" Remove-Item $file.FullName -Force } } foreach ($item in $ModuleItems) { $source = Join-Path $RepoRoot $item $dest = Join-Path $ModuleRoot $item # --- Case 1: Item is a FILE --- if (Test-Path $source -PathType Leaf) { if (-not (Test-Path $dest)) { Write-SyncLog "Copying new file: $item" Copy-Item -Path $source -Destination $dest -Force continue } if ((Get-Item $source).LastWriteTimeUtc -ne (Get-Item $dest).LastWriteTimeUtc) { Write-SyncLog "Updating changed file: $item" Copy-Item -Path $source -Destination $dest -Force } continue } # --- Case 2: Item is a DIRECTORY --- if (Test-Path $source -PathType Container) { # Always recreate the directory for deterministic sync if (Test-Path $dest) { Write-SyncLog "Removing existing directory: $item" Remove-Item $dest -Recurse -Force } Write-SyncLog "Copying fresh directory: $item" Copy-Item -Path $source -Destination $dest -Recurse -Force continue } } Write-Host "Sync complete." Write-SyncLog "Sync complete." Write-SyncLog "===============================================================" |