Handle directory change

This commit is contained in:
Alexandre Bodin 2019-11-19 15:45:28 +01:00
parent 1605997045
commit ca10e972e2
4 changed files with 134 additions and 92 deletions

View File

@ -32,51 +32,6 @@ const formatComponent = component => {
}; };
}; };
// /**
// * Updates a component schema file
// * @param {Object} component
// * @param {Object} infos
// */
// async function updateComponent({ component, infos }) {
// const { uid, __schema__: oldSchema } = component;
// // don't update collectionName if not provided
// const updatedSchema = {
// ...oldSchema,
// connection: infos.connection || oldSchema.connection,
// collectionName: infos.collectionName || oldSchema.collectionName,
// info: {
// name: infos.name || oldSchema.info.name,
// icon: infos.icon || oldSchema.info.icon,
// description: infos.description || oldSchema.info.description,
// },
// attributes: convertAttributes(infos.attributes),
// };
// await editSchema({ uid, schema: updatedSchema });
// if (component.category !== infos.category) {
// const oldDir = path.join(strapi.dir, 'components', component.category);
// const newDir = path.join(strapi.dir, 'components', infos.category);
// await fse.move(
// path.join(oldDir, component.__filename__),
// path.join(newDir, component.__filename__)
// );
// const list = await fse.readdir(oldDir);
// if (list.length === 0) {
// await fse.remove(oldDir);
// }
// return {
// uid: `${infos.category}.${component.modelName}`,
// };
// }
// return { uid };
// }
/** /**
* Returns a uid from a string * Returns a uid from a string
* @param {string} str - string to slugify * @param {string} str - string to slugify
@ -183,7 +138,7 @@ const updateComponentInModels = (oldUID, newUID) => {
* @param {Object} params.component Main component to create * @param {Object} params.component Main component to create
* @param {Array<Object>} params.components List of nested components to created or edit * @param {Array<Object>} params.components List of nested components to created or edit
*/ */
const createComponent = ({ component, components }) => { const createComponent = ({ component, components = [] }) => {
const componentsToCreate = components.filter(compo => !_.has(compo, 'uid')); const componentsToCreate = components.filter(compo => !_.has(compo, 'uid'));
const componentsToEdit = components.filter(compo => _.has(compo, 'uid')); const componentsToEdit = components.filter(compo => _.has(compo, 'uid'));
@ -203,7 +158,7 @@ const createComponent = ({ component, components }) => {
* @param {Object} params.component Main component to create * @param {Object} params.component Main component to create
* @param {Array<Object>} params.components List of nested components to created or edit * @param {Array<Object>} params.components List of nested components to created or edit
*/ */
const editComponent = (uid, { component, components }) => { const editComponent = (uid, { component, components = [] }) => {
const componentsToCreate = components.filter(compo => !_.has(compo, 'uid')); const componentsToCreate = components.filter(compo => !_.has(compo, 'uid'));
const componentsToEdit = components.filter(compo => _.has(compo, 'uid')); const componentsToEdit = components.filter(compo => _.has(compo, 'uid'));

View File

@ -42,8 +42,8 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
infos.category infos.category
)}_${nameToCollectionName(pluralize(infos.name))}`; )}_${nameToCollectionName(pluralize(infos.name))}`;
handler.uid = uid;
handler handler
.setUID(uid)
.set('connection', infos.connection || defaultConnection) .set('connection', infos.connection || defaultConnection)
.set('collectionName', infos.collectionName || defaultCollectionName) .set('collectionName', infos.collectionName || defaultCollectionName)
.set(['info', 'name'], infos.name) .set(['info', 'name'], infos.name)
@ -52,6 +52,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set('attributes', convertAttributes(infos.attributes)); .set('attributes', convertAttributes(infos.attributes));
tmpComponents.set(uid, handler); tmpComponents.set(uid, handler);
return handler; return handler;
}, },
@ -67,9 +68,20 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
const handler = tmpComponents.get(uid); const handler = tmpComponents.get(uid);
// TODO: handle category change to move the file const [, nameUID] = uid.split('.');
const newCategory = nameToSlug(infos.category);
const newUID = `${newCategory}.${nameUID}`;
if (newUID !== uid && tmpComponents.has(newUID)) {
throw new Error('component.edit.alreadyExists');
}
const newDir = path.join(strapi.dir, 'components', newCategory);
handler handler
.setUID(newUID)
.setDir(newDir)
.set('connection', infos.connection) .set('connection', infos.connection)
.set('collectionName', infos.collectionName) .set('collectionName', infos.collectionName)
.set(['info', 'name'], infos.name) .set(['info', 'name'], infos.name)
@ -77,8 +89,15 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set(['info', 'description'], infos.description) .set(['info', 'description'], infos.description)
.set('attributes', convertAttributes(infos.attributes)); .set('attributes', convertAttributes(infos.attributes));
// TODO: update relations if uid changed if (newUID !== uid) {
// TODO: update relations if uid changed this.components.forEach(compo => {
compo.updateComponent(uid, newUID);
});
this.contentTypes.forEach(ct => {
ct.updateComponent(uid, newUID);
});
}
return handler; return handler;
}, },

