def respond_to_client(self, response: HttpResponse): with wrap_context('responding to client'): self.send_response_only(response.status_code) if has_header(response.headers, 'Content-Encoding'): del response.headers['Content-Encoding'] if self.config.verbose >= 2: log.debug('removing Content-Encoding header') if not has_header(response.headers, 'Content-Length') and \ not has_header(response.headers, 'Transfer-Encoding') and response.content: response.headers['Content-Length'] = str(len(response.content)) log.warn('adding missing Content-Length header') if has_header(response.headers, 'Content-Length') and has_header( response.headers, 'Transfer-Encoding'): del response.headers['Content-Length'] log.warn( 'removed Content-Length header conflicting with Transfer-Encoding' ) for name, value in response.headers.items(): self.send_header(name, value) self.end_headers() if self.config.allow_chunking and response.headers.get( 'Transfer-Encoding') == 'chunked': send_chunked_response(self.wfile, response.content) else: self.wfile.write(response.content) self.close_connection = True if self.config.verbose >= 2: log.debug('> response sent', client_addr=self.client_address[0], client_port=self.client_address[1])
def generate_response(self, request_0: HttpRequest) -> HttpResponse: with wrap_context('generating response'): request = request_0.transform(self.extensions.transform_request) if request != request_0 and self.config.verbose >= 2: log.debug('request transformed') immediate_reponse = self.find_immediate_response(request) if immediate_reponse: return immediate_reponse.log('> immediate response', self.config.verbose) self.cache.clear_old() if self.cache.has_cached_response(request): return self.cache.replay_response(request).log( '> Cache: returning cached response', self.config.verbose) if self.config.replay and self.config.verbose: log.warn('request not found in cache', path=request.path) response: HttpResponse = proxy_request( request, default_url=self.config.dst_url, timeout=self.config.timeout, verbose=self.config.verbose) if self.cache.saving_enabled(request, response): self.cache.save_response(request, response) return response
def match_filename( filename: str, pattern: str, replacement_pattern: Optional[str], full: bool = False, padding: int = 0, ) -> Optional[Match]: re_match = match_regex_string(pattern, filename, full) if not re_match: log.warn('no match', file=filename) return None group_dict: Dict[int, Optional[str]] = { index + 1: group for index, group in enumerate(re_match.groups()) } apply_numeric_padding(group_dict, padding) if not replacement_pattern: return Match(name_from=filename, name_to=None, groups=group_dict, re_match=re_match) validate_replacement(re_match, replacement_pattern) new_name = expand_replacement(replacement_pattern, group_dict) return Match(name_from=filename, name_to=new_name, groups=group_dict, re_match=re_match)
def read_alsa_volume(): master_volume_regex = r'^.*Mono: Playback \d+ \[(\d+)%\] \[(-?\d+\.?\d*)dB\] \[on\]$' for line in shell_output('amixer get Master').split('\n'): match = re.match(master_volume_regex, line) if match: return int(match.group(1)) log.warn('Master volume could not have been read') return None
def read_mp3_tags(mp3_file: str) -> Tuple[str, str]: with wrap_context('reading mp3 tags'): audiofile = eyed3.load(mp3_file) if audiofile is None or audiofile.tag is None: log.warn('no IDv3 tags read', mp3_file=mp3_file) return '', '' artist = _oremptystr(audiofile.tag.artist).strip() title = _oremptystr(audiofile.tag.title).strip() log.info('IDv3 tags read', mp3_file=mp3_file, artist=artist, title=title) return artist, title
def find_usb_data_partition() -> str: candidates = list( filter(lambda m: m.endswith('/watchmodules'), map(lambda p: p.mountpoint, psutil.disk_partitions()))) if not candidates: log.warn('cant find any mounted watchmodules partition') return '/mnt/watchmaker/watchmodules' assert len( candidates ) <= 1, f'there are more than one partitions matching watchmodules: {candidates}' return candidates[0]
def read_pulseaudio_volume(): master_volume_regex = r'^(.*)Volume: front-left: \d+ / +(\d+)% / (.*)$' sink_volumes = [] for line in shell_output('pactl list sinks').split('\n'): match = re.match(master_volume_regex, line) if match: sink_volumes.append(int(match.group(2))) if sink_volumes: return sink_volumes[-1] log.warn('Master volume could not have been read') return None
def get_pulseaudio_sink_number(): master_volume_regex = r'^(\d+)(.*)RUNNING$' matches = [] aux_matches = [] for line in shell_output('pactl list sinks short').split('\n'): match = re.match(master_volume_regex, line) if match: matches.append(int(match.group(1))) aux_match = re.match(r'^(\d+)(.*)$', line) if aux_match: aux_matches.append(int(aux_match.group(1))) if matches: return matches[-1] log.warn('Running sink number not found, getting last') if aux_matches: return aux_matches[-1] log.warn('No sink found') return None
def flash_disk(disk: str, persistence: bool, boot_storage_surplus: int, modules: List[str], skip_fs: bool): set_workdir(os.path.join(script_real_dir(), '..')) log.info(f'checking required files existence') assert os.path.exists('squash/filesystem.squashfs') assert os.path.exists('content/boot-files') assert os.path.exists('content/grub') assert os.path.exists('modules/init') # TODO unmount disk partitions log.warn(f'writing to disk {disk}') wrap_shell(f'df {disk}') log.info('creating MBR') wrap_shell(f'''sudo wipefs {disk}''') wrap_shell(f'''sudo dd if=/dev/zero of={disk} seek=1 count=2047''') wrap_shell(f''' sudo parted --script {disk} \\ mklabel msdos ''') log.info('calculating partitions size') # depend on filesystem.squash size, expand by some surplus (for storage) squashfs_size = os.path.getsize('squash/filesystem.squashfs') boot_part_min_size = squashfs_size + dir_size('content/boot-files') + dir_size('content/grub') boot_part_end_mib = boot_part_min_size / 1024 ** 2 + boot_storage_surplus efi_part_end_mib = boot_part_end_mib + efi_part_size persistence_part_end_mib = efi_part_end_mib + persistence_part_size log.info(f'boot partition size: {boot_part_end_mib}MiB ({boot_storage_surplus}MiB surplus)') log.info('creating partitions space') if persistence: wrap_shell(f''' sudo parted --script {disk} \\ mkpart primary fat32 1MiB {boot_part_end_mib}MiB \\ set 1 lba on \\ set 1 boot on \\ mkpart primary fat32 {boot_part_end_mib}MiB {efi_part_end_mib}MiB \\ set 2 esp on \\ mkpart primary ext4 {efi_part_end_mib}MiB {persistence_part_end_mib}MiB \\ mkpart primary ext4 {persistence_part_end_mib}MiB 100% ''') else: wrap_shell(f''' sudo parted --script {disk} \\ mkpart primary fat32 1MiB {boot_part_end_mib}MiB \\ set 1 lba on \\ set 1 boot on \\ mkpart primary fat32 {boot_part_end_mib}MiB {efi_part_end_mib}MiB \\ set 2 esp on \\ mkpart primary ext4 {efi_part_end_mib}MiB 100% ''') wrap_shell('sync') log.info('making boot partition filesystem') wrap_shell(f'''sudo mkfs.fat -F32 {disk}1''') log.info('making EFI partition filesystem') wrap_shell(f'''sudo mkfs.fat -F32 {disk}2''') if persistence: log.info('making persistence partition filesystem') wrap_shell(f'''sudo mkfs.ext4 -F {disk}3''') log.info('making watchmodules partition filesystem') wrap_shell(f'''sudo mkfs.ext4 -F {disk}4''') else: log.info('making watchmodules partition filesystem') wrap_shell(f'''sudo mkfs.ext4 -F {disk}3''') wrap_shell('sync') log.info('setting partition names') if persistence: wrap_shell(f''' sudo mlabel -i {disk}1 ::boot sudo mlabel -i {disk}2 ::EFI sudo e2label {disk}3 persistence sudo e2label {disk}4 watchmodules ''') else: wrap_shell(f''' sudo mlabel -i {disk}1 ::boot sudo mlabel -i {disk}2 ::EFI sudo e2label {disk}3 watchmodules ''') wrap_shell('sync') log.info('mounting partitions') wrap_shell(f'''sudo mkdir -p /mnt/watchmaker''') wrap_shell(f''' sudo mkdir -p /mnt/watchmaker/boot sudo mount {disk}1 /mnt/watchmaker/boot ''') wrap_shell(f''' sudo mkdir -p /mnt/watchmaker/efi sudo mount {disk}2 /mnt/watchmaker/efi ''') wrap_shell(f'''sudo mkdir -p /mnt/watchmaker/watchmodules''') if persistence: wrap_shell(f''' sudo mkdir -p /mnt/watchmaker/persistence sudo mount {disk}3 /mnt/watchmaker/persistence ''') wrap_shell(f'''sudo mount {disk}4 /mnt/watchmaker/watchmodules''') else: wrap_shell(f'''sudo mount {disk}3 /mnt/watchmaker/watchmodules''') log.info('installing GRUB EFI bootloaders') wrap_shell(f''' sudo grub-install \\ --target=x86_64-efi \\ --efi-directory=/mnt/watchmaker/boot \\ --boot-directory=/mnt/watchmaker/boot/boot \\ --removable --recheck ''') wrap_shell(f''' sudo grub-install \\ --target=x86_64-efi \\ --efi-directory=/mnt/watchmaker/efi \\ --boot-directory=/mnt/watchmaker/boot/boot \\ --removable --recheck ''') log.info('installing GRUB i386-pc bootloader') wrap_shell(f''' sudo grub-install \\ --target=i386-pc \\ --boot-directory=/mnt/watchmaker/boot/boot \\ --recheck \\ {disk} ''') wrap_shell('sync') log.info('Fixing GRUB EFI by replacing with Debian GRUB') wrap_shell(f''' sudo rm /mnt/watchmaker/efi/EFI/BOOT/* sudo cp -r content/efi/* /mnt/watchmaker/efi/EFI/BOOT/ sudo rm /mnt/watchmaker/boot/EFI/BOOT/* sudo cp -r content/efi/* /mnt/watchmaker/boot/EFI/BOOT/ sudo cp -r /mnt/watchmaker/efi/EFI/BOOT /mnt/watchmaker/efi/EFI/debian sudo cp -r /mnt/watchmaker/boot/EFI/BOOT /mnt/watchmaker/boot/EFI/debian sudo cp -r content/grub/x86_64-efi /mnt/watchmaker/boot/boot/grub/ ''') log.info('making EFI Microsoft workaround') wrap_shell(f''' sudo cp -r /mnt/watchmaker/efi/EFI/BOOT /mnt/watchmaker/efi/EFI/Microsoft sudo cp -r /mnt/watchmaker/boot/EFI/BOOT /mnt/watchmaker/boot/EFI/Microsoft ''') log.info('GRUB config') wrap_shell(f''' sudo cp content/grub/grub.cfg /mnt/watchmaker/boot/boot/grub/ sudo cp content/grub/background.png /mnt/watchmaker/boot/boot/grub/ sudo cp content/grub/font.pf2 /mnt/watchmaker/boot/boot/grub/ sudo cp content/grub/loopback.cfg /mnt/watchmaker/boot/boot/grub/ sudo cp content/grub/GRUB_FINDME /mnt/watchmaker/boot/ ''') log.info('Boot base files') wrap_shell(f''' sudo cp -r content/boot-files/[BOOT] /mnt/watchmaker/boot/ sudo cp -r content/boot-files/d-i /mnt/watchmaker/boot/ sudo cp -r content/boot-files/dists /mnt/watchmaker/boot/ sudo cp -r content/boot-files/live /mnt/watchmaker/boot/ sudo cp -r content/boot-files/pool /mnt/watchmaker/boot/ sudo cp -r content/boot-files/.disk /mnt/watchmaker/boot/ ''') wrap_shell(f'''sudo mkdir -p /mnt/watchmaker/boot/storage''') log.info('EFI base files') wrap_shell(f''' sudo cp -r content/boot-files/[BOOT] /mnt/watchmaker/efi/ sudo cp -r content/boot-files/d-i /mnt/watchmaker/efi/ sudo cp -r content/boot-files/dists /mnt/watchmaker/efi/ sudo cp -r content/boot-files/live /mnt/watchmaker/efi/ sudo cp -r content/boot-files/pool /mnt/watchmaker/efi/ sudo cp -r content/boot-files/.disk /mnt/watchmaker/efi/ ''') if persistence: log.info('Persistence configuration') wrap_shell(f'''sudo cp -r content/persistence/persistence.conf /mnt/watchmaker/persistence/''') log.info('Copying squash filesystem') if not skip_fs: wrap_shell(f'''sudo cp squash/filesystem.squashfs /mnt/watchmaker/boot/live/''') log.info('Adding init module') wrap_shell(f'''sudo cp -r modules/init /mnt/watchmaker/watchmodules/''') log.info('Adding dev module') wrap_shell(f'''sudo mkdir -p /mnt/watchmaker/watchmodules/dev''') log.info('make watchmodules writable to non-root user') wrap_shell(f'''sudo chown igrek /mnt/watchmaker/watchmodules -R''') if modules: log.info(f'Adding optional modules: {modules}') target_path = '/mnt/watchmaker/watchmodules' for module in modules: install_module.add_module(module, target_path) log.info('unmounting') wrap_shell('sync') wrap_shell(f'''sudo umount /mnt/watchmaker/boot''') wrap_shell(f'''sudo umount /mnt/watchmaker/efi''') wrap_shell(f'''sudo umount /mnt/watchmaker/watchmodules''') if persistence: wrap_shell(f'''sudo umount /mnt/watchmaker/persistence''') wrap_shell('sync') log.info('Success')
def confirm(yes: bool, msg: str): if not yes: log.warn(msg) while input_required('[yes/no]... ') != 'yes': pass