2 # Copyright (C) 2001 Alexander S. Guy <a7r@andern.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2, or (at your option)
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA. */
20 # Copyright 2001, Russell Nelson <ipkg.py@russnelson.com>
21 # Added reading in of packages.
22 # Added missing package information fields.
23 # Changed render_control() to __repr__().
26 # The API doesn't validate package information fields. It should be
27 # throwing exceptions in the right places.
28 # Executions of tar could silently fail.
29 # Executions of tar *do* fail, and loudly, because you have to specify a full filename,
30 # and tar complains if any files are missing, and the ipkg spec doesn't require
31 # people to say "./control.tar.gz" or "./control" when they package files.
32 # It would be much better to require ./control or disallow ./control (either)
33 # rather than letting people pick. Some freedoms aren't worth their cost.
43 from stat import ST_SIZE
46 """A class for creating objects to manipulate (e.g. create) ipkg
48 def __init__(self, fn=None):
51 self.architecture = None
52 self.maintainer = None
54 self.description = None
59 self.recommends = None
62 self.filename_header = None
66 self.installed_size = None
71 # see if it is deb format
86 if sys.version[:1] > '2':
87 # when using Python 2.0 or newer
88 self.md5 = sum.hexdigest()
90 self.md5 = string.join(map((lambda x:"%02x" % ord(x)),sum.digest()),'')
92 self.size = stat[ST_SIZE]
93 self.filename = os.path.basename(fn)
94 ## sys.stderr.write(" extracting control.tar.gz from %s\n"% (fn,))
96 control = os.popen("ar p "+fn+" control.tar.gz | tar xfzO - '*control'","r")
98 control = os.popen("tar xfzO "+fn+" '*control.tar.gz' | tar xfzO - '*control'","r")
99 line = control.readline()
102 line = string.rstrip(line)
103 lineparts = re.match(r'([\w-]*?):\s*(.*)', line)
105 name = string.lower(lineparts.group(1))
106 value = lineparts.group(2)
108 line = control.readline()
110 if line[0] != ' ': break
111 line = string.rstrip(line)
112 value = value + '\n' + line
113 # don't allow package to override its own filename
114 if name == "filename":
115 self.filename_header = value
117 if self.__dict__.has_key(name):
118 self.__dict__[name] = value
120 line = control.readline()
123 data = os.popen("ar p "+fn+" data.tar.gz | tar tfz -","r")
125 data = os.popen("tar xfzO "+fn+" '*data.tar.gz' | tar tfz -","r")
127 line = data.readline()
129 self.file_list.append(string.rstrip(line))
132 self.scratch_dir = None
136 def read_control(self, control):
139 line = control.readline()
142 line = string.rstrip(line)
143 lineparts = re.match(r'([\w-]*?):\s*(.*)', line)
145 name = string.lower(lineparts.group(1))
146 value = lineparts.group(2)
148 line = control.readline()
150 if line[0] != ' ': break
151 value = value + '\n' + line
153 self.size = int(value)
154 elif self.__dict__.has_key(name):
155 self.__dict__[name] = value
157 return # consumes one blank line at end of package descriptoin
159 line = control.readline()
163 def _setup_scratch_area(self):
164 self.scratch_dir = "%s/%sipkg" % (tempfile.gettempdir(),
165 tempfile.gettempprefix())
166 self.file_dir = "%s/files" % (self.scratch_dir)
167 self.meta_dir = "%s/meta" % (self.scratch_dir)
169 os.mkdir(self.scratch_dir)
170 os.mkdir(self.file_dir)
171 os.mkdir(self.meta_dir)
173 def set_package(self, package):
174 self.package = package
176 def get_package(self):
179 def set_version(self, version):
180 self.version = version
182 def get_version(self):
185 def set_architecture(self, architecture):
186 self.architecture = architecture
188 def get_architecture(self):
189 return self.architecture
191 def set_maintainer(self, maintainer):
192 self.maintainer = maintainer
194 def get_maintainer(self):
195 return self.maintainer
197 def set_source(self, source):
200 def get_source(self):
203 def set_description(self, description):
204 self.description = description
206 def get_description(self):
207 return self.description
209 def set_depends(self, depends):
210 self.depends = depends
212 def get_depends(self, depends):
215 def set_provides(self, provides):
216 self.provides = provides
218 def get_provides(self, provides):
221 def set_replaces(self, replaces):
222 self.replaces = replaces
224 def get_replaces(self, replaces):
227 def set_conflicts(self, conflicts):
228 self.conflicts = conflicts
230 def get_conflicts(self, conflicts):
231 return self.conflicts
233 def set_suggests(self, suggests):
234 self.suggests = suggests
236 def get_suggests(self, suggests):
239 def set_section(self, section):
240 self.section = section
242 def get_section(self, section):
245 def get_file_list(self):
246 return self.file_list
248 def write_package(self, dirname):
249 buf = self.render_control()
250 file = open("%s/control" % self.meta_dir, 'w')
253 self._setup_scratch_area()
254 cmd = "cd %s ; tar cvfz %s/control.tar.gz control" % (self.meta_dir,
257 cmd_out, cmd_in, cmd_err = os.popen3(cmd)
259 while cmd_err.readline() != "":
266 bits = "control.tar.gz"
269 cmd = "cd %s ; tar cvfz %s/data.tar.gz" % (self.file_dir,
272 cmd_out, cmd_in, cmd_err = os.popen3(cmd)
274 while cmd_err.readline() != "":
281 bits = bits + " data.tar.gz"
283 file = "%s_%s_%s.ipk" % (self.package, self.version, self.architecture)
284 cmd = "cd %s ; tar cvfz %s/%s %s" % (self.scratch_dir,
289 cmd_out, cmd_in, cmd_err = os.popen3(cmd)
291 while cmd_err.readline() != "":
301 # XXX - Some checks need to be made, and some exceptions
302 # need to be thrown. -- a7r
304 if self.package: out = out + "Package: %s\n" % (self.package)
305 if self.version: out = out + "Version: %s\n" % (self.version)
306 if self.depends: out = out + "Depends: %s\n" % (self.depends)
307 if self.provides: out = out + "Provides: %s\n" % (self.provides)
308 if self.replaces: out = out + "Replaces: %s\n" % (self.replaces)
309 if self.conflicts: out = out + "Conflicts: %s\n" % (self.conflicts)
310 if self.suggests: out = out + "Suggests: %s\n" % (self.suggests)
311 if self.recommends: out = out + "Recommends: %s\n" % (self.recommends)
312 if self.section: out = out + "Section: %s\n" % (self.section)
313 if self.architecture: out = out + "Architecture: %s\n" % (self.architecture)
314 if self.maintainer: out = out + "Maintainer: %s\n" % (self.maintainer)
315 if self.md5: out = out + "MD5Sum: %s\n" % (self.md5)
316 if self.size: out = out + "Size: %d\n" % int(self.size)
317 if self.installed_size: out = out + "InstalledSize: %d\n" % int(self.installed_size)
318 if self.filename: out = out + "Filename: %s\n" % (self.filename)
319 if self.source: out = out + "Source: %s\n" % (self.source)
320 if self.description: out = out + "Description: %s\n" % (self.description)
326 # XXX - Why is the `os' module being yanked out before Package objects
327 # are being destroyed? -- a7r
331 """A currently unimplemented wrapper around the ipkg utility."""
336 def add_package(self, pkg):
337 package = pkg.package
338 arch = pkg.architecture
339 #name = ("%s:%s" % (package, arch))
340 name = ("%s" % (package))
341 if (not self.packages.has_key(name)):
342 self.packages[name] = pkg
343 (s, outtext) = commands.getstatusoutput("ipkg-compare-versions %s '>' %s" % (pkg.version, self.packages[name].version))
345 self.packages[name] = pkg
350 def read_packages_file(self, fn):
355 if pkg.get_package():
356 self.add_package(pkg)
362 def write_packages_file(self, fn):
364 names = self.packages.keys()
367 f.write(self.packages[name].__repr__())
371 return self.packages.keys()
373 def __getitem__(self, key):
374 return self.packages[key]
376 if __name__ == "__main__":
379 package.set_package("FooBar")
380 package.set_version("0.1-fam1")
381 package.set_architecture("arm")
382 package.set_maintainer("Testing <testing@testing.testing>")
383 package.set_depends("libc")
384 package.set_description("A test of the APIs.")
387 sys.stdout.write(package)
390 package.write_package("/tmp")