示例#1
0
def _install_from_github(package_id: str) -> str:
    try:
        path, version = package_id.split("@")
        org, repo = path.split("/")
    except ValueError:
        raise ValueError(
            "Invalid package ID. Must be given as [ORG]/[REPO]@[VERSION]"
            "\ne.g. 'OpenZeppelin/[email protected]'") from None

    base_install_path = _get_data_folder().joinpath("packages")
    install_path = base_install_path.joinpath(f"{org}")
    install_path.mkdir(exist_ok=True)
    install_path = install_path.joinpath(f"{repo}@{version}")
    if install_path.exists():
        raise FileExistsError("Package is aleady installed")

    headers = REQUEST_HEADERS.copy()
    headers.update(_maybe_retrieve_github_auth())

    if re.match(r"^[0-9a-f]+$", version):
        download_url = f"https://api.github.com/repos/{org}/{repo}/zipball/{version}"
    else:
        download_url = _get_download_url_from_tag(org, repo, version, headers)

    existing = list(install_path.parent.iterdir())
    _stream_download(download_url, str(install_path.parent), headers)

    installed = next(i for i in install_path.parent.iterdir()
                     if i not in existing)
    shutil.move(installed, install_path)

    try:
        if not install_path.joinpath("brownie-config.yaml").exists():
            brownie_config: Dict = {"project_structure": {}}

            contract_paths = set(
                i.relative_to(install_path).parts[0]
                for i in install_path.glob("**/*.sol"))
            contract_paths.update(
                i.relative_to(install_path).parts[0]
                for i in install_path.glob("**/*.vy"))
            if not contract_paths:
                raise InvalidPackage(
                    f"{package_id} does not contain any .sol or .vy files")
            if install_path.joinpath("contracts").is_dir():
                brownie_config["project_structure"]["contracts"] = "contracts"
            elif len(contract_paths) == 1:
                brownie_config["project_structure"][
                    "contracts"] = contract_paths.pop()
            else:
                raise InvalidPackage(
                    f"{package_id} has no `contracts/` subdirectory, and "
                    "multiple directories containing source files")

            with install_path.joinpath("brownie-config.yaml").open("w") as fp:
                yaml.dump(brownie_config, fp)

        project = load(install_path)
        project.close()
    except InvalidPackage:
        shutil.rmtree(install_path)
        raise
    except Exception as e:
        notify(
            "WARNING",
            f"Unable to compile {package_id} due to a {type(e).__name__} - you may still be able to"
            " import sources from the package, but will be unable to load the package directly.\n",
        )

    return f"{org}/{repo}@{version}"
