diff options
Diffstat (limited to 'windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1')
| -rw-r--r-- | windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 | 276 |
1 files changed, 273 insertions, 3 deletions
diff --git a/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 b/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 index 349f7ab..40b5879 100644 --- a/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 +++ b/windows/Documents/PowerShell/Microsoft.PowerShell_profile.ps1 @@ -1,6 +1,276 @@ -# Dotfiles special git command -function global:config { - git --git-dir="$env:USERPROFILE\.cfg" --work-tree="$env:USERPROFILE" $args +# Dotfiles Management System +if (Test-Path "$HOME\.cfg" -and Test-Path "$HOME\.cfg\refs") { + + # Core git wrapper with repository as work-tree + function _config { + param( + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] + [String[]]$Args + ) + git --git-dir="$HOME\.cfg" --work-tree="$HOME\.cfg" @Args + } + + # Detect OS (cross-platform, PowerShell-native) + $osPlatform = [System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform + if ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)) { + $global:CFG_OS = "windows" + } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::Linux)) { + $global:CFG_OS = "linux" + } elseif ($osPlatform([System.Runtime.InteropServices.OSPlatform]::OSX)) { + $global:CFG_OS = "macos" + } else { + $global:CFG_OS = "other" + } + + # Map system path to repository path + function _repo_path { + param([string]$FilePath) + + # If it's an absolute path that's not in HOME, handle it specially + if (($FilePath.StartsWith("\\") -or $FilePath.Contains(":")) -and -not $FilePath.StartsWith($HOME)) { + return "$CFG_OS/" + ($FilePath -replace '^[A-Z]:\\', '' -replace '\\', '/') + } + + # Check for paths that should go to the repository root + if ($FilePath -match '^(common|linux|macos|windows|profile)/.*|^README\.md$') { + return $FilePath -replace '\\', '/' + } + + # Remove HOME prefix if present + if ($FilePath.StartsWith($HOME)) { + $FilePath = $FilePath.Substring($HOME.Length + 1) + } + + # Default: put under OS-specific home + return "$CFG_OS/home/" + ($FilePath -replace '\\', '/') + } + + # Map repository path back to system path + function _sys_path { + param([string]$RepoPath) + + $osPathPattern = "$CFG_OS/" + + # Handle OS-specific files that are not in the home subdirectory + if ($RepoPath.StartsWith($osPathPattern) -and $RepoPath -notmatch '/home/') { + return ($RepoPath.Substring($osPathPattern.Length) -replace '/', '\\') + } + + switch -Wildcard ($RepoPath) { + "common/config/*" { + $file = $RepoPath.Substring("common/config/".Length) + switch ($CFG_OS) { + "linux" { return Join-Path ($env:XDG_CONFIG_HOME ?? "$HOME\.config") $file } + "macos" { return Join-Path "$HOME\Library\Application Support" $file } + "windows" { return Join-Path $env:LOCALAPPDATA $file } + default { return Join-Path "$HOME\.config" $file } + } + } + "common/assets/*" { return Join-Path "$HOME\.cfg" $RepoPath } + "common/*" { return Join-Path $HOME ($RepoPath.Substring("common/".Length)) } + "*/home/*" { return Join-Path $HOME ($RepoPath.Substring($RepoPath.IndexOf("home/") + 5)) } + "profile/*" { return Join-Path "$HOME\.cfg" $RepoPath } + "README.md" { return Join-Path "$HOME\.cfg" $RepoPath } + default { return Join-Path "$HOME\.cfg" $RepoPath } + } + } + + # Prompts for administrator permissions if needed and runs the command + function _admin_prompt { + param( + [Parameter(Mandatory=$true, ValueFromRemainingArguments=$true)] + [String[]]$Command + ) + if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { + Write-Host "Warning: This action requires administrator privileges." -ForegroundColor Yellow + Start-Process powershell.exe -ArgumentList "-NoProfile", "-Command", "Set-Location '$PWD'; & $Command" -Verb RunAs + } else { + & $Command + } + } + + # Main config command + function config { + param( + [string]$Command, + [string]$TargetDir = "", + [Parameter(ValueFromRemainingArguments=$true)] + [string[]]$Args + ) + + # Parse --target flag for add command + if ($Command -eq "add" -and $Args.Count -gt 0) { + $i = 0 + while ($i -lt $Args.Count) { + if ($Args[$i] -eq "--target" -or $Args[$i] -eq "-t") { + if ($i + 1 -lt $Args.Count) { + $TargetDir = $Args[$i + 1] + $Args = $Args[0..($i-1)] + $Args[($i+2)..($Args.Count-1)] + break + } else { + Write-Host "Error: --target requires a directory argument" -ForegroundColor Red + return + } + } + $i++ + } + } + + switch ($Command) { + "add" { + foreach ($file in $Args) { + if (-not $TargetDir) { + $repoPath = _repo_path $file + } else { + $fileName = if ($file.Contains("\\") -or $file.Contains(":")) { Split-Path $file -Leaf } else { $file } + $repoPath = "$TargetDir/$fileName" -replace '\\', '/' + } + + $fullRepoPath = Join-Path "$HOME\.cfg" $repoPath + $dir = Split-Path $fullRepoPath + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + Copy-Item -Path $file -Destination $fullRepoPath -Recurse -Force + _config add $repoPath + Write-Host "Added: $file -> $repoPath" -ForegroundColor Green + } + } + "rm" { + $rmOpts = @() + $fileList = @() + + foreach ($arg in $Args) { + if ($arg.StartsWith("-")) { + $rmOpts += $arg + } else { + $fileList += $arg + } + } + + foreach ($file in $fileList) { + $repoPath = _repo_path $file + if ($rmOpts -contains "-r") { + _config rm --cached -r $repoPath + } else { + _config rm --cached $repoPath + } + Remove-Item -Path $file -Recurse:($rmOpts -contains "-r") -Force + Write-Host "Removed: $file" -ForegroundColor Yellow + } + } + "sync" { + $direction = if ($Args.Count -gt 0) { $Args[0] } else { "to-repo" } + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ($direction -eq "to-repo") { + if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { + $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) + if ($diff) { + Copy-Item $sysFile $fullRepoPath -Force + Write-Host "Synced to repo: $sysFile" -ForegroundColor Cyan + } + } + } elseif ($direction -eq "from-repo") { + if ((Test-Path $fullRepoPath)) { + $diff = if (Test-Path $sysFile) { Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) } else { $true } + if ($diff) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Synced from repo: $sysFile" -ForegroundColor Cyan + } + } + } + } + } + "status" { + $autoSynced = @() + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + if ((Test-Path $sysFile) -and (Test-Path $fullRepoPath)) { + $diff = Compare-Object (Get-Content $fullRepoPath -ErrorAction SilentlyContinue) (Get-Content $sysFile -ErrorAction SilentlyContinue) + if ($diff) { + Copy-Item $sysFile $fullRepoPath -Force + $autoSynced += $repoFile + } + } + } + if ($autoSynced.Count -gt 0) { + Write-Host "=== Auto-synced Files ===" -ForegroundColor Magenta + foreach ($repoFile in $autoSynced) { + Write-Host "synced: $(_sys_path $repoFile) -> $repoFile" -ForegroundColor Cyan + } + Write-Host + } + _config status + Write-Host + } + "deploy" { + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ((Test-Path $fullRepoPath) -and $sysFile) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Deployed: $repoFile -> $sysFile" -ForegroundColor Green + } + } + } + "checkout" { + Write-Host "Checking out dotfiles from .cfg..." -ForegroundColor Blue + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + $fullRepoPath = Join-Path "$HOME\.cfg" $repoFile + + if ((Test-Path $fullRepoPath) -and $sysFile) { + $destDir = Split-Path $sysFile + if (($sysFile.StartsWith('\\') -or $sysFile.Contains(':')) -and -not $sysFile.StartsWith($HOME)) { + _admin_prompt "New-Item -ItemType Directory -Path '$destDir' -Force; Copy-Item '$fullRepoPath' '$sysFile' -Recurse -Force" + } else { + if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null } + Copy-Item $fullRepoPath $sysFile -Recurse -Force + } + Write-Host "Checked out: $repoFile -> $sysFile" -ForegroundColor Green + } + } + } + "backup" { + $timestamp = Get-Date -Format "yyyyMMddHHmmss" + $backupDir = Join-Path $HOME ".dotfiles_backup\$timestamp" + Write-Host "Backing up existing dotfiles to $backupDir..." -ForegroundColor Blue + + _config ls-files | ForEach-Object { + $repoFile = $_ + $sysFile = _sys_path $repoFile + if (Test-Path $sysFile) { + $destDirFull = Join-Path $backupDir (Split-Path $repoFile) + if (-not (Test-Path $destDirFull)) { New-Item -ItemType Directory -Path $destDirFull -Force | Out-Null } + Copy-Item $sysFile (Join-Path $backupDir $repoFile) -Recurse -Force + } + } + Write-Host "Backup complete. To restore, copy files from $backupDir to their original locations." -ForegroundColor Green + } + default { + _config $Command @Args + } + } + } } # Shows navigable menu of all options when hitting Tab |
