123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- #!/usr/bin/env python3
- ############################################################################
- #
- # MODULE: v.unpack
- # AUTHOR(S): Luca Delucchi
- #
- # PURPOSE: Unpack up a vector map packed with v.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 vector archive file (packed with v.pack) as a vector map
- # % keyword: vector
- # % 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_V_OUTPUT
- # % label: Name for output vector map
- # % description: 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 sys
- import shutil
- import tarfile
- import atexit
- from grass.script.utils import diff_files, try_rmdir
- from grass.script import core as grass
- from grass.script import db as grassdb
- from grass.exceptions import CalledModuleError
- def cleanup():
- try_rmdir(tmp_dir)
- def main():
- infile = options["input"]
- # create temporary directory
- global tmp_dir
- tmp_dir = grass.tempdir()
- grass.debug("tmp_dir = %s" % tmp_dir)
- # check if the input file exists
- if not os.path.exists(infile):
- grass.fatal(_("File <%s> not found") % infile)
- # copy the files to tmp dir
- 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_name = tar.getnames()[0]
- 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(fname)
- sys.stdout.write(f.read().decode())
- except KeyError:
- grass.fatal(_("Pack file unreadable: file '{}' missing".format(fname)))
- tar.close()
- return 0
- # set the output name
- if options["output"]:
- map_name = options["output"]
- else:
- map_name = data_name
- # grass env
- gisenv = grass.gisenv()
- mset_dir = os.path.join(
- gisenv["GISDBASE"], gisenv["LOCATION_NAME"], gisenv["MAPSET"]
- )
- new_dir = os.path.join(mset_dir, "vector", map_name)
- gfile = grass.find_file(name=map_name, element="vector", mapset=".")
- overwrite = os.getenv("GRASS_OVERWRITE")
- if gfile["file"] and overwrite != "1":
- grass.fatal(_("Vector map <%s> already exists") % map_name)
- elif overwrite == "1" and gfile["file"]:
- grass.warning(
- _("Vector map <%s> already exists and will be overwritten") % map_name
- )
- grass.run_command(
- "g.remove", flags="f", quiet=True, type="vector", name=map_name
- )
- shutil.rmtree(new_dir, True)
- # extract data
- tar.extractall()
- tar.close()
- if os.path.exists(os.path.join(data_name, "coor")):
- pass
- elif os.path.exists(os.path.join(data_name, "cell")):
- grass.fatal(
- _(
- "This GRASS GIS pack file contains raster data. Use "
- "r.unpack to unpack <%s>" % map_name
- )
- )
- else:
- grass.fatal(_("Pack file unreadable"))
- # check projection compatibility in a rather crappy way
- loc_proj = os.path.join(mset_dir, "..", "PERMANENT", "PROJ_INFO")
- loc_proj_units = os.path.join(mset_dir, "..", "PERMANENT", "PROJ_UNITS")
- skip_projection_check = False
- if not os.path.exists(os.path.join(tmp_dir, "PROJ_INFO")):
- if os.path.exists(loc_proj):
- grass.fatal(
- _(
- "PROJ_INFO file is missing, unpack vector map in XY (unprojected) location."
- )
- )
- skip_projection_check = True # XY location
- if not skip_projection_check:
- diff_result_1 = diff_result_2 = None
- if not grass.compare_key_value_text_files(
- filename_a=os.path.join(tmp_dir, "PROJ_INFO"),
- filename_b=loc_proj,
- proj=True,
- ):
- diff_result_1 = diff_files(os.path.join(tmp_dir, "PROJ_INFO"), loc_proj)
- if not grass.compare_key_value_text_files(
- filename_a=os.path.join(tmp_dir, "PROJ_UNITS"),
- filename_b=loc_proj_units,
- units=True,
- ):
- diff_result_2 = diff_files(
- os.path.join(tmp_dir, "PROJ_UNITS"), loc_proj_units
- )
- if diff_result_1 or diff_result_2:
- if flags["o"]:
- grass.warning(_("Projection information does not match. Proceeding..."))
- else:
- 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."
- )
- )
- # new db
- fromdb = os.path.join(tmp_dir, "db.sqlite")
- # copy file
- shutil.copytree(data_name, new_dir)
- # exist fromdb
- if os.path.exists(fromdb):
- # the db connection in the output mapset
- dbconn = grassdb.db_connection(force=True)
- todb = dbconn["database"]
- # return all tables
- list_fromtable = grass.read_command(
- "db.tables", driver="sqlite", database=fromdb
- ).splitlines()
- # return the list of old connection for extract layer number and key
- dbln = open(os.path.join(new_dir, "dbln"), "r")
- dbnlist = dbln.readlines()
- dbln.close()
- # check if dbf or sqlite directory exists
- if dbconn["driver"] == "dbf" and not os.path.exists(
- os.path.join(mset_dir, "dbf")
- ):
- os.mkdir(os.path.join(mset_dir, "dbf"))
- elif dbconn["driver"] == "sqlite" and not os.path.exists(
- os.path.join(mset_dir, "sqlite")
- ):
- os.mkdir(os.path.join(mset_dir, "sqlite"))
- # for each old connection
- for t in dbnlist:
- # it split the line of each connection, to found layer number and key
- if len(t.split("|")) != 1:
- values = t.split("|")
- else:
- values = t.split(" ")
- from_table = values[1]
- layer = values[0].split("/")[0]
- # we need to take care about the table name in case of several layer
- if options["output"]:
- if len(dbnlist) > 1:
- to_table = "%s_%s" % (map_name, layer)
- else:
- to_table = map_name
- else:
- to_table = from_table
- grass.verbose(_("Coping table <%s> as table <%s>") % (from_table, to_table))
- # copy the table in the default database
- try:
- grass.run_command(
- "db.copy",
- to_driver=dbconn["driver"],
- to_database=todb,
- to_table=to_table,
- from_driver="sqlite",
- from_database=fromdb,
- from_table=from_table,
- )
- except CalledModuleError:
- grass.fatal(
- _("Unable to copy table <%s> as table <%s>")
- % (from_table, to_table)
- )
- grass.verbose(
- _("Connect table <%s> to vector map <%s> at layer <%s>")
- % (to_table, map_name, layer)
- )
- # and connect the new tables with the right layer
- try:
- grass.run_command(
- "v.db.connect",
- flags="o",
- quiet=True,
- driver=dbconn["driver"],
- database=todb,
- map=map_name,
- key=values[2],
- layer=layer,
- table=to_table,
- )
- except CalledModuleError:
- grass.fatal(
- _("Unable to connect table <%s> to vector map <%s>")
- % (to_table, map_name)
- )
- grass.message(_("Vector map <%s> successfully unpacked") % map_name)
- if __name__ == "__main__":
- options, flags = grass.parser()
- atexit.register(cleanup)
- sys.exit(main())
|