示例#2
0
def _install_from_github(package_id: str) -> str:
    try:
        path, version = package_id.split("@")
        org, repo = path.split("/")
    except ValueError:
        raise ValueError(
            "Invalid package ID. Must be given as [ORG]/[REPO]@[VERSION]"
            "\ne.g. 'OpenZeppelin/[email protected]'") from None

    base_install_path = _get_data_folder().joinpath("packages")
    install_path = base_install_path.joinpath(f"{org}")
    install_path.mkdir(exist_ok=True)
    install_path = install_path.joinpath(f"{repo}@{version}")
    if install_path.exists():
        raise FileExistsError("Package is aleady installed")

    headers = REQUEST_HEADERS.copy()
    if os.getenv("GITHUB_TOKEN"):
        auth = b64encode(os.environ["GITHUB_TOKEN"].encode()).decode()
        headers.update({"Authorization": "Basic {}".format(auth)})

    response = requests.get(
        f"https://api.github.com/repos/{org}/{repo}/tags?per_page=100",
        headers=headers)
    if response.status_code != 200:
        msg = "Status {} when getting package versions from Github: '{}'".format(
            response.status_code,
            response.json()["message"])
        if response.status_code == 403:
            msg += (
                "\n\nIf this issue persists, generate a Github API token and store"
                " it as the environment variable `GITHUB_TOKEN`:\n"
                "https://github.blog/2013-05-16-personal-api-tokens/")
        raise ConnectionError(msg)

    data = response.json()
    if not data:
        raise ValueError("Github repository has no tags set")
    org, repo = data[0]["zipball_url"].split("/")[3:5]
    tags = [i["name"].lstrip("v") for i in data]
    if version not in tags:
        raise ValueError(
            "Invalid version for this package. Available versions are:\n" +
            ", ".join(tags)) from None

    download_url = next(i["zipball_url"] for i in data
                        if i["name"].lstrip("v") == version)

    existing = list(install_path.parent.iterdir())
    _stream_download(download_url, str(install_path.parent))

    installed = next(i for i in install_path.parent.iterdir()
                     if i not in existing)
    shutil.move(installed, install_path)

    try:
        if not install_path.joinpath("brownie-config.yaml").exists():
            brownie_config: Dict = {"project_structure": {}}

            contract_paths = set(
                i.relative_to(install_path).parts[0]
                for i in install_path.glob("**/*.sol"))
            contract_paths.update(
                i.relative_to(install_path).parts[0]
                for i in install_path.glob("**/*.vy"))
            if not contract_paths:
                raise InvalidPackage(
                    f"{package_id} does not contain any .sol or .vy files")
            if install_path.joinpath("contracts").is_dir():
                brownie_config["project_structure"]["contracts"] = "contracts"
            elif len(contract_paths) == 1:
                brownie_config["project_structure"][
                    "contracts"] = contract_paths.pop()
            else:
                raise InvalidPackage(
                    f"{package_id} has no `contracts/` subdirectory, and "
                    "multiple directories containing source files")

            with install_path.joinpath("brownie-config.yaml").open("w") as fp:
                yaml.dump(brownie_config, fp)

        project = load(install_path)
        project.close()
    except InvalidPackage:
        shutil.rmtree(install_path)
        raise
    except Exception as e:
        notify(
            "WARNING",
            f"Unable to compile {package_id} due to a {type(e).__name__} - you may still be able to"
            " import sources from the package, but will be unable to load the package directly.\n",
        )

    return f"{org}/{repo}@{version}"
示例#3
0
def _install_from_github(package_id: str) -> str:
    try:
        path, version = package_id.split("@")
        org, repo = path.split("/")
    except ValueError:
        raise ValueError(
            "Invalid package ID. Must be given as [ORG]/[REPO]@[VERSION]"
            "\ne.g. 'OpenZeppelin/[email protected]'") from None

    install_path = _get_data_folder().joinpath(f"packages/{org}")
    install_path.mkdir(exist_ok=True)
    install_path = install_path.joinpath(f"{repo}@{version}")
    if install_path.exists():
        raise FileExistsError("Package is aleady installed")

    headers: Dict = {}
    if os.getenv("GITHUB_TOKEN"):
        auth = b64encode(os.environ["GITHUB_TOKEN"].encode()).decode()
        headers = {"Authorization": "Basic {}".format(auth)}

    response = requests.get(
        f"https://api.github.com/repos/{org}/{repo}/tags?per_page=100",
        headers=headers)
    if response.status_code != 200:
        msg = "Status {} when getting package versions from Github: '{}'".format(
            response.status_code,
            response.json()["message"])
        if response.status_code == 403:
            msg += (
                "\n\nIf this issue persists, generate a Github API token and store"
                " it as the environment variable `GITHUB_TOKEN`:\n"
                "https://github.blog/2013-05-16-personal-api-tokens/")
        raise ConnectionError(msg)

    data = response.json()
    if not data:
        raise ValueError("Github repository has no tags set")
    org, repo = data[0]["zipball_url"].split("/")[3:5]
    tags = [i["name"].lstrip("v") for i in data]
    if version not in tags:
        raise ValueError(
            "Invalid version for this package. Available versions are:\n" +
            ", ".join(tags)) from None

    download_url = next(i["zipball_url"] for i in data
                        if i["name"].lstrip("v") == version)

    existing = list(install_path.parent.iterdir())
    _stream_download(download_url, str(install_path.parent))

    installed = next(i for i in install_path.parent.iterdir()
                     if i not in existing)
    shutil.move(installed, install_path)

    try:
        if not install_path.joinpath("contracts").exists():
            raise Exception
        new(str(install_path), ignore_existing=True)
        project = load(install_path)
        project.close()
    except Exception:
        shutil.rmtree(install_path)
        raise InvalidPackage(
            f"{package_id} cannot be interpreted as a Brownie project")

    return f"{org}/{repo}@{version}"