Skip to content
This repository was archived by the owner on Sep 12, 2019. It is now read-only.

Commit ab7a53a

Browse files
author
Phil Hawksworth
committed
Merge branch 'master' of github.com:netlify/netlify-dev-plugin
* 'master' of github.com:netlify/netlify-dev-plugin: small bugfix for this.log commit working functions refactor
2 parents 8fee56c + 26ecd50 commit ab7a53a

File tree

17 files changed

+333
-190
lines changed

17 files changed

+333
-190
lines changed

package-lock.json

Lines changed: 51 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"@oclif/command": "^1",
1111
"@oclif/config": "^1",
1212
"ascii-table": "0.0.9",
13+
"copy-template-dir": "^1.4.0",
1314
"fs-extra": "^7.0.1",
1415
"get-port": "^4.1.0",
1516
"http-proxy": "^1.17.0",

src/commands/functions/create.js

Lines changed: 130 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,28 @@
11
const fs = require('fs-extra')
22
const path = require('path')
3+
const copy = require('copy-template-dir')
34
const { flags } = require('@oclif/command')
45
const Command = require('@netlify/cli-utils')
56
const inquirer = require('inquirer')
67
const readRepoURL = require('../../utils/readRepoURL')
7-
const templatesDir = path.resolve(__dirname, '../../functions-templates')
88
const http = require('http')
99
const fetch = require('node-fetch')
1010
const cp = require('child_process')
1111

