Commit 43ad3985 authored by David Boddie's avatar David Boddie 💬
Browse files

Import initial sources

parents
This diff is collapsed.
#!/usr/bin/env python3
from os import environ, path
from subprocess import call
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
datadir = path.join(prefix, 'share')
destdir = environ.get('DESTDIR', '')
# Package managers set this so we don't need to run
if not destdir:
print('Updating icon cache...')
call(['gtk-update-icon-cache', '-qtf',
path.join(datadir, 'icons', 'hicolor')])
print('Updating desktop database...')
call(['update-desktop-database', '-q', path.join(datadir, 'applications')])
[Desktop Entry]
Name=Librem 5 Licenses
Type=Application
Terminal=false
StartupNotify=true
Exec=librem5-get-package-info
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=librem5-get-package-info
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="640pt" height="640pt" viewBox="0 0 640.000000 640.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
Annotated by David Boddie for Purism
Copyright (C) 2019 Purism SPC
Licensed under a Creative Commons Attribution-ShareAlike 4.0 Unported License.
http://creativecommons.org/licenses/by-sa/4.0/
</metadata>
<defs>
<linearGradient id="background" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#808080" />
<stop offset="30%" stop-color="white" />
<stop offset="70%" stop-color="white" />
<stop offset="100%" stop-color="#808080" />
</linearGradient>
</defs>
<path d="M 40,0 l 560,0 c 20,0 40,20 40,40 l 0,560 c 0,20 -20,40 -40,40
l -560,0 c -20,0 -40,-20 -40,-40 l 0,-560 c 0,-20 20,-40 40,-40 z"
stroke="none" fill="url(#background)" />
<g transform="translate(80,640) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1601 6007 c-76 -25 -104 -40 -147 -80 -63 -57 -99 -127 -114 -217
-14 -90 -14 -4930 0 -5020 15 -90 51 -160 114 -217 45 -41 69 -54 153 -81 59
-19 120 -32 151 -32 50 0 1518 261 1578 280 80 27 178 151 210 267 18 65 19
151 19 2293 0 2142 -1 2228 -19 2293 -32 116 -130 240 -210 267 -69 22 -1530
280 -1584 279 -35 0 -94 -13 -151 -32z m956 -122 c411 -74 761 -140 777 -145
48 -17 96 -59 137 -123 21 -33 39 -65 39 -71 0 -6 -8 3 -19 19 -29 47 -103
110 -152 129 -49 19 -1442 266 -1498 266 -42 0 -126 -40 -179 -86 -33 -28 -59
-75 -86 -158 -4 -10 -9 -16 -12 -13 -10 10 24 97 52 134 36 48 23 53 -15 6
-17 -21 -40 -67 -51 -102 -20 -62 -20 -104 -20 -2541 0 -2459 0 -2478 20
-2543 16 -50 33 -80 73 -123 64 -70 112 -93 194 -94 53 0 1448 239 1493 255
12 5 13 7 0 15 -8 5 -11 12 -6 17 4 4 12 0 17 -9 5 -10 16 -15 24 -12 8 4 12
11 8 17 -3 6 -1 7 5 3 14 -8 52 10 52 25 0 6 -6 7 -12 3 -7 -4 7 12 32 37 25
24 47 42 49 39 2 -3 12 20 22 50 15 46 18 50 18 24 2 -72 -106 -218 -180 -242
-67 -23 -1531 -282 -1587 -282 -33 0 -74 8 -97 19 -43 19 -104 81 -130 131
-46 89 -45 12 -45 2670 0 2692 -2 2590 49 2676 11 19 16 34 12 34 -17 0 -53
-75 -67 -140 -21 -98 -20 -5043 0 -5142 17 -80 35 -116 84 -170 34 -38 35 -40
12 -33 -54 16 -91 39 -126 77 -46 51 -70 105 -83 188 -15 90 -15 4929 0 5020
23 144 94 226 242 277 59 20 113 32 149 32 33 1 373 -56 805 -134z m-632 46
c40 -9 40 -9 -17 -10 -31 0 -60 4 -63 9 -7 12 24 12 80 1z m693 -122 c345 -60
629 -112 631 -115 2 -2 -7 -4 -21 -4 -39 0 -1180 199 -1203 210 -11 5 -29 11
-40 13 -11 3 -14 5 -6 6 7 0 295 -49 639 -110z m-25 -33 c834 -145 806 -138
857 -215 14 -20 35 -65 47 -101 l22 -65 1 -2190 c0 -2112 -1 -2192 -19 -2256
-10 -36 -31 -84 -47 -106 -58 -82 -22 -73 -861 -220 -513 -89 -784 -132 -816
-130 -72 6 -124 47 -154 122 -14 33 -29 68 -34 77 -12 24 -12 4993 0 5016 5 9
20 43 33 76 31 80 90 124 168 125 19 0 380 -59 803 -133z m-1033 -2576 c0
-1366 -2 -2486 -5 -2488 -3 -3 -5 1117 -5 2488 0 1371 2 2491 5 2488 3 -2 5
-1122 5 -2488z m1768 2476 c9 -9 -31 -6 -53 5 -16 7 -13 8 13 5 19 -3 36 -7
40 -10z m219 -3564 c-1 -598 -2 -108 -2 1088 0 1196 1 1686 2 1087 2 -598 2
-1576 0 -2175z m-298 -1406 c-5 -5 -568 -106 -589 -106 -7 0 -10 3 -6 8 9 9
508 99 560 101 22 0 37 -1 35 -3z m-1669 -30 c0 -26 48 -121 71 -142 13 -12
40 -31 59 -43 40 -24 33 -28 -9 -6 -43 22 -108 100 -125 152 -19 54 -20 67 -6
58 6 -3 10 -12 10 -19z m1000 -92 c-36 -7 -74 -13 -85 -12 -27 1 93 26 125 26
14 0 -4 -6 -40 -14z m-115 -19 c-18 -7 -585 -105 -607 -105 -12 0 -18 3 -14 8
11 11 525 100 581 100 28 0 46 -1 40 -3z"/>
<path d="M1400 5411 l-25 -7 -3 -157 c-3 -171 -1 -177 52 -158 l27 11 -3 157
c-2 94 -7 157 -13 159 -5 1 -21 -1 -35 -5z m24 -82 c8 -78 -2 -166 -20 -173
-16 -6 -17 18 -5 102 4 29 4 55 -1 58 -10 6 -11 58 -1 67 15 15 20 4 27 -54z"/>
<path d="M1400 5001 l-25 -7 -3 -154 c-1 -84 1 -157 5 -161 5 -5 22 -5 38 -1
l30 8 0 159 c0 97 -4 159 -10 161 -5 1 -21 -1 -35 -5z m24 -82 c7 -75 -2 -166
-19 -172 -8 -4 -11 25 -10 111 3 130 2 122 14 122 4 0 11 -27 15 -61z"/>
<path d="M1400 4591 l-25 -7 -3 -154 c-1 -84 1 -157 5 -161 5 -5 22 -5 38 -1
l30 8 0 159 c0 97 -4 159 -10 161 -5 1 -21 -1 -35 -5z m24 -82 c8 -76 -3 -169
-19 -169 -9 0 -11 30 -10 113 2 124 2 117 14 117 4 0 11 -27 15 -61z"/>
<path d="M1375 3918 c-3 -7 -4 -150 -3 -318 l3 -305 35 0 35 0 0 315 0 315
-33 3 c-20 2 -34 -2 -37 -10z"/>
<path d="M1667 5663 c-10 -9 -9 -4921 1 -4927 9 -5 1775 269 1791 278 16 10
16 4362 0 4372 -6 3 -397 66 -868 140 -471 73 -870 136 -887 139 -17 3 -33 2
-37 -2z m898 -153 c462 -71 850 -132 863 -135 l22 -5 0 -2170 0 -2170 -22 -5
c-13 -3 -401 -64 -863 -135 -462 -71 -850 -132 -862 -135 l-23 -5 0 2450 0
2450 23 -5 c12 -3 400 -64 862 -135z"/>
</g>
</svg>
# Initialize local variables to hold installation paths.
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
# Translate the desktop file template using the message catalogs from the po
# directory, found in the project's root, generating a desktop file in the
# build directory.
desktop_file = i18n.merge_file(
input: 'librem5-get-package-info.desktop.in',
output: 'librem5-get-package-info.desktop',
type: 'desktop',
po_dir: '../po',
install: true,
install_dir: join_paths(get_option('datadir'), 'applications')
)
# If found, use a tool to validate the desktop file.
desktop_utils = find_program('desktop-file-validate', required: false)
if desktop_utils.found()
test('Validate desktop file', desktop_utils,
args: [desktop_file]
)
endif
install_data('librem5-get-package-info.svg',
install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', 'scalable', 'apps'))
librem5-get-package-info (1.0.0) amber-phone; urgency=medium
* Initial release of a tool to list package information.
-- David Boddie <david.boddie@puri.sm> Mon, 11 Nov 2019 22:30:00 +0200
Source: librem5-get-package-info
Section: doc
Priority: optional
Maintainer: David Boddie <david.boddie@puri.sm>
Build-Depends:
debhelper (>= 10),
meson,
ninja-build
Standards-Version: 4.1.3
Homepage: https://source.puri.sm/Librem5/librem5-get-package-info
Package: librem5-get-package-info
Architecture: all
Depends:
python3-gi,
gir1.2-gtk-3.0,
python3-debian,
python3-apt,
${misc:Depends}
Description: Quick Start Guide viewer for the Librem 5 phone
A minimal viewer application to display the pages of the Quick Start Guide.
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: https://source.puri.sm/Librem5/librem5-get-package-info
Files: *
Copyright: Copyright (C) 2019 Purism SPC
License: GPL-3+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
#!/usr/bin/make -f
%:
dh $@ --buildsystem=meson
# Define the project and its metadata.
project('librem5_get_package_info',
version: '1.0.0',
meson_version: '>= 0.48.0',
)
# Import the i18n module to allow other build scripts to access its features.
i18n = import('i18n')
# Declare the project's subdirectories.
subdir('data')
subdir('src')
subdir('po')
# Add a script to handle tasks that are not automatically performed by Meson.
meson.add_install_script('build-aux/meson/postinstall.py')
# When needed, run the appropriate tool to extract translatable strings from
# the application sources and other files. This will typically be the xgettext
# tool, whose options we use to fill in some of the fields in the generated POT
# file.
i18n.gettext('librem5-get-package-info',
preset: 'glib',
args: [
'--copyright-holder=Purism SPC',
'--package-name="Librem 5 Get Package Info"',
'--package-version=' + meson.project_version(),
'--msgid-bugs-address=david.boddie@puri.sm'
]
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Simple Weather example
# This file is part of the Librem 5 developer documentation.
# Copyright (C) 2019 Purism SPC
# SPDX-License-Identifier: GPL-3.0+
# Author: David Boddie <david.boddie@puri.sm>
import gettext
import sys
# Placeholders to be replaced by the build system
localedir = '@localedir@'
pkgdatadir = '@pkgdatadir@'
prefix = '@prefix@'
sys.path.insert(1, pkgdatadir)
# Install a translator for Python code to use throughout the application.
gettext.install('librem5-get-package-info', localedir, names=['ngettext'])
if __name__ == '__main__':
from librem5_get_package_info.main import Application
app = Application()
sys.exit(app.run(sys.argv))
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This file is part of the Librem 5 Get Package Info tool.
# Display information about installed packages.
# Copyright (C) 2019 Purism SPC
# SPDX-License-Identifier: GPL-3.0+
# Author: David Boddie <david.boddie@puri.sm>
import gi
import os
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk
from .package_info import Worker
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='sm.puri.Get_Package_Info')
GLib.set_application_name('Get Package Info')
GLib.set_prgname('sm.puri.Get_Package_Info')
self.timeout_id = None
self.lines = []
self.ready = False
def do_activate(self):
window = Gtk.ApplicationWindow(application=self)
window.set_icon_name('sm.puri.Get_Package_Info')
header = Gtk.HeaderBar(title=_('Get Package Info'),
show_close_button=True)
window.set_titlebar(header)
self.output_dir = os.path.join(os.getenv('HOME'), '.local', 'share', 'librem5-get-package-info')
vbox = Gtk.Box(orientation='vertical', margin=8, spacing=12)
self.label = Gtk.Label(hexpand=True, hexpand_set=True, ellipsize=True)
self.label.set_xalign(0.0)
try:
if os.path.exists(self.output_dir):
self.ready = True
else:
os.mkdir(self.output_dir)
self.progress = Gtk.ProgressBar(show_text=True)
vbox.add(self.progress)
self.label.set_text(_('Finding package information'))
self.label.set_justify(Gtk.Justification.LEFT)
# Get a list of installed packages.
self.get_installed_packages()
except OSError:
self.label.set_text(_('Failed to initialize.\nPlease see '
'https://docs.puri.sm/Librem_5.html for information about '
'packages.'))
self.button = Gtk.Button(label=_('Open Package List'))
self.button.set_sensitive(self.ready)
self.button.connect('clicked', self.open_docs)
vbox.add(self.label)
vbox.add(self.button)
window.add(vbox)
window.set_default_size(360, 720)
window.show_all()
def get_installed_packages(self):
self.worker = Worker(['amber-security', 'amber-updates',
'amber-phone', 'amber'], '/',
self.output_dir)
self.lines.append(_('Reading package sources'))
self.update_label()
self.state = 'sources'
self.iter = self.worker.read_sources()
self.timeout_id = GLib.timeout_add(1, self.timeout, None)
def timeout(self, user_data):
if self.state == 'sources':
return self.read_source()
else:
return self.list_package()
def read_source(self):
try:
info = self.iter.__next__()
suite_name, i, total = info
self.progress.set_text('%i/%i' % (i, total))
self.progress.set_fraction(i/total)
if self.lines[-1] != suite_name:
self.lines.append(suite_name)
self.update_label()
except StopIteration:
# Start a new timer and stop the current one.
self.state = 'listing'
self.lines.append(_('Listing packages'))
self.lines.append('')
self.update_label()
self.iter = self.worker.list_packages()
return True
def list_package(self):
try:
name = self.iter.__next__()
self.lines[-1] = name
self.update_label()
except StopIteration:
self.update_label()
self.button.set_sensitive(self.ready)
return False
return True
def update_label(self):
self.label.set_text('\n'.join(self.lines))
def open_docs(self, *args):
os.system('gnome-www-browser ' + os.path.join(self.output_dir, 'index.html') + '&')
self.quit()
# Initialize local variables to hold installation paths.
localedir = join_paths(get_option('prefix'), get_option('localedir'))
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
moduledir = join_paths(pkgdatadir, meson.project_name())
conf = configuration_data()
conf.set('localedir', localedir)
conf.set('project_name', meson.project_name())
conf.set('prefix', get_option('prefix'))
conf.set('pkgdatadir', pkgdatadir)
configure_file(
input: 'librem5-get-package-info.py',
output: 'librem5-get-package-info',
configuration: conf,
install_dir: get_option('bindir')
)
# Declare the application's internal modules and their installation directory.
sources = [
'__init__.py',
'main.py',
'package_info.py'
]
install_data(sources, install_dir: moduledir)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This file is part of the Librem 5 Get Package Info tool.
# Read information about packages from dpkg and apt files.
# Copyright (C) 2019 Purism SPC
# SPDX-License-Identifier: GPL-3.0+
# Author: David Boddie <david.boddie@puri.sm>
import os
import subprocess
from debian import deb822
class Worker:
def __init__(self, suite_names, root_dir, output_dir):
self.suite_names = suite_names
self.root_dir = root_dir
self.output_dir = output_dir
def html_escape(self, text):
return text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt')
def read_sources(self):
self.sources = {}
files = []
total = 0
for suite_name in self.suite_names:
list_name = 'repo.pureos.net_pureos_dists_%s_main_source_Sources' % suite_name
sources_file = os.path.join(self.root_dir, 'var', 'lib', 'apt',
'lists', list_name)
files.append((suite_name, sources_file))
total += open(sources_file).read().count('\n\n')
i = 0
for suite_name, sources_file in files:
for source in deb822.Sources.iter_paragraphs(open(sources_file)):
names = [source['Package']]
names += [piece.strip() for piece in source['Binary'].split(',')]
for name in names:
if name not in self.sources:
self.sources[name] = source
i += 1
yield (suite_name, i, total)
def get_source_files(self, name):
try:
source = self.sources[name]
except KeyError:
return None
try:
for files_key in 'Files', 'Checksums-Sha256':
if files_key in source:
files = source[files_key]
break
else:
return None
return source, files
except KeyError:
return None
def get_copyright(self, prefix, name):
path = os.path.join(prefix, 'usr', 'share', 'doc', name, 'copyright')
if os.path.exists(path):
return os.path.join('/', 'usr', 'share', 'doc', name, 'copyright')
return None
def list_packages(self):
index_file = os.path.join(self.output_dir, 'index.html')
index_text = ('<html>\n<head>\n<title>Installed Software</title>\n'
'<style type="text/css">\n'
'h1 { font-size: 1.6em; text-align: center; '
'border-bottom: solid 2px #e0e0e0; padding-bottom: 4px }\n'
'.version { font-size: 0.8em }\n'
'dt { font-size: 1.5em; font-weight: bold }\n'
'dd { border-bottom: solid 1px #c0c0c0; margin-bottom: 2px }\n'
'.links { font-size: 1.5em; margin-left: 0.5em; '
'margin-right: 0.5em; text-align: center }\n'
'.links a { font-family: monospace; margin-right: 0.2em }\n'
'</style>\n'
'</head>\n<body>\n')
status_file = os.path.join(self.root_dir, 'var', 'lib', 'dpkg', 'status')
deb_host = 'https://repo.pureos.net/pureos/'
index_text += '<h1>Package Information</h1>\n\n'
current = None
links_text = '<p class="links">'
index_list_text = '<dl>\n'
for package in deb822.Packages.iter_paragraphs(open(status_file)):
if 'installed' not in package['Status']:
continue
name = package['Package']
homepage = package.get('Homepage', '')
version = package['Version']
if name[0] != current:
current = name[0]
index_list_text += '<dt><a name="%s">%s</a></dt>\n' % (current, current)
links_text += '<a href="#%s">%s</a> ' % (current, current)
index_list_text += ('<dd><a href="%s.html">%s</a><br />\n'
'<span class="version">%s</span></dd>\n') % (
name, name, version)
yield name
output_text = ('<html>\n<head>\n<title>%s</title>\n'
'<style type="text/css">\n'
'th { text-align: left }\n'
'pre { font-size: 0.9em }\n'
'</style>\n'
'</head>\n<body>\n') % self.html_escape(name)
output_text += '<h1>%s</h1>\n\n' % self.html_escape(name)
# Read the description from the package information.
description = package['Description']
output_text += '<h2>Description</h2>\n'
if description != None:
output_text += '<pre>\n'
for line in description.split('\n'):
line = line.lstrip()
if line == '.':
output_text += '\n'
else:
output_text += self.html_escape(line) + '\n'
output_text += '</pre>\n'
output_text += '<table>\n'
output_text += '<tr><th>Version</th><td>%s</td></tr>\n' % self.html_escape(version)
if homepage:
output_text += '<tr><th>Home page</th><td><a href="%s">%s</a></td></tr>\n' % (
homepage, self.html_escape(homepage))
# Use the package name to find the copyright file.
copyright_file = self.get_copyright(self.root_dir, name)
if copyright_file != None:
output_text += '<tr><th>Copyright</th><td><a href="file://%s">%s</a></td></tr>\n' % (
copyright_file, self.html_escape(copyright_file))
output_text += '</table>\n'
# Read source files.
info = self.get_source_files(name)
if info:
output_text += ('<h2>Source Files</h2>\n\n'
'These files can be downloaded to rebuild the package:\n\n')
source, files = info
output_text += '<ul>\n'
for item in files:
output_text += '<li><a href="%s%s/%s">%s</a></li>\n' % (deb_host,
source['Directory'], item['name'], self.html_escape(item['name']))
output_text += '</ul>\n'
open(os.path.join(self.output_dir, name + '.html'), 'w').write(output_text)