Skip to content

Commit a460b97

Browse files
[Fix] DXVK-NVAPI installation (#3347)
* Extract tool install/update into its own function * Restructure install/update function Variables were renamed to (hopefully) be clearer, Promises are awaited instead of chaining them together with ".then", and the "echoCommand" and "cleanCommand" were replaced with Node functions * Extract archives into their destination directories directly Before, we told tar to extract into the tool's directory (not into the final destination folder), and thus relied on the archive containing a sub-directory with the name we were looking for. DXVK-NVAPI doesn't do this, so we overwrote this behavior for it only. Now, we create the destination folder and extract to it, and use the `strip` parameter for tools that ship inside a sub-directory to remove this directory. This makes sure that the destination directory always exists, which resolves issues installing DXVK-NVAPI. --------- Co-authored-by: Etaash Mathamsetty <[email protected]>
1 parent 4b06f20 commit a460b97

File tree

1 file changed

+89
-94
lines changed

1 file changed

+89
-94
lines changed

src/backend/tools/index.ts

+89-94
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import {
88
writeFileSync,
99
readdirSync,
1010
copyFile,
11-
rm
11+
rm,
12+
mkdirSync,
13+
rmSync
1214
} from 'graceful-fs'
1315

14-
import { exec, spawn } from 'child_process'
16+
import { spawn } from 'child_process'
1517
import {
1618
downloadFile,
1719
execAsync,
@@ -46,10 +48,90 @@ import {
4648
} from '../utils/graphics/vulkan'
4749
import { lt as semverLt } from 'semver'
4850
import { createAbortController } from '../utils/aborthandler/aborthandler'
49-
import { mkdir } from 'fs'
5051
import { gameManagerMap } from '../storeManagers'
5152
import { sendFrontendMessage } from '../main_window'
5253

54+
interface Tool {
55+
name: string
56+
url: string
57+
os: string
58+
strip?: number
59+
}
60+
61+
async function installOrUpdateTool(tool: Tool) {
62+
if (tool.os !== process.platform) return
63+
64+
const {
65+
data: { assets }
66+
} = await axios.get(tool.url)
67+
68+
const { name, browser_download_url: downloadUrl } = assets[0]
69+
const latestVersion = name.replace('.tar.gz', '').replace('.tar.xz', '')
70+
const latestVersionArchivePath = `${toolsPath}/${tool.name}/${name}`
71+
72+
const installedVersionStorage = `${toolsPath}/${tool.name}/latest_${tool.name}`
73+
let installedVersion = ''
74+
if (existsSync(installedVersionStorage)) {
75+
installedVersion = readFileSync(installedVersionStorage)
76+
.toString()
77+
.split('\n')[0]
78+
}
79+
80+
const alreadyUpToDate =
81+
installedVersion === latestVersion &&
82+
existsSync(join(toolsPath, tool.name, installedVersion))
83+
if (alreadyUpToDate) return
84+
85+
mkdirSync(join(toolsPath, tool.name), { recursive: true })
86+
87+
logInfo([`Updating ${tool.name} to:`, latestVersion], LogPrefix.DXVKInstaller)
88+
89+
try {
90+
await downloadFile({
91+
url: downloadUrl,
92+
dest: latestVersionArchivePath,
93+
abortSignal: createAbortController(tool.name).signal
94+
})
95+
} catch (error) {
96+
logWarning(
97+
[`Error when downloading ${tool.name}`, error],
98+
LogPrefix.DXVKInstaller
99+
)
100+
showDialogBoxModalAuto({
101+
title: i18next.t('box.error.dxvk.title', 'DXVK/VKD3D error'),
102+
message: i18next.t(
103+
'box.error.dxvk.message',
104+
'Error installing DXVK/VKD3D! Check your connection!'
105+
),
106+
type: 'ERROR'
107+
})
108+
return
109+
}
110+
111+
logInfo(`Downloaded ${tool.name}, extracting...`, LogPrefix.DXVKInstaller)
112+
113+
const extractDestination = join(toolsPath, tool.name, latestVersion)
114+
mkdirSync(extractDestination, { recursive: true })
115+
try {
116+
await extractFiles({
117+
path: latestVersionArchivePath,
118+
destination: extractDestination,
119+
strip: tool.strip ?? 1
120+
})
121+
} catch (error) {
122+
logError(
123+
[`Extraction of ${tool.name} failed with:`, error],
124+
LogPrefix.DXVKInstaller
125+
)
126+
return
127+
} finally {
128+
rmSync(latestVersionArchivePath)
129+
}
130+
131+
writeFileSync(installedVersionStorage, latestVersion)
132+
logInfo(`${tool.name} updated!`, LogPrefix.DXVKInstaller)
133+
}
134+
53135
export const DXVK = {
54136
getLatest: async () => {
55137
if (isWindows) {
@@ -63,7 +145,7 @@ export const DXVK = {
63145
return
64146
}
65147

66-
const tools = [
148+
const tools: Tool[] = [
67149
{
68150
name: 'vkd3d',
69151
url: getVkd3dUrl(),
@@ -77,7 +159,8 @@ export const DXVK = {
77159
{
78160
name: 'dxvk-nvapi',
79161
url: 'https://api.github.com/repos/jp7677/dxvk-nvapi/releases/latest',
80-
os: 'linux'
162+
os: 'linux',
163+
strip: 0
81164
},
82165
{
83166
name: 'dxvk-macOS',
@@ -86,95 +169,7 @@ export const DXVK = {
86169
}
87170
]
88171

89-
tools.forEach(async (tool) => {
90-
if (tool.os !== process.platform) {
91-
return
92-
}
93-
94-
const {
95-
data: { assets }
96-
} = await axios.get(tool.url)
97-
98-
const { name, browser_download_url: downloadUrl } = assets[0]
99-
const pkg = name.replace('.tar.gz', '').replace('.tar.xz', '')
100-
101-
const latestVersion = `${toolsPath}/${tool.name}/${name}`
102-
const pastVersionCheck = `${toolsPath}/${tool.name}/latest_${tool.name}`
103-
let pastVersion = ''
104-
if (existsSync(pastVersionCheck)) {
105-
pastVersion = readFileSync(pastVersionCheck).toString().split('\n')[0]
106-
}
107-
108-
if (
109-
pastVersion === pkg &&
110-
existsSync(`${toolsPath}/${tool.name}/${pkg}`)
111-
) {
112-
return
113-
}
114-
115-
if (!existsSync(`${toolsPath}/${tool.name}`)) {
116-
mkdir(`${toolsPath}/${tool.name}`, { recursive: true }, (err) => {
117-
if (err) {
118-
logError(
119-
[`Error creating ${tool.name} folder`, err],
120-
LogPrefix.DXVKInstaller
121-
)
122-
}
123-
})
124-
}
125-
126-
const echoCommand = `echo ${pkg} > '${toolsPath}/${tool.name}/latest_${tool.name}'`
127-
const cleanCommand = `rm ${toolsPath}/${tool.name}/${name}`
128-
const destination = join(
129-
toolsPath,
130-
tool.name,
131-
tool.name === 'dxvk-nvapi' ? pkg : ''
132-
)
133-
134-
logInfo([`Updating ${tool.name} to:`, pkg], LogPrefix.DXVKInstaller)
135-
136-
return downloadFile({
137-
url: downloadUrl,
138-
dest: latestVersion,
139-
abortSignal: createAbortController(tool.name).signal
140-
})
141-
.then(async () => {
142-
logInfo(`downloaded ${tool.name}`, LogPrefix.DXVKInstaller)
143-
logInfo(`extracting ${tool.name}`, LogPrefix.DXVKInstaller)
144-
exec(echoCommand)
145-
await extractFiles({
146-
path: latestVersion,
147-
destination,
148-
strip: 0
149-
})
150-
.then(() => {
151-
logInfo(`${tool.name} updated!`, LogPrefix.DXVKInstaller)
152-
})
153-
.catch((error) => {
154-
logError(
155-
[`Extraction of ${tool.name} failed with:`, error],
156-
LogPrefix.DXVKInstaller
157-
)
158-
})
159-
.finally(() => {
160-
exec(cleanCommand)
161-
})
162-
})
163-
.catch((error: string) => {
164-
logWarning(
165-
[`Error when downloading ${tool.name}`, error],
166-
LogPrefix.DXVKInstaller
167-
)
168-
showDialogBoxModalAuto({
169-
title: i18next.t('box.error.dxvk.title', 'DXVK/VKD3D error'),
170-
message: i18next.t(
171-
'box.error.dxvk.message',
172-
'Error installing DXVK/VKD3D! Check your connection!'
173-
),
174-
type: 'ERROR'
175-
})
176-
})
177-
})
172+
tools.forEach(installOrUpdateTool)
178173
},
179174

180175
installRemove: async (

0 commit comments

Comments
 (0)