def get_origin_wise_metadata(config): """Method responsible for extracting metadata based on package origin.""" if config.repo_github and origin_is_github(config.repo_github): url = config.repo_github name = config.name version, version_tag = handle_gh_version(name=name, version=config.version, url=url) archive_url = generate_git_archive_tarball_url(git_url=url, git_ref=version_tag) sdist_metadata = get_sdist_metadata(sdist_url=archive_url, config=config, with_source=True) sdist_metadata["version"] = version pypi_metadata = {} elif config.from_local_sdist: sdist_metadata = get_sdist_metadata( sdist_url="", config=config, ) pypi_metadata = {} else: pypi_metadata = get_pypi_metadata(config) sdist_metadata = get_sdist_metadata( sdist_url=pypi_metadata["sdist_url"], config=config) return sdist_metadata, pypi_metadata
def parse_pkg_name_version(pkg_name: str, ) -> Tuple[str, str, Optional[str]]: origin = "" if origin_is_local_sdist(pkg_name): # Try to get package name and version from sdist archive # If the version is normalized, there should be no dash in it # Will get them from PKG-INFO later filename = Path(pkg_name).stem if filename.endswith(".tar"): filename = filename[:-4] name, _, version = filename.rpartition("-") if name == "": name = filename version = "" return "", name, version if origin_is_github(pkg_name): origin, pkg_name = pkg_name.rsplit("/", 1) origin += "/" if pkg_name.endswith(".git"): pkg_name = pkg_name[:-4] pkg = re.match(r"([a-zA-Z0-9\-_\.]+)=+([a-zA-Z0-9\-_\.]+)", pkg_name) if pkg: pkg_name = origin + pkg.group(1) version = pkg.group(2) return "", pkg_name, version return origin, pkg_name, None
def generate_recipe( self, folder_path: Union[str, Path] = ".", mantainers: Optional[List] = None, disable_extra: bool = False, ): """Write the recipe in a location. It will create a folder with the package name and the recipe will be there. :param folder_path: Path to the folder """ pkg_name = self.get_var_content(self["package"]["name"].values[0]) if origin_is_github(pkg_name): pkg_name = pkg_name.split("/")[-1] recipe_dir = Path(folder_path) / pkg_name logging.debug(f"Generating recipe on folder: {recipe_dir}") if not recipe_dir.is_dir(): recipe_dir.mkdir() recipe_path = recipe_dir / "meta.yaml" if not disable_extra: self._add_extra_section(mantainers) with recipe_path.open("w") as recipe: yaml.dump(self.get_clean_yaml(self._yaml), recipe) for file_to_recipe in self.files_to_copy: name = file_to_recipe.split(os.path.sep)[-1] if os.path.isfile(file_to_recipe): copyfile(file_to_recipe, os.path.join(recipe_dir, name))
def parse_pkg_name_version(pkg_name: str) -> Tuple[str, Optional[str]]: origin = "" if origin_is_github(pkg_name): origin, pkg_name = pkg_name.rsplit("/", 1) origin += "/" pkg = re.match(r"([a-zA-Z0-9\-_\.]+)=+([a-zA-Z0-9\-_\.]+)", pkg_name) if pkg: pkg_name = origin + pkg.group(1) version = pkg.group(2) return pkg_name, version return origin + pkg_name, None
def generate_recipes_from_list(list_pkgs, args): for pkg_name in list_pkgs: logging.debug(f"Starting grayskull for pkg: {pkg_name}") from_local_sdist = origin_is_local_sdist(pkg_name) if origin_is_github(pkg_name): pypi_label = "" elif from_local_sdist: pypi_label = " (local)" else: pypi_label = " (pypi)" print_msg(f"{Fore.GREEN}\n\n" f"#### Initializing recipe for " f"{Fore.BLUE}{pkg_name}{pypi_label} {Fore.GREEN}####\n") is_pkg_file = Path(pkg_name).is_file() and (not from_local_sdist) if is_pkg_file: args.output = pkg_name try: recipe, config = create_python_recipe( pkg_name, is_strict_cf=args.is_strict_conda_forge, download=args.download, url_pypi_metadata=args.url_pypi_metadata, sections_populate=args.sections_populate, from_local_sdist=from_local_sdist, extras_require_test=args.extras_require_test, ) except requests.exceptions.HTTPError as err: print_msg( f"{Fore.RED}Package seems to be missing.\nException: {err}\n\n" ) continue if args.sections_populate is None or "extra" in args.sections_populate: add_extra_section(recipe, args.maintainers) generate_recipe(recipe, config, args.output) print_msg(f"\n{Fore.GREEN}#### Recipe generated on " f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n") if args.is_recursive and config.missing_deps: generate_recipes_from_list(config.missing_deps, args)
def main(args=None): if not args: args = sys.argv[1:] if sys.argv[1:] else ["--help"] parser = argparse.ArgumentParser( description="Grayskull - Conda recipe generator") pypi_parser = parser.add_subparsers( help="Options to generate PyPI recipes") pypi_cmds = pypi_parser.add_parser("pypi", help="Generate recipes based on PyPI") pypi_cmds.add_argument("pypi_packages", nargs="+", help="Specify the PyPI packages name.", default=[]) pypi_cmds.add_argument( "--download", "-d", dest="download", action="store_true", default=False, help="Download the sdist package and PyPI information in the same folder" " the recipe is located.", ) pypi_cmds.add_argument( "--maintainers", "-m", dest="maintainers", nargs="+", help="List of maintainers which will be added to the recipe.", ) parser.add_argument( "--version", "-v", default=False, action="store_true", dest="version", help="Print Grayskull version and exit", ) parser.add_argument( "--heman", "--shera", default=False, action="store_true", dest="grayskull_power", help=argparse.SUPPRESS, ) pypi_cmds.add_argument( "--output", "-o", dest="output", default=".", help="Path to where the recipe will be created", ) pypi_cmds.add_argument( "--stdout", dest="stdout", default=True, help="Disable or enable stdout, if it is False, Grayskull" " will disable the prints. Default is True", ) pypi_cmds.add_argument( "--list-missing-deps", default=False, action="store_true", dest="list_missing_deps", help= "After the execution Grayskull will print all the missing dependencies.", ) pypi_cmds.add_argument( "--strict-conda-forge", default=False, action="store_true", dest="is_strict_conda_forge", help="It will generate the recipes strict for the conda-forge channel.", ) args = parser.parse_args(args) if args.version: print(grayskull.__version__) return logging.debug(f"All arguments received: args: {args}") if args.grayskull_power: print(f"{Fore.BLUE}By the power of Grayskull...\n" f"{Style.BRIGHT}I have the power!") return CLIConfig().stdout = args.stdout CLIConfig().list_missing_deps = args.list_missing_deps print_msg(Style.RESET_ALL) print_msg(clear_screen()) for pkg_name in args.pypi_packages: logging.debug(f"Starting grayskull for pkg: {pkg_name}") pypi_label = "" if origin_is_github(pkg_name) else " (pypi)" print_msg(f"{Fore.GREEN}\n\n" f"#### Initializing recipe for " f"{Fore.BLUE}{pkg_name}{pypi_label} {Fore.GREEN}####\n") pkg_name, pkg_version = parse_pkg_name_version(pkg_name) try: recipe = GrayskullFactory.create_recipe( "pypi", pkg_name, pkg_version, download=args.download, is_strict_cf=args.is_strict_conda_forge, ) except requests.exceptions.HTTPError as err: print_msg( f"{Fore.RED}Package seems to be missing on pypi.\nException: {err}\n\n" ) continue recipe.generate_recipe(args.output, mantainers=args.maintainers) print_msg(f"\n{Fore.GREEN}#### Recipe generated on " f"{os.path.realpath(args.output)} for {pkg_name} ####\n")