コード例 #1
0
ファイル: coprs_packages.py プロジェクト: schlupov/copr
def process_save_package(copr, source_type_text, package_name, view,
                         view_method, url_on_success):
    form = forms.get_package_form_cls_by_source_type_text(source_type_text)()

    if "reset" in flask.request.form:
        try:
            package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
        except IndexError:
            flask.flash(
                "Package {package_name} does not exist in copr_dir {copr_dir}."
                .format(package_name, copr.main_dir.full_name))
            return flask.redirect(url_on_success)  # should be url_on_fail

        try:
            PackagesLogic.reset_package(flask.g.user, package)
            db.session.commit()
        except InsufficientRightsException as e:
            flask.flash(str(e))
            return flask.redirect(url_on_success)  # should be url_on_fail

        flask.flash("Package default source successfully reset.")
        return flask.redirect(url_on_success)

    if form.validate_on_submit():
        try:
            if package_name:
                package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
            else:
                package = PackagesLogic.add(flask.app.g.user, copr.main_dir,
                                            form.package_name.data)

            package.source_type = helpers.BuildSourceEnum(source_type_text)
            package.webhook_rebuild = form.webhook_rebuild.data
            package.source_json = form.source_json
            package.chroot_blacklist_raw = form.chroot_blacklist.data
            package.max_builds = form.max_builds.data

            db.session.add(package)
            db.session.commit()
        except (InsufficientRightsException, IndexError) as e:
            db.session.rollback()
            flask.flash(str(e), "error")
        else:
            flask.flash(
                "Package successfully saved" if package_name else
                "New package has been created.", "success")

        return flask.redirect(url_on_success)

    kwargs = {
        "coprname": copr.name,
        "package_name": package_name,
        "source_type_text": source_type_text,
        "form": form,
    }

    kwargs.update({"group_name": copr.group.name} if copr.
                  is_a_group_project else {"username": copr.user.name})
    return view_method(**kwargs)
コード例 #2
0
ファイル: coprs_packages.py プロジェクト: bowlofeggs/copr
def process_save_package(copr, source_type_text, package_name, view, view_method, url_on_success):
    form = forms.get_package_form_cls_by_source_type_text(source_type_text)()

    if "reset" in flask.request.form:
        try:
            package = PackagesLogic.get(copr.id, package_name)[0]
        except IndexError:
            flask.flash("Package {package_name} does not exist in copr {copr}.".format(package_name, copr.full_name))
            return flask.redirect(url_on_success) # should be url_on_fail

        try:
            PackagesLogic.reset_package(flask.g.user, package)
            db.session.commit()
        except InsufficientRightsException as e:
            flask.flash(str(e))
            return flask.redirect(url_on_success) # should be url_on_fail

        flask.flash("Package default source successfully reset.")
        return flask.redirect(url_on_success)

    if form.validate_on_submit():
        try:
            if package_name:
                package = PackagesLogic.get(copr.id, package_name)[0]
            else:
                package = PackagesLogic.add(flask.app.g.user, copr, form.package_name.data)

            package.source_type = helpers.BuildSourceEnum(source_type_text)
            package.webhook_rebuild = form.webhook_rebuild.data
            package.source_json = form.source_json

            db.session.add(package)
            db.session.commit()
        except (InsufficientRightsException, IndexError) as e:
            db.session.rollback()
            flask.flash(str(e), "error")
        else:
            flask.flash("Package successfully saved" if package_name else "New package has been created.")

        return flask.redirect(url_on_success)

    kwargs = {
        "coprname": copr.name,
        "package_name": package_name,
        "source_type_text": source_type_text,
        "form": form,
    }

    kwargs.update({"group_name": copr.group.name} if copr.is_a_group_project else {"username": copr.user.name})
    return view_method(**kwargs)
コード例 #3
0
ファイル: complex_logic.py プロジェクト: tedwardia/copr
 def fork_package(self, package, fcopr):
     fpackage = PackagesLogic.get(fcopr.id, package.name).first()
     if not fpackage:
         fpackage = self.create_object(models.Package, package, exclude=["id", "copr_id"])
         fpackage.copr = fcopr
         db.session.add(fpackage)
     return fpackage
