def save_backup(): """Save the backup file.""" # We generate it from scratch, since that's the only way to remove # files. new_zip_data = BytesIO() new_zip = ZipFile(new_zip_data, 'w', compression=ZIP_LZMA) maps = [ item.p2c for item in UI['back_details'].items ] if not maps: messagebox.showerror( gettext('BEE2 Backup'), gettext('No maps were chosen to backup!'), ) return copy_loader.set_length('COPY', len(maps)) with copy_loader: for p2c in maps: # type: P2C old_zip = p2c.zip_file map_path = p2c.filename + '.p2c' scr_path = p2c.filename + '.jpg' if scr_path in zip_names(old_zip): with zip_open_bin(old_zip, scr_path) as f: new_zip.writestr(scr_path, f.read()) # Copy the map as bytes, so encoded characters are transfered # unaltered. with zip_open_bin(old_zip, map_path) as f: new_zip.writestr(map_path, f.read()) copy_loader.step('COPY') new_zip.close() # Finalize zip with open(BACKUPS['backup_path'], 'wb') as backup: backup.write(new_zip_data.getvalue()) BACKUPS['unsaved_file'] = new_zip_data # Remake the zipfile object, so it's open again. BACKUPS['backup_zip'] = new_zip = ZipFile( new_zip_data, mode='w', compression=ZIP_LZMA, ) # Update the items, so they use this zip now. for p2c in maps: p2c.zip_file = new_zip
def save_backup(): """Save the backup file.""" # We generate it from scratch, since that's the only way to remove # files. new_zip_data = BytesIO() new_zip = ZipFile(new_zip_data, 'w', compression=ZIP_LZMA) maps = [ item.p2c for item in UI['back_details'].items ] if not maps: messagebox.showerror( _('BEE2 Backup'), _('No maps were chosen to backup!'), ) return copy_loader.set_length('COPY', len(maps)) with copy_loader: for p2c in maps: # type: P2C old_zip = p2c.zip_file map_path = p2c.filename + '.p2c' scr_path = p2c.filename + '.jpg' if scr_path in zip_names(old_zip): with zip_open_bin(old_zip, scr_path) as f: new_zip.writestr(scr_path, f.read()) # Copy the map as bytes, so encoded characters are transfered # unaltered. with zip_open_bin(old_zip, map_path) as f: new_zip.writestr(map_path, f.read()) copy_loader.step('COPY') new_zip.close() # Finalize zip with open(BACKUPS['backup_path'], 'wb') as backup: backup.write(new_zip_data.getvalue()) BACKUPS['unsaved_file'] = new_zip_data # Remake the zipfile object, so it's open again. BACKUPS['backup_zip'] = new_zip = ZipFile( new_zip_data, mode='w', compression=ZIP_LZMA, ) # Update the items, so they use this zip now. for p2c in maps: p2c.zip_file = new_zip
def do_copy(zip_list, done_files): cache_path = os.path.abspath('../cache/') music_samp = os.path.abspath('../sounds/music_samp/') shutil.rmtree(cache_path, ignore_errors=True) shutil.rmtree(music_samp, ignore_errors=True) img_loc = os.path.join('resources', 'bee2') music_loc = os.path.join('resources', 'music_samp') for zip_path in zip_list: if os.path.isfile(zip_path): zip_file = ZipFile(zip_path) else: zip_file = FakeZip(zip_path) with zip_file: for path in zip_names(zip_file): loc = os.path.normcase(path) if not loc.startswith("resources"): continue # Don't re-extract images if loc.startswith(img_loc): continue if loc.startswith(music_loc): dest_path = os.path.join(music_samp, os.path.relpath(path, music_loc)) os.makedirs(os.path.dirname(dest_path), exist_ok=True) with zip_open_bin(zip_file, path) as src: with open(dest_path, 'wb') as dest: shutil.copyfileobj(src, dest) else: zip_file.extract(path, path=cache_path) with done_files.get_lock(): done_files.value += 1
def do_copy(zip_list, done_files): cache_path = os.path.abspath('../cache/') music_samp = os.path.abspath('../sounds/music_samp/') shutil.rmtree(cache_path, ignore_errors=True) shutil.rmtree(music_samp, ignore_errors=True) img_loc = os.path.join('resources', 'bee2') music_loc = os.path.join('resources', 'music_samp') for zip_path in zip_list: if os.path.isfile(zip_path): zip_file = ZipFile(zip_path) else: zip_file = FakeZip(zip_path) with zip_file: for path in zip_names(zip_file): loc = os.path.normcase(path) if not loc.startswith("resources"): continue # Don't re-extract images if loc.startswith(img_loc): continue if loc.startswith(music_loc): dest_path = os.path.join( music_samp, os.path.relpath(path, music_loc) ) os.makedirs(os.path.dirname(dest_path), exist_ok=True) with zip_open_bin(zip_file, path) as src: with open(dest_path, 'wb') as dest: shutil.copyfileobj(src, dest) else: zip_file.extract(path, path=cache_path) with done_files.get_lock(): done_files.value += 1
def restore_maps(maps: List[P2C]): """Copy the given maps to the game.""" game_dir = BACKUPS['game_path'] if game_dir is None: LOGGER.warning('No game selected to restore from?') return copy_loader.set_length('COPY', len(maps)) with copy_loader: for p2c in maps: back_zip = p2c.zip_file scr_path = p2c.filename + '.jpg' map_path = p2c.filename + '.p2c' abs_scr = os.path.join(game_dir, scr_path) abs_map = os.path.join(game_dir, map_path) if ( os.path.isfile(abs_scr) or os.path.isfile(abs_map) ): if not messagebox.askyesno( title='Overwrite File?', message=gettext('This map is already in the game directory.' 'Do you wish to overwrite it? ' '({})').format(p2c.title), parent=window, icon=messagebox.QUESTION, ): copy_loader.step('COPY') continue if scr_path in zip_names(back_zip): with zip_open_bin(back_zip, scr_path) as src: with open(abs_scr, 'wb') as dest: shutil.copyfileobj(src, dest) with zip_open_bin(back_zip, map_path) as src: with open(abs_map, 'wb') as dest: shutil.copyfileobj(src, dest) new_item = p2c.copy() new_item.zip_file = FakeZip(game_dir) BACKUPS['game'].append(new_item) copy_loader.step('COPY') refresh_game_details()
def restore_maps(maps: List[P2C]): """Copy the given maps to the game.""" game_dir = BACKUPS['game_path'] if game_dir is None: LOGGER.warning('No game selected to restore from?') return copy_loader.set_length('COPY', len(maps)) with copy_loader: for p2c in maps: back_zip = p2c.zip_file scr_path = p2c.filename + '.jpg' map_path = p2c.filename + '.p2c' abs_scr = os.path.join(game_dir, scr_path) abs_map = os.path.join(game_dir, map_path) if ( os.path.isfile(abs_scr) or os.path.isfile(abs_map) ): if not messagebox.askyesno( title='Overwrite File?', message=_('This map is already in the game directory.' 'Do you wish to overwrite it? ' '({})').format(p2c.title), parent=window, icon=messagebox.QUESTION, ): copy_loader.step('COPY') continue if scr_path in zip_names(back_zip): with zip_open_bin(back_zip, scr_path) as src: with open(abs_scr, 'wb') as dest: shutil.copyfileobj(src, dest) with zip_open_bin(back_zip, map_path) as src: with open(abs_map, 'wb') as dest: shutil.copyfileobj(src, dest) new_item = p2c.copy() new_item.zip_file = FakeZip(game_dir) BACKUPS['game'].append(new_item) copy_loader.step('COPY') refresh_game_details()
def from_file(cls, path, zip_file): """Initialise from a file. path is the file path for the map inside the zip, without extension. zip_file is either a ZipFile or FakeZip object. """ # Some P2Cs may have non-ASCII characters in descriptions, so we # need to read it as bytes and convert to utf-8 ourselves - zips # don't convert encodings automatically for us. try: with zip_open_bin(zip_file, path + '.p2c') as file: props = Property.parse( # Decode the P2C as UTF-8, and skip unknown characters. # We're only using it for display purposes, so that should # be sufficent. TextIOWrapper( file, encoding='utf-8', errors='replace', ), path, ) except KeyValError: # Silently fail if we can't parse the file. That way it's still # possible to backup. LOGGER.warning('Failed parsing puzzle file!', path, exc_info=True) props = Property('portal2_puzzle', []) title = None desc = _('Failed to parse this puzzle file. It can still be backed up.') else: props = props.find_key('portal2_puzzle', []) title = props['title', None] desc = props['description', _('No description found.')] if title is None: title = '<' + path.rsplit('/', 1)[-1] + '.p2c>' return cls( filename=os.path.basename(path), zip_file=zip_file, title=title, desc=desc, is_coop=srctools.conv_bool(props['coop', '0']), create_time=Date(props['timestamp_created', '']), mod_time=Date(props['timestamp_modified', '']), )
def save_backup(): """Save the backup file.""" # We generate it from scratch, since that's the only way to remove # files. new_zip_data = BytesIO() new_zip = ZipFile(new_zip_data, 'w', compression=ZIP_LZMA) maps = [ item.p2c for item in UI['back_details'].items ] copy_loader.set_length('COPY', len(maps)) with copy_loader: for p2c in maps: old_zip = p2c.zip_file map_path = p2c.path + '.p2c' scr_path = p2c.path + '.jpg' if scr_path in zip_names(old_zip): with zip_open_bin(old_zip, scr_path) as f: new_zip.writestr(scr_path, f.read()) with old_zip.open(map_path, 'r') as f: new_zip.writestr(map_path, f.read()) copy_loader.step('COPY') new_zip.close() # Finalize zip with open(BACKUPS['backup_path'], 'wb') as backup: backup.write(new_zip_data.getvalue()) BACKUPS['unsaved_file'] = new_zip_data # Remake the zipfile object, so it's open again. BACKUPS['backup_zip'] = new_zip = ZipFile( new_zip_data, mode='w', compression=ZIP_LZMA, ) # Update the items, so they use this zip now. for p2c in maps: p2c.zip_file = new_zip
def from_file(cls, path, zip_file): """Initialise from a file. path is the file path for the map inside the zip, without extension. zip_file is either a ZipFile or FakeZip object. """ # Some P2Cs may have non-ASCII characters in descriptions, so we # need to read it as bytes and convert to utf-8 ourselves - zips # don't convert encodings automatically for us. with zip_open_bin(zip_file, path + '.p2c') as file: props = Property.parse( # Decode the P2C as UTF-8, and skip unknown characters. # We're only using it for display purposes, so that should # be sufficent. EncodedFile( file, data_encoding='utf-8', errors='replace', ), path, ) props = props.find_key('portal2_puzzle', []) title = props['title', None] if title is None: title = '<' + path.rsplit('/', 1)[-1] + '.p2c>' return cls( path=path, zip_file=zip_file, title=title, desc=props['description', '...'], is_coop=utils.conv_bool(props['coop', '0']), create_time=Date(props['timestamp_created', '']), mod_time=Date(props['timestamp_modified', '']), )