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
* @param {string} str - string to slugify
@ -183,7 +138,7 @@ const updateComponentInModels = (oldUID, newUID) => {
* @param {Object} params.component Main component to create
* @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 componentsToEdit = components.filter(compo => _.has(compo, 'uid'));
@ -203,7 +158,7 @@ const createComponent = ({ component, components }) => {
* @param {Object} params.component Main component to create
* @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 componentsToEdit = components.filter(compo => _.has(compo, 'uid'));

View File

@ -42,8 +42,8 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
infos.category
)}_${nameToCollectionName(pluralize(infos.name))}`;
handler.uid = uid;
handler
.setUID(uid)
.set('connection', infos.connection || defaultConnection)
.set('collectionName', infos.collectionName || defaultCollectionName)
.set(['info', 'name'], infos.name)
@ -52,6 +52,7 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set('attributes', convertAttributes(infos.attributes));
tmpComponents.set(uid, handler);
return handler;
},
@ -67,9 +68,20 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
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
.setUID(newUID)
.setDir(newDir)
.set('connection', infos.connection)
.set('collectionName', infos.collectionName)
.set(['info', 'name'], infos.name)
@ -77,8 +89,15 @@ module.exports = function createComponentBuilder({ tmpComponents }) {
.set(['info', 'description'], infos.description)
.set('attributes', convertAttributes(infos.attributes));
// TODO: update relations if uid changed
// TODO: update relations if uid changed
if (newUID !== uid) {
this.components.forEach(compo => {
compo.updateComponent(uid, newUID);
});
this.contentTypes.forEach(ct => {
ct.updateComponent(uid, newUID);
});
}
return handler;
},

View File

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

View File

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