코드

import yaml
import subprocess
import sys
import os
import requests

# YAML 파일을 읽는 함수
def load_config(config_file):
    with open(config_file, 'r') as file:
        return yaml.safe_load(file)

# requirements.txt에서 패키지 목록을 읽는 함수
def load_requirements(requirements_file):
    with open(requirements_file, 'r') as file:
        return [line.strip() for line in file.readlines() if line.strip()]

# 플랫폼 및 아키텍처 매핑
def get_platform_string(os_name, architecture):
    platform_mapping = {
        'windows': {
            'amd64': 'win_amd64',
            'arm': 'win_arm64',
        },
        'linux': {
            'amd64': 'manylinux2014_x86_64',
            'arm': 'manylinux2014_aarch64',
        },
        'macosx': {
            'amd64': 'macosx_10_9_x86_64',
            'arm': 'macosx_11_0_arm64',
        }
    }
    return platform_mapping.get(os_name.lower(), {}).get(architecture.lower(), None)

# PyPI API를 사용해 패키지의 모든 버전을 조회하는 함수
def get_all_versions(package_name):
    url = f"https://pypi.org/pypi/{package_name}/json"
    response = requests.get(url)
    
    if response.status_code == 200:
        data = response.json()
        return list(data['releases'].keys())
    else:
        print(f"Failed to fetch versions for package {package_name}")
        return []

# pip download 명령어를 생성하는 함수
def create_pip_download_cmd(package, version, config):
    cmd = [sys.executable, '-m', 'pip', 'download', '--prefer-binary', '--no-deps', '--no-build-isolation']
    
    # 설정에서 레포지토리 주소 추가
    if 'repository' in config:
        cmd += ['-i', config['repository']]
    
    # 파이썬 버전 설정 (문자열로 변환)
    if 'python_version' in config:
        cmd += ['--python-version', str(config['python_version'])]

    # 플랫폼 설정
    platform_string = get_platform_string(config.get('os', ''), config.get('architecture', ''))
    if platform_string:
        cmd += ['--platform', platform_string]
    else:
        print(f"Unsupported OS or architecture: {config.get('os')}, {config.get('architecture')}")
        return None

    # 다운로드 경로 설정
    if 'download_path' in config:
        cmd += ['-d', config['download_path']]
    
    # 버전이 있을 경우, 패키지명에 버전을 추가
    if version:
        package_with_version = f"{package}=={version}"
    else:
        package_with_version = package
    
    cmd.append(package_with_version)
    
    return cmd


# 패키지를 다운로드하는 함수
def download_package(package_line, config):
    try:
        ignore_versions = config.get('ignore_versions', False)
        
        # 패키지 이름과 버전 분리
        if '==' in package_line:
            package_name, specified_version = package_line.split('==', 1)
        else:
            package_name = package_line
            specified_version = None
        
        # ignore_versions가 True일 경우 모든 버전을 조회하고 각각 다운로드
        if ignore_versions:
            all_versions = get_all_versions(package_name)
            if not all_versions:
                print(f"No versions found for {package_name}")
                return
            for version in all_versions:
                print(f"Downloading {package_name}=={version}")
                cmd = create_pip_download_cmd(package_name, version, config)
                if cmd:
                    result = subprocess.run(cmd)
                    if result.returncode == 0:
                        print(f"Downloaded {package_name}=={version}")
                    else:
                        print(f"Failed to download {package_name}=={version}. Skipping...")
        else:
            # 기존 동작 유지
            package_with_version = package_line
            cmd = create_pip_download_cmd(package_with_version, None, config)
            if cmd:
                subprocess.run(cmd, check=True)
                print(f"Downloaded {package_with_version}")
    except subprocess.CalledProcessError:
        print(f"Failed to download {package_line}. Skipping...")

# 다운로드 경로가 없으면 생성하는 함수
def ensure_download_path(config):
    download_path = config.get('download_path', './downloads')
    if not os.path.exists(download_path):
        os.makedirs(download_path)
        print(f"Created download path: {download_path}")

