Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git formats flexibility #3708

Merged
merged 1 commit into from
Oct 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cvat-ui/src/actions/tasks-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ export function createTaskAsync(data: any): ThunkAction<Promise<void>, {}, {}, A
};
gitPlugin.data.task = taskInstance;
gitPlugin.data.repos = data.advanced.repository;
gitPlugin.data.format = data.advanced.format;
gitPlugin.data.lfs = data.advanced.lfs;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import React, { RefObject } from 'react';
import { Row, Col } from 'antd/lib/grid';
import { PercentageOutlined } from '@ant-design/icons';
import Input from 'antd/lib/input';
import Select from 'antd/lib/select';
import Checkbox from 'antd/lib/checkbox';
import Form, { FormInstance, RuleObject, RuleRender } from 'antd/lib/form';
import Text from 'antd/lib/typography/Text';
import { Store } from 'antd/lib/form/interface';

import CVATTooltip from 'components/common/cvat-tooltip';
import patterns from 'utils/validation-patterns';

const { Option } = Select;

export interface AdvancedConfiguration {
bugTracker?: string;
imageQuality?: number;
Expand All @@ -23,6 +25,7 @@ export interface AdvancedConfiguration {
stopFrame?: number;
frameFilter?: string;
lfs: boolean;
format?: string,
repository?: string;
useZipChunks: boolean;
dataChunkSize?: number;
Expand All @@ -42,6 +45,7 @@ interface Props {
onSubmit(values: AdvancedConfiguration): void;
installedGit: boolean;
activeFileManagerTab: string;
dumpers: []
}

function validateURL(_: RuleObject, value: string): Promise<void> {
Expand Down Expand Up @@ -276,15 +280,37 @@ class AdvancedConfigurationForm extends React.PureComponent<Props> {
);
}

private renderGitFormat(): JSX.Element {
const { dumpers } = this.props;
return (
<Form.Item
initialValue='CVAT for video 1.1'
name='format'
label='Choose format'
>
<Select style={{ width: '100%' }} initialValue='CVAT for video 1.1'>
{
dumpers.map((dumper: any) =>
<Option value={dumper.name}>{dumper.name}</Option>)
}
</Select>
</Form.Item>
);
}

private renderGit(): JSX.Element {
return (
<>
<Row>
<Col span={24}>{this.renderGitRepositoryURL()}</Col>
</Row>
<Row>
<Col span={24}>{this.renderGitFormat()}</Col>
</Row>
<Row>
<Col span={24}>{this.renderGitLFSBox()}</Col>
</Row>

</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface Props {
taskId: number | null;
projectId: number | null;
installedGit: boolean;
dumpers:[]
}

type State = CreateTaskData;
Expand Down Expand Up @@ -311,13 +312,14 @@ class CreateTaskContent extends React.PureComponent<Props & RouteComponentProps,
}

private renderAdvancedBlock(): JSX.Element {
const { installedGit } = this.props;
const { installedGit, dumpers } = this.props;
const { activeFileManagerTab } = this.state;
return (
<Col span={24}>
<Collapse>
<Collapse.Panel key='1' header={<Text className='cvat-title'>Advanced configuration</Text>}>
<AdvancedConfigurationForm
dumpers={dumpers}
installedGit={installedGit}
activeFileManagerTab={activeFileManagerTab}
ref={this.advancedConfigurationComponent}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ interface Props {
error: string;
taskId: number | null;
installedGit: boolean;
dumpers: []
}

export default function CreateTaskPage(props: Props): JSX.Element {
const {
error, status, taskId, onCreate, installedGit,
error, status, taskId, onCreate, installedGit, dumpers,
} = props;

const location = useLocation();
Expand Down Expand Up @@ -79,6 +80,7 @@ export default function CreateTaskPage(props: Props): JSX.Element {
status={status}
onCreate={onCreate}
installedGit={installedGit}
dumpers={dumpers}
/>
</Col>
</Row>
Expand Down
15 changes: 13 additions & 2 deletions cvat-ui/src/components/task-page/details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import Text from 'antd/lib/typography/Text';
import Title from 'antd/lib/typography/Title';
import moment from 'moment';

import Descriptions from 'antd/lib/descriptions';
import getCore from 'cvat-core-wrapper';
import { getReposData, syncRepos } from 'utils/git-utils';
import { ActiveInference } from 'reducers/interfaces';
import AutomaticAnnotationProgress from 'components/tasks-page/automatic-annotation-progress';
import Descriptions from 'antd/lib/descriptions';
import UserSelector, { User } from './user-selector';
import BugTrackerEditor from './bug-tracker-editor';
import LabelsEditorComponent from '../labels-editor/labels-editor';
Expand All @@ -39,6 +39,7 @@ interface State {
subset: string;
repository: string;
repositoryStatus: string;
format: string;
}

export default class DetailsComponent extends React.PureComponent<Props, State> {
Expand All @@ -60,6 +61,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
name: taskInstance.name,
subset: taskInstance.subset,
repository: '',
format: '',
repositoryStatus: '',
};
}
Expand Down Expand Up @@ -100,6 +102,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>

this.setState({
repository: data.url,
format: data.format,
});
}
})
Expand Down Expand Up @@ -203,7 +206,7 @@ export default class DetailsComponent extends React.PureComponent<Props, State>

private renderDatasetRepository(): JSX.Element | boolean {
const { taskInstance } = this.props;
const { repository, repositoryStatus } = this.state;
const { repository, repositoryStatus, format } = this.state;

return (
!!repository && (
Expand All @@ -216,6 +219,14 @@ export default class DetailsComponent extends React.PureComponent<Props, State>
<a href={repository} rel='noopener noreferrer' target='_blank'>
{repository}
</a>
<br />
<p>
Using format
{' '}
<Text strong>
{format}
</Text>
</p>
{repositoryStatus === 'sync' && (
<Tag color='blue'>
<CheckCircleOutlined />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Intel Corporation
// Copyright (C) 2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -14,6 +14,7 @@ interface StateToProps {
status: string;
error: string;
installedGit: boolean;
dumpers:[]
}

interface DispatchToProps {
Expand All @@ -31,6 +32,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
return {
...creates,
installedGit: state.plugins.list.GIT_INTEGRATION,
dumpers: state.formats.annotationFormats.dumpers,
};
}

Expand Down
7 changes: 6 additions & 1 deletion cvat-ui/src/utils/git-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Intel Corporation
// Copyright (C) 2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -22,6 +22,7 @@ interface GitPlugin {
};
};
data: {
format: any;
task: any;
lfs: boolean;
repos: string;
Expand All @@ -37,6 +38,7 @@ interface ReposData {
value: 'sync' | '!sync' | 'merged';
error: string | null;
};
format: string
}

function waitForClone(cloneResponse: any): Promise<void> {
Expand Down Expand Up @@ -93,6 +95,7 @@ async function cloneRepository(this: any, plugin: GitPlugin, createdTask: any):
data: JSON.stringify({
path: plugin.data.repos,
lfs: plugin.data.lfs,
format: plugin.data.format,
tid: createdTask.id,
}),
})
Expand Down Expand Up @@ -127,6 +130,7 @@ export function registerGitPlugin(): void {
data: {
task: null,
lfs: false,
format: '',
repos: '',
},
callbacks: {
Expand All @@ -152,6 +156,7 @@ export async function getReposData(tid: number): Promise<ReposData | null> {
value: response.status.value,
error: response.status.error,
},
format: response.format,
};
}

Expand Down
12 changes: 12 additions & 0 deletions cvat/apps/dataset_manager/formats/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,19 @@ def __call__(self, *args, **kwargs):

return target


EXPORT_FORMATS = {}


def format_for(export_format, mode):
format_name = export_format
if mode == "annotation":
format_name = "CVAT for images 1.1"
elif export_format not in EXPORT_FORMATS:
format_name = "CVAT for video 1.1"
return format_name
Copy link
Contributor

@zhiltsov-max zhiltsov-max Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the logic behind this function? If it is only supposed for returning an initial value, maybe it's better to be renamed and/or moved to another place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an additional check if we can use selected git format with this task mode and if this format is presented in EXPORT_FORMATS. Also you may see this logic here: cvat/apps/dataset_repo/dataset_repo.py line 268 (in this branch moved to registry.py)



def exporter(name, version, ext, display_name=None, enabled=True, dimension=DimensionType.DIM_2D):
assert name not in EXPORT_FORMATS, "Export format '%s' already registered" % name
def wrap_with_params(f_or_cls):
Expand Down
23 changes: 13 additions & 10 deletions cvat/apps/dataset_repo/dataset_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
import re
import shutil
import subprocess
from glob import glob
import zipfile

import django_rq
import git
from django.db import transaction
from django.utils import timezone

from cvat.apps.dataset_manager.formats.registry import format_for
from cvat.apps.dataset_manager.task import export_task
from cvat.apps.dataset_repo.models import GitData, GitStatusChoice
from cvat.apps.engine.log import slogger
from cvat.apps.engine.models import Job, Task, User
from cvat.apps.engine.plugins import add_plugin
from cvat.apps.dataset_repo.models import GitData, GitStatusChoice


def _have_no_access_exception(ex):
Expand Down Expand Up @@ -66,6 +66,7 @@ def __init__(self, db_git, db_task, user):
self._branch_name = 'cvat_{}_{}'.format(db_task.id, self._task_name)
self._annotation_file = os.path.join(self._cwd, self._path)
self._sync_date = db_git.sync_date
self._format = db_git.format
self._lfs = db_git.lfs


Expand Down Expand Up @@ -265,16 +266,13 @@ def push(self, user, scheme, host, db_task, last_save):

# Dump an annotation
timestamp = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
if self._task_mode == "annotation":
format_name = "CVAT for images 1.1"
else:
format_name = "CVAT for video 1.1"
dump_name = os.path.join(db_task.get_task_dirname(),
"git_annotation_{}.zip".format(timestamp))
"git_annotation_{}_{}.zip".format(self._format, timestamp))

export_task(
task_id=self._tid,
dst_file=dump_name,
format_name=format_name,
format_name=self._format,
server_url=scheme + host,
save_images=False,
)
Expand Down Expand Up @@ -353,7 +351,7 @@ def remote_status(self, last_save):
return GitStatusChoice.NON_SYNCED


def initial_create(tid, git_path, lfs, user):
def initial_create(tid, git_path, export_format, lfs, user):
try:
db_task = Task.objects.get(pk = tid)
path_pattern = r"\[(.+)\]"
Expand All @@ -373,9 +371,12 @@ def initial_create(tid, git_path, lfs, user):
if len(_split) < 2 or _split[1] not in [".xml", ".zip"]:
raise Exception("Only .xml and .zip formats are supported")

format_name = format_for(export_format, db_task.mode)

db_git = GitData()
db_git.url = git_path
db_git.path = path
db_git.format = format_name
db_git.task = db_task
db_git.lfs = lfs

Expand Down Expand Up @@ -416,7 +417,7 @@ def get(tid, user):
response = {}
response["url"] = {"value": None}
response["status"] = {"value": None, "error": None}

response["format"] = {"format": None}
db_task = Task.objects.get(pk = tid)
if GitData.objects.filter(pk = db_task).exists():
db_git = GitData.objects.select_for_update().get(pk = db_task)
Expand All @@ -428,12 +429,14 @@ def get(tid, user):
if rq_job is not None and (rq_job.is_queued or rq_job.is_started):
db_git.status = GitStatusChoice.SYNCING
response['status']['value'] = str(db_git.status)
response['format'] = str(db_git.format)
else:
try:
_git = Git(db_git, db_task, user)
_git.init_repos(True)
db_git.status = _git.remote_status(db_task.updated_date)
response['status']['value'] = str(db_git.status)
response['format'] = str(db_git.format)
except git.exc.GitCommandError as ex:
_have_no_access_exception(ex)
db_git.save()
Expand Down
19 changes: 19 additions & 0 deletions cvat/apps/dataset_repo/migrations/0006_gitdata_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 2.1.3 on 2019-02-05 17:08

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
('dataset_repo', '0005_auto_20201019_1100'),
]

replaces = [('git', '0006_gitdata_format')]

operations = [
migrations.AddField(
model_name='gitdata',
name='format',
field=models.CharField(max_length=256)
),
]
1 change: 1 addition & 0 deletions cvat/apps/dataset_repo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class GitData(models.Model):
task = models.OneToOneField(Task, on_delete = models.CASCADE, primary_key = True)
url = models.URLField(max_length = 2000)
path = models.CharField(max_length=256)
format = models.CharField(max_length=256)
sync_date = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=20, default=GitStatusChoice.NON_SYNCED)
lfs = models.BooleanField(default=True)
Loading