Example #1
0
def _create_qgis_projects(action, au_uids):
    gws.log.debug(f'create qgis projects for {au_uids!r}')

    dd = action.data_dir

    extents = _enum_extents(action, au_uids)
    layers = _enum_layers(action, au_uids)

    for au_uid in au_uids:
        path = f'{dd}/qgs/{au_uid}.qgs'

        ls = [la for la in layers if la['au_uid'] == au_uid]
        if not ls:
            os2.unlink(path)
            continue

        ext = extents.get(au_uid)
        if not ext:
            continue

        au_props = [au for au in action.au_list if au.uid == au_uid]
        if not au_props:
            continue

        res = action.qgis_template.render({
            'extent': ext,
            'layers': ls,
            'au': au_props[0],
        })

        gws.write_file(path, res.content)
        gws.log.debug(f'created {path!r}')
Example #2
0
def create_and_save(root: gws.IRoot):
    cfg = create(root)

    if not cfg:
        force = root.application.var('server.mapproxy.forceStart')
        if force:
            gws.log.warn('mapproxy: no configuration, using default')
            cfg = DEFAULT_CONFIG
        else:
            gws.log.warn('mapproxy: no configuration, not starting')
            gws.lib.os2.unlink(CONFIG_PATH)
            return

    cfg_str = yaml.dump(cfg)

    # make sure the config is ok before starting the server!
    test_path = CONFIG_PATH + '.test.yaml'
    gws.write_file(test_path, cfg_str)

    try:
        make_wsgi_app(test_path)
    except Exception as e:
        raise gws.ConfigurationError(f'MAPPROXY ERROR: {e!r}') from e

    gws.lib.os2.unlink(test_path)

    # write into the real config path
    gws.write_file(CONFIG_PATH, cfg_str)
Example #3
0
    def _worker(self, signo):
        with gws.lib.misc.lock(_lockfile) as ok:
            if not ok:
                try:
                    pid = int(gws.read_file(_lockfile))
                except:
                    pid = None
                if not pid or not psutil.pid_exists(pid):
                    gws.log.info(
                        f'MONITOR: locked by dead pid={pid!r}, releasing')
                else:
                    gws.log.info(f'MONITOR: locked by pid={pid!r}')
                    return

            gws.write_file(_lockfile, str(os.getpid()))
            changed = self._poll()

            if not changed:
                return

            for path in changed:
                gws.log.info(f'MONITOR: changed {path!r}')

            # @TODO: smarter reload

            reconf = any(gws.APP_DIR not in path for path in changed)

            gws.log.info(f'MONITOR: begin reload (reconfigure={reconf})')

            if not self._reload(reconf):
                return

        # finally, reload ourselves
        gws.log.info(f'MONITOR: bye bye')
        control.reload('spool')
Example #4
0
def environ(root: gws.IRoot):
    base_dir = gws.ensure_dir(gws.TMP_DIR + '/qqq')

    # it's all a bit blurry, but the server appears to read 'ini' from OPTIONS_DIR
    # while the app uses a profile
    # NB: for some reason, the profile path will be profiles/profiles/default (sic!)

    gws.ensure_dir('profiles', base_dir)
    gws.ensure_dir('profiles/default', base_dir)
    gws.ensure_dir('profiles/default/QGIS', base_dir)
    gws.ensure_dir('profiles/profiles', base_dir)
    gws.ensure_dir('profiles/profiles/default', base_dir)
    gws.ensure_dir('profiles/profiles/default/QGIS', base_dir)

    ini = _make_ini(root, base_dir)
    gws.write_file(base_dir + '/profiles/default/QGIS/QGIS3.ini', ini)
    gws.write_file(base_dir + '/profiles/profiles/default/QGIS/QGIS3.ini', ini)

    # server options, as documented on
    # see https://docs.qgis.org/testing/en/docs/user_manual/working_with_ogc/server/config.html#environment-variables

    server_env = {
        # not used here 'QGIS_PLUGINPATH': '',
        # not used here 'QGIS_SERVER_LOG_FILE': '',

        # see https://github.com/qgis/QGIS/pull/35738
        'QGIS_SERVER_IGNORE_BAD_LAYERS': 'true',

        'MAX_CACHE_LAYERS': root.application.var('server.qgis.maxCacheLayers'),
        'QGIS_OPTIONS_PATH': base_dir + '/profiles/profiles/default',
        'QGIS_SERVER_CACHE_DIRECTORY': gws.ensure_dir('servercache', base_dir),
        'QGIS_SERVER_CACHE_SIZE': root.application.var('server.qgis.serverCacheSize'),
        'QGIS_SERVER_LOG_LEVEL': root.application.var('server.qgis.serverLogLevel'),
        # 'QGIS_SERVER_MAX_THREADS': 4,
        # 'QGIS_SERVER_PARALLEL_RENDERING': 'false',
    }

    # qgis app options, mostly undocumented

    qgis_env = {
        'QGIS_PREFIX_PATH': '/usr',
        'QGIS_DEBUG': root.application.var('server.qgis.debug'),
        # 'QGIS_GLOBAL_SETTINGS_FILE': '/global_settings.ini',
        'QGIS_CUSTOM_CONFIG_PATH': base_dir
    }

    # finally, there are lots of GDAL settings, some of those seem relevant
    # http://trac.osgeo.org/gdal/wiki/ConfigOptions

    gdal_env = {
        'GDAL_FIX_ESRI_WKT': 'GEOGCS',
        'GDAL_DEFAULT_WMS_CACHE_PATH': gws.ensure_dir('gdalcache', base_dir),
    }

    return gws.merge(
        server_env,
        qgis_env,
        gdal_env,
    )
