ae-biu
Version:
Born For AE, Born To Do
212 lines (185 loc) • 5.8 kB
JavaScript
// @flow
import program from 'commander'
import chalk from 'chalk'
import Confirm from 'prompt-confirm'
import Input from 'prompt-input'
import http from 'http'
import ProgressBar from 'progress'
import fs from 'fs'
import { promisify } from 'util'
import decompress from 'decompress'
import isEmptyDir from './utils/is-empty-dir'
import isND from './utils/is-nd'
import { spawnSync } from 'child_process'
/**
* Help
*/
program.on('--help', () => {
console.log()
console.log(' Examples:')
console.log()
console.log(chalk.yellow(' # Create a new project'))
console.log()
console.log(chalk.blue(' $ ae init'))
console.log()
console.log(chalk.yellow(' # Create a new project with name'))
console.log()
console.log(chalk.blue(' $ ae init your-project-name'))
console.log()
console.log(chalk.yellow(' # Create a new project with specific branch'))
console.log()
console.log(chalk.blue(' $ ae init -b dev'))
})
/**
* Usage
*/
program
.usage('[project-name] [--branch]')
.option('-b, --branch [branch]', 'Use specific branch as template')
.parse(process.argv)
let dest = process.cwd()
const projectName = program.args[0] || 'ae-example'
let branch = program.branch
if (typeof branch !== 'string') {
branch = 'master'
}
const AE_TEMPLATE = `http://git.sdp.nd/fed/ae-boilerplate/repository/archive.zip?ref=${branch}`
const handleError = async (error: ?Error): Promise<any> => {
console.log()
error && console.error(error)
// clean dest directory
await promisify(fs.rmdir)(dest)
process.exit(1)
}
const unzipFile = async (zipFile: string, dest: string): Promise<any> => {
try {
await decompress(zipFile, dest, {
strip: 1 // remove leading directory
})
} catch (error) {
await handleError(error)
}
}
const installPackage = () => {
console.log(chalk.yellow('Install 📦 '))
console.log()
const isWin32 = process.platform === 'win32'
const subProcess = spawnSync(isWin32 ? 'npm.cmd' : 'npm', ['install'], {
stdio: 'inherit'
})
console.log()
if (subProcess.status === 1) {
console.log(chalk.red('😕 There is something wrong 👆 when installing packages, you may need to install packages by yourself'))
} else {
console.log(chalk.yellow('🎉 All Done, coding now !!!'))
}
}
const updatePkg = async (dest: string): Promise<any> => {
const pkgPath = `${dest}/package.json`
try {
const pkgContent = await promisify(fs.readFile)(pkgPath, 'utf8')
const pkg = JSON.parse(pkgContent)
console.log()
const pkgNameInput = new Input({
name: 'name',
message: `Name(${projectName}):`
})
let data = await pkgNameInput.run()
pkg.name = (data && data.name && data.name.trim()) || projectName
pkg.description = `${pkg.name} - Powered By AE(Admin Engine)`
const defaultVersion = '0.0.1-alpha.1'
const pkgVersionInput = new Input({
name: 'version',
message: `Version(${defaultVersion}):`
})
data = await pkgVersionInput.run()
pkg.version = (data && data.version && data.version.trim()) || defaultVersion
// add languages to package.json for ae-i18n
if (!pkg.ae) {
pkg.ae = {}
}
pkg.ae.languages = ['zh-CN', 'en'] // default languages
// fix wrong scripts, it will be removed after ae-boilerplate update
Object.keys(pkg.scripts).map(script => {
pkg.scripts[script] = pkg.scripts[script].replace(/\sSDP_ENV=\S+\s/g, ' ')
})
data = JSON.stringify(pkg, null, 2)
await promisify(fs.writeFile)(pkgPath, data)
process.chdir(dest)
console.log()
await installPackage()
process.exit(0)
} catch (error) {
await handleError(error)
}
}
const downloadFiles = async (dest: string): Promise<any> => {
const zipFileName = dest + '/temp.zip'
const req = http.get(AE_TEMPLATE)
req.on('response', async (res) => {
// broken
if (res.statusCode >= 400) {
console.log()
console.log(chalk.red('There is something wrong with your network, maybe wrong branch name'))
await handleError()
}
// length can be NaN, but no why
const length = parseInt(res.headers['content-length'], 10)
!isNaN(length) && console.log()
const bar = !isNaN(length) ? new ProgressBar(chalk.cyan('downloading [:bar] :rate/bps :percent :etas'), {
complete: '=',
incomplete: '-',
width: 20,
total: length,
clear: true
}) : null
res.on('data', (chunk) => {
fs.appendFileSync(zipFileName, chunk)
bar && bar.tick(chunk.length)
})
res.on('end', async () => {
await unzipFile(zipFileName, dest)
try {
await promisify(fs.unlink)(zipFileName)
} catch (error) {
await handleError(error)
}
console.log()
console.log(chalk.yellow('Download success'))
await updatePkg(dest)
})
})
req.on('error', async (error) => {
await handleError(error)
})
}
const run = async (): Promise<any> => {
if (await isND()) {
if (isEmptyDir(dest)) {
downloadFiles(dest)
} else {
console.log()
const confirm = new Confirm(chalk.yellow(`Current directory is not empty, Do you want to create a new directory named as ${chalk.blue(projectName)}`))
const answer = await confirm.run()
if (answer) {
dest += `/${projectName}`
try {
await promisify(fs.mkdir)(dest)
} catch (error) {
console.log()
console.log(chalk.red('Directory already exist, please check'))
process.exit(1)
}
downloadFiles(dest)
} else {
console.log()
console.log(chalk.red('Process exit!!!'))
process.exit(0)
}
}
} else {
console.log(chalk.red('Maybe you are not a NDer'))
}
}
run()