Skip to content

Instantly share code, notes, and snippets.

@Xainey
Created September 13, 2017 05:53
Show Gist options
  • Save Xainey/f0d211c4061dcf13a4a90283a81dce73 to your computer and use it in GitHub Desktop.
Save Xainey/f0d211c4061dcf13a4a90283a81dce73 to your computer and use it in GitHub Desktop.
PowerShell Dependency Resolver for DotSourcing Classes
# Quick Draft to Share
class Node {
[String] $name
[Boolean] $isImported = $false
[System.Collections.Generic.List[Node]] $edges
hidden static [System.Collections.Generic.List[Node]] $resolved = [System.Collections.Generic.List[Node]]::new()
hidden static [System.Collections.Generic.List[Node]] $unresolved = [System.Collections.Generic.List[Node]]::new()
Node ([String] $name) {
$this.name = $name
$this.edges = [System.Collections.Generic.List[Node]]::new()
}
[Void] addEdge([Node] $node) {
$this.edges.Add($node)
}
[System.Collections.Generic.List[Node]] getResolved(){
[Node]::resolved.Clear()
[Node]::unresolved.Clear()
$this.resolve()
return ([Node]::resolved)
}
[String[]] getUnloaded(){
return ($this.getResolved() | Where-Object {$_.isImported -eq $false}).Name
}
hidden [Void] resolve () {
[Node]::unresolved.add($this)
foreach ($edge in $this.edges) {
if($this.name -eq $edge.name) { continue } # shouldnt depend on self lol
if ($edge -in [Node]::resolved) { continue }
if($edge -in [Node]::unresolved) { throw "Oh noes circular dependency: {0} -> {1}" -f $this.name, $edge.name }
$edge.resolve()
}
[Node]::resolved.add($this)
[Node]::unresolved.Remove($this) | Out-Null
}
}
class Loader {
[System.Collections.Generic.List[String]] $sourceFiles
$Nodes = @{}
Loader($sourcefiles){
$this.sourceFiles = (Get-ChildItem -Path $sourcefiles -Recurse -ErrorAction SilentlyContinue)
}
[Loader] populateNodes() {
foreach($file in $this.sourceFiles) {
$this.Nodes.Add($file, [Node]::new($file))
}
return $this
}
[Loader] populateEdges() {
foreach($node in $this.Nodes.GetEnumerator()) {
$needs = [Loader]::getUnloadedTypes($node.Name)
foreach($need in $needs) {
# File Names have to be unique
$needKey = ($this.Nodes.Keys | Where-Object { $_ -like "*$need.ps1" } | Select-Object -First 1)
$node.Value.addEdge($this.Nodes[$needKey])
}
}
return $this
}
[Void] loadDependencies() {
while($this.sourceFiles.ToArray().Count -gt 0) {
$importables = $this.Nodes[$this.sourceFiles[0]].getUnloaded()
foreach($import in $importables) {
try {
Write-Host "Importing: $import" -ForegroundColor Gray
. $import
Write-Host "Success!" -ForegroundColor Green
} catch {
Write-Error "Crap: $_"
}
$this.Nodes[$import].isImported = $true
$this.sourceFiles.Remove($import) | Out-Null
}
}
}
static [System.Collections.Generic.List[String]] getUnloadedTypes([String] $file) {
$tokens = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$tokens, [ref]$null)
$types = ($tokens | Select * -Unique | Where-Object {$_.TokenFlags -eq "TypeName"}).Text
$unloaded = [System.Collections.Generic.List[String]]::new()
foreach ($type in $types) {
if (!([System.Management.Automation.PSTypeName]$type).Type) {
$unloaded.Add($type)
}
}
return $unloaded
}
}
$Loader = [Loader]::new("C:\Posh\MyModule\src\*.ps1")
$Loader.populateNodes().populateEdges().loadDependencies()
@abelal83
Copy link

abelal83 commented Sep 5, 2018

This looks interesting but as I'm on my phone and not able test curious what does it do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment