/
apt-clone
executable file
·148 lines (137 loc) · 6.23 KB
/
apt-clone
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/python3
# Copyright (C) 2011 Canonical
#
# Authors:
# Michael Vogt
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; version 3.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from __future__ import print_function
import argparse
import os
import sys
from apt_clone import AptClone
if __name__ == "__main__":
# command line parser
parser = argparse.ArgumentParser(description="Clone/restore package info")
parser.add_argument("--debug", action="store_true", default=False,
help="enable debug output")
subparser = parser.add_subparsers(title="Commands")
# info
command = subparser.add_parser(
"info",
help="info about a apt-clone archive")
command.add_argument("source")
command.set_defaults(command="info")
# clone
command = subparser.add_parser(
"clone",
help="create a clone-file into <destination>. An alternative source dir can be specified with --source.")
command.add_argument("--source", default="/",
help="The source dir of the system or chroot, usually '/'")
command.add_argument("destination")
command.add_argument("--with-dpkg-repack",
action="store_true", default=False,
help="add no longer downloadable package to the state bundle (that can make it rather big)")
command.add_argument("--with-dpkg-status",
action="store_true", default=False,
help="include full copy of dpkg-status file, mostly useful for debugging")
command.add_argument("--extra-files", nargs='*',
help="include extra files (glob)")
command.set_defaults(command="clone")
# restore
command = subparser.add_parser(
"restore",
help="restore a clone file from <source>. An alternative destination can be given with --destination.")
command.add_argument("source")
command.add_argument("--destination", default="/")
command.add_argument("--simulate", action="store_true", default=False)
command.add_argument(
"--rewrite-server",
help="rewrite all URIs in sources.list to the specified url")
command.add_argument("--exclude", nargs='*',
help="exclude the listed package names from the restore")
command.set_defaults(command="restore")
# restore on new distro
command = subparser.add_parser(
"restore-new-distro",
help="restore a clone file from <source> to <destination> and try "\
"upgrading along the way. this can be used so that the current "\
"release is cloned, a new install is done and then the old clone "\
"is installed")
command.add_argument("source")
command.add_argument("new_distro_codename")
command.add_argument("--destination", default="/")
command.add_argument("--simulate", action="store_true", default=False)
command.set_defaults(command="restore-new-distro")
# show-diff
command = subparser.add_parser(
"show-diff",
help="show the difference of a clone file from <source> to the system. "
"An alternative destination can be given with --destination.")
command.add_argument("source")
command.add_argument("--destination", default="/")
command.set_defaults(command="show-diff")
# parse
args = parser.parse_args()
if not hasattr(args, "command"):
parser.error("no command specified")
if args.debug:
import logging
logging.basicConfig(level=logging.DEBUG)
# do the actual work
clone = AptClone()
if args.command == "info":
info = clone.info(args.source)
print(info)
if args.command == "clone":
clone.save_state(args.source, args.destination,
args.with_dpkg_repack, args.with_dpkg_status,
extra_files=args.extra_files)
print("not installable: %s" % ", ".join(clone.not_downloadable))
print("version mismatch: %s" % ", ".join(clone.version_mismatch))
if not args.with_dpkg_repack:
print("\nNote that you can use --with-dpkg-repack to include "
"those packges in the clone file.")
elif args.command == "restore":
if not os.path.exists(args.source):
print("can not find source file '%s'" % args.source)
sys.exit(1)
if args.simulate:
miss = clone.simulate_restore_state(args.source, args.exclude)
print("missing: %s" % ",".join(sorted(list(miss))))
else:
clone.restore_state(args.source, args.destination,
args.exclude,
mirror=args.rewrite_server)
elif args.command == "show-diff":
clone.show_diff(args.source, args.destination)
elif args.command == "restore-new-distro":
# this is a bit of magic, the idea is that if we clone into a new
# release and we are on it already we do not want to remove
# packages because they are probably new defaults pkgs. If however
# we are not yet on the new release its fine to remove installed
# pkgs as part of the upgrade
import lsb_release
codename = lsb_release.get_lsb_information()["CODENAME"]
if (args.new_distro_codename and args.new_distro_codename == codename):
protect_installed = True
else:
protect_installed = False
if args.simulate:
miss = clone.simulate_restore_state(
args.source, args.new_distro_codename)
print("missing: %s" % ",".join(sorted(list(miss))))
else:
clone.restore_state(
args.source, args.destination, args.new_distro_codename, protect_installed)