Beispiel #1
0
def save_file(file, pkg_name, version):
    """
    Parameters
    ----------
    file : :class:`werkzeug.datastructures.FileStorage` object
        The file as retrieved by Flask.
    pkg_name : str
    version : str

    Returns:
    --------
    local_path : :class:`pathlib.Path`
        The path to the saved file.
    """
    # Save the package file to the local package dir. Thus far it's
    # just been floating around in magic Flask land.
    server_path = Path(current_app.config['SERVER_PATH'])
    package_dir = Path(current_app.config['PACKAGE_DIR'])
    local_path = server_path / package_dir
    local_path = local_path / pkg_name / (version + ".nupkg")

    # Check if the package's directory already exists. Create if needed.
    create_parent_dirs(local_path)

    logger.debug("Saving uploaded file to filesystem.")
    try:
        file.save(str(local_path))
    except Exception as err:  # TODO: specify exceptions
        logger.error("Unknown exception: %s" % err)
        raise err
    else:
        logger.info("Succesfully saved package to '%s'" % str(local_path))

    return local_path
Beispiel #2
0
def delete_version(session, package_name, version):
    """

    Parameters
    ----------
    session : :class:`sqlalchemy.orm.session.Session`
    package_name : str
        The NuGet name of the package - the "id" tag in the NuSpec file.
    version : str
    """
    msg = "db.delete_version({}, {})"
    logger.debug(msg.format(package_name, version))
    sql = (session.query(Version).join(Package).filter(
        Package.name == package_name).filter(Version.version == version))
    version = sql.one()
    pkg = version.package

    session.delete(version)

    # update the Package.latest_version value, or delete the Package
    versions = (session.query(Version).join(Package).filter(
        Package.name == package_name)).all()
    if len(versions) > 0:
        pkg.latest_version = max(v.version for v in versions)
    else:
        logger.info("No more versions exist. Deleting package %s" % pkg)
        session.delete(pkg)
    session.commit()
Beispiel #3
0
def delete(package=None, version=None):
    """
    Used by `nuget delete`.
    """
    logger.debug("Route: /delete")
    if not core.require_auth(request.headers):
        return "api_error: Missing or Invalid API key", 401  # TODO

    if package is not None:
        pkg_name = package
    else:
        pkg_name = request.args.get('id')

    if version is None:
        version = request.args.get('version')
    path = core.get_package_path(pkg_name, version)
    path = Path(current_app.config['SERVER_PATH']
                ) / current_app.config['PACKAGE_DIR'] / path

    if path.exists():
        path.unlink()

    try:
        db.delete_version(session, pkg_name, version)
    except NoResultFound:
        msg = "Version '{}' of Package '{}' was not found."
        return msg.format(pkg_name, version), 404

    logger.info("Sucessfully deleted package %s version %s." %
                (pkg_name, version))

    return '', 204
Beispiel #4
0
def find_by_pkg_name(session, package_name, version=None):
    """
    Find a package by name. If version is `None`, returns all versions.

    Parameters
    ----------
    session : :class:`sqlalchemy.orm.session.Session`
    package_name : str
        The NuGet name of the package - the "id" tag in the NuSpec file.
    version : str
        The version of the package to download. If `None`, then return all
        versions.

    Returns
    -------
    results : list of :class:`Version`
    """
    logger.debug("db.find_by_pkg_name('%s', version='%s')" %
                 (package_name, version))
    query = (session.query(Version).join(Package).filter(
        Package.name == package_name))

    stmt = query.statement.compile(dialect=sqlite.dialect(),
                                   compile_kwargs={"literal_binds": True})
    logger.debug(stmt)

    if version:
        query = query.filter(Version.version == version)
    query.order_by(desc(Version.version))

    results = query.all()
    logger.info("Found %d results." % len(results))
    logger.debug(results)

    return results
