]> git.decadent.org.uk Git - dak.git/blob - daklib/filewriter.py
Merge branch 'pu/xz-for-indices'
[dak.git] / daklib / filewriter.py
1 #!/usr/bin/env python
2 """
3 Helper code for file writing with optional compression.
4
5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2011 Torsten Werner <twerner@debian.org>
7 @license: GNU General Public License version 2 or later
8 """
9
10 ################################################################################
11
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26 ################################################################################
27
28 from daklib.config import Config
29
30 from daklib.daksubprocess import check_call
31
32 import os, os.path
33
34 class BaseFileWriter(object):
35     '''
36     Base class for compressed and uncompressed file writing.
37     '''
38     def __init__(self, template, **keywords):
39         '''
40         The template argument is a string template like
41         "dists/%(suite)s/%(component)s/Contents-%(architecture)s.gz" that
42         should be relative to the archive's root directory. The keywords
43         include strings for suite, component, architecture and booleans
44         uncompressed, gzip, bzip2.
45         '''
46         compression = keywords.get('compression', ['none'])
47         self.uncompressed = 'none' in compression
48         self.gzip = 'gzip' in compression
49         self.bzip2 = 'bzip2' in compression
50         self.xz = 'xz' in compression
51         self.path = template % keywords
52
53     def open(self):
54         '''
55         Returns a file object for writing.
56         '''
57         # create missing directories
58         try:
59             os.makedirs(os.path.dirname(self.path))
60         except:
61             pass
62         self.file = open(self.path + '.new', 'w')
63         return self.file
64
65     # internal helper function
66     def rename(self, filename):
67         tempfilename = filename + '.new'
68         os.chmod(tempfilename, 0o664)
69         os.rename(tempfilename, filename)
70
71     def close(self):
72         '''
73         Closes the file object and does the compression and rename work.
74         '''
75         self.file.close()
76         if self.gzip:
77             check_call('gzip -9cn --rsyncable <%s.new >%s.gz.new' % (self.path, self.path),
78                 shell = True)
79             self.rename('%s.gz' % self.path)
80         if self.bzip2:
81             check_call('bzip2 -9 <%s.new >%s.bz2.new' % (self.path, self.path), shell = True)
82             self.rename('%s.bz2' % self.path)
83         if self.xz:
84             check_call('xz -c <{0}.new >{0}.xz.new'.format(self.path), shell=True)
85             self.rename('{0}.xz'.format(self.path))
86         if self.uncompressed:
87             self.rename(self.path)
88         else:
89             os.unlink(self.path + '.new')
90
91 class BinaryContentsFileWriter(BaseFileWriter):
92     def __init__(self, **keywords):
93         '''
94         The value of the keywords suite, component, and architecture are
95         strings. The value of component may be omitted if not applicable.
96         Output files are gzip compressed only.
97         '''
98         flags = {
99             'compression': ['gzip'],
100         }
101         flags.update(keywords)
102         if flags['debtype'] == 'deb':
103             template = "%(archive)s/dists/%(suite)s/%(component)s/Contents-%(architecture)s"
104         else: # udeb
105             template = "%(archive)s/dists/%(suite)s/%(component)s/Contents-udeb-%(architecture)s"
106         BaseFileWriter.__init__(self, template, **flags)
107
108 class SourceContentsFileWriter(BaseFileWriter):
109     def __init__(self, **keywords):
110         '''
111         The value of the keywords suite and component are strings.
112         Output files are gzip compressed only.
113         '''
114         flags = {
115             'compression': ['gzip'],
116         }
117         flags.update(keywords)
118         template = "%(archive)s/dists/%(suite)s/%(component)s/Contents-source"
119         BaseFileWriter.__init__(self, template, **flags)
120
121 class PackagesFileWriter(BaseFileWriter):
122     def __init__(self, **keywords):
123         '''
124         The value of the keywords suite, component, debtype and architecture
125         are strings.  Output files are gzip compressed only.
126         '''
127         flags = {
128             'compression': ['gzip', 'bzip2'],
129         }
130         flags.update(keywords)
131         if flags['debtype'] == 'deb':
132             template = "%(archive)s/dists/%(suite)s/%(component)s/binary-%(architecture)s/Packages"
133         else: # udeb
134             template = "%(archive)s/dists/%(suite)s/%(component)s/debian-installer/binary-%(architecture)s/Packages"
135         BaseFileWriter.__init__(self, template, **flags)
136
137 class SourcesFileWriter(BaseFileWriter):
138     def __init__(self, **keywords):
139         '''
140         The value of the keywords suite and component are strings. Output
141         files are gzip compressed only.
142         '''
143         flags = {
144             'compression': ['gzip', 'bzip2'],
145         }
146         flags.update(keywords)
147         template = "%(archive)s/dists/%(suite)s/%(component)s/source/Sources"
148         BaseFileWriter.__init__(self, template, **flags)
149
150 class TranslationFileWriter(BaseFileWriter):
151     def __init__(self, **keywords):
152         '''
153         The value of the keywords suite, component and language are strings.
154         Output files are bzip2 compressed only.
155         '''
156         flags = {
157             'compression': ['bzip2'],
158             'language':     'en',
159         }
160         flags.update(keywords)
161         template = "%(archive)s/dists/%(suite)s/%(component)s/i18n/Translation-%(language)s"
162         super(TranslationFileWriter, self).__init__(template, **flags)