#!/usr/bin/env python3 ############################################################################ # # MODULE: r.unpack # AUTHOR(S): Hamish Bowman, Otago University, New Zealand # Converted to Python by Martin Landa # PURPOSE: Unpack up a raster map packed with r.pack # COPYRIGHT: (C) 2010-2017 by the GRASS Development Team # # This program is free software under the GNU General # Public License (>=v2). Read the file COPYING that # comes with GRASS for details. # ############################################################################# # %module # % description: Imports a GRASS GIS specific raster archive file (packed with r.pack) as a raster map # % keyword: raster # % keyword: import # % keyword: copying # %end # %option G_OPT_F_BIN_INPUT # % description: Name of input pack file # % key_desc: name.pack # %end # %option G_OPT_R_OUTPUT # % description: Name for output raster map (default: taken from input file internals) # % required: no # % guisection: Output settings # %end # %flag # % key: o # % label: Override projection check (use current location's projection) # % description: Assume that the dataset has same projection as the current location # % guisection: Output settings # %end # %flag # % key: p # % label: Print projection information of input pack file and exit # % guisection: Print # %end import os import re import sys import shutil import tarfile import atexit from grass.script.utils import diff_files, try_rmdir from grass.script import core as grass def cleanup(): try_rmdir(tmp_dir) def main(): infile = options['input'] global tmp_dir tmp_dir = grass.tempdir() grass.debug('tmp_dir = {tmpdir}'.format(tmpdir=tmp_dir)) if not os.path.exists(infile): grass.fatal(_('File {name} not found.'.format(name=infile))) gisenv = grass.gisenv() mset_dir = os.path.join(gisenv['GISDBASE'], gisenv['LOCATION_NAME'], gisenv['MAPSET']) input_base = os.path.basename(infile) shutil.copyfile(infile, os.path.join(tmp_dir, input_base)) os.chdir(tmp_dir) tar = tarfile.TarFile.open(name=input_base, mode='r') try: data_names = [ tarinfo.name for tarinfo in tar.getmembers() if '/' not in tarinfo.name ] except: grass.fatal(_("Pack file unreadable")) if flags['p']: # print proj info and exit try: for fname in ['PROJ_INFO', 'PROJ_UNITS']: f = tar.extractfile('{}/{}'.format(data_names[0], fname)) sys.stdout.write(f.read().decode()) except KeyError: grass.fatal(_("Pack file unreadable: file '{}' missing".format(fname))) tar.close() return 0 if options['output']: map_name = options['output'] else: map_name = data_names[0].split('@')[0] gfile = grass.find_file(name=map_name, element='cell', mapset='.') if gfile['file']: if os.environ.get('GRASS_OVERWRITE', '0') != '1': grass.fatal(_('Raster map <{name}> already exists'.format(name=map_name))) else: grass.warning( _('Raster map <{name}> already exists and will be overwritten'.format(name=map_name))) # extract data tar.extractall() tar.close() os.chdir(data_names[0]) if os.path.exists('cell'): pass elif os.path.exists('coor'): grass.fatal(_('This GRASS GIS pack file contains vector data. Use ' 'v.unpack to unpack <{name}>'.format(name=map_name))) else: grass.fatal(_("Pack file unreadable")) # check projection compatibility in a rather crappy way if flags['o']: grass.warning(_("Overriding projection check (using current location's projection).")) else: diff_result_1 = diff_result_2 = None proj_info_file_1 = 'PROJ_INFO' proj_info_file_2 = os.path.join(mset_dir, '..', 'PERMANENT', 'PROJ_INFO') skip_projection_check = False if not os.path.exists(proj_info_file_1): if os.path.exists(proj_info_file_2): grass.fatal( _("PROJ_INFO file is missing, unpack raster map in XY (unprojected) location.")) skip_projection_check = True # XY location if not skip_projection_check: if not grass.compare_key_value_text_files(filename_a=proj_info_file_1, filename_b=proj_info_file_2, proj=True): diff_result_1 = diff_files(proj_info_file_1, proj_info_file_2) proj_units_file_1 = 'PROJ_UNITS' proj_units_file_2 = os.path.join(mset_dir, '..', 'PERMANENT', 'PROJ_UNITS') if not grass.compare_key_value_text_files(filename_a=proj_units_file_1, filename_b=proj_units_file_2, units=True): diff_result_2 = diff_files(proj_units_file_1, proj_units_file_2) if diff_result_1 or diff_result_2: if diff_result_1: grass.warning(_("Difference between PROJ_INFO file of packed map " "and of current location:\n{diff}").format(diff=''.join(diff_result_1))) if diff_result_2: grass.warning(_("Difference between PROJ_UNITS file of packed map " "and of current location:\n{diff}").format(diff=''.join(diff_result_2))) grass.fatal(_("Projection of dataset does not appear to match current location." " In case of no significant differences in the projection definitions," " use the -o flag to ignore them and use" " current location definition.")) maps = [] vrt_file = None for index, data in enumerate(data_names): if index > 0: map_name = data for element in [ 'cats', 'cell', 'cellhd', 'cell_misc', 'colr', 'fcell', 'hist' ]: src_path = os.path.join(tmp_dir, data, element) if not os.path.exists(src_path): continue path = os.path.join(mset_dir, element) if not os.path.exists(path): os.mkdir(path) if element == 'cell_misc': if index > 0: maps.append( "{map_name}@{mapset}".format( map_name=map_name, mapset=gisenv['MAPSET'], ), ) path = os.path.join( mset_dir, element, map_name, ) if index == 0: vrt_file = os.path.join(path, 'vrt') if os.path.exists(path): shutil.rmtree(path) shutil.copytree(src_path, path) else: shutil.copyfile( src_path, os.path.join(mset_dir, element, map_name), ) # Update vrt file if maps: if vrt_file and os.path.exists(vrt_file): files = '\n'.join(maps) with open(vrt_file, 'w') as f: f.write(files) grass.message(_('Raster map <{name}> unpacked'.format(name=map_name))) if __name__ == "__main__": options, flags = grass.parser() atexit.register(cleanup) sys.exit(main())