natalie 12.6 KB
Newer Older
J
James Troup 已提交
1 2 3
#!/usr/bin/env python

# Manipulate override files
J
James Troup 已提交
4
# Copyright (C) 2000, 2001, 2002, 2003  James Troup <james@nocrew.org>
5
# $Id: natalie,v 1.7 2005-11-15 09:50:32 ajt Exp $
J
James Troup 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

# 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; either version 2 of the License, or
# (at your option) any later version.

# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

################################################################################

J
James Troup 已提交
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
# On 30 Nov 1998, James Troup wrote:
# 
# > James Troup<2> <troup2@debian.org>
# > 
# >    James is a clone of James; he's going to take over the world.
# >    After he gets some sleep.
# 
# Could you clone other things too? Sheep? Llamas? Giant mutant turnips?
# 
# Your clone will need some help to take over the world, maybe clone up an
# army of penguins and threaten to unleash them on the world, forcing
# governments to sway to the new James' will!
# 
# Yes, I can envision a day when James' duplicate decides to take a horrific
# vengance on the James that spawned him and unleashes his fury in the form
# of thousands upon thousands of chickens that look just like Captin Blue
# Eye! Oh the horror.
# 
# Now you'll have to were name tags to people can tell you apart, unless of
# course the new clone is truely evil in which case he should be easy to
# identify!
# 
# Jason
# Chicken. Black. Helicopters.
# Be afraid.

# <Pine.LNX.3.96.981130011300.30365Z-100000@wakko>

################################################################################

53
import pg, sys, time;
J
James Troup 已提交
54
import utils, db_access, logging;
J
James Troup 已提交
55 56 57 58 59 60
import apt_pkg;

################################################################################

Cnf = None;
projectB = None;
J
James Troup 已提交
61
Logger = None;
J
James Troup 已提交
62 63 64

################################################################################

J
James Troup 已提交
65
def usage (exit_code=0):
J
sync  
James Troup 已提交
66
    print """Usage: natalie.py [OPTIONS]
J
James Troup 已提交
67
  -h, --help               print this help and exit
J
James Troup 已提交
68

J
sync  
James Troup 已提交
69 70
  -c, --component=CMPT     list/set overrides by component
                                  (contrib,*main,non-free)
J
James Troup 已提交
71
  -s, --suite=SUITE        list/set overrides by suite
J
sync  
James Troup 已提交
72 73 74
                                  (experimental,stable,testing,*unstable)
  -t, --type=TYPE          list/set overrides by type
                                  (*deb,dsc,udeb)
J
James Troup 已提交
75

J
James Troup 已提交
76 77 78
  -a, --add                add overrides (changes and deletions are ignored)
  -S, --set                set overrides
  -l, --list               list overrides
J
sync  
James Troup 已提交
79

J
James Troup 已提交
80 81
  -q, --quiet              be less verbose

J
sync  
James Troup 已提交
82 83 84 85 86
 starred (*) values are default"""
    sys.exit(exit_code)

################################################################################

J
James Troup 已提交
87
def process_file (file, suite, component, type, action):
J
James Troup 已提交
88 89
    suite_id = db_access.get_suite_id(suite);
    if suite_id == -1:
J
James Troup 已提交
90
        utils.fubar("Suite '%s' not recognised." % (suite));
J
James Troup 已提交
91 92 93

    component_id = db_access.get_component_id(component);
    if component_id == -1:
J
James Troup 已提交
94
        utils.fubar("Component '%s' not recognised." % (component));
J
James Troup 已提交
95 96 97

    type_id = db_access.get_override_type_id(type);
    if type_id == -1:
J
James Troup 已提交
98
        utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc.)" % (type));
J
James Troup 已提交
99 100 101 102

    # --set is done mostly internal for performance reasons; most
    # invocations of --set will be updates and making people wait 2-3
    # minutes while 6000 select+inserts are run needlessly isn't cool.
J
James Troup 已提交
103

J
James Troup 已提交
104 105 106 107 108 109 110
    original = {};
    new = {};
    c_skipped = 0;
    c_added = 0;
    c_updated = 0;
    c_removed = 0;
    c_error = 0;
J
James Troup 已提交
111

J
James Troup 已提交
112
    q = projectB.query("SELECT o.package, o.priority, o.section, o.maintainer, p.priority, s.section FROM override o, priority p, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s and o.priority = p.id and o.section = s.id"
J
James Troup 已提交
113 114 115 116 117 118 119
                       % (suite_id, component_id, type_id));
    for i in q.getresult():
        original[i[0]] = i[1:];

    start_time = time.time();
    projectB.query("BEGIN WORK");
    for line in file.readlines():
120
        line = utils.re_comments.sub('', line).strip();
J
James Troup 已提交
121 122
        if line == "":
            continue;
J
James Troup 已提交
123

J
James Troup 已提交
124
        maintainer_override = None;
J
James Troup 已提交
125
        if type == "dsc":
126
            split_line = line.split(None, 2);
