我有一台在线的机器。它有我在不在线的机器上需要的设置。理想情况下,应该有一种简单的方法来复制/克隆已安装的软件包。
唉,我发现这并非易事。我尝试了几种建议的解决方案:
- 建立我自己的存储库:https://ubuntuforums.org/showthread.php?t=352460
- 我无法让目标机器接受我的文件夹结构;还需要从上游下载,但无法利用我的“工作”机器
- 关注以下几个答案如何在没有互联网(离线)的情况下安装软件或软件包?
- keryx(崩溃)
- /var/cache(不包含我安装的所有软件包)
- aptoncd - 非常接近...但我仍然需要一个包含所有包的文件夹
答案1
我编写了一个简单的python实用程序来使用apt list --installed
并apt download <pkg>
创建我需要使用的“缓存”文件夹aptoncd
。它还将更新缓存文件夹而无需重新下载任何内容。
用法:<cmd> <cache_dir> [optional_regex_pkgs_to_ignore|...]
cmd
--> 保存此脚本的文件名cache dir
--> 文件夹用于保存缓存的输出。如果它包含现有的 .debs,则不会重新下载它们。一个好的位置是/var/cache/apt/archive
ubuntu16.04(如果您有 sudo)pkgs_to_ignore
--> 以正则表达式格式列出要忽略的软件包,并以空格分隔。例如,'google.*'
将跳过googleearth
和googleearth-package
。请注意'
versus"
- 这会阻止 bash.*
在正则表达式中扩展 。- 这是必要的,因为这种
apt
方法不适用于完全在外部安装的罕见程序apt
,例如对我来说是 Google-Earth。
- 这是必要的,因为这种
希望这对某些人有帮助。似乎与现有的(众多)问题略有不同。请注意,这并不是试图重新发明包管理器轮子;如果名称不变,它不关心包版本更新。如果这很重要,只需将其指向不同的缓存文件夹,它就会重新下载一切。
#!/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()