feat: cleanup folder before install

If an app gets installed insure that any existing folder in apps gets deleted. This will prevent the
user from getting in a limbo if an installation fails and the files are copied already
This commit is contained in:
Nicolas Meienberger 2022-08-23 21:16:14 +02:00
parent 9c2bcc2280
commit a92b5857f8
7 changed files with 49 additions and 11 deletions

View file

@ -9,6 +9,7 @@ const fs: {
readdirSync: typeof readdirSync;
copyFileSync: typeof copyFileSync;
copySync: typeof copyFileSync;
createFileSync: typeof createFileSync;
} = jest.genMockFromModule('fs-extra');
let mockFiles = Object.create(null);
@ -45,12 +46,14 @@ const mkdirSync = (p: string) => {
mockFiles[p] = Object.create(null);
};
const rmSync = (p: string, options: { recursive: boolean }) => {
if (options.recursive) {
delete mockFiles[p];
} else {
delete mockFiles[p][Object.keys(mockFiles[p])[0]];
const rmSync = (p: string) => {
if (mockFiles[p] instanceof Array) {
mockFiles[p].forEach((file: string) => {
delete mockFiles[path.join(p, file)];
});
}
delete mockFiles[p];
};
const readdirSync = (p: string) => {
@ -85,6 +88,10 @@ const copySync = (source: string, destination: string) => {
}
};
const createFileSync = (p: string) => {
mockFiles[p] = '';
};
fs.readdirSync = readdirSync;
fs.existsSync = existsSync;
fs.readFileSync = readFileSync;
@ -93,6 +100,7 @@ fs.mkdirSync = mkdirSync;
fs.rmSync = rmSync;
fs.copyFileSync = copyFileSync;
fs.copySync = copySync;
fs.createFileSync = createFileSync;
fs.__createMockFiles = createMockFiles;
module.exports = fs;

View file

@ -54,6 +54,7 @@ const createApp = async (props: IProps) => {
MockFiles[`${config.ROOT_FOLDER}/.env`] = 'TEST=test';
MockFiles[`${config.ROOT_FOLDER}/repos/repo-id`] = '';
MockFiles[`${config.ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/config.json`] = JSON.stringify(appInfo);
MockFiles[`${config.ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/docker-compose.yml`] = 'compose';
MockFiles[`${config.ROOT_FOLDER}/repos/repo-id/apps/${appInfo.id}/metadata/description.md`] = 'md desc';
if (installed) {

View file

@ -109,6 +109,32 @@ describe('Install app', () => {
expect(envMap.get('RANDOM_FIELD')).toBeDefined();
expect(envMap.get('RANDOM_FIELD')).toHaveLength(32);
});
it('Should correctly copy app from repos to apps folder', async () => {
await AppsService.installApp(app1.id, { TEST_FIELD: 'test' });
const appFolder = fs.readdirSync(`${config.ROOT_FOLDER}/apps/${app1.id}`);
expect(appFolder).toBeDefined();
expect(appFolder.indexOf('docker-compose.yml')).toBeGreaterThanOrEqual(0);
});
it('Should cleanup any app folder existing before install', async () => {
const { MockFiles, appInfo } = await createApp({});
app1 = appInfo;
MockFiles[`/tipi/apps/${appInfo.id}/docker-compose.yml`] = 'test';
MockFiles[`/tipi/apps/${appInfo.id}/test.yml`] = 'test';
MockFiles[`/tipi/apps/${appInfo.id}`] = ['test.yml', 'docker-compose.yml'];
// @ts-ignore
fs.__createMockFiles(MockFiles);
expect(fs.existsSync(`${config.ROOT_FOLDER}/apps/${app1.id}/test.yml`)).toBe(true);
await AppsService.installApp(app1.id, { TEST_FIELD: 'test' });
expect(fs.existsSync(`${config.ROOT_FOLDER}/apps/${app1.id}/test.yml`)).toBe(false);
expect(fs.existsSync(`${config.ROOT_FOLDER}/apps/${app1.id}/docker-compose.yml`)).toBe(true);
});
});
describe('Uninstall app', () => {

View file

@ -65,7 +65,7 @@ const installApp = async (id: string, form: Record<string, string>): Promise<App
if (app) {
await startApp(id);
} else {
ensureAppFolder(id);
ensureAppFolder(id, true);
const appIsValid = await checkAppRequirements(id);
if (!appIsValid) {

View file

@ -15,6 +15,7 @@ export enum AppCategoriesEnum {
DATA = 'data',
MUSIC = 'music',
FINANCE = 'finance',
GAMING = 'gaming',
}
export enum FieldTypes {

View file

@ -42,9 +42,13 @@ export const getSeed = () => {
return seed.toString();
};
export const ensureAppFolder = (appName: string) => {
export const ensureAppFolder = (appName: string, cleanup = false) => {
if (cleanup) {
deleteFolder(`/apps/${appName}`);
}
if (!fileExists(`/apps/${appName}/docker-compose.yml`)) {
fs.removeSync(getAbsolutePath(`/apps/${appName}`));
deleteFolder(`/apps/${appName}`);
// Copy from apps repo
fs.copySync(getAbsolutePath(`/repos/${config.APPS_REPO_ID}/apps/${appName}`), getAbsolutePath(`/apps/${appName}`));
}

View file

@ -25,7 +25,5 @@ rm -rf "${ROOT_FOLDER}/app-data"
rm -rf "${ROOT_FOLDER}/data/postgres"
mkdir -p "${ROOT_FOLDER}/app-data"
# Put {"installed":""} in state/apps.json
echo '{"installed":""}' >"${ROOT_FOLDER}/state/apps.json"
cd "$ROOT_FOLDER"
"${ROOT_FOLDER}/scripts/start.sh"