This file is indexed.

/usr/lib/python3/dist-packages/shredder/application.py is in rmlint-gui 2.6.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python
# encoding: utf-8

"""Shredder's GtkApplication implementation.

It loads all initially required resources and triggers
the gui build by instancing the MainWindow.
"""

# Stdlib:
import os
import sys
import gettext
import logging

# External:
from gi.repository import Gtk, Gio, Rsvg, GdkPixbuf

# Internal
from shredder import APP_TITLE
from shredder.util import load_css_from_data
from shredder.about import AboutDialog
from shredder.runner import Script
from shredder.window import MainWindow

from shredder.views.settings import SettingsView
from shredder.views.locations import LocationView
from shredder.views.runner import RunnerView
from shredder.views.editor import EditorView


LOGGER = logging.getLogger('application')


def have_feature(feature):
    """Execute rmlint --version to check for some feature.

    --version will print the compile time configuration of rmlint.
    If a feature is missing, -somefeature is printed. A + in front else.
    """
    proc = Gio.Subprocess.new(
        ['rmlint', '--version'],
        Gio.SubprocessFlags.STDERR_PIPE
    )
    result, _, data = proc.communicate_utf8()
    if not result or not data:
        return False

    return '+' + feature in data


def _create_action(name, callback=None):
    """Create a named GAction with a callback for its activation"""
    action = Gio.SimpleAction.new(name, None)
    if callback is not None:
        action.connect('activate', callback)

    return action


def _load_app_icon():
    """Load & render the application svg icon from the resource bundle"""
    logo_svg = Gio.resources_lookup_data('/org/gnome/shredder/shredder.svg', 0)
    logo_handle = Rsvg.Handle.new_from_data(logo_svg.get_data())
    logo_handle.set_dpi_x_y(75, 75)
    return logo_handle.get_pixbuf().scale_simple(
        200, 200, GdkPixbuf.InterpType.HYPER
    )


class Application(Gtk.Application):
    """GtkApplication implementation of Shredder."""
    def __init__(self, options):
        Gtk.Application.__init__(
            self,
            application_id='org.gnome.Shredder',
            flags=Gio.ApplicationFlags.FLAGS_NONE
        )
        self.cmd_opts = options
        self.settings = self.win = None

        # Check compile time features of rmlint that we need later.
        if not have_feature('replay'):
            LOGGER.error('No support for +replay in rmlint binary.')
            LOGGER.error('Please recompile with --with-json-glib…')
            LOGGER.error('…and `json-glib-1.0` installed on your system.')
            sys.exit(-1)

    def do_activate(self, **kw):
        Gtk.Application.do_activate(self, **kw)
        self.win.present()

    def do_startup(self, **kw):
        Gtk.Application.do_startup(self, **kw)

        # Make tranlsating strings possible:
        # (We use the same message catalouge as rmlint)
        gettext.install('rmlint')

        rel_dir = os.path.dirname(__file__)
        resource_file = os.path.join(rel_dir, 'resources/shredder.gresource')
        LOGGER.info('Loading resources from: ' + resource_file)
        resource_bundle = Gio.Resource.load(resource_file)
        Gio.resources_register(resource_bundle)

        # Load the application CSS files.
        css_data = Gio.resources_lookup_data(
            '/org/gnome/shredder/shredder.css', 0
        )

        try:
            load_css_from_data(css_data.get_data())
        except Exception as err:
            LOGGER.warning("Failed to load css data: " + str(err))

        # Init the config system
        self.settings = Gio.Settings.new('org.gnome.Shredder')

        self.win = MainWindow(self)

        self.add_action(_create_action(
            'settings', lambda *_: self.win.views.switch('settings')
        ))
        self.add_action(_create_action(
            'about', lambda *_: AboutDialog(self.win).show_all()
        ))
        self.add_action(_create_action(
            'search', lambda *_: self.win.views.set_search_mode(True)
        ))
        self.add_action(_create_action(
            'activate', lambda *_: self.win.views.do_default_action()
        ))
        self.add_action(_create_action(
            'quit', lambda *_: self.quit()
        ))

        self.set_accels_for_action('app.quit', ['<Ctrl>Q'])
        self.set_accels_for_action('app.search', ['<Ctrl>F'])
        self.set_accels_for_action('app.activate', ['<Ctrl>Return'])

        # Set the fallback window title.
        # This is only used if no .desktop file is provided.
        self.win.set_wmclass(APP_TITLE, APP_TITLE)

        # Load the application icon
        self.win.set_default_icon(_load_app_icon())

        LOGGER.debug('Instancing views.')
        self.win.views.add_view(SettingsView(self), 'settings')
        self.win.views.add_view(LocationView(self), 'locations')
        self.win.views.add_view(RunnerView(self), 'runner')
        self.win.views.add_view(EditorView(self), 'editor')
        LOGGER.debug('Done instancing views.')

        initial_view = 'locations'

        if self.cmd_opts.tagged or self.cmd_opts.untagged:
            self.win.views['runner'].trigger_run(
                self.cmd_opts.untagged or [],
                self.cmd_opts.tagged or []
            )
            initial_view = 'runner'

        if self.cmd_opts.show_settings:
            initial_view = 'settings'

        for path in self.cmd_opts.locations or []:
            self.win.views['locations'].add_recent_item(path)

        if self.cmd_opts.script:
            self.win.views['editor'].override_script(
                Script(self.cmd_opts.script)
            )
            initial_view = 'editor'

        # Set the default view visible at startup
        self.win.views.switch(initial_view)
        self.win.show_all()