+ os.unlink(dest)
+ os.symlink(source, dest)
+
+ def create_output_directories(self):
+ for path in (self.suite_path(), self.suite_release_path()):
+ try:
+ os.makedirs(path)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ def _update_hashfile_table(self, session, fileinfo, hashes):
+ # Mark all by-hash files as obsolete. We will undo that for the ones
+ # we still reference later.
+ query = """
+ UPDATE hashfile SET unreferenced = CURRENT_TIMESTAMP
+ WHERE suite_id = :id AND unreferenced IS NULL"""
+ session.execute(query, {'id': self.suite.suite_id})
+
+ if self.suite.byhash:
+ query = "SELECT path FROM hashfile WHERE suite_id = :id"
+ q = session.execute(query, {'id': self.suite.suite_id})
+ known_hashfiles = set(row[0] for row in q)
+ updated = set()
+ new = set()
+
+ # Update the hashfile table with new or updated files
+ for filename in fileinfo:
+ if not os.path.exists(filename):
+ # probably an uncompressed index we didn't generate
+ continue
+ byhashdir = os.path.join(os.path.dirname(filename), 'by-hash')
+ for h in hashes:
+ field = h.release_field
+ hashfile = os.path.join(byhashdir, field, fileinfo[filename][field])
+ if hashfile in known_hashfiles:
+ updated.add(hashfile)
+ else:
+ new.add(hashfile)
+
+ if updated:
+ session.execute("""
+ UPDATE hashfile SET unreferenced = NULL
+ WHERE path = ANY(:p) AND suite_id = :id""",
+ {'p': list(updated), 'id': self.suite.suite_id})
+ if new:
+ session.execute("""
+ INSERT INTO hashfile (path, suite_id)
+ VALUES (:p, :id)""",
+ [{'p': hashfile, 'id': self.suite.suite_id} for hashfile in new])
+
+ session.commit()
+
+ def _make_byhash_links(self, fileinfo, hashes):
+ # Create hardlinks in by-hash directories
+ for filename in fileinfo:
+ if not os.path.exists(filename):
+ # probably an uncompressed index we didn't generate
+ continue
+
+ for h in hashes:
+ field = h.release_field
+ hashfile = os.path.join(os.path.dirname(filename), 'by-hash', field, fileinfo[filename][field])
+ try:
+ os.makedirs(os.path.dirname(hashfile))
+ except OSError as exc:
+ if exc.errno != errno.EEXIST:
+ raise
+ try:
+ os.link(filename, hashfile)
+ except OSError as exc:
+ if exc.errno != errno.EEXIST:
+ raise
+
+ def generate_release_files(self):
+ """
+ Generate Release files for the given suite
+
+ @type suite: string
+ @param suite: Suite name
+ """
+
+ suite = self.suite
+ session = object_session(suite)
+
+ architectures = get_suite_architectures(suite.suite_name, skipall=True, skipsrc=True, session=session)
+
+ # Attribs contains a tuple of field names and the database names to use to
+ # fill them in
+ attribs = ( ('Origin', 'origin'),
+ ('Label', 'label'),
+ ('Suite', 'release_suite_output'),
+ ('Version', 'version'),
+ ('Codename', 'codename'),
+ ('Changelogs', 'changelog_url'),
+ )
+
+ # A "Sub" Release file has slightly different fields
+ subattribs = ( ('Archive', 'suite_name'),
+ ('Origin', 'origin'),
+ ('Label', 'label'),
+ ('Version', 'version') )
+
+ # Boolean stuff. If we find it true in database, write out "yes" into the release file
+ boolattrs = ( ('NotAutomatic', 'notautomatic'),
+ ('ButAutomaticUpgrades', 'butautomaticupgrades'),
+ ('Acquire-By-Hash', 'byhash'),
+ )
+
+ cnf = Config()
+
+ suite_suffix = cnf.find("Dinstall::SuiteSuffix", "")
+
+ self.create_output_directories()
+ self.create_release_symlinks()
+
+ outfile = os.path.join(self.suite_release_path(), "Release")
+ out = open(outfile + ".new", "w")
+
+ for key, dbfield in attribs:
+ # Hack to skip NULL Version fields as we used to do this
+ # We should probably just always ignore anything which is None
+ if key in ("Version", "Changelogs") and getattr(suite, dbfield) is None:
+ continue
+
+ out.write("%s: %s\n" % (key, getattr(suite, dbfield)))