コード例 #4
0
ファイル: complex_logic.py プロジェクト: 0-T-0/copr
 def fork_package(self, package, fcopr):
     fpackage = PackagesLogic.get(fcopr.id, package.name).first()
     if not fpackage:
         fpackage = self.create_object(models.Package, package, exclude=["id", "copr_id"])
         fpackage.copr = fcopr
         db.session.add(fpackage)
     return fpackage
コード例 #5
0
ファイル: apiv3_packages.py プロジェクト: schlupov/copr
def get_package(ownername, projectname, packagename):
    copr = get_copr(ownername, projectname)
    try:
        package = PackagesLogic.get(copr.main_dir.id, packagename)[0]
    except IndexError:
        raise ObjectNotFound("No package with name {name} in copr {copr}".format(name=packagename, copr=copr.name))
    return flask.jsonify(to_dict(package))
コード例 #6
0
ファイル: complex_logic.py プロジェクト: tkdchen/copr
 def get_package_safe(copr, package_name):
     try:
         return PackagesLogic.get(copr.id, package_name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise ObjectNotFound(
             message="Package {} in the copr {} does not exist."
             .format(package_name, copr))
コード例 #7
0
def dist_git_upload_completed():
    """
    Mark BuildChroot in a Build as uploaded, which means:
        - set it to pending state
        - set BuildChroot.git_hash
        - if it's the last BuildChroot in a Build:
            - delete local srpm
    BuildChroot is identified with task_id which is build id + git branch name
        - For example: 56-f22 -> build 55, chroots fedora-22-*
    """
    result = {"updated": False}

    if "task_id" in flask.request.json:
        app.logger.debug(flask.request.data)
        task_id = flask.request.json["task_id"]
        build_chroots = BuildsLogic.get_chroots_from_dist_git_task_id(task_id)
        build = build_chroots[0].build

        # Is it OK?
        if "git_hash" in flask.request.json and "repo_name" in flask.request.json:
            git_hash = flask.request.json["git_hash"]
            pkg_name = flask.request.json["pkg_name"]
            pkg_version = flask.request.json["pkg_version"]

            # Now I need to assign a package to this build
            package = PackagesLogic.get(build.copr.id, pkg_name).first()
            if not package:
                package = PackagesLogic.add(build.copr.owner, build.copr,
                                            pkg_name)
                db.session.add(package)
                db.session.flush()

            build.package_id = package.id
            build.pkg_version = pkg_version

            for ch in build_chroots:
                ch.status = helpers.StatusEnum("pending")
                ch.git_hash = git_hash

        # Failed?
        elif "error" in flask.request.json:
            error_type = flask.request.json["error"]

            try:
                build.fail_type = helpers.FailTypeEnum(error_type)
            except KeyError:
                build.fail_type = helpers.FailTypeEnum("unknown_error")

            for ch in build_chroots:
                ch.status = helpers.StatusEnum("failed")

        # is it the last chroot?
        if not build.has_importing_chroot:
            BuildsLogic.delete_local_srpm(build)

        db.session.commit()

        result.update({"updated": True})

    return flask.jsonify(result)
コード例 #8
0
ファイル: backend_general.py プロジェクト: seocam/copr
def dist_git_upload_completed():
    """
    Mark BuildChroot in a Build as uploaded, which means:
        - set it to pending state
        - set BuildChroot.git_hash
        - if it's the last BuildChroot in a Build:
            - delete local srpm
    BuildChroot is identified with task_id which is build id + git branch name
        - For example: 56-f22 -> build 55, chroots fedora-22-*
    """
    result = {"updated": False}

    if "task_id" in flask.request.json:
        app.logger.debug(flask.request.data)
        task_id = flask.request.json["task_id"]
        build_chroots = BuildsLogic.get_chroots_from_dist_git_task_id(task_id)
        build = build_chroots[0].build

        # Is it OK?
        if "git_hash" in flask.request.json and "repo_name" in flask.request.json:
            git_hash = flask.request.json["git_hash"]
            repo_name = flask.request.json["repo_name"]
            pkg_name = flask.request.json["pkg_name"]
            pkg_version = flask.request.json["pkg_version"]

            # Now I need to assign a package to this build
            package = PackagesLogic.get(build.copr.id, pkg_name).first()
            if not package:
                package = PackagesLogic.add(build.copr.owner, build.copr, pkg_name)
                db.session.add(package)
                db.session.flush()

            build.package_id = package.id
            build.pkg_version = pkg_version

            for ch in build_chroots:
                ch.status = helpers.StatusEnum("pending")
                ch.git_hash = git_hash

        # Failed?
        elif "error" in flask.request.json:
            error_type = flask.request.json["error"]

            try:
                build.fail_type = helpers.FailTypeEnum(error_type)
            except KeyError:
                build.fail_type = helpers.FailTypeEnum("unknown_error")

            for ch in build_chroots:
                ch.status = helpers.StatusEnum("failed")

        # is it the last chroot?
        if not build.has_importing_chroot:
            BuildsLogic.delete_local_srpm(build)

        db.session.commit()

        result.update({"updated": True})

    return flask.jsonify(result)
コード例 #9
0
ファイル: coprs_builds.py プロジェクト: evilkost/copr
def process_package_edit(copr, package_name, view):
    if request.form["source_type"] == "git_and_tito":
        form = forms.PackageFormTitoFactory
        form_var = "form_tito"
    elif request.form["source_type"] == "mock_scm":
        form = forms.PackageFormMockFactory
        form_var = "form_mock"
    else:
        raise Exception("Wrong source type")
    form = form.create_form_cls()()

    if form.validate_on_submit():
        package = PackagesLogic.get(copr.id, package_name).first()
        package.source_type = helpers.BuildSourceEnum(form.source_type.data)

        if package.source_type == helpers.BuildSourceEnum("git_and_tito"):
            package.source_json = json.dumps({
                "git_url": form.git_url.data,
                "git_branch": form.git_branch.data,
                "git_dir": form.git_directory.data,
                "tito_test": form.tito_test.data})
        elif package.source_type == helpers.BuildSourceEnum("mock_scm"):
            package.source_json = json.dumps({
                "scm_type": form.scm_type.data,
                "scm_url": form.scm_url.data,
                "scm_branch": form.scm_branch.data,
                "spec": form.spec.data})

        db.session.add(package)
        db.session.commit()

    return render_package_edit(copr, package_name, view, **{form_var: form})
コード例 #10
0
 def get_package_safe(copr_dir, package_name):
     try:
         return PackagesLogic.get(copr_dir.id, package_name).one()
     except sqlalchemy.orm.exc.NoResultFound:
         raise ObjectNotFound(
             message="Package {} in the copr_dir {} does not exist.".format(
                 package_name, copr_dir))
コード例 #11
0
def copr_build_package(copr, package_name):
    form = forms.BuildFormRebuildFactory.create_form_cls(
        copr.active_chroots)(meta={
            'csrf': False
        })

    try:
        package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
    except IndexError:
        raise LegacyApiError(
            "No package with name {name} in copr {copr}".format(
                name=package_name, copr=copr.name))

    if form.validate_on_submit():
        try:
            build = PackagesLogic.build_package(flask.g.user, copr, package,
                                                form.selected_chroots,
                                                **form.data)
            db.session.commit()
        except (InsufficientRightsException, ActionInProgressException,
                NoPackageSourceException) as e:
            raise LegacyApiError(str(e))
    else:
        raise LegacyApiError(form.errors)

    return flask.jsonify({
        "output": "ok",
        "ids": [build.id],
        "message": "Build was added to {0}.".format(copr.name)
    })
コード例 #12
0
def process_package_edit(copr, package_name, view):
    if request.form["source_type"] == "git_and_tito":
        form = forms.PackageFormTitoFactory
        form_var = "form_tito"
    elif request.form["source_type"] == "mock_scm":
        form = forms.PackageFormMockFactory
        form_var = "form_mock"
    else:
        raise Exception("Wrong source type")
    form = form.create_form_cls()()

    if form.validate_on_submit():
        package = PackagesLogic.get(copr.id, package_name).first()
        package.source_type = helpers.BuildSourceEnum(form.source_type.data)

        if package.source_type == helpers.BuildSourceEnum("git_and_tito"):
            package.source_json = json.dumps({
                "git_url": form.git_url.data,
                "git_branch": form.git_branch.data,
                "git_dir": form.git_directory.data,
                "tito_test": form.tito_test.data
            })
        elif package.source_type == helpers.BuildSourceEnum("mock_scm"):
            package.source_json = json.dumps({
                "scm_type": form.scm_type.data,
                "scm_url": form.scm_url.data,
                "scm_branch": form.scm_branch.data,
                "spec": form.spec.data
            })

        db.session.add(package)
        db.session.commit()

    return render_package_edit(copr, package_name, view, **{form_var: form})
コード例 #13
0
ファイル: api_general.py プロジェクト: bowlofeggs/copr
def copr_get_package(copr, package_name):
    try:
        package = PackagesLogic.get(copr.id, package_name)[0]
    except IndexError:
        raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name))

    params = get_package_record_params()
    return flask.jsonify({'package': package.to_dict(**params)})
