Skip to content

Commit 65db2cd

Browse files
Merge pull request #1 from redvanworkshop/feature/external-tool-builders
Adding Requested Featured: External Build Tools
2 parents 7eb6b57 + 945da0b commit 65db2cd

File tree

9 files changed

+205
-39
lines changed

9 files changed

+205
-39
lines changed

commands/setup.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const prompt = require('prompt')
55
const slug = require('slug')
66

77
const config = require('../lib/config')()
8+
const builds = require('../lib/builds')
89

910
module.exports = async () => {
1011
const setDefaults =
@@ -129,14 +130,18 @@ module.exports = async () => {
129130
newConfig[client] = {}
130131
}
131132

133+
// Fetch Build Scripts from Project Directory
134+
const builders = builds(result.d)
135+
132136
// Create / Overwrite SFCC Instance for Client
133137
newConfig[client][alias] = {
134138
h: result.h,
135139
v: result.v,
136140
a: result.a,
137141
d: result.d,
138142
u: result.u,
139-
p: result.p
143+
p: result.p,
144+
b: builders
140145
}
141146

142147
// Write Config File

commands/watch.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const chalk = require('chalk')
33
const chokidar = require('chokidar')
44
const ora = require('ora')
55
const path = require('path')
6+
const {exec} = require('child_process')
67

78
const logger = require('../lib/logger')()
89
const notify = require('../lib/notify')()
@@ -34,28 +35,55 @@ module.exports = options => {
3435

3536
if (selected) {
3637
let spinner
37-
const watcher = chokidar.watch('dir', {
38+
const watcher = chokidar.watch(selected.d, {
3839
ignored: [/[/\\]\./, '**/node_modules/**'],
3940
ignoreInitial: true,
4041
persistent: true,
41-
awaitWriteFinish: true,
42-
atomic: true
42+
awaitWriteFinish: true
4343
})
4444

45-
// Add Instance Directory to Watch List
46-
watcher.add(selected.d)
45+
const buildCheck = file => {
46+
if (Object.keys(selected.b).length > 0) {
47+
const checkPath = path.dirname(file).replace(path.normalize(selected.d), '')
48+
Object.keys(selected.b).map(build => {
49+
const builder = selected.b[build]
50+
if (
51+
builder.enabled &&
52+
new RegExp(builder.watch.join('|')).test(checkPath) &&
53+
typeof builder.cmd.exec !== 'undefined' &&
54+
builder.cmd.exec.length > 0
55+
) {
56+
const cmd = builder.cmd.exec
57+
const building = build.split('_')
58+
console.log(
59+
`\n${chalk.bgGreen.white.bold(' BUILDING ')} ${chalk.cyan.bold(
60+
building[1]
61+
)} for cartridge ${chalk.magenta.bold(building[0])} ...\n\n`
62+
)
63+
64+
exec(cmd, (err, data, stderr) => {
65+
if (err || stderr) {
66+
console.log(chalk.red.bold(`✖ Build Error: ${err} {stderr}`))
67+
}
68+
})
69+
}
70+
})
71+
}
72+
}
4773

4874
// Watch for File Changes
4975
watcher.on('change', file => {
5076
upload({file, spinner, selected, client, instance, options})
77+
buildCheck(file)
5178
})
5279
watcher.on('add', file => {
5380
upload({file, spinner, selected, client, instance, options})
81+
buildCheck(file)
5482
})
5583

5684
// @TODO: Watch for Removing Files
5785
watcher.on('unlink', file => {
58-
console.log('UNLINK', file)
86+
console.log(`${chalk.red('✗ REMOVING')} ${file.replace(selected.d, '.')}`)
5987
})
6088

6189
// Watch for Errors
@@ -91,7 +119,7 @@ module.exports = options => {
91119
if (useLog) {
92120
logger.log(logMessage, true)
93121
} else {
94-
spinner = ora(`${logMessage} [Ctrl-C to Cancel]`).start()
122+
spinner = ora(`${chalk.bold(logMessage)} [Ctrl-C to Cancel]\n`).start()
95123
}
96124
})
97125
} else if (client && instance) {

lib/builds.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
const convert = require('xml-js')
2+
const fs = require('fs')
3+
const os = require('os').type()
4+
const path = require('path')
5+
const slug = require('slug')
6+
7+
module.exports = project => {
8+
let externalToolBuilders = []
9+
let build = {}
10+
11+
// Look for *.launch files in .externalToolBuilders folder
12+
fs.readdirSync(project).map(fileName => {
13+
const filePath = path.join(project, fileName)
14+
if (fs.statSync(filePath).isDirectory()) {
15+
const buildPath = path.join(filePath, '.externalToolBuilders')
16+
if (fs.existsSync(buildPath) && fs.statSync(buildPath).isDirectory()) {
17+
fs.readdirSync(buildPath).map(buildFile => {
18+
if (path.extname(buildFile) === '.launch') {
19+
externalToolBuilders.push(path.join(buildPath, buildFile))
20+
}
21+
})
22+
}
23+
}
24+
})
25+
26+
// Loop through found .externalToolBuilders files and parse build instructions
27+
if (externalToolBuilders.length > 0) {
28+
externalToolBuilders.map(launch => {
29+
const xml = fs.readFileSync(launch)
30+
const json = convert.xml2json(xml)
31+
const builder = json ? JSON.parse(json) : null
32+
const name = slug(
33+
path.basename(path.dirname(path.dirname(launch))).replace('_', '-') +
34+
'_' +
35+
path.basename(launch).replace('.launch', ''),
36+
{lower: true, replacement: '-'}
37+
)
38+
39+
// setup placeholder for this config file
40+
build[name] = {
41+
enabled: false,
42+
watch: [],
43+
cmd: {
44+
basedir: null,
45+
exec: null
46+
}
47+
}
48+
49+
if (
50+
builder &&
51+
typeof builder.elements !== 'undefined' &&
52+
builder.elements.length === 1 &&
53+
builder.elements[0].name === 'launchConfiguration' &&
54+
builder.elements[0].elements
55+
) {
56+
builder.elements[0].elements.map(elm => {
57+
// Get Watch Directories
58+
if (elm.attributes.key === 'org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE') {
59+
const buildScopeJson = convert.xml2json(
60+
elm.attributes.value.replace('${working_set:', '').replace(/}$/, '')
61+
)
62+
const buildScope = buildScopeJson ? JSON.parse(buildScopeJson) : null
63+
64+
if (
65+
buildScope &&
66+
typeof buildScope.elements !== 'undefined' &&
67+
buildScope.elements.length === 1 &&
68+
buildScope.elements[0].name === 'resources' &&
69+
builder.elements[0].elements
70+
) {
71+
buildScope.elements[0].elements.map(buildSrc => {
72+
build[name].watch.push(buildSrc.attributes.path)
73+
})
74+
}
75+
}
76+
77+
// Check if we should enable this build
78+
if (elm.attributes.key === 'org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS') {
79+
build[name].enabled =
80+
elm.attributes.value.includes('full') ||
81+
elm.attributes.value.includes('incremental') ||
82+
elm.attributes.value.includes('auto')
83+
}
84+
85+
// Get Build Instructuctions
86+
if (elm.attributes.key === 'org.eclipse.ui.externaltools.ATTR_LOCATION') {
87+
const buildFilePath = elm.attributes.value.replace('${workspace_loc:', '').replace(/}$/, '')
88+
const buildFileXml = fs.readFileSync(path.join(project, buildFilePath))
89+
const buildFileJson = convert.xml2json(buildFileXml)
90+
const buildInstructions = buildFileJson ? JSON.parse(buildFileJson) : null
91+
92+
if (
93+
buildInstructions &&
94+
typeof buildInstructions.elements !== 'undefined' &&
95+
buildInstructions.elements.length === 1 &&
96+
buildInstructions.elements[0].name === 'project' &&
97+
buildInstructions.elements[0].elements
98+
) {
99+
buildInstructions.elements[0].elements.map(buildInstruction => {
100+
build[name].cmd.basedir =
101+
typeof buildInstructions.elements[0].attributes.basedir !== 'undefined'
102+
? path.join(
103+
project,
104+
path.basename(path.dirname(path.dirname(launch))),
105+
buildInstructions.elements[0].attributes.basedir
106+
)
107+
: null
108+
buildInstruction.elements.map(instruction => {
109+
if (instruction.name === 'exec') {
110+
let exec = instruction.attributes.executable
111+
if (
112+
(exec === 'cmd' && os === 'Windows_NT') ||
113+
(exec !== 'cmd' && (os === 'Darwin' || os === 'Linux'))
114+
) {
115+
instruction.elements.map(arg => {
116+
if (arg.name === 'arg') {
117+
exec = exec.concat(' ' + arg.attributes.value)
118+
}
119+
})
120+
121+
// Replace commands that are not needed outside Eclipse
122+
exec = exec.replace('/bin/bash -l -c ', '')
123+
exec = exec.replace(/\${basedir}/g, build[name].cmd.basedir)
124+
125+
build[name].cmd.exec = exec
126+
}
127+
}
128+
})
129+
})
130+
}
131+
}
132+
})
133+
}
134+
})
135+
}
136+
137+
return build
138+
}

lib/search.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = async (selected, groups, options) => {
1111
const excluding = options.exclude && options.exclude.length > 0 ? ` '${options.exclude.join(', ')}'` : ''
1212
const filters = options.filter && options.filter.length > 0 ? ` containing '${options.filter}'` : ''
1313

14-
const text = `Searching${including}${excluding} Logs${filters} [Ctrl-C to Cancel]`
14+
const text = chalk.bold(`Searching${including}${excluding} Logs${filters}`).concat(' [Ctrl-C to Cancel]\n')
1515
const spinner = ora(text)
1616
const output = fn => {
1717
spinner.stop()

lib/tail.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = async (selected, logs, groups, options) => {
1111
const excluding = options.exclude && options.exclude.length > 0 ? ` '${options.exclude.join(', ')}'` : ''
1212
const filters = options.filter && options.filter.length > 0 ? ` containing '${options.filter}'` : ''
1313

14-
const text = `Streaming${including}${excluding} Logs${filters} [Ctrl-C to Cancel]`
14+
const text = chalk.bold(`Streaming${including}${excluding} Logs${filters}`).concat(' [Ctrl-C to Cancel]\n')
1515
const spinner = ora(text)
1616
const output = fn => {
1717
spinner.stop()

lib/upload.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const path = require('path')
22
const pRetry = require('p-retry')
3+
const chalk = require('chalk')
34

45
const logger = require('../lib/logger')()
56
const notify = require('../lib/notify')()
@@ -9,14 +10,13 @@ const mkdirp = require('./mkdirp')
910
module.exports = async ({file, spinner, selected, client, instance, options}) => {
1011
const src = path.relative(process.cwd(), file)
1112
const uploading = new Set()
12-
1313
const useLog = options.log
1414
const errorsOnly = options.errorsOnly
1515

1616
if (!uploading.has(src)) {
1717
const dir = path.dirname(file).replace(path.normalize(selected.d), '')
1818
const dest = path.join('/', 'Cartridges', selected.v, dir)
19-
const text = `Watching ${client} ${instance} [Ctrl-C to Cancel]`
19+
const text = chalk.bold(`Watching ${client} ${instance}`).concat(' [Ctrl-C to Cancel]\n')
2020

2121
uploading.add(src)
2222

@@ -25,18 +25,17 @@ module.exports = async ({file, spinner, selected, client, instance, options}) =>
2525
title: `${client} ${instance}`,
2626
icon: path.join(__dirname, '../icons/', 'sfcc-uploading.png'),
2727
subtitle: 'UPLOADING ...',
28-
message: `${path.basename(src)} => ${dest}`
28+
message: `${path.basename(src)}`
2929
})
3030
}
3131

32-
let logMessage = `Uploading ${file.replace(selected.d, '.')} ...`
32+
let logMessage = `${chalk.cyan('▲ UPLOADING')} ${file.replace(selected.d, '.')}...`
3333

3434
if (useLog) {
3535
logger.log(logMessage)
3636
} else {
37-
spinner.stopAndPersist({text: logMessage})
38-
spinner.text = text
39-
spinner.start()
37+
spinner.stop()
38+
console.log(logMessage)
4039
}
4140

4241
try {
@@ -49,7 +48,7 @@ module.exports = async ({file, spinner, selected, client, instance, options}) =>
4948
}
5049

5150
const tryToMkdir = () => mkdirp(dest, request)
52-
const tryToWrite = () => write(src, dest, request)
51+
const tryToWrite = () => write(file, dest, request)
5352

5453
await pRetry(tryToMkdir, {retries: 5})
5554
await pRetry(tryToWrite, {retries: 5})
@@ -59,11 +58,11 @@ module.exports = async ({file, spinner, selected, client, instance, options}) =>
5958
title: `${client} ${instance}`,
6059
icon: path.join(__dirname, '../icons/', 'sfcc-success.png'),
6160
subtitle: 'UPLOAD COMPLETE',
62-
message: `${path.basename(src)} => ${dest}`
61+
message: `${path.basename(src)}`
6362
})
6463
}
6564

66-
logMessage = `${path.basename(src)} pushed to ${client} ${instance}`
65+
logMessage = `${chalk.green('COMPLETE')} ${file.replace(selected.d, '.')}`
6766

6867
if (useLog) {
6968
logger.log(logMessage)

lib/write.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
const fs = require('fs-extra')
22
const path = require('path')
3-
const debug = require('debug')('write')
43
const axios = require('axios')
54
const followRedirects = require('follow-redirects')
65

76
followRedirects.maxBodyLength = 100 * 1024 * 1024
87

98
module.exports = (src, dest, options) => {
109
try {
11-
debug(`Uploading ${src}`)
12-
1310
const url = path.join('/', dest, path.basename(src))
1411
const stream = fs.createReadStream(src)
15-
1612
const config = Object.assign(
1713
{
1814
url,
@@ -24,6 +20,12 @@ module.exports = (src, dest, options) => {
2420
options
2521
)
2622

27-
return axios(config).then(() => url)
23+
const request = axios(config)
24+
.then(() => url)
25+
.catch(error => {
26+
console.log('error', error)
27+
})
28+
29+
return request
2830
} catch (err) {}
2931
}

package-lock.json

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

0 commit comments

Comments
 (0)