natalie 12.5 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.6 2003-04-15 16:03:31 troup 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 167 168
            if action == "add" or old_priority_id == priority_id and \
               old_section_id == section_id and \
               old_maintainer_override == maintainer_override:
                # If it's unchanged or we're in 'add only' mode, ignore it
169
                c_skipped += 1;
J
James Troup 已提交
170
                continue;
J
James Troup 已提交
171
            else:
J
James Troup 已提交
172 173
                # If it's changed, delete the old one so we can
                # reinsert it with the new information
174
                c_updated += 1;
J
James Troup 已提交
175 176
                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 已提交
177 178 179 180 181 182 183 184
                # 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 已提交
185
        else:
186
            c_added += 1;
J
James Troup 已提交
187
            update_p = 0;
J
James Troup 已提交
188

J
James Troup 已提交
189 190 191 192 193 194 195
        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:
            projectB.query("INSERT INTO override (suite, component, type, package, priority, section) VALUES (%s, %s, %s, '%s', %s, %s)"
                           % (suite_id, component_id, type_id, package, priority_id, section_id));

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

J
James Troup 已提交
199 200 201 202 203 204
    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));
205
                c_removed += 1;
J
James Troup 已提交
206
                Logger.log(["removed override",suite,component,type,package]);
J
James Troup 已提交
207 208

    projectB.query("COMMIT WORK");
J
James Troup 已提交
209 210
    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 已提交
211
    Logger.log(["set complete",c_updated, c_added, c_removed, c_skipped, c_error]);
J
James Troup 已提交
212 213 214 215 216 217

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

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

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

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

    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():
231
            print utils.result_join(i);
J
James Troup 已提交
232 233 234
    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():
235
            print utils.result_join(i[:-1]);
J
James Troup 已提交
236 237 238 239

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

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

J
James Troup 已提交
242
    Cnf = utils.get_conf();
J
James Troup 已提交
243
    Arguments = [('a', "add", "Natalie::Options::Add"),
J
James Troup 已提交
244
                 ('c', "component", "Natalie::Options::Component", "HasArg"),
J
James Troup 已提交
245
                 ('h', "help", "Natalie::Options::Help"),
J
James Troup 已提交
246 247 248 249 250
                 ('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 已提交
251 252

    # Default arguments
J
James Troup 已提交
253
    for i in [ "add", "help", "list", "quiet", "set" ]:
R
Ryan Murray 已提交
254
	if not Cnf.has_key("Natalie::Options::%s" % (i)):
255 256 257 258 259 260 261
	    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 已提交
262

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

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

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

    action = None;
J
James Troup 已提交
272
    for i in [ "add", "list", "set" ]:
J
James Troup 已提交
273
        if Cnf["Natalie::Options::%s" % (i)]:
J
James Troup 已提交
274
            if action:
J
James Troup 已提交
275
                utils.fubar("Can not perform more than one action at once.");
J
James Troup 已提交
276 277 278 279 280 281 282
            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 已提交
283
        Logger = logging.Logger(Cnf, "natalie");
J
James Troup 已提交
284
        if file_list:
J
James Troup 已提交
285
            for file in file_list:
J
James Troup 已提交
286
                process_file(utils.open_file(file), suite, component, type, action);
J
James Troup 已提交
287
        else:
J
James Troup 已提交
288
            process_file(sys.stdin, suite, component, type, action);
J
James Troup 已提交
289
        Logger.close();
J
James Troup 已提交
290 291 292 293 294 295

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

if __name__ == '__main__':
    main()