コード例 #14
0
def copr_edit_package(copr, package_name, source_type_text):
    try:
        package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
    except IndexError:
        raise LegacyApiError(
            "Package {name} does not exists in copr_dir {copr_dir}.".format(
                name=package_name, copr_dir=copr_dir.name))
    return process_package_add_or_edit(copr, source_type_text, package=package)
コード例 #15
0
def copr_get_package(copr, package_name):
    try:
        package = PackagesLogic.get(copr.id, package_name)[0]
    except IndexError:
        raise LegacyApiError(
            "No package with name {name} in copr {copr}".format(
                name=package_name, copr=copr.name))
    return flask.jsonify({'package': package.to_dict()})
コード例 #16
0
def copr_get_package(copr, package_name):
    try:
        package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
    except IndexError:
        raise LegacyApiError(
            "No package with name {name} in copr_dir {copr_dir}".format(
                name=package_name, copr_dir=copr.main_dir.name))

    params = get_package_record_params()
    return flask.jsonify({'package': package.to_dict(**params)})
コード例 #17
0
ファイル: apiv3_packages.py プロジェクト: schlupov/copr
def package_reset():
    copr = get_copr()
    form = forms.BasePackageForm()
    try:
        package = PackagesLogic.get(copr.main_dir.id, form.package_name.data)[0]
    except IndexError:
        raise ObjectNotFound("No package with name {name} in copr {copr}"
                             .format(name=form.package_name.data, copr=copr.name))

    PackagesLogic.reset_package(flask.g.user, package)
    db.session.commit()
    return flask.jsonify(to_dict(package))