J
James Troup 已提交
127 128 129 130 131
            if len(split_line) == 2:
                (package, section) = split_line;
            elif len(split_line) == 3:
                (package, section, maintainer_override) = split_line;
            else:
J
James Troup 已提交
132
                utils.warn("'%s' does not break into 'package section [maintainer-override]'." % (line));
133
                c_error += 1;
J
James Troup 已提交
134 135 136
                continue;
            priority = "source";
        else: # binary or udeb
137
            split_line = line.split(None, 3);
J
James Troup 已提交
138 139 140 141 142
            if len(split_line) == 3:
                (package, priority, section) = split_line;
            elif len(split_line) == 4:
                (package, priority, section, maintainer_override) = split_line;
            else:
J
James Troup 已提交
143
                utils.warn("'%s' does not break into 'package priority section [maintainer-override]'." % (line));
144
                c_error += 1;
J
James Troup 已提交
145 146 147 148
                continue;

        section_id = db_access.get_section_id(section);
        if section_id == -1:
J
James Troup 已提交
149
            utils.warn("'%s' is not a valid section. ['%s' in suite %s, component %s]." % (section, package, suite, component));
150
            c_error += 1;
J
James Troup 已提交
151 152 153
            continue;
        priority_id = db_access.get_priority_id(priority);
        if priority_id == -1:
J
James Troup 已提交
154
            utils.warn("'%s' is not a valid priority. ['%s' in suite %s, component %s]." % (priority, package, suite, component));
155
            c_error += 1;
J
James Troup 已提交
156 157 158
            continue;

        if new.has_key(package):
J
James Troup 已提交
159
            utils.warn("Can't insert duplicate entry for '%s'; ignoring all but the first. [suite %s, component %s]" % (package, suite, component));
160
            c_error += 1;
J
James Troup 已提交
161 162 163
            continue;
        new[package] = "";
        if original.has_key(package):
J
James Troup 已提交
164
            (old_priority_id, old_section_id, old_maintainer_override, old_priority, old_section) = original[package];
J
James Troup 已提交
165 166
            if action == "add" or old_priority_id == priority_id and \
               old_section_id == section_id and \
167 168
               ((old_maintainer_override == maintainer_override) or \
		(old_maintainer_override == "" and maintainer_override == None)):
J
James Troup 已提交
169
                # If it's unchanged or we're in 'add only' mode, ignore it
170
                c_skipped += 1;
J
James Troup 已提交
171
                continue;
J
James Troup 已提交
172
            else:
J
James Troup 已提交
173 174
                # If it's changed, delete the old one so we can
                # reinsert it with the new information
175
                c_updated += 1;
J
James Troup 已提交
176 177
                projectB.query("DELETE FROM override WHERE suite = %s AND component = %s AND package = '%s' AND type = %s"
                               % (suite_id, component_id, package, type_id));
J
James Troup 已提交
178 179 180 181 182 183 184 185
                # Log changes
                if old_priority_id != priority_id:
                    Logger.log(["changed priority",package,old_priority,priority]);
                if old_section_id != section_id:
                    Logger.log(["changed section",package,old_section,section]);
                if old_maintainer_override != maintainer_override:
                    Logger.log(["changed maintainer override",package,old_maintainer_override,maintainer_override]);
                update_p = 1;
J
James Troup 已提交
186
        else:
187
            c_added += 1;
J
James Troup 已提交
188
            update_p = 0;
J
James Troup 已提交
189

J
James Troup 已提交
190 191 192 193
        if maintainer_override:
            projectB.query("INSERT INTO override (suite, component, type, package, priority, section, maintainer) VALUES (%s, %s, %s, '%s', %s, %s, '%s')"
                           % (suite_id, component_id, type_id, package, priority_id, section_id, maintainer_override));
        else:
194
            projectB.query("INSERT INTO override (suite, component, type, package, priority, section,maintainer) VALUES (%s, %s, %s, '%s', %s, %s, '')"
J
James Troup 已提交
195 196
                           % (suite_id, component_id, type_id, package, priority_id, section_id));

J
James Troup 已提交
197 198
        if not update_p:
            Logger.log(["new override",suite,component,type,package,priority,section,maintainer_override]);
J
James Troup 已提交
199

J
James Troup 已提交
200 201 202 203 204 205
    if not action == "add":
        # Delete any packages which were removed
        for package in original.keys():
            if not new.has_key(package):
                projectB.query("DELETE FROM override WHERE suite = %s AND component = %s AND package = '%s' AND type = %s"
                               % (suite_id, component_id, package, type_id));
206
                c_removed += 1;
J
James Troup 已提交
207
                Logger.log(["removed override",suite,component,type,package]);
J
James Troup 已提交
208 209

    projectB.query("COMMIT WORK");
J
James Troup 已提交
210 211
    if not Cnf["Natalie::Options::Quiet"]:
        print "Done in %d seconds. [Updated = %d, Added = %d, Removed = %d, Skipped = %d, Errors = %d]" % (int(time.time()-start_time), c_updated, c_added, c_removed, c_skipped, c_error);
