Como copiar pacotes de uma máquina on-line para uma máquina off-line

0

Eu tenho uma máquina que está online. Tem a configuração que eu preciso em uma máquina que não está online. Idealmente, haveria uma maneira trivial de copiar / clonar os pacotes instalados.

Infelizmente, eu não achei isso trivial. Eu tentei várias soluções propostas:

  • crie meu próprio repositório: link
    • Não consegui que a máquina de destino aceitasse minha estrutura de pastas; também exigiu o download do upstream que não aproveita minha máquina "em funcionamento"
  • siga uma série de respostas em Como posso instalar software ou pacotes sem Internet (offline)?
    • keryx (falha)
    • / var / cache (não contém todos os pacotes que eu instalei)
    • aptoncd - fica bem perto ... mas ainda preciso de uma pasta com TODOS os pacotes
por mike 21.12.2016 / 20:12

1 resposta

2

Eu escrevi um utilitário python simples para usar apt list --installed e apt download <pkg> para criar a pasta "cache" que eu preciso usar com aptoncd . Ele também atualizará a pasta de cache sem baixar novamente nada.

USAGE : <cmd> <cache_dir> [optional_regex_pkgs_to_ignore|...]

  • cmd - > o nome do arquivo em que você salva este script
  • cache dir - > pasta para salvar a saída em cache. Se ela contiver .debs existentes, eles não serão baixados novamente. Uma boa localização é /var/cache/apt/archive no ubuntu16.04 (se você tiver sudo)
  • pkgs_to_ignore - > lista separada por espaços de pacotes a serem ignorados, no formato regex. Por exemplo, 'google.*' irá ignorar googleearth e googleearth-package . Observe o ' versus " - isso evita que o bash expanda o .* no regex.
    • Necessário porque essa abordagem apt não funcionará para o programa raro instalado totalmente fora de apt , por exemplo, o Google-Earth para mim.

Espero que isso ajude alguém. Parecia um pouco diferente das questões (numerosas) existentes. Observe que isso não tenta reinventar a roda do gerenciador de pacotes; ele não se importa com as atualizações da versão do pacote se o nome não estiver alterado. Se isso for importante, apenas aponte para uma pasta de cache diferente e ele fará o download novamente de tudo .

 #!/usr/bin/python3

'''
program to make a flat folder of all packages your system uses:
    - pulls all installed packages: 
        -'apt list --installed' 
    - downloads any packages/.deb's that are not in your cache folder
        - 'apt download <package>'

This was created to facilitate setting up / updating an off-line
machine based on an existing machine (presumably online) where you 
have the programs you need set up.

the easiest way to get the packages over to the offline machine is via
tool 'aptoncd'  ("sudo apt install aptoncd"), which will make an iso of
your packages, and optionally auto-launch a CD writer.

--- USAGE ---
<cmd> <working_dir> [ignore-pkg-globs|...]
'''

import sys
from os import path
from glob import glob
import os
import subprocess
import re

NARGS=2
DEBUG=0

def get_all_installed_packages():
    print("==== asking apt for a list of all installed packaged ====")
    result = subprocess.run(["apt", "list", "--installed"],
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            universal_newlines=True)
    if not 0 == result.returncode:
        msg = "apt list call failed with " + str(result.returncode)
        print(msg)
        raise RuntimeError(msg)

    split_re = re.compile(r"(.*)/(.*)(\[.*\])")
    packages = []
    for line in result.stdout.split(os.linesep):
        contents = split_re.match(line)
        if contents:
            groups = [item.strip() for item in contents.groups()]
            if DEBUG:
                print("found pkg: <{0}>  -- {1}|{2}".format(*groups))
            packages.append(groups[0])
        else:
            print("IGNORING <" + line + ">:")

    if len(packages) < 20:
        msg = "ERROR: you only found <{0}> packages, this seems wrong!".format(len(packages))
        print(msg)
        raise RuntimeError(msg)

    print("==== found {0} installed packages! ====".format(len(packages)))

    return packages

def download_packages(pkg_list, ignore_pkgs):
    if not pkg_list:
        print(" ==== nothing to download! ====")
        return
    print("==== downloading the following (missing) packages: ====")
    print(" | ".join(pkg_list))

    for pkg in pkg_list:
        if DEBUG:
            print("processing package <{0}>".format(pkg))
        ignore = 0
        for pattern in ignore_pkgs:
            if pattern.match(pkg):
                if DEBUG:
                    print("matched <{0}> to ignore pattern <{1}>".format(
                           pkg, pattern.pattern))
                ignore += 1

        if ignore:
            print("---- ignoring {0} {1} ----".format(pkg, ignore))
        else:
            print("---- downloading {0} ----".format(pkg))
            result = subprocess.run(["apt", "download", pkg],
                                stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT,
                                universal_newlines=True)
            if 0 != result.returncode:
                msg = "ERROR: run apt download failed with <{0}>. "
                msg += "output=\n{1}\n------\n\n".format(
                    result.returncode, result.stdout)
                raise RuntimeError(msg)

    print("==== DONE DOWNLOADING ====")

def main():
    if len(sys.argv) < NARGS:
        print(__doc__)
        msg = "ERROR, requires >= {0} args!".format(NARGS-1)
        print(msg)
        sys.exit(1)

    print("args=" + ";".join(sys.argv))

    ignore_pkgs_re = [re.compile(x) for x in sys.argv[2:]]
    package_dir = path.abspath(path.normpath(sys.argv[1]))

    if not path.isdir(package_dir):
        msg = "ERROR: path <{0}> is not a dir!".format(package_dir)
        print(msg)
        raise ValueError(msg)

    save_cwd = os.getcwd()
    try:
        os.chdir(package_dir)
        existing_debs = glob("*deb")
        for deb in existing_debs:
            if DEBUG > 1:
                print("found deb = " + deb)
            pass

        installed_packages = get_all_installed_packages()

        to_download = []
        for pkg in installed_packages:
            matching_deb = [x for x in existing_debs if x.startswith(pkg)]
            if matching_deb:
                if DEBUG:
                    print("found existing match for <{0}> with <{1}>".format(
                          pkg, "|".join(matching_deb)))
            else:
                if DEBUG:
                    print("no existing cache deb found for pkg <" + pkg + ">")
                to_download.append(pkg)

        download_packages(to_download, ignore_pkgs_re)

    finally:
        os.chdir(save_cwd)

if __name__ == "__main__":
    print("running as main")
    main()
    
por mike 21.12.2016 / 20:18