Example #5
0
    def _inject_html_boxes(self, tri, boxes, project_path):
        # iterate the template XML tree and inject our boxes
        # see `caps.py` for the print layout structure

        root_el = xml2.from_path(self.provider.path)
        for layout_el in xml2.all(root_el, 'Layouts Layout'):
            for item_el in layout_el.children:
                uuid = item_el.attributes.get('uuid')
                if uuid in boxes:
                    item_el.attributes['html'] = boxes[uuid]

        gws.write_file(project_path, xml2.to_string(root_el))
Example #6
0
    def caps(self, p: CapsParams):
        """Print the capabilities of a document in JSON format"""

        xml = gws.read_file(p.path)
        mod = gws.import_from_path(f'gws/plugin/qgis/caps.py')
        res = mod.parse(xml)

        js = gws.lib.json2.to_pretty_string(res,
                                            default=_caps_json,
                                            ascii=False)

        if p.out:
            gws.write_file(p.out, js)
            gws.log.info(f'saved to {p.out!r}')
        else:
            print(js)
Example #7
0
def _enum_images(action):
    dd = action.data_dir
    images = []

    for path in os2.find_files(f'{dd}/png', ext='png'):
        fn = _fnbody(path)
        converted_path = f'{dd}/cnv/{fn}.png'

        if os2.file_mtime(converted_path) < os2.file_mtime(path):
            try:
                # reduce the image palette (20-30 colors work just fine for scanned plans)
                gws.log.debug(f'converting {path!r}')
                img = PIL.Image.open(path)
                img = img.convert('RGBA')
                img = img.convert('P',
                                  palette=PIL.Image.ADAPTIVE,
                                  colors=action.image_quality)
                img.save(converted_path)
                os2.chown(converted_path)

                # copy the pgw along
                pgw = gws.read_file(f'{dd}/png/{fn}.pgw')
                gws.write_file(f'{dd}/cnv/{fn}.pgw', pgw)
            except Exception as e:
                gws.log.error(f'error converting {path!r}: {e}')
                continue

        try:
            palette = _image_palette(converted_path)
        except Exception as e:
            gws.log.error(
                f'error getting palette from {converted_path!r}: {e}')
            continue

        images.append({
            'uid': '_r_' + fn,
            'fname': fn,
            'path': converted_path,
            'palette': palette
        })

    return images
Example #8
0
    def find_features(self, args, source_layers):
        if not args.shapes:
            return []

        shape = args.shapes[0]
        if shape.geometry_type != gws.GeometryType.point:
            return []

        ps = gws.gis.ows.client.prepared_search(
            inverted_crs=self.inverted_crs,
            limit=args.limit,
            point=shape,
            protocol=self.protocol,
            protocol_version=self.version,
            request_crs=self.force_crs,
            request_crs_format=gws.CrsFormat.EPSG,
            source_layers=source_layers,
        )

        params = gws.merge(ps.params, args.params)

        fmt = self.preferred_formats.get(gws.OwsVerb.GetFeatureInfo)
        if fmt:
            params.setdefault('INFO_FORMAT', fmt)

        op_args = self.operation_args(gws.OwsVerb.GetFeatureInfo,
                                      params=params)
        text = gws.gis.ows.request.get_text(**op_args)
        gws.write_file('/gws-var/res.xml', text)
        features = featureinfo.parse(text, crs=ps.request_crs, axis=ps.axis)

        if features is None:
            gws.log.debug(f'WMS NOT_PARSED params={params!r}')
            return []
        gws.log.debug(f'WMS FOUND={len(features)} params={params!r}')

        return [f.transform_to(shape.crs) for f in features]