コード例 #18
0
ファイル: apiv3_packages.py プロジェクト: schlupov/copr
def package_edit(ownername, projectname, package_name, source_type_text=None):
    copr = get_copr(ownername, projectname)
    data = rename_fields(get_form_compatible_data(preserve=["python_versions"]))
    try:
        package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
        source_type_text = source_type_text or package.source_type_text
    except IndexError:
        raise ObjectNotFound("Package {name} does not exists in copr {copr}."
                             .format(name=package_name, copr=copr.full_name))

    process_package_add_or_edit(copr, source_type_text, package=package, data=data)
    return flask.jsonify(to_dict(package))
コード例 #19
0
ファイル: coprs_packages.py プロジェクト: danvratil/copr
def process_save_package(copr, package_name, view, view_method, url_on_success):
    if flask.request.form["source_type"] == "git_and_tito":
        form = forms.PackageFormTito()
    elif flask.request.form["source_type"] == "mock_scm":
        form = forms.PackageFormMock()
    elif flask.request.form["source_type"] == "pypi":
        form = forms.PackageFormPyPI()
    else:
        raise Exception("Wrong source type")

    if form.validate_on_submit():
        if package_name:
            package = PackagesLogic.get(copr.id, package_name).first()
        else:
            package = PackagesLogic.add(flask.app.g.user, copr, form.package_name.data)

        package.source_type = helpers.BuildSourceEnum(form.source_type.data)
        package.webhook_rebuild = form.webhook_rebuild.data

        if package.source_type == helpers.BuildSourceEnum("git_and_tito"):
            package.source_json = json.dumps({
                "git_url": form.git_url.data,
                "git_branch": form.git_branch.data,
                "git_dir": form.git_directory.data,
                "tito_test": form.tito_test.data})
        elif package.source_type == helpers.BuildSourceEnum("mock_scm"):
            package.source_json = json.dumps({
                "scm_type": form.scm_type.data,
                "scm_url": form.scm_url.data,
                "scm_branch": form.scm_branch.data,
                "spec": form.spec.data})
        elif package.source_type == helpers.BuildSourceEnum("pypi"):
            package.source_json = json.dumps({
                "pypi_package_name": form.pypi_package_name.data,
                "python_versions": form.python_versions.data})

        try:
            db.session.add(package)
            db.session.commit()
        except (ActionInProgressException, InsufficientRightsException) as e:
            db.session.rollback()
            flask.flash(str(e), "error")
        else:
            flask.flash("Package successfully saved" if package_name else "New package has been created.")

        return flask.redirect(url_on_success)

    return view_method(username=copr.owner.name, coprname=copr.name,
                       package_name=package_name, source_type=form.source_type.data, form=form)
