@@ -10,7 +10,13 @@ import log from 'electron-log';
10
10
import { AddressInfo , createServer , Socket } from 'net' ;
11
11
import { app , nativeTheme } from 'electron' ;
12
12
import { IPythonEnvironment } from './tokens' ;
13
- import { exec , execFile , ExecFileOptions , execFileSync } from 'child_process' ;
13
+ import {
14
+ exec ,
15
+ execFile ,
16
+ ExecFileOptions ,
17
+ execFileSync ,
18
+ execSync
19
+ } from 'child_process' ;
14
20
15
21
export const DarkThemeBGColor = '#212121' ;
16
22
export const LightThemeBGColor = '#ffffff' ;
@@ -710,3 +716,117 @@ export function launchTerminalInDirectory(
710
716
exec ( `gnome-terminal --working-directory="${ dirPath } "${ callCommands } ` ) ;
711
717
}
712
718
}
719
+
720
+ export function getJlabCLICommandSymlinkPath ( ) : string {
721
+ if ( process . platform === 'darwin' ) {
722
+ return '/usr/local/bin/jlab' ;
723
+ }
724
+ }
725
+
726
+ export function getJlabCLICommandTargetPath ( ) : string {
727
+ if ( process . platform === 'darwin' ) {
728
+ return `${ getAppDir ( ) } /app/jlab` ;
729
+ }
730
+ }
731
+
732
+ export function jlabCLICommandIsSetup ( ) : boolean {
733
+ if ( process . platform !== 'darwin' ) {
734
+ return true ;
735
+ }
736
+
737
+ const symlinkPath = getJlabCLICommandSymlinkPath ( ) ;
738
+ const targetPath = getJlabCLICommandTargetPath ( ) ;
739
+
740
+ if ( ! fs . existsSync ( symlinkPath ) ) {
741
+ return false ;
742
+ }
743
+
744
+ const stats = fs . lstatSync ( symlinkPath ) ;
745
+ if ( ! stats . isSymbolicLink ( ) ) {
746
+ return false ;
747
+ }
748
+
749
+ try {
750
+ fs . accessSync ( targetPath , fs . constants . X_OK ) ;
751
+ } catch ( error ) {
752
+ log . error ( 'App CLI is not executable' , error ) ;
753
+ return false ;
754
+ }
755
+
756
+ return fs . readlinkSync ( symlinkPath ) === targetPath ;
757
+ }
758
+
759
+ export async function setupJlabCLICommandWithElevatedRights ( ) : Promise <
760
+ boolean
761
+ > {
762
+ if ( process . platform !== 'darwin' ) {
763
+ return false ;
764
+ }
765
+
766
+ const symlinkPath = getJlabCLICommandSymlinkPath ( ) ;
767
+ const targetPath = getJlabCLICommandTargetPath ( ) ;
768
+
769
+ if ( ! fs . existsSync ( targetPath ) ) {
770
+ log . error ( `Target path "${ targetPath } " does not exist! ` ) ;
771
+ return false ;
772
+ }
773
+
774
+ const shellCommands : string [ ] = [ ] ;
775
+ const symlinkParentDir = path . dirname ( symlinkPath ) ;
776
+
777
+ // create parent directory
778
+ if ( ! fs . existsSync ( symlinkParentDir ) ) {
779
+ shellCommands . push ( `mkdir -p ${ symlinkParentDir } ` ) ;
780
+ }
781
+
782
+ // create symlink
783
+ shellCommands . push ( `ln -f -s \\"${ targetPath } \\" \\"${ symlinkPath } \\"` ) ;
784
+
785
+ // make files executable
786
+ shellCommands . push ( `chmod 755 \\"${ symlinkPath } \\"` ) ;
787
+ shellCommands . push ( `chmod 755 \\"${ targetPath } \\"` ) ;
788
+
789
+ const command = `do shell script "${ shellCommands . join (
790
+ ' && '
791
+ ) } " with administrator privileges`;
792
+
793
+ return new Promise < boolean > ( ( resolve , reject ) => {
794
+ const cliSetupProc = exec ( `osascript -e '${ command } '` ) ;
795
+
796
+ cliSetupProc . on ( 'exit' , ( exitCode : number ) => {
797
+ if ( exitCode === 0 ) {
798
+ resolve ( true ) ;
799
+ } else {
800
+ log . error ( `Failed to setup CLI with exit code ${ exitCode } ` ) ;
801
+ reject ( ) ;
802
+ }
803
+ } ) ;
804
+
805
+ cliSetupProc . on ( 'error' , ( err : Error ) => {
806
+ log . error ( err ) ;
807
+ reject ( ) ;
808
+ } ) ;
809
+ } ) ;
810
+ }
811
+
812
+ export async function setupJlabCommandWithUserRights ( ) {
813
+ const symlinkPath = getJlabCLICommandSymlinkPath ( ) ;
814
+ const targetPath = getJlabCLICommandTargetPath ( ) ;
815
+
816
+ if ( ! fs . existsSync ( targetPath ) ) {
817
+ return ;
818
+ }
819
+
820
+ try {
821
+ if ( ! fs . existsSync ( symlinkPath ) ) {
822
+ const cmd = `ln -s ${ targetPath } ${ symlinkPath } ` ;
823
+ execSync ( cmd , { shell : '/bin/bash' } ) ;
824
+ fs . chmodSync ( symlinkPath , 0o755 ) ;
825
+ }
826
+
827
+ // after a DMG install, mode resets
828
+ fs . chmodSync ( targetPath , 0o755 ) ;
829
+ } catch ( error ) {
830
+ log . error ( error ) ;
831
+ }
832
+ }
0 commit comments