-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathinstall.js
133 lines (112 loc) · 4.15 KB
/
install.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
'use strict'
//
// Compatibility with older node.js as path.exists got moved to `fs`.
//
const fs = require('node:fs')
const path = require('node:path')
const os = require('node:os')
const hook = path.join(__dirname, 'hook')
const root = path.resolve(__dirname, '..', '..', '..')
const exists = fs.existsSync || path.existsSync
//
// Gather the location of the possible hidden .git directory, the hooks
// directory which contains all git hooks and the absolute location of the
// `pre-commit` file. The path needs to be absolute in order for the symlinking
// to work correctly.
//
let git = getGitFolderPath(root)
let hooks
let precommit
// Function to recursively finding .git folder
function getGitFolderPath (currentPath) {
const git = path.resolve(currentPath, '.git')
if (!exists(git) || !fs.lstatSync(git).isDirectory()) {
console.log('pre-commit:')
console.log('pre-commit: Not found .git folder in', git)
const newPath = path.resolve(currentPath, '..')
// Stop if we on top folder
if (currentPath === newPath) {
return null
}
return getGitFolderPath(newPath)
}
console.log('pre-commit:')
console.log('pre-commit: Found .git folder in', git)
return git
}
//
// Resolve git directory for submodules
//
if (exists(git) && fs.lstatSync(git).isFile()) {
const gitinfo = fs.readFileSync(git).toString()
const gitdirmatch = /gitdir: (.+)/.exec(gitinfo)
const gitdir = gitdirmatch.length === 2 ? gitdirmatch[1] : null
if (gitdir !== null) {
git = path.resolve(root, gitdir)
hooks = path.resolve(git, 'hooks')
precommit = path.resolve(hooks, 'pre-commit')
}
}
//
// Bail out if we don't have an `.git` directory as the hooks will not get
// triggered. If we do have directory create a hooks folder if it doesn't exist.
//
if (!git) {
console.log('pre-commit:')
console.log('pre-commit: Not found any .git folder for installing pre-commit hook')
process.exit(0)
}
hooks = path.resolve(git, 'hooks')
precommit = path.resolve(hooks, 'pre-commit')
if (!exists(hooks)) fs.mkdirSync(hooks)
//
// If there's an existing `pre-commit` hook we want to back it up instead of
// overriding it and losing it completely as it might contain something
// important.
//
if (exists(precommit) && !fs.lstatSync(precommit).isSymbolicLink()) {
console.log('pre-commit:')
console.log('pre-commit: Detected an existing git pre-commit hook')
fs.writeFileSync(precommit + '.old', fs.readFileSync(precommit))
console.log('pre-commit: Old pre-commit hook backuped to pre-commit.old')
console.log('pre-commit:')
}
//
// We cannot create a symlink over an existing file so make sure it's gone and
// finish the installation process.
//
try { fs.unlinkSync(precommit) } catch {}
// Create generic precommit hook that launches this modules hook (as well
// as stashing - unstashing the unstaged changes)
// TODO: we could keep launching the old pre-commit scripts
let hookRelativeUnixPath = hook.replace(root, '.')
if (os.platform() === 'win32') {
hookRelativeUnixPath = hookRelativeUnixPath.replace(/[\\/]+/g, '/')
}
const precommitContent = '#!/usr/bin/env bash' + os.EOL +
'if git diff --cached --quiet; then' + os.EOL +
' echo "No staged changes detected, skipping pre-commit hook."' + os.EOL +
' exit 0' + os.EOL +
'fi' + os.EOL +
hookRelativeUnixPath + os.EOL +
'RESULT=$?' + os.EOL +
'[ $RESULT -ne 0 ] && exit 1' + os.EOL +
'exit 0' + os.EOL
//
// It could be that we do not have rights to this folder which could cause the
// installation of this module to completely fail. We should just output the
// error instead destroying the whole npm install process.
//
try { fs.writeFileSync(precommit, precommitContent) } catch (e) {
console.error('pre-commit:')
console.error('pre-commit: Failed to create the hook file in your .git/hooks folder because:')
console.error('pre-commit: ' + e.message)
console.error('pre-commit: The hook was not installed.')
console.error('pre-commit:')
}
try { fs.chmodSync(precommit, '777') } catch (e) {
console.error('pre-commit:')
console.error('pre-commit: chmod 0777 the pre-commit file in your .git/hooks folder because:')
console.error('pre-commit: ' + e.message)
console.error('pre-commit:')
}