Example #9
0
    def caps(self, p: CapsParams):
        """Print the capabilities of a service in JSON format"""

        protocol = None

        if p.type:
            protocol = p.type.lower()
        else:
            u = p.src.lower()
            for s in ('wms', 'wmts', 'wfs'):
                if s in u:
                    protocol = s
                    break

        if not protocol:
            raise gws.Error('unknown service')

        if p.src.startswith(('http:', 'https:')):
            xml = gws.gis.ows.request.get_text(
                p.src,
                protocol=t.cast(gws.OwsProtocol, protocol.upper()),
                verb=gws.OwsVerb.GetCapabilities)
        else:
            xml = gws.read_file(p.src)

        mod = gws.import_from_path(
            f'gws/plugin/ows_provider/{protocol}/caps.py')
        res = mod.parse(xml)

        js = gws.lib.json2.to_pretty_string(res, default=_caps_json)

        if p.out:
            gws.write_file(p.out, js)
            gws.log.info(f'saved to {p.out!r}')
        else:
            print(js)
Example #10
0
    def configure(self):
        

        self.crs = self.var('crs')
        self.db = t.cast(
            gws.ext.db.provider.postgres.Object,
            gws.base.db.require_provider(self, 'gws.ext.db.provider.postgres'))

        self.templates: t.List[gws.ITemplate] = gws.base.template.bundle(self, self.var('templates'))
        self.qgis_template: gws.ITemplate = gws.base.template.find(self.templates, subject='bplan.qgis')
        self.info_template: gws.ITemplate = gws.base.template.find(self.templates, subject='bplan.info')

        self.plan_table = self.db.configure_table(self.var('planTable'))
        self.meta_table = self.db.configure_table(self.var('metaTable'))
        self.data_dir = self.var('dataDir')

        self.au_list = self.var('administrativeUnits')
        self.type_list = self.var('planTypes')
        self.image_quality = self.var('imageQuality')

        p = self.var('exportDataModel')
        self.export_data_model: t.Optional[gws.IDataModel] = self.create_child('gws.base.model', p) if p else None

        for sub in 'png', 'pdf', 'cnv', 'qgs':
            gws.ensure_dir(self.data_dir + '/' + sub)

        self.key_col = 'plan_id'
        self.au_key_col = 'ags'
        self.au_name_col = 'gemeinde'
        self.type_col = 'typ'
        self.time_col = 'rechtskr'
        self.x_coord_col = 'utm_ost'
        self.y_coord_col = 'utm_nord'

        gws.write_file(_RELOAD_FILE, gws.random_string(16))
        self.root.application.monitor.add_path(_RELOAD_FILE)
Example #11
0
    def _do_render(self, text, context, parser, runtime):
        def err(e, path, line):
            gws.log.warn(
                f'TEMPLATE: {e.__class__.__name__}:{e} in {path}:{line}')

        if self.root.application.developer_option('template.raise_errors'):
            err = None

        if self.root.application.developer_option('template.save_compiled'):
            gws.write_file(
                gws.VAR_DIR + '/debug_template_' + gws.to_uid(self.path) +
                '_' + gws.sha256(text),
                chartreux.translate(text,
                                    commands=parser,
                                    path=self.path or '<string>'))

        return chartreux.render(
            text,
            context,
            path=self.path or '<string>',
            error=err,
            runtime=runtime,
            commands=parser,
        )
Example #12
0
 def signal_reload(self, source):
     gws.log.debug(f'bplan reload signal {source!r}')
     gws.write_file(_RELOAD_FILE, gws.random_string(16))
Example #13
0
def _save_intermediate(path, txt, ext):
    p = gws.lib.os2.parse_path(path)
    gws.write_file(f"{gws.CONFIG_DIR}/{p['name']}.parsed.{ext}", txt)
Example #14
0
 def save(self, path=None):
     path = path or self.path
     if not path:
         raise ValueError('no path')
     gws.write_file(path, str(self.bs))