-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a setting to specify default repositories #5547
Changes from all commits
cff7ec6
783ab70
64ee268
c547abd
a51d4ae
d1b5ca6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,169 @@ | ||||||||||||
/*--------------------------------------------------------------------------------------------- | ||||||||||||
* Copyright (C) 2024 Posit Software, PBC. All rights reserved. | ||||||||||||
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information. | ||||||||||||
*--------------------------------------------------------------------------------------------*/ | ||||||||||||
|
||||||||||||
import * as positron from 'positron'; | ||||||||||||
import * as vscode from 'vscode'; | ||||||||||||
import * as path from 'path'; | ||||||||||||
import * as fs from 'fs'; | ||||||||||||
|
||||||||||||
import { JupyterKernelSpec } from './jupyter-adapter'; | ||||||||||||
import { getArkKernelPath } from './kernel'; | ||||||||||||
import { getPandocPath } from './pandoc'; | ||||||||||||
import { EXTENSION_ROOT_DIR } from './constants'; | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* Create a new Jupyter kernel spec. | ||||||||||||
* | ||||||||||||
* @param rHomePath The R_HOME path for the R version | ||||||||||||
* @param runtimeName The (display) name of the runtime | ||||||||||||
* @param sessionMode The mode in which to create the session | ||||||||||||
* | ||||||||||||
* @returns A JupyterKernelSpec definining the kernel's path, arguments, and | ||||||||||||
* metadata. | ||||||||||||
*/ | ||||||||||||
export function createJupyterKernelSpec( | ||||||||||||
rHomePath: string, | ||||||||||||
runtimeName: string, | ||||||||||||
sessionMode: positron.LanguageRuntimeSessionMode): JupyterKernelSpec { | ||||||||||||
|
||||||||||||
// Path to the kernel executable | ||||||||||||
const kernelPath = getArkKernelPath(); | ||||||||||||
if (!kernelPath) { | ||||||||||||
throw new Error('Unable to find R kernel'); | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Check the R kernel log level setting | ||||||||||||
const config = vscode.workspace.getConfiguration('positron.r'); | ||||||||||||
const logLevel = config.get<string>('kernel.logLevel') ?? 'warn'; | ||||||||||||
const logLevelForeign = config.get<string>('kernel.logLevelExternal') ?? 'warn'; | ||||||||||||
const userEnv = config.get<object>('kernel.env') ?? {}; | ||||||||||||
const profile = config.get<string>('kernel.profile'); | ||||||||||||
|
||||||||||||
|
||||||||||||
/* eslint-disable */ | ||||||||||||
const env = <Record<string, string>>{ | ||||||||||||
'RUST_BACKTRACE': '1', | ||||||||||||
'RUST_LOG': logLevelForeign + ',ark=' + logLevel, | ||||||||||||
'R_HOME': rHomePath, | ||||||||||||
...userEnv | ||||||||||||
}; | ||||||||||||
Comment on lines
+46
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor observation: we are using a little interface for env vars elsewhere in positron-r (but I don't think this matters that much and I see this code pre-existed, it's just moving in this PR): positron/extensions/positron-r/src/session.ts Lines 30 to 32 in 1492e58
positron/extensions/positron-r/src/session.ts Line 927 in 1492e58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good observation! Indeed I didn't touch this (just moved it to keep the file from becoming too unwieldy) but that'd be an improvement. |
||||||||||||
/* eslint-enable */ | ||||||||||||
|
||||||||||||
if (profile) { | ||||||||||||
env['ARK_PROFILE'] = profile; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if (process.platform === 'linux') { | ||||||||||||
// Workaround for | ||||||||||||
// https://github.com/posit-dev/positron/issues/1619#issuecomment-1971552522 | ||||||||||||
env['LD_LIBRARY_PATH'] = rHomePath + '/lib'; | ||||||||||||
} else if (process.platform === 'darwin') { | ||||||||||||
// Workaround for | ||||||||||||
// https://github.com/posit-dev/positron/issues/3732 | ||||||||||||
env['DYLD_LIBRARY_PATH'] = rHomePath + '/lib'; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Inject the path to the Pandoc executable into the environment; R packages | ||||||||||||
// that use Pandoc for rendering will need this. | ||||||||||||
// | ||||||||||||
// On MacOS, the binary path lives alongside the app bundle; on other | ||||||||||||
// platforms, it's a couple of directories up from the app root. | ||||||||||||
const pandocPath = getPandocPath(); | ||||||||||||
if (pandocPath) { | ||||||||||||
env['RSTUDIO_PANDOC'] = pandocPath; | ||||||||||||
} | ||||||||||||
|
||||||||||||
// R script to run on session startup | ||||||||||||
const startupFile = path.join(EXTENSION_ROOT_DIR, 'resources', 'scripts', 'startup.R'); | ||||||||||||
|
||||||||||||
const argv = [ | ||||||||||||
kernelPath, | ||||||||||||
'--connection_file', '{connection_file}', | ||||||||||||
'--log', '{log_file}', | ||||||||||||
'--startup-file', `${startupFile}`, | ||||||||||||
'--session-mode', `${sessionMode}`, | ||||||||||||
]; | ||||||||||||
|
||||||||||||
// Only create profile if requested in configuration | ||||||||||||
if (profile) { | ||||||||||||
argv.push(...[ | ||||||||||||
'--profile', '{profile_file}', | ||||||||||||
]); | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Set the default repositories | ||||||||||||
const defaultRepos = config.get<string>('defaultRepositories') ?? 'auto'; | ||||||||||||
if (defaultRepos === 'auto') { | ||||||||||||
const reposConf = findReposConf(); | ||||||||||||
if (reposConf) { | ||||||||||||
// If there's a `repos.conf` file in a well-known directory, use | ||||||||||||
// that. | ||||||||||||
argv.push(...['--repos-conf', reposConf]); | ||||||||||||
} else if (vscode.env.uiKind === vscode.UIKind.Web) { | ||||||||||||
// No repos.conf; if we're web mode use Posit's Public Package | ||||||||||||
// Manager | ||||||||||||
argv.push(...['--default-repos', 'posit-ppm']); | ||||||||||||
} | ||||||||||||
// In all other cases when `auto` is set, we don't specify | ||||||||||||
// `--default-repos` at all, and let Ark choose an appropriate | ||||||||||||
// repository (usually `cran.rstudio.com) | ||||||||||||
} else { | ||||||||||||
// The remaining options map directly to Ark's `--default-repos` | ||||||||||||
// command line option | ||||||||||||
argv.push(...['--default-repos', defaultRepos]); | ||||||||||||
} | ||||||||||||
|
||||||||||||
argv.push(...[ | ||||||||||||
// The arguments after `--` are passed verbatim to R | ||||||||||||
'--', | ||||||||||||
'--interactive', | ||||||||||||
]); | ||||||||||||
|
||||||||||||
// Create a kernel spec for this R installation | ||||||||||||
const kernelSpec: JupyterKernelSpec = { | ||||||||||||
'argv': argv, | ||||||||||||
'display_name': runtimeName, // eslint-disable-line | ||||||||||||
'language': 'R', | ||||||||||||
'env': env, | ||||||||||||
}; | ||||||||||||
|
||||||||||||
// Unless the user has chosen to restore the workspace, pass the | ||||||||||||
// `--no-restore-data` flag to R. | ||||||||||||
if (!config.get<boolean>('restoreWorkspace')) { | ||||||||||||
kernelSpec.argv.push('--no-restore-data'); | ||||||||||||
} | ||||||||||||
|
||||||||||||
// If the user has supplied extra arguments to R, pass them along. | ||||||||||||
const extraArgs = config.get<Array<string>>('extraArguments'); | ||||||||||||
const quietMode = config.get<boolean>('quietMode'); | ||||||||||||
if (quietMode && extraArgs?.indexOf('--quiet') === -1) { | ||||||||||||
extraArgs?.push('--quiet'); | ||||||||||||
} | ||||||||||||
if (extraArgs) { | ||||||||||||
kernelSpec.argv.push(...extraArgs); | ||||||||||||
} | ||||||||||||
|
||||||||||||
return kernelSpec; | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* Attempt to find a `repos.conf` file in Positron or RStudio XDG | ||||||||||||
* configuration directories. | ||||||||||||
* | ||||||||||||
* Returns the path to the file if found, or `undefined` if no | ||||||||||||
*/ | ||||||||||||
function findReposConf(): string | undefined { | ||||||||||||
const xdg = require('xdg-portable/cjs'); | ||||||||||||
const configDirs: Array<string> = xdg.configDirs(); | ||||||||||||
for (const product of ['rstudio', 'positron']) { | ||||||||||||
for (const configDir of configDirs) { | ||||||||||||
const reposConf = path.join(configDir, product, 'repos.conf'); | ||||||||||||
if (fs.existsSync(reposConf)) { | ||||||||||||
return reposConf; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
} | ||||||||||||
return; | ||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking this chance to have a side discussion:
In my
.Rprofile
, I haveIn terms of what we feature, is there a reason to push cran.rstudio.com over cloud.r-project.org? I guess I've implicitly preferred the latter from some super vague reasons around rstudio->posit rebrand and avoiding overt branding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we necessarily want to push cran.rstudio.com (Posit also sponsors
cloud.r-project.org
), I just used it to match ark's existing behavior. Might be worth providing acloud.r-project.org
option too, let's see what folks say.