コード例 #20
0
ファイル: api_general.py プロジェクト: RadimS97/copr
def copr_reset_package(copr, package_name):
    try:
        package = PackagesLogic.get(copr.id, package_name)[0]
    except IndexError:
        raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name))

    try:
        PackagesLogic.reset_package(flask.g.user, package)
        db.session.commit()
    except InsufficientRightsException as e:
        raise LegacyApiError(str(e))

    return flask.jsonify({
        "output": "ok",
        "message": "Package's default source was successfully reseted.",
        'package': package.to_dict(),
    })
コード例 #21
0
ファイル: apiv3_packages.py プロジェクト: schlupov/copr
def package_build():
    copr = get_copr()
    data = rename_fields(get_form_compatible_data(preserve=["python_versions"]))
    form = forms.RebuildPackageFactory.create_form_cls(copr.active_chroots)(data, meta={'csrf': False})
    try:
        package = PackagesLogic.get(copr.main_dir.id, form.package_name.data)[0]
    except IndexError:
        raise ObjectNotFound("No package with name {name} in copr {copr}"
                             .format(name=form.package_name.data, copr=copr.name))
    if form.validate_on_submit():
        buildopts = {k: v for k, v in form.data.items() if k in data}
        build = PackagesLogic.build_package(flask.g.user, copr, package, form.selected_chroots,
                                            copr_dirname=form.project_dirname.data, **buildopts)
        db.session.commit()
    else:
        raise BadRequest(form.errors)
    return flask.jsonify(build_to_dict(build))
コード例 #22
0
def copr_reset_package(copr, package_name):
    try:
        package = PackagesLogic.get(copr.main_dir.id, package_name)[0]
    except IndexError:
        raise LegacyApiError(
            "No package with name {name} in copr {copr}".format(
                name=package_name, copr=copr.name))

    try:
        PackagesLogic.reset_package(flask.g.user, package)
        db.session.commit()
    except InsufficientRightsException as e:
        raise LegacyApiError(str(e))

    return flask.jsonify({
        "output": "ok",
        "message": "Package's default source was successfully reseted.",
        'package': package.to_dict(),
    })
コード例 #23
0
ファイル: api_general.py プロジェクト: bowlofeggs/copr
def copr_build_package(copr, package_name):
    form = forms.BuildFormRebuildFactory.create_form_cls(copr.active_chroots)(csrf_enabled=False)

    try:
        package = PackagesLogic.get(copr.id, package_name)[0]
    except IndexError:
        raise LegacyApiError("No package with name {name} in copr {copr}".format(name=package_name, copr=copr.name))

    if form.validate_on_submit():
        try:
            build = PackagesLogic.build_package(flask.g.user, copr, package, form.selected_chroots, **form.data)
            db.session.commit()
        except (InsufficientRightsException, ActionInProgressException, NoPackageSourceException) as e:
            raise LegacyApiError(str(e))
    else:
        raise LegacyApiError(form.errors)

    return flask.jsonify({
        "output": "ok",
        "ids": [build.id],
        "message": "Build was added to {0}.".format(copr.name)
    })
コード例 #24
0
ファイル: api_general.py プロジェクト: RadimS97/copr
def copr_edit_package(copr, package_name, source_type):
    try:
        package = PackagesLogic.get(copr.id, package_name)[0]
    except IndexError:
        raise LegacyApiError("Package {name} does not exists in copr {copr}.".format(name=package_name, copr=copr.full_name))
    return process_package_add_or_edit(copr, source_type, package=package)
