blob: e6cee07eee7223a369b953778341f8b083f9260d [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as path from 'path'
import * as fs from 'fs'
import * as vscode from 'vscode'
import { outputChannel } from '../adapter/activateDaffodilDebug'
import { downloadAndExtract, fetchRetry } from '../utils'
import { parseStringPromise } from 'xml2js'
/**
* Only the default version of Daffodil is bundled with the extension, all other versions are
* downloaded. The CLI zip is an official daffodil release that contains all the daffodil jars
* (and their transitive dependencies) that the debugger needs for a particular Daffodil version.
* The debugger doesn't need all the jars that it bundles (e.g. daffodil-cli.jar) but those will
* just be ignored.
*
* If - The bundled version of the Daffodil CLI matches the Daffodil version wanting to be used
* then default to use that path.
* If - The global storage path for the Daffodil version already exists, use that path.
* Else - Download and extract the Daffodil CLI that matches the version desired to the global
* storage path.
*/
export async function checkIfDaffodilJarsNeeded(
daffodilVersion: string
): Promise<string> {
const context = (await vscode.commands.executeCommand(
'getContext'
)) as vscode.ExtensionContext
// If the Daffodil Version desired is bundled in the extension, use that path
const extensionPath = path.join(
context.asAbsolutePath('./dist'),
`daffodil/apache-daffodil-${daffodilVersion}-bin`
)
if (fs.existsSync(extensionPath)) {
outputChannel.appendLine(`[INFO] Using bundled Daffodil CLI JARs.`)
return extensionPath
}
// If not a valid daffodil version provided and it doesn't exist already in cache then throw error
if (!(await checkIfValidDaffodilVersion(daffodilVersion))) {
throw new Error(
'Invalid Daffodil Version provided. Make sure dfdlDebugger.daffodilVersion is a valid version of Daffodil'
)
}
// downloadAndExtractToGlobalStorage only tries to download the Daffodil CLI release file if
// the desired version's bin folder doesn't already exists.
return await downloadAndExtractToGlobalStorage(context, daffodilVersion)
}
// Helper function to get the list of valid Daffodil versions
async function getValidDaffodilVersions(): Promise<string[]> {
const url = 'https://daffodil.apache.org/doap.rdf'
const resp = await fetchRetry(url)
if (!resp) {
throw new Error(`Failed to fetch DOAP RDF ${url}`)
}
const xmlText = await resp.text()
const data = await parseStringPromise(xmlText, { explicitArray: false })
const project = data['rdf:RDF']['Project']
const releases = project['release']
const releaseArray = Array.isArray(releases) ? releases : [releases]
return releaseArray
.filter((rel) => rel['Version']['name'] == 'Apache Daffodil') // only look at Daffodil releases
.map((rel: any) => rel['Version']['revision'] ?? '')
.filter((s) => s != '') // make sure no empty strings are saved
}
// Helper function to check if the given daffodil version is a valid version or not
const checkIfValidDaffodilVersion = async (
daffodilVersion: string
): Promise<boolean> =>
(await getValidDaffodilVersions()).includes(daffodilVersion)
export async function downloadAndExtractToGlobalStorage(
context: vscode.ExtensionContext,
daffodilVersion: string
): Promise<string> {
/**
* Global storage paths:
* Mac: /Users/<username>/Library/Application Support/Code/User/globalStorage/asf.apache-daffodil-vscode
* Windows: %APPDATA%\Code\User\globalStorage\asf.apache-daffodil-vscode
* Linux: /home/<username>/.config/Code/User/globalStorage/asf.apache-daffodil-vscode
*/
const destFolder = path.join(context.globalStorageUri.fsPath, 'daffodil')
const binName = `apache-daffodil-${daffodilVersion}-bin`
const binFolder = path.join(destFolder, binName)
if (!fs.existsSync(binFolder)) {
const url = `https://www.apache.org/dyn/closer.lua/download/daffodil/${daffodilVersion}/bin/${binName}.zip`
try {
await downloadAndExtract('Daffodil CLI JARs', url, destFolder)
} catch (err) {
/**
* If error hit trying to download and extract throw the error
*/
throw `[ERROR] downloading and extracting Daffodil CLI JARs for ${daffodilVersion}: ${err}`
}
} else {
outputChannel.appendLine(
`[INFO] Daffodil CLI JARs already exists. Skipping download.`
)
}
return binFolder
}