Beispiel #5
0
def push():
    """
    Used by `nuget push`.
    """
    logger.debug("push()")
    logger.debug("  args: {}".format(request.args))
    logger.debug("  header: {}".format(request.headers))
    if not core.require_auth(request.headers):
        return "api_error: Missing or Invalid API key", 401

    logger.debug("Checking for uploaded file.")
    if 'package' not in request.files:
        logger.error("Package file was not uploaded.")
        return "error: File not uploaded", 409
    file = request.files['package']

    # Save the file to a temporary location
    file = core.save_file(file, "_temp", str(uuid4()))

    # Open the zip file that was sent and extract out the .nuspec file."
    try:
        nuspec = core.extract_nuspec(file)
    except Exception as err:
        logger.error("Exception: %s" % err)
        return "api_error: Zero or multiple nuspec files found", 400

    # The NuSpec XML file uses namespaces.
    ns = {'nuspec': core.extract_namespace(nuspec)}

    # Make sure both the ID and the version are provided in the .nuspec file.
    try:
        metadata, pkg_name, version = core.parse_nuspec(nuspec, ns)
    except ApiException as err:
        return str(err), 400
    except Exception as err:
        logger.error(err)
        return str(err), 400

    valid_id = re.compile('^[A-Z0-9\.\~\+\_\-]+$', re.IGNORECASE)

    # Make sure that the ID and version are sane
    if not re.match(valid_id, pkg_name) or not re.match(valid_id, version):
        logger.error("Invalid ID or version.")
        return "api_error: Invlaid ID or Version", 400

    # and that we don't already have that ID+version in our database
    if db.validate_id_and_version(session, pkg_name, version):
        logger.error("Package %s version %s already exists" %
                     (pkg_name, version))
        return "api_error: Package version already exists", 409

    # Hash the uploaded file and encode the hash in Base64. For some reason.
    try:
        # rename our file.
        # Check if the package's directory already exists. Create if needed.
        new = file.parent.parent / pkg_name / (version + ".nupkg")
        core.create_parent_dirs(new)
        logger.debug("Renaming %s to %s" % (str(file), new))
        file.rename(new)
        hash_, filesize = core.hash_and_encode_file(str(new))
    except Exception as err:
        logger.error("Exception: %s" % err)
        return "api_error: Unable to save file", 500

    try:
        dependencies = core.determine_dependencies(metadata, ns)
    except Exception as err:
        logger.error("Exception: %s" % err)
        return "api_error: Unable to parse dependencies.", 400

    logger.debug(dependencies)

    # and finaly, update our database.
    logger.debug("Updating database entries.")

    db.insert_or_update_package(session,
                                package_name=pkg_name,
                                title=et_to_str(
                                    metadata.find('nuspec:title', ns)),
                                latest_version=version)
    pkg_id = (session.query(
        db.Package).filter(db.Package.name == pkg_name).one()).package_id
    logger.debug("package_id = %d" % pkg_id)
    db.insert_version(
        session,
        authors=et_to_str(metadata.find('nuspec:authors', ns)),
        copyright_=et_to_str(metadata.find('nuspec:copyright', ns)),
        dependencies=dependencies,
        description=et_to_str(metadata.find('nuspec:description', ns)),
        package_hash=hash_,
        package_hash_algorithm='SHA512',
        package_size=filesize,
        icon_url=et_to_str(metadata.find('nuspec:iconUrl', ns)),
        is_prerelease='-' in version,
        license_url=et_to_str(metadata.find('nuspec:licenseUrl', ns)),
        owners=et_to_str(metadata.find('nuspec:owners', ns)),
        package_id=pkg_id,
        project_url=et_to_str(metadata.find('nuspec:projectUrl', ns)),
        release_notes=et_to_str(metadata.find('nuspec:releaseNotes', ns)),
        require_license_acceptance=et_to_str(
            metadata.find('nuspec:requireLicenseAcceptance', ns)) == 'true',
        tags=et_to_str(metadata.find('nuspec:tags', ns)),
        title=et_to_str(metadata.find('nuspec:id', ns)),
        version=version,
    )

    logger.info(
        "Sucessfully updated database entries for package %s version %s." %
        (pkg_name, version))

    resp = make_response('', 201)
    return resp