1+ <#
2+ . SYNOPSIS
3+ Builds the website.
4+ . DESCRIPTION
5+ Builds a static site using PowerShell.
6+
7+ * The site will be configured using any `config.*` files.
8+ * Functions and filters will be loaded from any `functions.*` or `filters.*` files.
9+ * All files will be processed using `buildFile.ps1` (any `*.*.ps1` file should be run).
10+ . EXAMPLE
11+ ./build.ps1
12+ #>
13+ param (
14+ [string []]
15+ $FilePath ,
16+
17+ [string ]
18+ $Root = $PSScriptRoot
19+ )
20+
121# Push into the script root directory
222if ($PSScriptRoot ) { Push-Location $PSScriptRoot }
323
24+ # Creation of a sitewide object to hold configuration information.
25+ $Site = [Ordered ]@ {}
26+ $Site.Files =
27+ if ($filePath ) { Get-ChildItem - Recurse - File - Path $FilePath }
28+ else { Get-ChildItem - Recurse - File }
29+
30+ $Site.PSScriptRoot = " $PSScriptRoot "
31+
432# region Common Functions and Filters
533$functionFileNames = ' functions' , ' function' , ' filters' , ' filter'
634$functionPattern = " (?>$ ( $functionFileNames -join ' |' ) )\.ps1$"
@@ -13,10 +41,6 @@ foreach ($file in $functionFiles) {
1341}
1442# endregion Common Functions and Filters
1543
16- # Creation of a sitewide object to hold configuration information.
17- $Site = [Ordered ]@ {}
18- $Site.Files = Get-ChildItem - Recurse - File
19-
2044# Set an alias to buildFile.ps1
2145Set-Alias BuildFile ./ buildFile.ps1
2246
@@ -34,6 +58,11 @@ $gitHubEvent =
3458if (Test-Path ' CNAME' ) {
3559 $Site.CNAME = $CNAME = (Get-Content - Path ' CNAME' - Raw).Trim()
3660 $Site.RootUrl = " https://$CNAME /"
61+ } elseif (
62+ ($site.PSScriptRoot | Split-Path - Leaf) -like ' *.*'
63+ ) {
64+ $site.CNAME = $CNAME = ($site.PSScriptRoot | Split-Path - Leaf)
65+ $site.RootUrl = " https://$CNAME /"
3766}
3867
3968# If we have a config.json file, it can be used to set the site configuration.
@@ -70,7 +99,7 @@ if (Test-Path 'config.ps1') {
7099}
71100
72101# Start the clock
73- $lastBuildTime = [DateTime ]::Now
102+ $site [ ' LastBuildTime ' ] = $ lastBuildTime = [DateTime ]::Now
74103# region Build Files
75104
76105# Start the clock on the build process
@@ -119,8 +148,188 @@ if ($lastBuild) {
119148$newLastBuild | ConvertTo-Json - Depth 2 > lastBuild.json
120149# endregion lastBuild.json
121150
151+ # region sitemap.xml
152+ if (-not $Site.NoSitemap ) {
153+ $siteMapXml = @ (
154+ ' <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
155+ :nextPage foreach ($key in $site.PagesByUrl.Keys | Sort-Object { " $_ " .Length}) {
156+ $keyUri = $key -as [Uri ]
157+ $page = $site.PagesByUrl [$key ]
158+ if ($site.Disallow ) {
159+ foreach ($disallow in $site.Disallow ) {
160+ if ($keyUri.LocalPath -like " *$disallow *" ) { continue nextPage }
161+ if ($keyUri.AbsoluteUri -like " *$disallow *" ) { continue nextPage }
162+ }
163+ }
164+ if ($page.NoIndex ) { continue }
165+ if ($page.NoSitemap ) { continue }
166+ if ($page.OutputFile.Extension -ne ' .html' ) { continue }
167+ " <url>"
168+ " <loc>$key </loc>"
169+ if ($site.PagesByUrl [$key ].Date -is [DateTime ]) {
170+ " <lastmod>$ ( $site.PagesByUrl [$key ].Date.ToString(' yyyy-MM-dd' )) </lastmod>"
171+ }
172+ " </url>"
173+ }
174+ ' </urlset>'
175+ ) -join ' ' -as [xml ]
176+ if ($siteMapXml ) {
177+ $siteMapXml.Save ((
178+ Join-Path $site.PSScriptRoot sitemap.xml
179+ ))
180+ }
181+ }
182+ # endregion sitemap.xml
183+
184+ # region index.rss
185+ if (-not $Site.NoRss ) {
186+ $pagesByDate = $site.PagesByUrl.GetEnumerator () |
187+ Sort-Object { $_.Value.Date } - Descending
188+ $rssXml = @ (
189+ ' <rss version="2.0">'
190+ ' <channel>'
191+ " <title>$ ( [Security.SecurityElement ]::Escape($ (
192+ if ($site.Title ) { $site.Title } else { $site.CNAME }
193+ ))) </title>"
194+ " <link>$ ( $site.RootUrl ) </link>"
195+ " <description>$ ( [Security.SecurityElement ]::Escape($ (
196+ if ($site.Description ) { $site.Description } else { $site.Title }
197+ ))) </description>"
198+ " <pubDate>$ ( $pagesByDate [0 ].Value.Date.ToString(' R' )) </pubDate>"
199+ " <lastBuildDate>$ ( $lastBuildTime.ToString (' R' )) </lastBuildDate>"
200+ " <language>$ ( [Security.SecurityElement ]::Escape($site.Language )) </language>"
201+ :nextPage foreach ($keyValue in $pagesByDate ) {
202+ $key = $keyValue.Key
203+ $keyUri = $key -as [Uri ]
204+ $page = $keyValue.Value
205+ if ($site.Disallow ) {
206+ foreach ($disallow in $site.Disallow ) {
207+ if ($keyUri.LocalPath -like " *$disallow *" ) { continue nextPage }
208+ if ($keyUri.AbsoluteUri -like " *$disallow *" ) { continue nextPage }
209+ }
210+ }
211+ if ($site.PagesByUrl [$key ].NoIndex) { continue }
212+ if ($site.PagesByUrl [$key ].NoSitemap) { continue }
213+ if ($site.PagesByUrl [$key ].OutputFile.Extension -ne ' .html' ) { continue }
214+ " <item>"
215+ " <title>$ ( [Security.SecurityElement ]::Escape($ (
216+ if ($page.Title ) { $page.Title }
217+ elseif ($site.Title ) { $site.Title }
218+ else { $site.CNAME }
219+ ))) </title>"
220+ if ($site.PagesByUrl [$key ].Date -is [DateTime ]) {
221+ " <pubDate>$ ( $site.PagesByUrl [$key ].Date.ToString(' R' )) </pubDate>"
222+ }
223+ " <description>$ ( [Security.SecurityElement ]::Escape($ (
224+ if ($page.Description ) { $page.Description }
225+ elseif ($site.Description ) { $site.Description }
226+ ))) </description>"
227+ " <link>$key </link>"
228+ " <guid isPermaLink='true'>$key </guid>"
229+ " </item>"
230+ }
231+ ' </channel>'
232+ ' </rss>'
233+ ) -join ' ' -as [xml ]
234+
235+ if ($rssXml ) {
236+ $rssOutputPath = Join-Path $site.PSScriptRoot ' RSS' | Join-Path - ChildPath ' index.rss'
237+ if (-not (Test-Path $rssOutputPath )) {
238+ # Create the file if it doesn't exist
239+ $null = New-Item - ItemType File - Force $rssOutputPath
240+ }
241+ $rssXml.Save ($rssOutputPath )
242+ }
243+ }
244+
245+
246+ # endregion index.rss
247+
248+ # region robots.txt
249+ if (-not $Site.NoRobots ) {
250+ @ (
251+ " User-agent: *"
252+ if ($site.Disallow ) {
253+ foreach ($disallow in $site.Disallow ) {
254+ " Disallow: $disallow "
255+ }
256+ }
257+ if ($site.Allow ) {
258+ foreach ($allow in $site.Allow ) {
259+ " Allow: $allow "
260+ }
261+ }
262+ if ($site.CNAME -and -not $site.NoSitemap ) {
263+ " Sitemap: https://$ ( $site.CNAME ) /sitemap.xml"
264+ }
265+ ) > robots.txt
266+ }
267+ # endregion robots.txt
268+
269+ # region index.json
270+ if (-not $Site.NoIndex ) {
271+ $fileIndex =
272+ if ($filePath ) { Get-ChildItem - Recurse - File - Path $FilePath }
273+ else { Get-ChildItem - Recurse - File }
274+
275+ $replacement =
276+ if ($filePath ) {
277+ " ^" + ([regex ]::Escape($filePath ) -replace ' \*' , ' .{0,}?' )
278+ } else {
279+ " ^" + [regex ]::Escape(" $pwd " )
280+ }
281+
282+ $indexObject = [Ordered ]@ {}
283+ $gitCommand = $ExecutionContext.SessionState.InvokeCommand.GetCommand (' git' , ' Application' )
284+ foreach ($file in $fileIndex ) {
285+ $gitDates =
286+ try {
287+ (& $gitCommand log -- follow -- format=% ci -- date default $file.FullName * > & 1 ) -as [datetime []]
288+ } catch {
289+ $null
290+ }
291+ $LASTEXITCODE = 0
292+
293+ $indexObject [$file.FullName -replace $replacement ] = [Ordered ]@ {
294+ Name = $file.Name
295+ Length = $file.Length
296+ Extension = $file.Extension
297+ CreatedAt =
298+ if ($gitDates ) {
299+ $gitDates [-1 ]
300+ } else {
301+ $file.CreationTime
302+ }
303+ LastWriteTime =
304+ if ($gitDates ) {
305+ $gitDates [0 ]
306+ } else {
307+ $file.LastWriteTime
308+ }
309+ }
310+ }
311+
312+ foreach ($indexKey in $indexObject.Keys ) {
313+ if (-not $indexObject [$indexKey ].CreatedAt) {
314+ if ($indexObject [" $indexKey .ps1" ].CreatedAt) {
315+ $indexObject [$indexKey ].CreatedAt = $indexObject [" $indexKey .ps1" ].CreatedAt
316+ }
317+ }
318+ if (-not $indexObject [$indexKey ].LastWriteTime) {
319+ if ($indexObject [" $indexKey .ps1" ].LastWriteTime) {
320+ $indexObject [$indexKey ].LastWriteTime = $indexObject [" $indexKey .ps1" ].LastWriteTime
321+ }
322+ }
323+ }
324+
325+ $indexObject | ConvertTo-Json - Depth 4 > index.json
326+ }
327+ # endregion index.json
328+
122329# region archive.zip
123- # Create an archive of the current deployment.
124- Compress-Archive - Path $pwd - DestinationPath " archive.zip" - CompressionLevel Optimal - Force
330+ if ($site.Archive ) {
331+ # Create an archive of the current deployment.
332+ Compress-Archive - Path $pwd - DestinationPath " archive.zip" - CompressionLevel Optimal - Force
333+ }
125334# endregion archive.zip
126- if ($PSScriptRoot ) { Pop-Location }
335+ if ($PSScriptRoot ) { Pop-Location }
0 commit comments