You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
5.9 KiB
TypeScript
196 lines
5.9 KiB
TypeScript
// Copyright (C) 2020 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
import getCore from 'cvat-core';
|
|
|
|
const core = getCore();
|
|
const baseURL = core.config.backendAPI.slice(0, -7);
|
|
|
|
interface GitPlugin {
|
|
name: string;
|
|
description: string;
|
|
cvat: {
|
|
classes: {
|
|
Task: {
|
|
prototype: {
|
|
save: {
|
|
leave: (plugin: GitPlugin, task: any) => Promise<any>;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
data: {
|
|
task: any;
|
|
lfs: boolean;
|
|
repos: string;
|
|
};
|
|
callbacks: {
|
|
onStatusChange: ((status: string) => void) | null;
|
|
};
|
|
}
|
|
|
|
interface ReposData {
|
|
url: string;
|
|
status: {
|
|
value: 'sync' | '!sync' | 'merged';
|
|
error: string | null;
|
|
};
|
|
}
|
|
|
|
function waitForClone(cloneResponse: any): Promise<void> {
|
|
return new Promise((resolve, reject): void => {
|
|
async function checkCallback(): Promise<void> {
|
|
core.server.request(
|
|
`${baseURL}/git/repository/check/${cloneResponse.rq_id}`,
|
|
{
|
|
method: 'GET',
|
|
},
|
|
).then((response: any): void => {
|
|
if (['queued', 'started'].includes(response.status)) {
|
|
setTimeout(checkCallback, 1000);
|
|
} else if (response.status === 'finished') {
|
|
resolve();
|
|
} else if (response.status === 'failed') {
|
|
let message = 'Repository status check failed. ';
|
|
if (response.stderr) {
|
|
message += response.stderr;
|
|
}
|
|
|
|
reject(message);
|
|
} else {
|
|
const message = `Repository status check returned the status "${response.status}"`;
|
|
reject(message);
|
|
}
|
|
}).catch((error: any): void => {
|
|
const message = `Can not sent a request to clone the repository. ${error.toString()}`;
|
|
reject(message);
|
|
});
|
|
}
|
|
|
|
setTimeout(checkCallback, 1000);
|
|
});
|
|
}
|
|
|
|
async function cloneRepository(
|
|
this: any,
|
|
plugin: GitPlugin,
|
|
createdTask: any,
|
|
): Promise<any> {
|
|
return new Promise((resolve, reject): any => {
|
|
if (typeof (this.id) !== 'undefined' || plugin.data.task !== this) {
|
|
// not the first save, we do not need to clone the repository
|
|
// or anchor set for another task
|
|
resolve(createdTask);
|
|
} else if (plugin.data.repos) {
|
|
if (plugin.callbacks.onStatusChange) {
|
|
plugin.callbacks.onStatusChange('The repository is being cloned..');
|
|
}
|
|
|
|
core.server.request(`${baseURL}/git/repository/create/${createdTask.id}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-type': 'application/json',
|
|
},
|
|
data: JSON.stringify({
|
|
path: plugin.data.repos,
|
|
lfs: plugin.data.lfs,
|
|
tid: createdTask.id,
|
|
}),
|
|
}).then(waitForClone).then((): void => {
|
|
resolve(createdTask);
|
|
}).catch((error: any): void => {
|
|
createdTask.delete().finally((): void => {
|
|
reject(
|
|
new core.exceptions.PluginError(
|
|
typeof (error) === 'string'
|
|
? error : error.message,
|
|
),
|
|
);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
export function registerGitPlugin(): void {
|
|
const plugin: GitPlugin = {
|
|
name: 'Git',
|
|
description: 'Plugin allows to work with git repositories',
|
|
cvat: {
|
|
classes: {
|
|
Task: {
|
|
prototype: {
|
|
save: {
|
|
leave: cloneRepository,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
data: {
|
|
task: null,
|
|
lfs: false,
|
|
repos: '',
|
|
},
|
|
callbacks: {
|
|
onStatusChange: null,
|
|
},
|
|
};
|
|
|
|
core.plugins.register(plugin);
|
|
}
|
|
|
|
export async function getReposData(tid: number): Promise<ReposData | null> {
|
|
const response = await core.server.request(
|
|
`${baseURL}/git/repository/get/${tid}`,
|
|
{
|
|
method: 'GET',
|
|
},
|
|
);
|
|
|
|
if (!response.url.value) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
url: response.url.value.split(/\s+/)[0],
|
|
status: {
|
|
value: response.status.value,
|
|
error: response.status.error,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function syncRepos(tid: number): Promise<void> {
|
|
return new Promise((resolve, reject): void => {
|
|
core.server.request(`${baseURL}/git/repository/push/${tid}`, {
|
|
method: 'GET',
|
|
}).then((syncResponse: any): void => {
|
|
async function checkSync(): Promise<void> {
|
|
const id = syncResponse.rq_id;
|
|
const response = await core.server.request(`${baseURL}/git/repository/check/${id}`, {
|
|
method: 'GET',
|
|
});
|
|
|
|
if (['queued', 'started'].includes(response.status)) {
|
|
setTimeout(checkSync, 1000);
|
|
} else if (response.status === 'finished') {
|
|
resolve();
|
|
} else if (response.status === 'failed') {
|
|
const message = `Can not push to remote repository. Message: ${response.stderr}`;
|
|
reject(new Error(message));
|
|
} else {
|
|
const message = `Check returned status "${response.status}".`;
|
|
reject(new Error(message));
|
|
}
|
|
}
|
|
|
|
setTimeout(checkSync, 1000);
|
|
}).catch((error: any): void => {
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|