Commands/Get-CTAN.ps1
|
function Get-CTAN { <# .SYNOPSIS Gets CTAN .DESCRIPTION Gets data from CTAN, the Comprehesive TeX Archive Network .EXAMPLE # Get all CTAN packages Get-CTAN .EXAMPLE # Get all CTAN packages using the alias `ctan` ctan .EXAMPLE # Get all CTAN packages using the alias `ctan.org` ctan.org .EXAMPLE ctan -ListAuthor .EXAMPLE ctan.org -Author knuth .EXAMPLE ctan -ListTopic .EXAMPLE ctan.org -Topic word-count .EXAMPLE ctan -ListLicense .LINK https://ctan.org/ .LINK https://ctan.org/help/json .LINK https://ctan.org/help/json/2.0/pkg .LINK https://ctan.org/help/json/2.0/authors .LINK https://ctan.org/help/json/2.0/topics #> [CmdletBinding( DefaultParameterSetName='https://ctan.org/json/2.0/packages', SupportsPaging )] [Alias('ctan', 'ctan.org')] param( # The name of a specific package. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/pkg')] [string] $Package, # The name of a specific ctan author. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/author')] [string] $Author, # The name of a specific ctan topic. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/topic')] [string] $Topic, # The phrase to search for using the ctan api. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/search/json')] [Alias('Phrase')] [string] $Search, # The maximum number of items to return. [Parameter(ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/search/json')] [ValidateRange(1,256)] [Alias('Maxiumum')] [int] $Max = 128, # The sections to search. If none are provided, all sections will be searched. [Parameter(ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/search/json')] [ValidateSet('Package','Author','Topic','Portal')] [string[]] $SearchSection, # If set, will get a list of topics from ctan. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/topics')] [Alias('ListTopics', 'TopicList')] [switch] $ListTopic, # If set, will get a list of authors from ctan. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/authors')] [Alias('ListAuthors', 'AuthorList')] [switch] $ListAuthor, # If set, will get a list of licenses from ctan. [Parameter(Mandatory,ValueFromPipelineByPropertyName, ParameterSetName='https://ctan.org/json/2.0/licenses')] [Alias('ListLicenses', 'LicenseList')] [switch] $ListLicense, # If set, will remove any cached response. [switch] $Force ) begin { # First create ourselves a cache if (-not $script:ctanCache) { $script:ctanCache = [Ordered]@{} } } process { # Next get the url by looking at the parameter set name # Parameter set names represent a base url to the ctan api # Thus this one command can represent any number of endpoints. $url = switch -regex ($PSCmdlet.ParameterSetName) { '(?>author|topic|pkg)$' { # Packages, authors, and topics are all the same @( $PSCmdlet.ParameterSetName "$Author".ToLower() "$Topic".ToLower() "$Package".ToLower() ) -ne '' -join '/' # just join things by a slash break } '/search/' { # Search is the "complicated" one. We have to: @( # * Include the base url "$($PSCmdlet.ParameterSetName)?" @( # * Encode the search term "phrase=$( [Web.HttpUtility]::UrlEncode($search) -replace '\+', '%20' )" # * Add an offset if we `-Skip` N items if ($psCmdlet.PagingParameters.Skip) { "offset=$($psCmdlet.PagingParameters.Skip)" $psCmdlet.PagingParameters.Remove('Skip') } # * Provide a maximum value "max=$max" # * If the provided a section if ($SearchSection) { # * Set ext to true "ext=true" # * and include the right term for the section switch ($SearchSection) { package {"PKG=true"} author {"AUTHORS=true"} topic {"TOPICS=true"} portal {"PORTAL=true"} } } ) -join '&' # * Join all of our query strings with `&` ) -join '' } default { # For any other parameter set, we simply use it as the url. $PSCmdlet.ParameterSetName } } # Return if magically there is no url. if (-not $url) { return } # If -Force is passed if ($Force) { # invalidate the cache. $script:ctanCache.Remove($url) } # If we don't have a cached value if (-not $script:ctanCache[$url]) { # get one. $script:ctanCache[$url] = Invoke-RestMethod -Uri $url } # If -First was provided (and less than 1mb) if ($psCmdlet.PagingParameters.First -lt 1mb) { # we will pipe to select-object $selectSplat = [Ordered]@{First = $psCmdlet.PagingParameters.First} # If we were searching and had hits if (@($script:ctanCache[$url].hits -ne $null).Count) { # output the first N hits $script:ctanCache[$url].hits | Select-Object @selectSplat } else { # otherwise # -Skip could also be useful if ($PSCmdlet.PagingParameters.Skip) { $selectSplat.Skip = $PSCmdlet.PagingParameters.Skip } $script:ctanCache[$url] | Select-Object @selectSplat } } else { # If no -First was provided, then output the cached value $script:ctanCache[$url] } # and we're done. } } |