77 getBundledEnvInstallerPath ,
88 getBundledPythonEnvPath ,
99 getBundledPythonPath ,
10+ getLogFilePath ,
1011 installCondaPackEnvironment ,
1112 isBaseCondaEnv ,
1213 isEnvInstalledByDesktopApp ,
@@ -16,11 +17,16 @@ import {
1617import yargs from 'yargs/yargs' ;
1718import * as fs from 'fs' ;
1819import * as path from 'path' ;
19- import { appData } from './config/appdata' ;
20+ import { appData , ApplicationData } from './config/appdata' ;
2021import { IEnvironmentType , IPythonEnvironment } from './tokens' ;
21- import { SettingType , userSettings } from './config/settings' ;
22+ import {
23+ SettingType ,
24+ UserSettings ,
25+ userSettings ,
26+ WorkspaceSettings
27+ } from './config/settings' ;
2228import { Registry } from './registry' ;
23- import { app } from 'electron' ;
29+ import { app , shell } from 'electron' ;
2430import {
2531 condaEnvPathForCondaExePath ,
2632 getCondaChannels ,
@@ -188,6 +194,97 @@ export function parseCLIArgs(argv: string[]) {
188194 }
189195 }
190196 )
197+ . command (
198+ 'config <action>' ,
199+ 'Manage JupyterLab Desktop settings' ,
200+ yargs => {
201+ yargs
202+ . positional ( 'action' , {
203+ describe : 'Setting action' ,
204+ choices : [ 'list' , 'set' , 'unset' ] ,
205+ default : 'list'
206+ } )
207+ . option ( 'project' , {
208+ describe : 'Set config for project at current working directory' ,
209+ type : 'boolean' ,
210+ default : false
211+ } )
212+ . option ( 'project-path' , {
213+ describe : 'Set / list config for project at specified path' ,
214+ type : 'string'
215+ } ) ;
216+ } ,
217+ async argv => {
218+ console . log ( 'Note: This is an experimental feature.' ) ;
219+
220+ const action = argv . action ;
221+ switch ( action ) {
222+ case 'list' :
223+ handleConfigListCommand ( argv ) ;
224+ break ;
225+ case 'set' :
226+ handleConfigSetCommand ( argv ) ;
227+ break ;
228+ case 'unset' :
229+ handleConfigUnsetCommand ( argv ) ;
230+ break ;
231+ default :
232+ console . log ( 'Invalid input for "config" command.' ) ;
233+ break ;
234+ }
235+ }
236+ )
237+ . command (
238+ 'appdata <action>' ,
239+ 'Manage JupyterLab Desktop app data' ,
240+ yargs => {
241+ yargs . positional ( 'action' , {
242+ describe : 'App data action' ,
243+ choices : [ 'list' ] ,
244+ default : 'list'
245+ } ) ;
246+ } ,
247+ async argv => {
248+ console . log ( 'Note: This is an experimental feature.' ) ;
249+
250+ const action = argv . action ;
251+ switch ( action ) {
252+ case 'list' :
253+ handleAppDataListCommand ( argv ) ;
254+ break ;
255+ default :
256+ console . log ( 'Invalid input for "appdata" command.' ) ;
257+ break ;
258+ }
259+ }
260+ )
261+ . command (
262+ 'logs <action>' ,
263+ 'Manage JupyterLab Desktop logs' ,
264+ yargs => {
265+ yargs . positional ( 'action' , {
266+ describe : 'Logs action' ,
267+ choices : [ 'show' , 'open' ] ,
268+ default : 'show'
269+ } ) ;
270+ } ,
271+ async argv => {
272+ console . log ( 'Note: This is an experimental feature.' ) ;
273+
274+ const action = argv . action ;
275+ switch ( action ) {
276+ case 'show' :
277+ handleLogsShowCommand ( argv ) ;
278+ break ;
279+ case 'open' :
280+ handleLogsOpenCommand ( argv ) ;
281+ break ;
282+ default :
283+ console . log ( 'Invalid input for "logs" command.' ) ;
284+ break ;
285+ }
286+ }
287+ )
191288 . parseAsync ( ) ;
192289}
193290
@@ -816,6 +913,225 @@ export async function handleEnvSetSystemPythonPathCommand(argv: any) {
816913 userSettings . save ( ) ;
817914}
818915
916+ function handleConfigListCommand ( argv : any ) {
917+ const listLines : string [ ] = [ ] ;
918+
919+ let projectPath = argv . projectPath
920+ ? path . resolve ( argv . projectPath )
921+ : process . cwd ( ) ;
922+
923+ listLines . push ( 'Project / Workspace settings' ) ;
924+ listLines . push ( '============================' ) ;
925+ listLines . push ( `[Project path: ${ projectPath } ]` ) ;
926+ listLines . push (
927+ `[Source file: ${ WorkspaceSettings . getWorkspaceSettingsPath ( projectPath ) } ]`
928+ ) ;
929+ listLines . push ( '\nSettings' ) ;
930+ listLines . push ( '========' ) ;
931+
932+ const wsSettings = new WorkspaceSettings ( projectPath ) . settings ;
933+ const wsSettingKeys = Object . keys ( wsSettings ) . sort ( ) ;
934+ if ( wsSettingKeys . length > 0 ) {
935+ for ( let key of wsSettingKeys ) {
936+ const value = wsSettings [ key ] . value ;
937+ listLines . push ( `${ key } : ${ JSON . stringify ( value ) } ` ) ;
938+ }
939+ } else {
940+ listLines . push ( 'No setting overrides found in project directory.' ) ;
941+ }
942+ listLines . push ( '\n' ) ;
943+
944+ listLines . push ( 'Global settings' ) ;
945+ listLines . push ( '===============' ) ;
946+ listLines . push ( `[Source file: ${ UserSettings . getUserSettingsPath ( ) } ]` ) ;
947+ listLines . push ( '\nSettings' ) ;
948+ listLines . push ( '========' ) ;
949+
950+ const settingKeys = Object . values ( SettingType ) . sort ( ) ;
951+ const settings = userSettings . settings ;
952+
953+ for ( let key of settingKeys ) {
954+ const setting = settings [ key ] ;
955+ listLines . push (
956+ `${ key } : ${ JSON . stringify ( setting . value ) } [${
957+ setting . differentThanDefault ? 'modified' : 'set to default'
958+ } ${ setting . wsOverridable ? ', project overridable' : '' } ]`
959+ ) ;
960+ }
961+
962+ console . log ( listLines . join ( '\n' ) ) ;
963+ }
964+
965+ function handleConfigSetCommand ( argv : any ) {
966+ const parseSetting = ( ) : { key : string ; value : string } => {
967+ if ( argv . _ . length !== 3 ) {
968+ console . error ( `Invalid setting. Use "set settingKey value" format.` ) ;
969+ return { key : undefined , value : undefined } ;
970+ }
971+
972+ return { key : argv . _ [ 1 ] , value : JSON . parse ( argv . _ [ 2 ] ) } ;
973+ } ;
974+
975+ let projectPath = '' ;
976+ let isProjectSetting = false ;
977+
978+ if ( argv . project || argv . projectPath ) {
979+ projectPath = argv . projectPath
980+ ? path . resolve ( argv . projectPath )
981+ : process . cwd ( ) ;
982+ if (
983+ argv . projectPath &&
984+ ! ( fs . existsSync ( projectPath ) && fs . statSync ( projectPath ) . isFile ( ) )
985+ ) {
986+ console . error ( `Invalid project path! "${ projectPath } "` ) ;
987+ return ;
988+ }
989+
990+ isProjectSetting = true ;
991+ }
992+
993+ let key , value ;
994+ try {
995+ const keyVal = parseSetting ( ) ;
996+ key = keyVal . key ;
997+ value = keyVal . value ;
998+ } catch ( error ) {
999+ console . error ( 'Failed to parse setting!' ) ;
1000+ return ;
1001+ }
1002+
1003+ if ( ! ( key && value ) ) {
1004+ return ;
1005+ }
1006+
1007+ if ( ! ( key in SettingType ) ) {
1008+ console . error ( `Invalid setting key! "${ key } "` ) ;
1009+ return ;
1010+ }
1011+
1012+ if ( isProjectSetting ) {
1013+ const setting = userSettings . settings [ key ] ;
1014+ if ( ! setting . wsOverridable ) {
1015+ console . error ( `Setting "${ key } " is not overridable by project.` ) ;
1016+ return ;
1017+ }
1018+
1019+ const wsSettings = new WorkspaceSettings ( projectPath ) ;
1020+ wsSettings . setValue ( key as SettingType , value ) ;
1021+ wsSettings . save ( ) ;
1022+ } else {
1023+ userSettings . setValue ( key as SettingType , value ) ;
1024+ userSettings . save ( ) ;
1025+ }
1026+
1027+ console . log (
1028+ `${
1029+ isProjectSetting ? 'Project' : 'Global'
1030+ } setting "${ key } " set to "${ value } " successfully.`
1031+ ) ;
1032+ }
1033+
1034+ function handleConfigUnsetCommand ( argv : any ) {
1035+ const parseKey = ( ) : string => {
1036+ if ( argv . _ . length !== 2 ) {
1037+ console . error ( `Invalid setting. Use "set settingKey value" format.` ) ;
1038+ return undefined ;
1039+ }
1040+
1041+ return argv . _ [ 1 ] ;
1042+ } ;
1043+
1044+ let projectPath = '' ;
1045+ let isProjectSetting = false ;
1046+
1047+ if ( argv . project || argv . projectPath ) {
1048+ projectPath = argv . projectPath
1049+ ? path . resolve ( argv . projectPath )
1050+ : process . cwd ( ) ;
1051+ if (
1052+ argv . projectPath &&
1053+ ! ( fs . existsSync ( projectPath ) && fs . statSync ( projectPath ) . isFile ( ) )
1054+ ) {
1055+ console . error ( `Invalid project path! "${ projectPath } "` ) ;
1056+ return ;
1057+ }
1058+
1059+ isProjectSetting = true ;
1060+ }
1061+
1062+ let key = parseKey ( ) ;
1063+
1064+ if ( ! key ) {
1065+ return ;
1066+ }
1067+
1068+ if ( ! ( key in SettingType ) ) {
1069+ console . error ( `Invalid setting key! "${ key } "` ) ;
1070+ return ;
1071+ }
1072+
1073+ if ( isProjectSetting ) {
1074+ const setting = userSettings . settings [ key ] ;
1075+ if ( ! setting . wsOverridable ) {
1076+ console . error ( `Setting "${ key } " is not overridable by project.` ) ;
1077+ return ;
1078+ }
1079+
1080+ const wsSettings = new WorkspaceSettings ( projectPath ) ;
1081+ wsSettings . unsetValue ( key as SettingType ) ;
1082+ wsSettings . save ( ) ;
1083+ } else {
1084+ userSettings . unsetValue ( key as SettingType ) ;
1085+ userSettings . save ( ) ;
1086+ }
1087+
1088+ console . log (
1089+ `${ isProjectSetting ? 'Project' : 'Global' } setting "${ key } " reset to ${
1090+ isProjectSetting ? 'global ' : ''
1091+ } default successfully.`
1092+ ) ;
1093+ }
1094+
1095+ function handleAppDataListCommand ( argv : any ) {
1096+ const listLines : string [ ] = [ ] ;
1097+
1098+ listLines . push ( 'Application data' ) ;
1099+ listLines . push ( '================' ) ;
1100+ listLines . push ( `[Source file: ${ ApplicationData . getAppDataPath ( ) } ]` ) ;
1101+ listLines . push ( '\nData' ) ;
1102+ listLines . push ( '====' ) ;
1103+
1104+ const skippedKeys = new Set ( [ 'newsList' ] ) ;
1105+ const appDataKeys = Object . keys ( appData ) . sort ( ) ;
1106+
1107+ for ( let key of appDataKeys ) {
1108+ if ( key . startsWith ( '_' ) || skippedKeys . has ( key ) ) {
1109+ continue ;
1110+ }
1111+ const data = ( appData as any ) [ key ] ;
1112+ listLines . push ( `${ key } : ${ JSON . stringify ( data ) } ` ) ;
1113+ }
1114+
1115+ console . log ( listLines . join ( '\n' ) ) ;
1116+ }
1117+
1118+ function handleLogsShowCommand ( argv : any ) {
1119+ const logFilePath = getLogFilePath ( ) ;
1120+ console . log ( `Log file path: ${ logFilePath } ` ) ;
1121+
1122+ if ( ! ( fs . existsSync ( logFilePath ) && fs . statSync ( logFilePath ) . isFile ( ) ) ) {
1123+ console . log ( 'Log file does not exist!' ) ;
1124+ return ;
1125+ }
1126+
1127+ const logs = fs . readFileSync ( logFilePath ) ;
1128+ console . log ( logs . toString ( ) ) ;
1129+ }
1130+
1131+ function handleLogsOpenCommand ( argv : any ) {
1132+ shell . openPath ( getLogFilePath ( ) ) ;
1133+ }
1134+
8191135export async function launchCLIinEnvironment (
8201136 envPath : string
8211137) : Promise < boolean > {
0 commit comments