mirror of
https://github.com/ScoopInstaller/Scoop.git
synced 2025-10-30 06:07:56 +00:00
391 lines
12 KiB
PowerShell
391 lines
12 KiB
PowerShell
# Description: Functions for interacting with the Scoop database cache
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Get SQLite .NET driver
|
|
.DESCRIPTION
|
|
Download and extract the SQLite .NET driver from NuGet.
|
|
.PARAMETER Version
|
|
System.String
|
|
The version of the SQLite .NET driver to download.
|
|
.INPUTS
|
|
None
|
|
.OUTPUTS
|
|
System.Boolean
|
|
True if the SQLite .NET driver was successfully downloaded and extracted, otherwise false.
|
|
#>
|
|
function Get-SQLite {
|
|
param (
|
|
[string]$Version = '1.0.118'
|
|
)
|
|
# Install SQLite
|
|
try {
|
|
Write-Host "Downloading SQLite $Version..." -ForegroundColor DarkYellow
|
|
$sqlitePkgPath = "$env:TEMP\sqlite.zip"
|
|
$sqliteTempPath = "$env:TEMP\sqlite"
|
|
$sqlitePath = "$PSScriptRoot\..\supporting\sqlite"
|
|
Invoke-WebRequest -Uri "https://api.nuget.org/v3-flatcontainer/stub.system.data.sqlite.core.netframework/$version/stub.system.data.sqlite.core.netframework.$version.nupkg" -OutFile $sqlitePkgPath
|
|
Write-Host "Extracting SQLite $Version..." -ForegroundColor DarkYellow -NoNewline
|
|
Expand-Archive -Path $sqlitePkgPath -DestinationPath $sqliteTempPath -Force
|
|
New-Item -Path $sqlitePath -ItemType Directory -Force | Out-Null
|
|
Move-Item -Path "$sqliteTempPath\build\net451\*", "$sqliteTempPath\lib\net451\System.Data.SQLite.dll" -Destination $sqlitePath -Force
|
|
Remove-Item -Path $sqlitePkgPath, $sqliteTempPath -Recurse -Force
|
|
Write-Host ' Done' -ForegroundColor DarkYellow
|
|
return $true
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Open Scoop SQLite database.
|
|
.DESCRIPTION
|
|
Open Scoop SQLite database connection and create the necessary tables if not exists.
|
|
.INPUTS
|
|
None
|
|
.OUTPUTS
|
|
System.Data.SQLite.SQLiteConnection
|
|
The SQLite database connection if **PassThru** is used.
|
|
#>
|
|
function Open-ScoopDB {
|
|
# Load System.Data.SQLite
|
|
if (!('System.Data.SQLite.SQLiteConnection' -as [Type])) {
|
|
try {
|
|
if (!(Test-Path -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll")) {
|
|
Get-SQLite | Out-Null
|
|
}
|
|
Add-Type -Path "$PSScriptRoot\..\supporting\sqlite\System.Data.SQLite.dll"
|
|
} catch {
|
|
throw "Scoop's Database cache requires the ADO.NET driver:`n`thttp://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki"
|
|
}
|
|
}
|
|
$dbPath = Join-Path $scoopdir 'scoop.db'
|
|
$db = New-Object -TypeName System.Data.SQLite.SQLiteConnection
|
|
$db.ConnectionString = "Data Source=$dbPath"
|
|
$db.ParseViaFramework = $true # Allow UNC path
|
|
$db.Open()
|
|
$tableCommand = $db.CreateCommand()
|
|
$tableCommand.CommandText = "CREATE TABLE IF NOT EXISTS 'app' (
|
|
name TEXT NOT NULL COLLATE NOCASE,
|
|
description TEXT NOT NULL,
|
|
version TEXT NOT NULL,
|
|
bucket VARCHAR NOT NULL,
|
|
manifest JSON NOT NULL,
|
|
binary TEXT,
|
|
shortcut TEXT,
|
|
dependency TEXT,
|
|
suggest TEXT,
|
|
PRIMARY KEY (name, version, bucket)
|
|
)"
|
|
$tableCommand.CommandType = [System.Data.CommandType]::Text
|
|
$tableCommand.ExecuteNonQuery() | Out-Null
|
|
$tableCommand.Dispose()
|
|
return $db
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Set Scoop database item(s).
|
|
.DESCRIPTION
|
|
Insert or replace item(s) into the Scoop SQLite database.
|
|
.PARAMETER InputObject
|
|
System.Object[]
|
|
The database item(s) to insert or replace.
|
|
.INPUTS
|
|
System.Object[]
|
|
.OUTPUTS
|
|
None
|
|
#>
|
|
function Set-ScoopDBItem {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
|
|
[psobject[]]
|
|
$InputObject
|
|
)
|
|
|
|
begin {
|
|
$db = Open-ScoopDB
|
|
$dbTrans = $db.BeginTransaction()
|
|
# TODO Support [hashtable]$InputObject
|
|
$colName = @($InputObject | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name)
|
|
$dbQuery = "INSERT OR REPLACE INTO app ($($colName -join ', ')) VALUES ($('@' + ($colName -join ', @')))"
|
|
$dbCommand = $db.CreateCommand()
|
|
$dbCommand.CommandText = $dbQuery
|
|
$dbCommand.CommandType = [System.Data.CommandType]::Text
|
|
}
|
|
process {
|
|
foreach ($item in $InputObject) {
|
|
$item.PSObject.Properties | ForEach-Object {
|
|
$dbCommand.Parameters.AddWithValue("@$($_.Name)", $_.Value) | Out-Null
|
|
}
|
|
$dbCommand.ExecuteNonQuery() | Out-Null
|
|
}
|
|
}
|
|
end {
|
|
try {
|
|
$dbTrans.Commit()
|
|
} catch {
|
|
$dbTrans.Rollback()
|
|
throw $_
|
|
} finally {
|
|
$dbCommand.Dispose()
|
|
$dbTrans.Dispose()
|
|
$db.Dispose()
|
|
}
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Set Scoop app database item(s).
|
|
.DESCRIPTION
|
|
Insert or replace Scoop app(s) into the database.
|
|
.PARAMETER Path
|
|
System.String
|
|
The path to the bucket.
|
|
.PARAMETER CommitHash
|
|
System.String
|
|
The commit hash to compare with the HEAD.
|
|
.INPUTS
|
|
None
|
|
.OUTPUTS
|
|
None
|
|
#>
|
|
function Set-ScoopDB {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Position = 0, ValueFromPipeline)]
|
|
[string[]]
|
|
$Path
|
|
)
|
|
|
|
begin {
|
|
$list = [System.Collections.Generic.List[psobject]]::new()
|
|
$arch = Get-DefaultArchitecture
|
|
}
|
|
process {
|
|
if ($Path.Count -eq 0) {
|
|
$bucketPath = Get-LocalBucket | ForEach-Object { Find-BucketDirectory $_ }
|
|
$Path = (Get-ChildItem $bucketPath -Filter '*.json' -Recurse).FullName
|
|
}
|
|
$Path | ForEach-Object {
|
|
$manifestRaw = [System.IO.File]::ReadAllText($_)
|
|
$manifest = ConvertFrom-Json $manifestRaw -ErrorAction SilentlyContinue
|
|
if ($null -ne $manifest.version) {
|
|
$list.Add([pscustomobject]@{
|
|
name = $($_ -replace '.*[\\/]([^\\/]+)\.json$', '$1')
|
|
description = if ($manifest.description) { $manifest.description } else { '' }
|
|
version = $manifest.version
|
|
bucket = $($_ -replace '.*buckets[\\/]([^\\/]+)(?:[\\/].*)', '$1')
|
|
manifest = $manifestRaw
|
|
binary = $(
|
|
$result = @()
|
|
@(arch_specific 'bin' $manifest $arch) | ForEach-Object {
|
|
if ($_ -is [System.Array]) {
|
|
$result += "$($_[1]).$($_[0].Split('.')[-1])"
|
|
} else {
|
|
$result += $_
|
|
}
|
|
}
|
|
$result -replace '.*?([^\\/]+)?(\.(exe|bat|cmd|ps1|jar|py))$', '$1' -join ' | '
|
|
)
|
|
shortcut = $(
|
|
$result = @()
|
|
@(arch_specific 'shortcuts' $manifest $arch) | ForEach-Object {
|
|
$result += $_[1]
|
|
}
|
|
$result -replace '.*?([^\\/]+$)', '$1' -join ' | '
|
|
)
|
|
dependency = $manifest.depends -join ' | '
|
|
suggest = $(
|
|
$suggest_output = @()
|
|
$manifest.suggest.PSObject.Properties | ForEach-Object {
|
|
$suggest_output += $_.Value -join ' | '
|
|
}
|
|
$suggest_output -join ' | '
|
|
)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
end {
|
|
if ($list.Count -ne 0) {
|
|
Set-ScoopDBItem $list
|
|
}
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Select Scoop database item(s).
|
|
.DESCRIPTION
|
|
Select item(s) from the Scoop SQLite database.
|
|
The pattern is matched against the name, binaries, and shortcuts columns for apps.
|
|
.PARAMETER Pattern
|
|
System.String
|
|
The pattern to search for. If is an empty string, all items will be returned.
|
|
.PARAMETER From
|
|
System.String[]
|
|
The fields to search from.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Data.DataTable
|
|
The selected database item(s).
|
|
#>
|
|
function Select-ScoopDBItem {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
|
|
[AllowEmptyString()]
|
|
[string]
|
|
$Pattern,
|
|
[Parameter(Mandatory, Position = 1)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string[]]
|
|
$From
|
|
)
|
|
|
|
begin {
|
|
$db = Open-ScoopDB
|
|
$dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
|
|
$result = New-Object System.Data.DataTable
|
|
$dbQuery = "SELECT * FROM app WHERE $(($From -join ' LIKE @Pattern OR ') + ' LIKE @Pattern')"
|
|
$dbQuery = "SELECT * FROM ($($dbQuery + ' ORDER BY version DESC')) GROUP BY name, bucket"
|
|
$dbCommand = $db.CreateCommand()
|
|
$dbCommand.CommandText = $dbQuery
|
|
$dbCommand.CommandType = [System.Data.CommandType]::Text
|
|
$dbAdapter.SelectCommand = $dbCommand
|
|
}
|
|
process {
|
|
$dbCommand.Parameters.AddWithValue('@Pattern', $(if ($Pattern -eq '') { '%' } else { '%' + $Pattern + '%' })) | Out-Null
|
|
[void]$dbAdapter.Fill($result)
|
|
}
|
|
end {
|
|
$dbAdapter.Dispose()
|
|
$db.Dispose()
|
|
return $result
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Get Scoop database item.
|
|
.DESCRIPTION
|
|
Get item from the Scoop SQLite database.
|
|
.PARAMETER Name
|
|
System.String
|
|
The name of the item to get.
|
|
.PARAMETER Bucket
|
|
System.String
|
|
The bucket of the item to get.
|
|
.PARAMETER Version
|
|
System.String
|
|
The version of the item to get. If not provided, the latest version will be returned.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Data.DataTable
|
|
The selected database item.
|
|
#>
|
|
function Get-ScoopDBItem {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory, Position = 0, ValueFromPipeline)]
|
|
[string]
|
|
$Name,
|
|
[Parameter(Mandatory, Position = 1)]
|
|
[string]
|
|
$Bucket,
|
|
[Parameter(Position = 2)]
|
|
[string]
|
|
$Version
|
|
)
|
|
|
|
begin {
|
|
$db = Open-ScoopDB
|
|
$dbAdapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter
|
|
$result = New-Object System.Data.DataTable
|
|
$dbQuery = 'SELECT * FROM app WHERE name = @Name AND bucket = @Bucket'
|
|
if ($Version) {
|
|
$dbQuery += ' AND version = @Version'
|
|
} else {
|
|
$dbQuery += ' ORDER BY version DESC LIMIT 1'
|
|
}
|
|
$dbCommand = $db.CreateCommand()
|
|
$dbCommand.CommandText = $dbQuery
|
|
$dbCommand.CommandType = [System.Data.CommandType]::Text
|
|
$dbAdapter.SelectCommand = $dbCommand
|
|
}
|
|
process {
|
|
$dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
|
|
$dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
|
|
$dbCommand.Parameters.AddWithValue('@Version', $Version) | Out-Null
|
|
[void]$dbAdapter.Fill($result)
|
|
}
|
|
end {
|
|
$dbAdapter.Dispose()
|
|
$db.Dispose()
|
|
return $result
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Remove Scoop database item(s).
|
|
.DESCRIPTION
|
|
Remove item(s) from the Scoop SQLite database.
|
|
.PARAMETER Name
|
|
System.String
|
|
The name of the item to remove.
|
|
.PARAMETER Bucket
|
|
System.String
|
|
The bucket of the item to remove.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
None
|
|
#>
|
|
function Remove-ScoopDBItem {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
|
[string]
|
|
$Name,
|
|
[Parameter(Mandatory, Position = 1, ValueFromPipelineByPropertyName)]
|
|
[string]
|
|
$Bucket
|
|
)
|
|
|
|
begin {
|
|
$db = Open-ScoopDB
|
|
$dbTrans = $db.BeginTransaction()
|
|
$dbQuery = 'DELETE FROM app WHERE bucket = @Bucket'
|
|
$dbCommand = $db.CreateCommand()
|
|
$dbCommand.CommandText = $dbQuery
|
|
$dbCommand.CommandType = [System.Data.CommandType]::Text
|
|
}
|
|
process {
|
|
$dbCommand.Parameters.AddWithValue('@Bucket', $Bucket) | Out-Null
|
|
if ($Name) {
|
|
$dbCommand.CommandText = $dbQuery + ' AND name = @Name'
|
|
$dbCommand.Parameters.AddWithValue('@Name', $Name) | Out-Null
|
|
}
|
|
$dbCommand.ExecuteNonQuery() | Out-Null
|
|
}
|
|
end {
|
|
try {
|
|
$dbTrans.Commit()
|
|
} catch {
|
|
$dbTrans.Rollback()
|
|
throw $_
|
|
} finally {
|
|
$dbCommand.Dispose()
|
|
$dbTrans.Dispose()
|
|
$db.Dispose()
|
|
}
|
|
}
|
|
}
|