3 # 'Fix' stable to make debian-cd and dpkg -BORGiE users happy
4 # Copyright (C) 2000, 2001, 2002 James Troup <james@nocrew.org>
5 # $Id: claire.py,v 1.15 2002-06-05 00:18:32 troup Exp $
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ################################################################################
23 # "Look around... leaves are brown... and the sky's a hazy shade of winter,
24 # Look around... leaves are brown... there's a patch of snow on the ground."
25 # -- Simon & Garfunkel / 'A Hazy Shade'
27 ################################################################################
29 import os, pg, re, string, sys
30 import utils, db_access
33 ################################################################################
35 re_strip_section_prefix = re.compile(r'.*/');
40 ################################################################################
42 def usage (exit_code=0):
43 print """Usage: claire [OPTIONS]
44 Create compatability symlinks from legacy locations to the pool.
46 -v, --verbose explain what is being done
47 -h, --help show this help and exit"""
51 ################################################################################
53 # Relativize an absolute symlink from 'src' -> 'dest' relative to 'root'.
55 def clean_symlink (src, dest, root):
56 src = string.replace(src, root, '', 1);
57 dest = string.replace(dest, root, '', 1);
58 dest = os.path.dirname(dest);
60 for i in xrange(len(string.split(dest, '/'))):
61 new_src = new_src + '../';
64 ################################################################################
66 def fix_component_section (component, section):
68 component = utils.extract_component_from_section(section)[1];
70 # FIXME: ugly hacks to work around override brain damage
71 section = re_strip_section_prefix.sub('', section);
72 section = string.replace(string.lower(section), 'non-us', '');
73 if section == "main" or section == "contrib" or section == "non-free":
76 section = section + '/';
78 return (component, section);
80 ################################################################################
82 def find_dislocated_stable(Cnf, projectB):
86 q = projectB.query("""
87 SELECT DISTINCT ON (f.id) c.name, sec.section, l.path, f.filename, f.id
88 FROM component c, override o, section sec, source s, files f, location l,
89 dsc_files df, suite su, src_associations sa, files f2, location l2
90 WHERE su.suite_name = 'stable' AND sa.suite = su.id AND sa.source = s.id
91 AND f2.id = s.file AND f2.location = l2.id AND df.source = s.id
92 AND f.id = df.file AND f.location = l.id AND o.package = s.source
93 AND sec.id = o.section AND NOT (f.filename ~ '^potato/')
94 AND l.component = c.id AND o.suite = su.id
96 # Only needed if you have files in legacy-mixed locations
97 # UNION SELECT DISTINCT ON (f.id) null, sec.section, l.path, f.filename, f.id
98 # FROM component c, override o, section sec, source s, files f, location l,
99 # dsc_files df, suite su, src_associations sa, files f2, location l2
100 # WHERE su.suite_name = 'stable' AND sa.suite = su.id AND sa.source = s.id
101 # AND f2.id = s.file AND f2.location = l2.id AND df.source = s.id
102 # AND f.id = df.file AND f.location = l.id AND o.package = s.source
103 # AND sec.id = o.section AND NOT (f.filename ~ '^potato/') AND o.suite = su.id
104 # AND NOT EXISTS (SELECT l.path FROM location l WHERE l.component IS NOT NULL AND f.location = l.id);
105 for i in q.getresult():
107 (component, section) = fix_component_section(i[0], i[1]);
108 dest = "%sdists/%s/%s/source/%s%s" % (Cnf["Dir::Root"], Cnf.get("Suite::Stable::CodeName", "stable"), component, section, os.path.basename(i[3]));
109 src = clean_symlink(src, dest, Cnf["Dir::Root"]);
110 if not os.path.exists(dest):
111 if Cnf.Find("Claire::Options::Verbose"):
112 print src+' -> '+dest
113 os.symlink(src, dest);
114 dislocated_files[i[4]] = dest;
117 architectures = Cnf.ValueList("Suite::Stable::Architectures");
118 for arch in [ "source", "all" ]:
119 if architectures.count(arch):
120 architectures.remove(arch);
121 q = projectB.query("""
122 SELECT DISTINCT ON (f.id) c.name, a.arch_string, sec.section, b.package,
123 b.version, l.path, f.filename, f.id
124 FROM architecture a, bin_associations ba, binaries b, component c, files f,
125 location l, override o, section sec, suite su
126 WHERE su.suite_name = 'stable' AND ba.suite = su.id AND ba.bin = b.id
127 AND f.id = b.file AND f.location = l.id AND o.package = b.package
128 AND sec.id = o.section AND NOT (f.filename ~ '^potato/')
129 AND b.architecture = a.id AND l.component = c.id AND o.suite = su.id
130 UNION SELECT DISTINCT ON (f.id) null, a.arch_string, sec.section, b.package,
131 b.version, l.path, f.filename, f.id
132 FROM architecture a, bin_associations ba, binaries b, component c, files f,
133 location l, override o, section sec, suite su
134 WHERE su.suite_name = 'stable' AND ba.suite = su.id AND ba.bin = b.id
135 AND f.id = b.file AND f.location = l.id AND o.package = b.package
136 AND sec.id = o.section AND NOT (f.filename ~ '^potato/')
137 AND b.architecture = a.id AND o.suite = su.id AND NOT EXISTS
138 (SELECT l.path FROM location l WHERE l.component IS NOT NULL AND f.location = l.id);
140 for i in q.getresult():
141 (component, section) = fix_component_section(i[0], i[2]);
144 version = utils.re_no_epoch.sub('', i[4]);
147 dest = "%sdists/%s/%s/binary-%s/%s%s_%s.deb" % (Cnf["Dir::Root"], Cnf.get("Suite::Stable::CodeName", "stable"), component, architecture, section, package, version);
148 src = clean_symlink(src, dest, Cnf["Dir::Root"]);
149 if not os.path.exists(dest):
150 if Cnf.Find("Claire::Options::Verbose"):
151 print src+' -> '+dest
152 os.symlink(src, dest);
153 dislocated_files[i[7]] = dest;
154 # Add per-arch symlinks for arch: all debs
155 if architecture == "all":
156 for arch in architectures:
157 dest = "%sdists/%s/%s/binary-%s/%s%s_%s.deb" % (Cnf["Dir::Root"], Cnf.get("Suite::Stable::CodeName", "stable"), component, arch, section, package, version);
158 if not os.path.exists(dest):
159 if Cnf.Find("Claire::Options::Verbose"):
160 print src+' -> '+dest
161 os.symlink(src, dest);
163 return dislocated_files
165 ################################################################################
168 global Cnf, projectB;
170 Cnf = utils.get_conf()
172 Arguments = [('h',"help","Claire::Options::Help"),
173 ('v',"verbose","Claire::Options::Verbose")];
174 for i in ["help", "verbose" ]:
175 if not Cnf.has_key("Claire::Options::%s" % (i)):
176 Cnf["Claire::Options::%s" % (i)] = "";
178 apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
179 Options = Cnf.SubTree("Claire::Options")
184 projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
186 db_access.init(Cnf, projectB);
188 find_dislocated_stable(Cnf, projectB);
190 #######################################################################################
192 if __name__ == '__main__':