Skip to content

Commit

Permalink
fix executable linking on windows for real
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jan 11, 2018
1 parent 957e08d commit db9be90
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
jest.setTimeout(30000)

const fs = require('fs')
const path = require('path')
const { linkBin } = require('@vue/cli-shared-utils')
const create = require('@vue/cli-test-utils/createTestProject')

const runSilently = fn => {
Expand Down Expand Up @@ -37,10 +37,9 @@ test('should work', async () => {
require('yorkie/src/install')(path.join(project.dir, 'node_modules'))
// since yorkie isn't actually installed in the test project, we need to
// symlink it
fs.symlinkSync(
linkBin(
path.resolve(require.resolve('yorkie/src/install'), '../../'),
path.join(project.dir, 'node_modules', 'yorkie'),
'junction' // needed for windows
path.join(project.dir, 'node_modules', 'yorkie')
)
})
const hook = await read('.git/hooks/pre-commit')
Expand Down
26 changes: 26 additions & 0 deletions packages/@vue/cli-shared-utils/env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { execSync } = require('child_process')

// env detection
exports.hasYarn = (() => {
if (process.env.VUE_CLI_TEST) {
return true
}
try {
execSync('yarnpkg --version', { stdio: 'ignore' })
return true
} catch (e) {
return false
}
})()

exports.hasGit = () => {
if (process.env.VUE_CLI_TEST) {
return true
}
try {
execSync('git --version', { stdio: 'ignore' })
return true
} catch (e) {
return false
}
}
103 changes: 4 additions & 99 deletions packages/@vue/cli-shared-utils/index.js
Original file line number Diff line number Diff line change
@@ -1,99 +1,4 @@
const joi = require('joi')
const chalk = require('chalk')
const spinner = require('./spinner')
const readline = require('readline')
const { execSync } = require('child_process')
const padStart = require('string.prototype.padstart')

const format = (label, msg) => {
return msg.split('\n').map((line, i) => {
return i === 0
? `${label} ${line}`
: padStart(line, chalk.reset(label).length)
}).join('\n')
}

Object.assign(exports, spinner)

exports.log = msg => console.log(msg || '')

exports.info = msg => {
console.log(format(chalk.bgBlue.black(' INFO '), msg))
}

exports.done = msg => {
console.log(format(chalk.bgGreen.black(' DONE '), msg))
}

exports.warn = msg => {
console.warn(format(chalk.bgYellow.black(' WARN '), chalk.yellow(msg)))
}

exports.error = msg => {
console.error(format(chalk.bgRed(' ERROR '), chalk.red(msg)))
if (msg instanceof Error) {
console.error(msg.stack)
}
}

exports.clearConsole = title => {
if (process.stdout.isTTY) {
const blank = '\n'.repeat(process.stdout.rows)
console.log(blank)
readline.cursorTo(process.stdout, 0, 0)
readline.clearScreenDown(process.stdout)
if (title) {
console.log(title)
}
}
}

// silent all logs except errors during tests and keep record
if (process.env.VUE_CLI_TEST) {
const logs = {}
Object.keys(exports).forEach(key => {
if (key !== 'error') {
exports[key] = (...args) => {
if (!logs[key]) logs[key] = []
logs[key].push(args)
}
}
})
exports.logs = logs
}

// proxy to joi for option validation
exports.createSchema = fn => fn(joi)

exports.validate = (obj, schema, options = {}) => {
joi.validate(obj, schema, options, err => {
if (err) {
throw err
}
})
}

// env detection
exports.hasYarn = (() => {
if (process.env.VUE_CLI_TEST) {
return true
}
try {
execSync('yarnpkg --version', { stdio: 'ignore' })
return true
} catch (e) {
return false
}
})()

exports.hasGit = () => {
if (process.env.VUE_CLI_TEST) {
return true
}
try {
execSync('git --version', { stdio: 'ignore' })
return true
} catch (e) {
return false
}
}
Object.assign(exports, require('./env'))
Object.assign(exports, require('./logger'))
Object.assign(exports, require('./validate'))
Object.assign(exports, require('./linkBin'))
27 changes: 27 additions & 0 deletions packages/@vue/cli-shared-utils/linkBin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* eslint-disable vue-libs/no-async-functions */

// cross-platform executable link, mostly for Windows

const fs = require('fs')
const path = require('path')
const { promisify } = require('util')

const chmod = promisify(fs.chmod)
const symlink = promisify(fs.symlink)
const mkdirp = promisify(require('mkdirp'))
const cmdShim = promisify(require('cmd-shim'))

exports.linkBin = async (src, dest) => {
if (!process.env.VUE_CLI_TEST && !process.env.VUE_CLI_DEBUG) {
throw new Error(`linkBin should only be used during tests or debugging.`)
}
if (process.platform === 'win32') {
// not doing mutex lock because this is only used in dev and the
// src will not be modified
await cmdShim(src, dest)
} else {
await mkdirp(path.dirname(dest))
await symlink(src, dest)
await chmod(dest, '755')
}
}
61 changes: 61 additions & 0 deletions packages/@vue/cli-shared-utils/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const chalk = require('chalk')
const spinner = require('./spinner')
const readline = require('readline')
const padStart = require('string.prototype.padstart')

Object.assign(exports, spinner)

const format = (label, msg) => {
return msg.split('\n').map((line, i) => {
return i === 0
? `${label} ${line}`
: padStart(line, chalk.reset(label).length)
}).join('\n')
}

exports.log = msg => console.log(msg || '')

exports.info = msg => {
console.log(format(chalk.bgBlue.black(' INFO '), msg))
}

exports.done = msg => {
console.log(format(chalk.bgGreen.black(' DONE '), msg))
}

exports.warn = msg => {
console.warn(format(chalk.bgYellow.black(' WARN '), chalk.yellow(msg)))
}

exports.error = msg => {
console.error(format(chalk.bgRed(' ERROR '), chalk.red(msg)))
if (msg instanceof Error) {
console.error(msg.stack)
}
}

exports.clearConsole = title => {
if (process.stdout.isTTY) {
const blank = '\n'.repeat(process.stdout.rows)
console.log(blank)
readline.cursorTo(process.stdout, 0, 0)
readline.clearScreenDown(process.stdout)
if (title) {
console.log(title)
}
}
}

// silent all logs except errors during tests and keep record
if (process.env.VUE_CLI_TEST) {
const logs = {}
Object.keys(exports).forEach(key => {
if (key !== 'error') {
exports[key] = (...args) => {
if (!logs[key]) logs[key] = []
logs[key].push(args)
}
}
})
exports.logs = logs
}
1 change: 1 addition & 0 deletions packages/@vue/cli-shared-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"homepage": "https://github.com/vuejs/vue-cli/packages/@vue/cli-shared-utils#readme",
"dependencies": {
"chalk": "^2.3.0",
"cmd-shim": "^2.0.2",
"joi": "^13.1.0",
"ora": "^1.3.0",
"readline": "^1.3.0",
Expand Down
12 changes: 12 additions & 0 deletions packages/@vue/cli-shared-utils/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const joi = require('joi')

// proxy to joi for option validation
exports.createSchema = fn => fn(joi)

exports.validate = (obj, schema, options = {}) => {
joi.validate(obj, schema, options, err => {
if (err) {
throw err
}
})
}
2 changes: 1 addition & 1 deletion packages/@vue/cli/lib/Creator.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ module.exports = class Creator {
const deps = Object.keys(options.plugins)
if (isTestOrDebug) {
// in development, avoid installation process
setupDevProject(context, deps)
await setupDevProject(context, deps)
} else {
await installDeps(context, packageManager, deps, cliOptions.registry)
}
Expand Down
9 changes: 3 additions & 6 deletions packages/@vue/cli/lib/util/setupDevProject.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const fs = require('fs')
const path = require('path')
const mkdirp = require('mkdirp')
const { linkBin } = require('@vue/cli-shared-utils')

module.exports = function setupDevProject (targetDir, deps) {
const pkg = require(path.resolve(targetDir, 'package.json'))
Expand All @@ -19,11 +19,8 @@ module.exports = function setupDevProject (targetDir, deps) {
path.resolve(targetDir, 'package.json'),
JSON.stringify(pkg, null, 2)
)
const binPath = path.join(targetDir, 'node_modules', '.bin')
mkdirp.sync(binPath)
fs.symlinkSync(
return linkBin(
require.resolve('@vue/cli-service/bin/vue-cli-service'),
path.join(binPath, 'vue-cli-service'),
'junction' // needed for windows
path.join(targetDir, 'node_modules', '.bin', 'vue-cli-service')
)
}

0 comments on commit db9be90

Please sign in to comment.