コード例 #25
0
ファイル: builds_logic.py プロジェクト: schlupov/copr
    def update_state_from_dict(cls, build, upd_dict):
        """
        :param build:
        :param upd_dict:
            example:
            {
              "builds":[
               {
                 "id": 1,
                 "copr_id": 2,
                 "started_on": 1390866440
               },
               {
                 "id": 2,
                 "copr_id": 1,
                 "status": 0,
                 "chroot": "fedora-18-x86_64",
                 "result_dir": "baz",
                 "ended_on": 1390866440
               }]
            }
        """
        log.info("Updating build {} by: {}".format(build.id, upd_dict))

        # create the package if it doesn't exist
        pkg_name = upd_dict.get('pkg_name', None)
        if pkg_name:
            if not PackagesLogic.get(build.copr_dir.id, pkg_name).first():
                try:
                    package = PackagesLogic.add(
                        build.copr.user, build.copr_dir,
                        pkg_name, build.source_type, build.source_json)
                    db.session.add(package)
                    db.session.commit()
                except (IntegrityError, DuplicateException) as e:
                    app.logger.exception(e)
                    db.session.rollback()
                    return
            build.package = PackagesLogic.get(build.copr_dir.id, pkg_name).first()

        for attr in ["built_packages", "srpm_url", "pkg_version"]:
            value = upd_dict.get(attr, None)
            if value:
                setattr(build, attr, value)

        # update source build status
        if str(upd_dict.get("task_id")) == str(build.task_id):
            build.result_dir = upd_dict.get("result_dir", "")

            new_status = upd_dict.get("status")
            if new_status == StatusEnum("succeeded"):
                new_status = StatusEnum("importing")
                chroot_status=StatusEnum("waiting")
                if not build.build_chroots:
                    # create the BuildChroots from Package setting, if not
                    # already set explicitly for concrete build
                    for chroot in build.package.chroots:
                        buildchroot = models.BuildChroot(
                            build=build,
                            status=chroot_status,
                            mock_chroot=chroot,
                            git_hash=None,
                        )
                        db.session.add(buildchroot)
                else:
                    for buildchroot in build.build_chroots:
                        buildchroot.status = chroot_status
                        db.session.add(buildchroot)

            build.source_status = new_status
            if new_status == StatusEnum("failed") or \
                   new_status == StatusEnum("skipped"):
                for ch in build.build_chroots:
                    ch.status = new_status
                    ch.ended_on = upd_dict.get("ended_on") or time.time()
                    db.session.add(ch)

            if new_status == StatusEnum("failed"):
                build.fail_type = FailTypeEnum("srpm_build_error")

            cls.process_update_callback(build)
            db.session.add(build)
            return

        if "chroot" in upd_dict:
            # update respective chroot status
            for build_chroot in build.build_chroots:
                if build_chroot.name == upd_dict["chroot"]:
                    build_chroot.result_dir = upd_dict.get("result_dir", "")

                    if "status" in upd_dict and build_chroot.status not in BuildsLogic.terminal_states:
                        build_chroot.status = upd_dict["status"]

                    if upd_dict.get("status") in BuildsLogic.terminal_states:
                        build_chroot.ended_on = upd_dict.get("ended_on") or time.time()

                    if upd_dict.get("status") == StatusEnum("starting"):
                        build_chroot.started_on = upd_dict.get("started_on") or time.time()

                    db.session.add(build_chroot)

                    # If the last package of a module was successfully built,
                    # then send an action to create module repodata on backend
                    if (build.module
                            and upd_dict.get("status") == StatusEnum("succeeded")
                            and all(b.status == StatusEnum("succeeded") for b in build.module.builds)):
                        ActionsLogic.send_build_module(build.copr, build.module)

        cls.process_update_callback(build)
        db.session.add(build)
コード例 #26
0
ファイル: apiv3_packages.py プロジェクト: schlupov/copr
def package_add(ownername, projectname, package_name, source_type_text):
    copr = get_copr(ownername, projectname)
    data = rename_fields(get_form_compatible_data(preserve=["python_versions"]))
    process_package_add_or_edit(copr, source_type_text, data=data)
    package = PackagesLogic.get(copr.main_dir.id, package_name).first()
    return flask.jsonify(to_dict(package))