Skip to content

Commit c6992ef

Browse files
authored
New: Add --capturedir and --rootdir to grunt migration tasks (fixes #3667) (#3668)
* New: Add --capturedir and --rootdir to grunt migration tasks (fixes #3667) * Added comments * remove unnecessary lines
1 parent 714e446 commit c6992ef

7 files changed

Lines changed: 91 additions & 55 deletions

File tree

grunt/helpers.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,17 @@ module.exports = function(grunt) {
194194
return [].concat(exports.defaults.includes, buildIncludes, dependencies);
195195
},
196196

197-
generateConfigData: function() {
197+
generateConfigData: function({
198+
rootDir = __dirname.split(path.sep).slice(0, -1).join(path.sep)
199+
} = {}) {
198200

199201
const localConfigPath = exports.getLocalConfig();
200202
const localConfig = localConfigPath
201203
? fs.readJSONSync(localConfigPath)
202204
: {};
203205
const defaults = Object.assign({}, exports.defaults, localConfig);
204206

205-
const root = __dirname.split(path.sep).slice(0, -1).join(path.sep);
207+
const root = rootDir;
206208
const adaptJSON = fs.readJSONSync(`${root}/adapt.json`);
207209
const sourcedir = appendSlash(grunt.option('sourcedir')) || defaults.sourcedir;
208210
const outputdir = appendSlash(grunt.option('outputdir')) || defaults.outputdir;
@@ -223,14 +225,11 @@ module.exports = function(grunt) {
223225
// add root path if necessary, and point to course/config.json
224226

225227
const configPath = path.join(path.resolve(root, configDir), coursedir, 'config.' + jsonext);
226-
let buildConfig;
228+
let buildConfig = {};
227229

228230
try {
229231
buildConfig = grunt.file.readJSON(configPath).build || {};
230-
} catch (error) {
231-
grunt.log.error(error);
232-
process.exit();
233-
}
232+
} catch (error) {}
234233

235234
const isDevelopmentBuild = process.argv.some(arg => (arg === 'dev' || arg.includes(':dev') || arg.includes('--dev')));
236235
const cacheAge = isNaN(grunt.option('cacheage'))
@@ -282,7 +281,10 @@ module.exports = function(grunt) {
282281
});
283282
framework.load();
284283

285-
data.availableLanguageNames = framework.getData().languageNames;
284+
data.availableLanguageNames = [];
285+
try {
286+
data.availableLanguageNames = framework.getData().languageNames;
287+
} catch (err) {}
286288

287289
return data;
288290
},
@@ -369,8 +371,11 @@ module.exports = function(grunt) {
369371
},
370372

371373
/** @returns {Framework} */
372-
getFramework: function({ useOutputData = Boolean(grunt.option('outputdir')) } = {}) {
373-
const buildConfig = exports.generateConfigData();
374+
getFramework: function({
375+
useOutputData = Boolean(grunt.option('outputdir')),
376+
rootDir = process.cwd()
377+
} = {}) {
378+
const buildConfig = exports.generateConfigData({ rootDir });
374379
const framework = new Framework({
375380
rootPath: buildConfig.root,
376381
outputPath: buildConfig.outputdir,

grunt/helpers/Data.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,13 @@ class Data {
5454
this.configFile = null;
5555
/** @type {[Language]} */
5656
this.languages = null;
57+
/** @type {string} */
58+
this.coursePath = path.join(this.sourcePath, this.courseDir).replace(/\\/g, '/');
5759
}
5860

5961
/** @returns {Data} */
6062
load() {
61-
const coursePath = path.join(this.sourcePath, this.courseDir).replace(/\\/g, '/');
62-
this.languages = globs.sync(path.join(coursePath, '*/')).map(languagePath => {
63+
this.languages = globs.sync(path.join(this.coursePath, '*/')).map(languagePath => {
6364
const language = new Language({
6465
framework: this.framework,
6566
languagePath,
@@ -73,7 +74,8 @@ class Data {
7374
}).filter(lang => lang.isValid);
7475
this.configFile = new JSONFile({
7576
framework: this.framework,
76-
path: path.join(coursePath, `config.${this.jsonext}`)
77+
path: path.join(this.coursePath, `config.${this.jsonext}`),
78+
jsonext: this.jsonext
7779
});
7880
this.configFile.load();
7981
return this;

grunt/helpers/Framework.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class Framework {
2929
*/
3030
constructor({
3131
rootPath = process.cwd(),
32-
outputPath = process.cwd() + '/build/',
33-
sourcePath = process.cwd() + '/src/',
32+
outputPath = path.join(rootPath, '/build/'),
33+
sourcePath = path.join(rootPath, '/src/'),
3434
courseDir = 'course',
3535
includedFilter = function() { return true; },
3636
jsonext = 'json',
@@ -42,9 +42,9 @@ class Framework {
4242
/** @type {string} */
4343
this.rootPath = rootPath.replace(/\\/g, '/');
4444
/** @type {string} */
45-
this.outputPath = outputPath.replace(/\\/g, '/');
45+
this.outputPath = path.join(this.rootPath, outputPath).replace(/\\/g, '/');
4646
/** @type {string} */
47-
this.sourcePath = sourcePath.replace(/\\/g, '/');
47+
this.sourcePath = path.join(this.rootPath, sourcePath).replace(/\\/g, '/');
4848
/** @type {string} */
4949
this.courseDir = courseDir;
5050
/** @type {function} */
@@ -90,7 +90,8 @@ class Framework {
9090
* @returns {Data}
9191
*/
9292
getData({
93-
useOutputData = this.useOutputData
93+
useOutputData = this.useOutputData,
94+
performLoad = true
9495
} = {}) {
9596
const data = new Data({
9697
framework: this,
@@ -100,7 +101,7 @@ class Framework {
100101
trackingIdType: this.trackingIdType,
101102
log: this.log
102103
});
103-
data.load();
104+
if (performLoad) data.load();
104105
return data;
105106
}
106107

grunt/helpers/data/Language.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class Language {
8080
const file = new LanguageFile({
8181
framework: this.framework,
8282
language: this,
83+
jsonext: this.jsonext,
8384
path: jsonFilePath,
8485
data: null,
8586
hasChanged: false

grunt/helpers/data/LanguageFile.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ class LanguageFile extends JSONFile {
1515
* @param {Framework} options.framework
1616
* @param {Language} options.language
1717
* @param {string} options.path
18+
* @param {string} options.jsonext
1819
* @param {Object} options.data
1920
* @param {boolean} options.hasChanged
2021
*/
2122
constructor({
2223
framework = null,
2324
language = null,
2425
path = null,
26+
jsonext = null,
2527
data = null,
2628
hasChanged = false
2729
} = {}) {
28-
super({ framework, path, data, hasChanged });
30+
super({ framework, path, jsonext, data, hasChanged });
2931
/** @type {Language} */
3032
this.language = language;
3133
}

grunt/helpers/lib/JSONFile.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ class JSONFile {
2222
constructor({
2323
framework = null,
2424
path = null,
25+
jsonext = null,
2526
data = null,
2627
hasChanged = false
2728
} = {}) {
2829
/** @type {Framework} */
2930
this.framework = framework;
3031
/** @type {string} */
3132
this.path = path;
33+
/** @type {string} */
34+
this.jsonext = jsonext;
3235
/** @type {Object|Array} */
3336
this.data = data;
3437
/** @type {boolean} */

grunt/tasks/migration.js

Lines changed: 57 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ module.exports = function(grunt) {
1515
return {
1616
...fileItem.item,
1717
__index__: fileItem.index,
18-
__path__: unix(fileItem.file.path)
18+
__path__: unix(fileItem.file.path),
19+
__jsonext__: fileItem.file.jsonext
1920
};
2021
}
2122

2223
function undressPathIndex(object) {
2324
const clone = { ...object };
2425
delete clone.__index__;
2526
delete clone.__path__;
27+
delete clone.__jsonext__;
2628
return clone;
2729
}
2830

@@ -35,17 +37,48 @@ module.exports = function(grunt) {
3537
const migrations = await import('adapt-migrations');
3638
const logger = migrations.Logger.getInstance();
3739
const cwd = process.cwd();
38-
const outputPath = path.join(cwd, './migrations/');
40+
const tempPath = path.join(cwd, './migrations/');
3941
const cache = new migrations.CacheManager();
4042
const cachePath = await cache.getCachePath({
4143
outputPath: buildConfig.outputdir,
42-
tempPath: outputPath
44+
tempPath
4345
});
4446

45-
const framework = Helpers.getFramework();
46-
logger.debug(`Using ${framework.useOutputData ? framework.outputPath : framework.sourcePath} folder for course data...`);
47+
if (mode === 'capture') {
48+
const capturePath = grunt.option('capturedir') || tempPath;
49+
if (!fs.existsSync(capturePath)) fs.mkdirSync(capturePath);
50+
const fromFramework = Helpers.getFramework({
51+
rootDir: path.resolve(grunt.option('rootdir') || process.cwd())
52+
});
53+
const fromPlugins = fromFramework.getPlugins().getAllPackageJSONFileItems().map(fileItem => fileItem.item);
54+
const languages = fromFramework.getData().languages.map((language) => language.name);
55+
const languageFile = path.join(capturePath, 'captureLanguages.json');
56+
fs.writeJSONSync(languageFile, languages);
57+
languages.forEach(async (language, index) => {
58+
logger.debug(`Migration -- Capture ${language}`);
59+
const data = fromFramework.getData();
60+
// get all items from config.json file and all language files, append __index__ and __path__ to each item
61+
const content = [
62+
...data.configFile.fileItems,
63+
...data.languages[index].getAllFileItems()
64+
].map(dressPathIndex).map(obj => {
65+
// reduce __path__ to relative paths about src/course/ or build/course/ so
66+
// that they're easier to restore elsewhere later
67+
obj.__path__ = obj.__path__.slice(data.coursePath.length).replace(/^\//, '');
68+
return obj;
69+
});
70+
const captured = await migrations.capture({ content, fromPlugins, logger });
71+
const outputFile = path.join(capturePath, `capture_${language}.json`);
72+
fs.writeJSONSync(outputFile, captured);
73+
});
4774

48-
const plugins = framework.getPlugins().getAllPackageJSONFileItems().map(fileItem => fileItem.item);
75+
logger.output(capturePath, 'capture');
76+
return next();
77+
}
78+
79+
const toFramework = Helpers.getFramework();
80+
logger.debug(`Using ${toFramework.useOutputData ? toFramework.outputPath : toFramework.sourcePath} folder for course data...`);
81+
const plugins = toFramework.getPlugins().getAllPackageJSONFileItems().map(fileItem => fileItem.item);
4982
const migrationScripts = Array.from(await new Promise(resolve => {
5083
globs([
5184
'*/*/migrations/**/*.js',
@@ -67,40 +100,20 @@ module.exports = function(grunt) {
67100
logger
68101
});
69102

70-
if (mode === 'capture') {
71-
72-
if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
73-
const languages = framework.getData().languages.map((language) => language.name);
74-
const languageFile = path.join(outputPath, 'captureLanguages.json');
75-
fs.writeJSONSync(languageFile, languages);
76-
languages.forEach(async (language, index) => {
77-
logger.debug(`Migration -- Capture ${language}`);
78-
const data = framework.getData();
79-
// get all items from config.json file and all language files, append __index__ and __path__ to each item
80-
const content = [
81-
...data.configFile.fileItems,
82-
...data.languages[index].getAllFileItems()
83-
].map(dressPathIndex);
84-
const captured = await migrations.capture({ content, fromPlugins: plugins, logger });
85-
const outputFile = path.join(outputPath, `capture_${language}.json`);
86-
fs.writeJSONSync(outputFile, captured);
87-
});
88-
89-
logger.output(outputPath, 'capture');
90-
return next();
91-
}
92-
93103
if (mode === 'migrate') {
104+
const capturePath = grunt.option('capturedir') || tempPath;
105+
const toFrameworkData = toFramework.getData({ performLoad: false });
106+
const coursePath = toFrameworkData.coursePath;
94107
try {
95-
const languagesFile = path.join(outputPath, 'captureLanguages.json');
108+
const languagesFile = path.join(capturePath, 'captureLanguages.json');
96109
const languages = fs.readJSONSync(languagesFile);
97110

98111
for (const language of languages) {
99112
logger.debug(`Migration -- Migrate ${language}`);
100113
const Journal = migrations.Journal;
101-
if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
102-
const outputFile = path.join(outputPath, `capture_${language}.json`);
103-
const { content, fromPlugins } = fs.readJSONSync(outputFile);
114+
if (!fs.existsSync(capturePath)) fs.mkdirSync(capturePath);
115+
const outputFile = path.join(capturePath, `capture_${language}.json`);
116+
let { content, fromPlugins } = fs.readJSONSync(outputFile);
104117
const originalFromPlugins = JSON.parse(JSON.stringify(fromPlugins));
105118
const journal = new Journal({
106119
logger,
@@ -113,6 +126,11 @@ module.exports = function(grunt) {
113126
});
114127
await migrations.migrate({ journal, logger });
115128

129+
// change out jsonext
130+
content = content.map(item => {
131+
item.__path__ = item.__path__.replace('.' + item.__jsonext__, '.' + buildConfig.jsonext);
132+
return item;
133+
});
116134
// group all content items by path
117135
const outputFilePathItems = _.groupBy(content, '__path__');
118136
// sort items inside each path
@@ -127,13 +145,17 @@ module.exports = function(grunt) {
127145
const stripped = isSingleObject
128146
? undressPathIndex(outputItems[0]) // config.json, course.json
129147
: outputItems.map(undressPathIndex); // contentObjects.json, articles.json, blocks.json, components.json
130-
fs.writeJSONSync(outputPath, stripped, { replacer: null, spaces: 2 });
148+
// write files to specified --outputdir= location
149+
const outputFilePath = path.join(coursePath, outputPath);
150+
const outputDir = path.parse(outputFilePath).dir;
151+
fs.ensureDirSync(outputDir);
152+
fs.writeJSONSync(outputFilePath, stripped, { replacer: null, spaces: 2 });
131153
});
132154
}
133155
} catch (error) {
134156
logger.error(error.stack);
135157
}
136-
logger.output(outputPath, 'migrate');
158+
logger.output(capturePath, 'migrate');
137159
return next();
138160
}
139161

0 commit comments

Comments
 (0)