View File

@ -59,14 +59,15 @@ function createSchemaManager() {
await builder await builder
.flush() .flush()
.catch(error => { .catch(error => {
strapi.log.error('Error writing schema files', error); strapi.log.error('Error writing schema files');
strapi.log.error(error);
return builder.rollback(); return builder.rollback();
}) })
.catch(error => { .catch(error => {
strapi.log.error( strapi.log.error(
'Error rolling back schema files. You might need to fix your files manually', 'Error rolling back schema files. You might need to fix your files manually'
error
); );
strapi.log.error(error);
throw new Error('Invalid schema edition'); throw new Error('Invalid schema edition');
}); });

View File

@ -5,48 +5,61 @@ const fse = require('fs-extra');
const _ = require('lodash'); const _ = require('lodash');
module.exports = function createSchemaHandler(infos) { module.exports = function createSchemaHandler(infos) {
const uid = infos.uid; const initialState = {
const dir = infos.dir; uid: infos.uid,
const filename = infos.filename; dir: infos.dir,
filename: infos.filename,
schema: infos.schema || {},
};
const state = _.cloneDeep(initialState);
// always keep it the same to rollback // always keep it the same to rollback
let initialSchema = Object.freeze(infos.schema); Object.freeze(initialState.schema);
let schema = _.cloneDeep(infos.schema) || {};
let modified = false; let modified = false;
let deleted = false; let deleted = false;
return { return {
uid, get uid() {
dir, return state.uid;
filename,
// Flag schema for deletion
delete() {
deleted = true;
}, },
// get a copy of the full schema setUID(val) {
get schema() {
return _.cloneDeep(schema);
},
// set a new schema object
set schema(val) {
modified = true; modified = true;
schema = _.cloneDeep(val);
state.uid = val;
return this;
},
setDir(val) {
modified = true;
state.dir = val;
return this;
},
get schema() {
return _.cloneDeep(state.schema);
},
setSchema(val) {
modified = true;
state.schema = _.cloneDeep(val);
return this;
}, },
// get a particuar path inside the schema // get a particuar path inside the schema
get(path) { get(path) {
return _.get(schema, path); return _.get(state.schema, path);
}, },
// set a particuar path inside the schema // set a particuar path inside the schema
set(path, val) { set(path, val) {
modified = true; modified = true;
_.set(schema, path, val || _.get(schema, path)); _.set(state.schema, path, val || _.get(state.schema, path));
return this; return this;
}, },
@ -55,15 +68,22 @@ module.exports = function createSchemaHandler(infos) {
unset(path) { unset(path) {
modified = true; modified = true;
_.unset(schema, path); _.unset(state.schema, path);
return this; return this;
}, },
delete() {
deleted = true;
return this;
},
// utils // utils
removeComponent(uid) { removeComponent(uid) {
Object.keys(schema.attributes).forEach(key => { const { attributes } = state.schema;
const attr = schema.attributes[key];
Object.keys(attributes).forEach(key => {
const attr = attributes[key];
if (attr.type === 'component' && attr.component === uid) { if (attr.type === 'component' && attr.component === uid) {
this.unset(['attributes', key]); this.unset(['attributes', key]);
@ -74,7 +94,7 @@ module.exports = function createSchemaHandler(infos) {
Array.isArray(attr.components) && Array.isArray(attr.components) &&
attr.components.includes(uid) attr.components.includes(uid)
) { ) {
const updatedComponentList = schema.attributes[key].components.filter( const updatedComponentList = attributes[key].components.filter(
val => val !== uid val => val !== uid
); );
this.set(['attributes', key, 'components'], updatedComponentList); this.set(['attributes', key, 'components'], updatedComponentList);
@ -84,22 +104,58 @@ module.exports = function createSchemaHandler(infos) {
return this; return this;
}, },
updateComponent(uid, newUID) {
const { attributes } = state.schema;
Object.keys(attributes).forEach(key => {
const attr = attributes[key];
if (attr.type === 'component' && attr.component === uid) {
this.set(['attributes', key, 'component'], newUID);
}
if (
attr.type === 'dynamiczone' &&
Array.isArray(attr.components) &&
attr.components.includes(uid)
) {
const updatedComponentList = attributes[key].components.map(val =>
val === uid ? newUID : uid
);
this.set(['attributes', key, 'components'], updatedComponentList);
}
});
return this;
},
// save the schema to disk // save the schema to disk
async flush() { async flush() {
const filePath = path.join(dir, filename); const initialPath = path.join(initialState.dir, initialState.filename);
const filePath = path.join(state.dir, state.filename);
if (deleted === true) { if (deleted === true) {
await fse.remove(filePath); await fse.remove(initialPath);
const list = await fse.readdir(dir); const list = await fse.readdir(initialState.dir);
if (list.length === 0) { if (list.length === 0) {
await fse.remove(dir); await fse.remove(initialState.dir);
} }
} }
if (modified === true) { if (modified === true) {
await fse.ensureFile(filePath); await fse.ensureFile(filePath);
return fse.writeJSON(filePath, schema, { spaces: 2 }); await fse.writeJSON(filePath, state.schema, { spaces: 2 });
// remove from oldPath
if (initialPath !== filePath) {
await fse.remove(initialPath);
const list = await fse.readdir(initialState.dir);
if (list.length === 0) {
await fse.remove(initialState.dir);
}
}
} }
return Promise.resolve(); return Promise.resolve();
@ -107,22 +163,33 @@ module.exports = function createSchemaHandler(infos) {
// reset the schema to its initial value // reset the schema to its initial value
async rollback() { async rollback() {
const filePath = path.join(dir, filename); const initialPath = path.join(initialState.dir, initialState.filename);
const filePath = path.join(state.dir, state.filename);
// it was a creation so it needs to be deleted // it was a creation so it needs to be deleted
if (!uid) { if (!initialState.uid) {
await fse.remove(filePath); await fse.remove(filePath);
const list = await fse.readdir(dir); const list = await fse.readdir(state.dir);
if (list.length === 0) { if (list.length === 0) {
await fse.remove(dir); await fse.remove(state.dir);
} }
return; return;
} }
if (modified === true || deleted === true) { if (modified === true || deleted === true) {
await fse.ensureFile(filePath); await fse.ensureFile(initialPath);
return fse.writeJSON(filePath, initialSchema, { spaces: 2 }); await fse.writeJSON(initialPath, initialState.schema, { spaces: 2 });
// remove
if (initialPath !== filePath) {
await fse.remove(filePath);
const list = await fse.readdir(state.dir);
if (list.length === 0) {
await fse.remove(state.dir);
}
}
} }
return Promise.resolve(); return Promise.resolve();