J
James Troup 已提交
212
    Logger.log(["set complete",c_updated, c_added, c_removed, c_skipped, c_error]);
J
James Troup 已提交
213 214 215 216 217 218

################################################################################

def list(suite, component, type):
    suite_id = db_access.get_suite_id(suite);
    if suite_id == -1:
J
James Troup 已提交
219
        utils.fubar("Suite '%s' not recognised." % (suite));
J
James Troup 已提交
220 221 222

    component_id = db_access.get_component_id(component);
    if component_id == -1:
J
James Troup 已提交
223
        utils.fubar("Component '%s' not recognised." % (component));
J
James Troup 已提交
224 225 226

    type_id = db_access.get_override_type_id(type);
    if type_id == -1:
227
        utils.fubar("Type '%s' not recognised. (Valid types are deb, udeb and dsc)" % (type));
J
James Troup 已提交
228 229 230 231

    if type == "dsc":
        q = projectB.query("SELECT o.package, s.section, o.maintainer FROM override o, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.section = s.id ORDER BY s.section, o.package" % (suite_id, component_id, type_id));
        for i in q.getresult():
232
            print utils.result_join(i);
J
James Troup 已提交
233 234 235
    else:
        q = projectB.query("SELECT o.package, p.priority, s.section, o.maintainer, p.level FROM override o, priority p, section s WHERE o.suite = %s AND o.component = %s AND o.type = %s AND o.priority = p.id AND o.section = s.id ORDER BY s.section, p.level, o.package" % (suite_id, component_id, type_id));
        for i in q.getresult():
236
            print utils.result_join(i[:-1]);
J
James Troup 已提交
237 238 239 240

################################################################################

def main ():
J
James Troup 已提交
241
    global Cnf, projectB, Logger;
J
James Troup 已提交
242

J
James Troup 已提交
243
    Cnf = utils.get_conf();
J
James Troup 已提交
244
    Arguments = [('a', "add", "Natalie::Options::Add"),
J
James Troup 已提交
245
                 ('c', "component", "Natalie::Options::Component", "HasArg"),
J
James Troup 已提交
246
                 ('h', "help", "Natalie::Options::Help"),
J
James Troup 已提交
247 248 249 250 251
                 ('l', "list", "Natalie::Options::List"),
                 ('q', "quiet", "Natalie::Options::Quiet"),
                 ('s', "suite", "Natalie::Options::Suite", "HasArg"),
                 ('S', "set", "Natalie::Options::Set"),
                 ('t', "type", "Natalie::Options::Type", "HasArg")];
J
James Troup 已提交
252 253

    # Default arguments
J
James Troup 已提交
254
    for i in [ "add", "help", "list", "quiet", "set" ]:
R
Ryan Murray 已提交
255
	if not Cnf.has_key("Natalie::Options::%s" % (i)):
256 257 258 259 260 261 262
	    Cnf["Natalie::Options::%s" % (i)] = "";
    if not Cnf.has_key("Natalie::Options::Component"):
	Cnf["Natalie::Options::Component"] = "main";
    if not Cnf.has_key("Natalie::Options::Suite"):
	Cnf["Natalie::Options::Suite"] = "unstable";
    if not Cnf.has_key("Natalie::Options::Type"):
	Cnf["Natalie::Options::Type"] = "deb";
J
James Troup 已提交
263

J
James Troup 已提交
264 265
    file_list = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);

J
sync  
James Troup 已提交
266
    if Cnf["Natalie::Options::Help"]:
J
James Troup 已提交
267
        usage();
J
sync  
James Troup 已提交
268

J
James Troup 已提交
269 270
    projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
    db_access.init(Cnf, projectB);
J
James Troup 已提交
271 272

    action = None;
J
James Troup 已提交
273
    for i in [ "add", "list", "set" ]:
J
James Troup 已提交
274
        if Cnf["Natalie::Options::%s" % (i)]:
J
James Troup 已提交
275
            if action:
J
James Troup 已提交
276
                utils.fubar("Can not perform more than one action at once.");
J
James Troup 已提交
277 278 279 280 281 282 283
            action = i;

    (suite, component, type) = (Cnf["Natalie::Options::Suite"], Cnf["Natalie::Options::Component"], Cnf["Natalie::Options::Type"])

    if action == "list":
        list(suite, component, type);
    else:
J
James Troup 已提交
284
        Logger = logging.Logger(Cnf, "natalie");
J
James Troup 已提交
285
        if file_list:
J
James Troup 已提交
286
            for file in file_list:
J
James Troup 已提交
287
                process_file(utils.open_file(file), suite, component, type, action);
J
James Troup 已提交
288
        else:
J
James Troup 已提交
289
            process_file(sys.stdin, suite, component, type, action);
J
James Troup 已提交
290
        Logger.close();
J
James Troup 已提交
291 292 293 294 295 296

#######################################################################################

if __name__ == '__main__':
    main()