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
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()
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
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
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