trelease.py - amprolla - devuan's apt repo merger
 (HTM) git clone https://git.parazyd.org/amprolla
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       trelease.py (4908B)
       ---
            1 # See LICENSE file for copyright and license details.
            2 
            3 """
            4 Release file functions and helpers
            5 """
            6 
            7 from datetime import datetime  # , timedelta
            8 from gzip import decompress as gzip_decomp
            9 from lzma import compress as lzma_comp
           10 from os.path import getsize, isfile
           11 from subprocess import Popen
           12 
           13 import lib.globalvars as globalvars
           14 from lib.config import (checksums, distrolabel, gpgdir, release_aliases,
           15                         release_keys, signingkey, signrelease, arches)
           16 from lib.log import info
           17 from lib.parse import parse_release_head, parse_release
           18 
           19 
           20 def rewrite_release_head(headers):
           21     """
           22     Rewrites the necessary headers in a Release file
           23     Used to override needed values defined in config.release_aliases
           24     """
           25     if headers['Suite'] in release_aliases:
           26         headers['Label'] = distrolabel
           27         suitename = headers['Suite']
           28         for var in release_aliases[suitename]:
           29             headers[var] = release_aliases[suitename][var]
           30 
           31     return headers
           32 
           33 
           34 def write_release(oldrel, newrel, filelist, rmstr, rewrite=True):
           35     """
           36     Generates a valid Release file
           37     if sign=False: do not use gnupg to sign the file
           38     if rewrite=True: rewrite the Release headers as defined in the config
           39 
           40     Arguments taken: oldrel, newrel, filelist, rmstr
           41         * location of the old Release file (used to take metadata)
           42         * location where to write the new Release file
           43         * list of files to make checksums
           44         * string to remove from the path of the hashed file
           45     """
           46     time1 = datetime.utcnow()
           47     # time2 = datetime.utcnow() + timedelta(days=7)
           48 
           49     prettyt1 = time1.strftime('%a, %d %b %Y %H:%M:%S UTC')
           50     # prettyt2 = time2.strftime('%a, %d %b %Y %H:%M:%S UTC')
           51 
           52     # this holds our local data in case we don't want to rehash files
           53     if isfile(newrel):
           54         local_rel = open(newrel).read()
           55         local_rel = parse_release(local_rel)
           56 
           57     old = open(oldrel).read()
           58     new = open(newrel, 'w')
           59 
           60     rel_cont = parse_release_head(old)
           61 
           62     rel_cont['Date'] = prettyt1
           63     # rel_cont['Valid-Until'] = prettyt2
           64 
           65     _archlist = ''
           66     for i in arches:
           67         if i == 'source':
           68             continue
           69         if i == 'binary-all':
           70             continue
           71         i = i.replace('binary-', ' ')
           72         _archlist += i
           73     rel_cont['Architectures'] = _archlist
           74 
           75     if rewrite:
           76         rel_cont = rewrite_release_head(rel_cont)
           77 
           78     for k in release_keys:
           79         if k in rel_cont:
           80             new.write('%s: %s\n' % (k, rel_cont[k]))
           81 
           82     if globalvars.rehash:
           83         rehash_release(filelist, new, rmstr)
           84     else:
           85         info('Reusing old checksums')
           86         for csum in checksums:
           87             new.write('%s:\n' % csum['name'])
           88             for i, j in local_rel.items():
           89                 new.write(' %s %8s %s\n' % (j[0], j[1], i))
           90 
           91     new.close()
           92 
           93     if signrelease:
           94         sign_release(newrel)
           95 
           96 
           97 def rehash_release(_filelist, fdesc, rmstr):
           98     """
           99     Calculates checksums of a given filelist and writes them to the given
          100     file descriptor. Takes rmstr as the third argument, which is a string to
          101     remove from the path of the hashed file when writing it to a file.
          102     """
          103     info('Hashing checksums')
          104     for csum in checksums:
          105         fdesc.write('%s:\n' % csum['name'])
          106         for i in _filelist:
          107             if isfile(i):
          108                 cont = open(i, 'rb').read()
          109                 fdesc.write(' %s %8s %s\n' % (csum['f'](cont).hexdigest(),
          110                                               getsize(i),
          111                                               i.replace(rmstr+'/', '')))
          112             elif i.endswith('.xz') and isfile(i.replace('.xz', '.gz')):
          113                 xzstr = lzma_comp(open(i.replace('.xz', '.gz'), 'rb').read())
          114                 fdesc.write(' %s %8s %s\n' % (csum['f'](xzstr).hexdigest(),
          115                                               len(xzstr),
          116                                               i.replace(rmstr+'/', '')))
          117             elif not i.endswith('.gz') and isfile(i+'.gz'):
          118                 uncomp = gzip_decomp(open(i+'.gz', 'rb').read())
          119                 fdesc.write(' %s %8s %s\n' % (csum['f'](uncomp).hexdigest(),
          120                                               len(uncomp),
          121                                               i.replace(rmstr+'/', '')))
          122     return
          123 
          124 
          125 def sign_release(infile):
          126     """
          127     Signs both the clearsign and the detached signature of a Release file.
          128 
          129     Takes a valid path to a release file as an argument.
          130     """
          131     args = ['gpg', '-q', '--default-key', signingkey, '--batch', '--yes',
          132             '--homedir', gpgdir]
          133 
          134     clearargs = args + ['--clearsign', '-a', '-o',
          135                         infile.replace('Release', 'InRelease'), infile]
          136     detachargs = args + ['-sb', '-o', infile+'.gpg', infile]
          137 
          138     info('Signing Release (clearsign)')
          139     cleargpg = Popen(clearargs)
          140     cleargpg.wait(timeout=5)
          141 
          142     info('Signing Release (detached sign)')
          143     detachgpg = Popen(detachargs)
          144     detachgpg.wait(timeout=5)