# 메인 실행 함수
def main():
    # 설정 파일 및 requirements.txt 파일 경로
    config_file = 'config.yaml'
    requirements_file = 'requirements.txt'
    
    # 설정 로드
    config = load_config(config_file)
    
    # 다운로드 경로 확인 및 생성
    ensure_download_path(config)
    
    # requirements.txt 파일에서 패키지 목록 로드
    packages = load_requirements(requirements_file)
    
    # 패키지 다운로드 실행
    for package_line in packages:
        download_package(package_line, config)

if __name__ == "__main__":
    main()

설정파일 예시(config.yaml)

repository: https://pypi.org/simple
python_version: 3.8
os: windows  # windows or linux
architecture: amd64  # amd64 or arm
download_path: ./downloads  # 패키지 다운로드 경로
ignore_versions: true # true시 모든 버전 설치, false시 지정 버전 설치(지정 버전 없으면 최신 버전)

패키지 리스트 예시(requirements.txt)

tqdm==버전
pyyaml

Deprecated

import yaml
import subprocess
import sys
import os

# YAML 파일을 읽는 함수
def load_config(config_file):
    with open(config_file, 'r') as file:
        return yaml.safe_load(file)

# requirements.txt에서 패키지 목록을 읽는 함수
def load_requirements(requirements_file):
    with open(requirements_file, 'r') as file:
        return [line.strip() for line in file.readlines() if line.strip()]

# 플랫폼 및 아키텍처 매핑
def get_platform_string(os_name, architecture):
    platform_mapping = {
        'windows': {
            'amd64': 'win_amd64',
            'arm': 'win_arm64',
        },
        'linux': {
            'amd64': 'manylinux2014_x86_64',
            'arm': 'manylinux2014_aarch64',
        },
        'macosx': {
            'amd64': 'macosx_10_9_x86_64',
            'arm': 'macosx_11_0_arm64',
        }
    }
    return platform_mapping.get(os_name.lower(), {}).get(architecture.lower(), None)

# pip download 명령어를 생성하는 함수
def create_pip_download_cmd(package, config):
    cmd = [sys.executable, '-m', 'pip', 'download', '--prefer-binary', '--no-deps']  # --no-deps 추가
    
    # 설정에서 레포지토리 주소 추가
    if 'repository' in config:
        cmd += ['-i', config['repository']]
    
    # 파이썬 버전 설정 (문자열로 변환)
    if 'python_version' in config:
        cmd += ['--python-version', str(config['python_version'])]

    # 플랫폼 설정
    platform_string = get_platform_string(config.get('os', ''), config.get('architecture', ''))
    if platform_string:
        cmd += ['--platform', platform_string]
    else:
        print(f"Unsupported OS or architecture: {config.get('os')}, {config.get('architecture')}")
        return None

    # 다운로드 경로 설정
    if 'download_path' in config:
        cmd += ['-d', config['download_path']]
    
    # 패키지 이름 추가 (버전이 있는 경우 포함)
    cmd.append(package)
    
    return cmd


# 패키지를 다운로드하는 함수
def download_package(package, config):
    try:
        # 패키지 다운로드 명령어 생성
        cmd = create_pip_download_cmd(package, config)
        if cmd is None:
            print(f"Skipping {package} due to unsupported platform or architecture.")
            return
        
        print(f"Downloading {package} with command: {' '.join(cmd)}")
        
        # 패키지 다운로드 실행
        subprocess.run(cmd, check=True)
        print(f"{package} downloaded successfully.")
    
    except subprocess.CalledProcessError:
        print(f"Failed to download {package}. Skipping...")

# 다운로드 경로가 없으면 생성하는 함수
def ensure_download_path(config):
    download_path = config.get('download_path', './downloads')
    if not os.path.exists(download_path):
        os.makedirs(download_path)
        print(f"Created download path: {download_path}")

# 메인 실행 함수
def main():
    # 설정 파일 및 requirements.txt 파일 경로
    config_file = 'config.yaml'
    requirements_file = 'requirements.txt'
    
    # 설정 로드
    config = load_config(config_file)
    
    # 다운로드 경로 확인 및 생성
    ensure_download_path(config)
    
    # requirements.txt 파일에서 패키지 목록 로드
    packages = load_requirements(requirements_file)
    
    # 패키지 다운로드 실행
    for package in packages:
        download_package(package, config)

if __name__ == "__main__":
    main()
profile
내가 뭘 해봤는지는 시리즈 탭에 다 정리해뒀슈

0개의 댓글