12+
const templatesDir = path.resolve(__dirname, '../../functions-templates')
13+
1214
class FunctionsCreateCommand extends Command {
1315
async run() {
1416
const { flags, args } = this.parse(FunctionsCreateCommand)
15-
16-
/* get functions dir (and make it if necessary) */
1717
const { config } = this.netlify
18-
const functionsDir = flags.functions || (config.build && config.build.functions)
19-
if (!functionsDir) {
20-
this.log('No functions folder specified in netlify.toml or as an argument')
21-
process.exit(1)
22-
}
2318

24-
if (!fs.existsSync(functionsDir)) {
25-
console.log(`functions folder ${functionsDir} specified in netlify.toml but folder not found, creating it...`)
26-
fs.mkdirSync(functionsDir)
27-
console.log(`functions folder ${functionsDir} created`)
28-
}
19+
const functionsDir = ensureFunctionDirExists(flags, config, this.log)
2920

3021
/* either download from URL or scaffold from template */
3122
if (flags.url) {
32-
// // --url flag specified, download from there
33-
const folderContents = await readRepoURL(flags.url)
34-
const functionName = flags.url.split('/').slice(-1)[0]
35-
const nameToUse = await getNameFromArgs(args, flags, functionName)
36-
const fnFolder = path.join(functionsDir, nameToUse)
37-
if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
38-
this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
39-
process.exit(1)
40-
}
41-
42-
try {
43-
fs.mkdirSync(fnFolder, { recursive: true })
44-
} catch (e) {
45-
// Ignore
46-
}
47-
await Promise.all(
48-
folderContents.map(({ name, download_url }) => {
49-
return fetch(download_url).then(res => {
50-
const finalName = path.basename(name, '.js') === functionName ? nameToUse + '.js' : name
51-
const dest = fs.createWriteStream(path.join(fnFolder, finalName))
52-
res.body.pipe(dest)
53-
})
54-
})
55-
)
56-
57-
console.log(`installing dependencies for ${nameToUse}...`)
58-
cp.exec('npm i', { cwd: path.join(functionsDir, nameToUse) }, () => {
59-
console.log(`installing dependencies for ${nameToUse} complete `)
60-
})
23+
await downloadFromURL(flags, args, functionsDir)
6124
} else {
62-
// // no --url flag specified, pick from a provided template
63-
const templatePath = await pickTemplate()
64-
// pull the rest of the metadata from the template
65-
const { onComplete, copyAssets, templateCode } = require(path.join(templatesDir, templatePath))
66-
67-
let template
68-
try {
69-
template = templateCode() // we may pass in args in future to customize the template
70-
} catch (err) {
71-
console.error('an error occurred retrieving template code, please check ' + templatePath, err)
72-
process.exit(0)
73-
}
74-
75-
const name = await getNameFromArgs(args, flags, path.basename(templatePath, '.js'))
76-
77-
this.log(`Creating function ${name}`)
78-
79-
const functionPath = flags.dir
80-
? path.join(functionsDir, name, name + '.js')
81-
: path.join(functionsDir, name + '.js')
82-
if (fs.existsSync(functionPath)) {
83-
this.log(`Function ${functionPath} already exists`)
84-
process.exit(1)
85-
}
86-
87-
if (flags.dir) {
88-
const fnFolder = path.join(functionsDir, name)
89-
if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
90-
this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
91-
process.exit(1)
92-
}
93-
94-
try {
95-
fs.mkdirSync(fnFolder, { recursive: true })
96-
} catch (e) {
97-
// Ignore
98-
}
99-
} else if (fs.existsSync(functionPath.replace(/\.js/, ''))) {
100-
this.log(`A folder version of the function ${name} already exists at ${functionPath.replace(/\.js/, '')}`)
101-
process.exit(1)
102-
}
103-
104-
fs.writeFileSync(functionPath, template)
105-
if (copyAssets) {
106-
copyAssets.forEach(src =>
107-
fs.copySync(path.join(templatesDir, 'assets', src), path.join(functionsDir, src), {
108-
overwrite: false,
109-
errorOnExist: false // went with this to make it idempotent, might change in future
110-
})
111-
) // copy assets if specified
112-
}
113-
if (onComplete) onComplete() // do whatever the template wants to do after it is scaffolded
25+
await scaffoldFromTemplate(flags, args, functionsDir, this.log)
11426
}
11527
}
11628
}
@@ -171,17 +83,133 @@ async function getNameFromArgs(args, flags, defaultName) {
17183

17284
// pick template from our existing templates
17385
async function pickTemplate() {
174-
let templates = fs.readdirSync(templatesDir).filter(x => path.extname(x) === '.js') // only js templates for now
175-
templates = templates
176-
.map(t => require(path.join(templatesDir, t)))
177-
.sort((a, b) => (a.priority || 999) - (b.priority || 999)) // doesnt scale but will be ok for now
178-
const { templatePath } = await inquirer.prompt([
86+
// let templates = fs.readdirSync(templatesDir).filter(x => x.split('.').length === 1) // only folders
87+
const registry = require(path.join(templatesDir, 'template-registry.js'))
88+
let templates = registry.sort((a, b) => (a.priority || 999) - (b.priority || 999)) // doesnt scale but will be ok for now
89+
const { chosentemplate } = await inquirer.prompt([
17990
{
180-
name: 'templatePath',
91+
name: 'chosentemplate',
18192
message: 'pick a template',
18293
type: 'list',
183-
choices: templates.map(t => t.metadata)
94+
choices: templates.map(t => ({
95+
// confusing but this is the format inquirer wants
96+
name: t.description,
97+
value: t.name,
98+
short: t.name
99+
}))
184100
}
185101
])
186-
return templatePath
102+
return registry.find(x => x.name === chosentemplate)
103+
}
104+
105+
/* get functions dir (and make it if necessary) */
106+
function ensureFunctionDirExists(flags, config, log) {
107+
const functionsDir = flags.functions || (config.build && config.build.functions)
108+
if (!functionsDir) {
109+
log('No functions folder specified in netlify.toml or as an argument')
110+
process.exit(1)
111+
}
112+
if (!fs.existsSync(functionsDir)) {
113+
log(`functions folder ${functionsDir} specified in netlify.toml but folder not found, creating it...`)
114+
fs.mkdirSync(functionsDir)
115+
log(`functions folder ${functionsDir} created`)
116+
}
117+
return functionsDir
118+
}
119+
120+
// Download files from a given github URL
121+
async function downloadFromURL(flags, args, functionsDir) {
122+
const folderContents = await readRepoURL(flags.url)
123+
const functionName = flags.url.split('/').slice(-1)[0]
124+
const nameToUse = await getNameFromArgs(args, flags, functionName)
125+
const fnFolder = path.join(functionsDir, nameToUse)
126+
if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
127+
this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
128+
process.exit(1)
129+
}
130+
131+
try {
132+
fs.mkdirSync(fnFolder, { recursive: true })
133+
} catch (e) {
134+
// Ignore
135+
}
136+
await Promise.all(
137+
folderContents.map(({ name, download_url }) => {
138+
return fetch(download_url).then(res => {
139+
const finalName = path.basename(name, '.js') === functionName ? nameToUse + '.js' : name
140+
const dest = fs.createWriteStream(path.join(fnFolder, finalName))
141+
res.body.pipe(dest)
142+
})
143+
})
144+
)
145+
146+
console.log(`installing dependencies for ${nameToUse}...`)
147+
cp.exec('npm i', { cwd: path.join(functionsDir, nameToUse) }, () => {
148+
console.log(`installing dependencies for ${nameToUse} complete `)
149+
})
150+
}
151+
152+
// no --url flag specified, pick from a provided template
153+
async function scaffoldFromTemplate(flags, args, functionsDir, log) {
154+
const { onComplete, name: templateName } = await pickTemplate() // pull the rest of the metadata from the template
155+
156+
const pathToTemplate = path.join(templatesDir, templateName)
157+
if (!fs.existsSync(pathToTemplate)) {
158+
throw new Error(`there isnt a corresponding folder to the selected name, ${templateName} template is misconfigured`)
159+
}
160+
161+
const name = await getNameFromArgs(args, flags, templateName)
162+
163+
log(`Creating function ${name}`)
164+
const functionPath = ensureFunctionPathIsOk(functionsDir, flags, name)
165+
166+
log('from ', pathToTemplate, ' to ', functionPath)
167+
const vars = { NETLIFY_STUFF_TO_REPLACTE: 'REPLACEMENT' } // SWYX: TODO
168+
let hasPackageJSON = false
169+
copy(pathToTemplate, functionPath, vars, (err, createdFiles) => {
170+
if (err) throw err
171+
createdFiles.forEach(filePath => {
172+
log(`Created ${filePath}`)
173+
if (filePath.includes('package.json')) hasPackageJSON = true
174+
})
175+
// rename functions with different names from default
176+
if (name !== templateName) {
177+
fs.renameSync(path.join(functionPath, templateName + '.js'), path.join(functionPath, name + '.js'))
178+
}
179+
// npm install
180+
if (hasPackageJSON) {
181+
console.log(`installing dependencies for ${name}...`)
182+
cp.exec('npm i', { cwd: path.join(functionPath) }, () => {
183+
console.log(`installing dependencies for ${name} complete `)
184+
})
185+
}
186+
187+
if (onComplete) onComplete() // do whatever the template wants to do after it is scaffolded
188+
})
189+
}
190+
191+
function ensureFunctionPathIsOk(functionsDir, flags, name) {
192+
// const functionPath = flags.dir ? path.join(functionsDir, name, name + '.js') : path.join(functionsDir, name + '.js')
193+
const functionPath = path.join(functionsDir, name)
194+
if (fs.existsSync(functionPath)) {
195+
this.log(`Function ${functionPath} already exists, cancelling...`)
196+
process.exit(1)
197+
}
198+
// if (flags.dir) {
199+
// const fnFolder = path.join(functionsDir, name)
200+
// if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
201+
// this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
202+
// process.exit(1)
203+
// }
204+
205+
// try {
206+
// fs.mkdirSync(fnFolder, { recursive: true })
207+
// } catch (e) {
208+
// // Ignore
209+
// }
210+
// } else if (fs.existsSync(functionPath.replace(/\.js/, ''))) {
211+
// this.log(`A folder version of the function ${name} already exists at ${functionPath.replace(/\.js/, '')}`)
212+
// process.exit(1)
213+
// }
214+
return functionPath
187215
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy