@@ -2,29 +2,94 @@ const fs = require('fs-extra')
22const path = require ( 'path' )
33const nm = require ( '../../utils/nm' )
44
5+ const isWindows = process . platform === 'win32'
6+ const removeIfExists = ( filePath ) => {
7+ try {
8+ fs . rmSync ( filePath , { force : true } )
9+ } catch ( error ) {
10+ if ( error . code !== 'ENOENT' ) {
11+ throw error
12+ }
13+ }
14+ }
15+
16+ const makePosixLink = ( source , dest ) => {
17+ removeIfExists ( dest )
18+ fs . symlinkSync ( source , dest )
19+ try {
20+ fs . chmodSync ( source , 0o755 )
21+ } catch ( error ) {
22+ if ( error . code !== 'ENOENT' ) throw error
23+ }
24+ }
25+
26+ const makeWindowsShims = ( source , dest ) => {
27+ removeIfExists ( dest )
28+ let linked = false
29+ try {
30+ fs . symlinkSync ( source , dest , 'file' )
31+ linked = true
32+ } catch ( error ) {
33+ if ( ! [ 'EACCES' , 'EPERM' , 'UNKNOWN' ] . includes ( error . code ) ) {
34+ throw error
35+ }
36+ fs . copyFileSync ( source , dest )
37+ }
38+
39+ try {
40+ fs . chmodSync ( source , 0o755 )
41+ } catch ( error ) {
42+ if ( ! [ 'ENOENT' , 'EPERM' , 'EINVAL' ] . includes ( error . code ) ) {
43+ throw error
44+ }
45+ }
46+
47+ const nodePath = process . execPath
48+ const cmdContent = `@ECHO OFF\r\n"${ nodePath } " "${ source } " %*\r\n`
49+ const psContent = `& "${ nodePath } " "${ source } " $args\r\n`
50+
51+ removeIfExists ( `${ dest } .cmd` )
52+ removeIfExists ( `${ dest } .ps1` )
53+
54+ fs . writeFileSync ( `${ dest } .cmd` , cmdContent , 'utf8' )
55+ fs . writeFileSync ( `${ dest } .ps1` , psContent , 'utf8' )
56+
57+ return linked
58+ }
59+
60+ const createBinEntry = ( command , relativePath , targetDir ) => {
61+ const binDir = path . join ( nm , '.bin' )
62+ const source = path . join ( targetDir , relativePath )
63+ const dest = path . join ( binDir , command )
64+
65+ fs . ensureDirSync ( binDir )
66+
67+ if ( isWindows ) {
68+ makeWindowsShims ( source , dest )
69+ } else {
70+ makePosixLink ( source , dest )
71+ }
72+
73+ if ( ! isWindows ) return
74+
75+ try {
76+ fs . chmodSync ( dest , 0o755 )
77+ } catch ( error ) {
78+ if ( ! [ 'ENOENT' , 'EPERM' , 'EINVAL' ] . includes ( error . code ) ) {
79+ throw error
80+ }
81+ }
82+ }
83+
584const bin = ( key , target ) => {
685 const pkgJSON = require ( path . join ( target , 'package.json' ) )
786 if ( ! pkgJSON . bin ) return
8- fs . ensureDirSync ( path . join ( nm , '.bin' ) )
87+
988 if ( typeof pkgJSON . bin === 'string' ) {
10- try {
11- fs . unlinkSync ( path . join ( nm , '.bin' , key ) )
12- } catch ( e ) { }
13- fs . symlinkSync (
14- path . join ( target , pkgJSON . bin ) ,
15- path . join ( nm , '.bin' , key )
16- )
17- fs . chmodSync ( path . join ( target , pkgJSON . bin ) , '0755' )
89+ createBinEntry ( key , pkgJSON . bin , target )
1890 } else if ( typeof pkgJSON . bin === 'object' ) {
1991 Object . keys ( pkgJSON . bin ) . forEach ( ( cmd ) => {
20- try {
21- fs . unlinkSync ( path . join ( nm , '.bin' , cmd ) )
22- } catch ( e ) { }
23- fs . symlinkSync (
24- path . join ( target , pkgJSON . bin [ cmd ] ) ,
25- path . join ( nm , '.bin' , cmd )
26- )
27- fs . chmodSync ( path . join ( target , pkgJSON . bin [ cmd ] ) , '0755' )
92+ createBinEntry ( cmd , pkgJSON . bin [ cmd ] , target )
2893 } )
2994 }
3095}
0 commit comments