Docstrings for modules all over sugar and shell.
These are just the doc strings I created as I was spelunking through to see how Sugar manages launching applications. The resulting auto-documentation is neither polished or finished, but it should help people reading the code somewhat. There are a few minor code cleanups: * activityhandle (replacing C idiom for initialisation with a Python one) * bundle registry (using a parameterised directory name so that it shows up in the documentation) * validate_activity_id function, use isinstance( item, (str,unicode)) for the query, rather than two separate checks with isinstance
This commit is contained in:
parent
508a59b99b
commit
3f10890319
@ -25,6 +25,13 @@ from sugar.presence import presenceservice
|
||||
from sugar import profile
|
||||
|
||||
class HomeActivity(gobject.GObject):
|
||||
"""Activity which appears in the "Home View" of the Sugar shell
|
||||
|
||||
This class stores the Sugar Shell's metadata regarding a
|
||||
given activity/application in the system. It interacts with
|
||||
the sugar.activity.* modules extensively in order to
|
||||
accomplish its tasks.
|
||||
"""
|
||||
__gsignals__ = {
|
||||
'launch-timeout': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE,
|
||||
@ -32,6 +39,15 @@ class HomeActivity(gobject.GObject):
|
||||
}
|
||||
|
||||
def __init__(self, bundle, activity_id):
|
||||
"""Initialise the HomeActivity
|
||||
|
||||
bundle -- sugar.activity.bundle.Bundle instance,
|
||||
provides the information required to actually
|
||||
create the new instance. This is, in effect,
|
||||
the "type" of activity being created.
|
||||
activity_id -- unique identifier for this instance
|
||||
of the activity type
|
||||
"""
|
||||
gobject.GObject.__init__(self)
|
||||
self._window = None
|
||||
self._xid = None
|
||||
@ -52,6 +68,8 @@ class HomeActivity(gobject.GObject):
|
||||
self._launch_timeout_id = 0
|
||||
|
||||
def _launch_timeout_cb(self, user_data=None):
|
||||
"""Callback for launch operation timeouts
|
||||
"""
|
||||
logging.debug("Activity %s (%s) launch timed out" %
|
||||
(self._activity_id, self.get_type))
|
||||
self._launch_timeout_id = 0
|
||||
@ -78,17 +96,33 @@ class HomeActivity(gobject.GObject):
|
||||
self._service = service
|
||||
|
||||
def get_service(self):
|
||||
"""Retrieve the application's sugar introspection service
|
||||
|
||||
Note that non-native Sugar applications will not have
|
||||
such a service, so the return value will be None in
|
||||
those cases.
|
||||
"""
|
||||
return self._service
|
||||
|
||||
def get_title(self):
|
||||
"""Retrieve the application's root window's suggested title"""
|
||||
if not self._launched:
|
||||
raise RuntimeError("Activity is still launching.")
|
||||
return self._window.get_name()
|
||||
|
||||
def get_icon_name(self):
|
||||
"""Retrieve the bundle's icon (file) name"""
|
||||
return self._bundle.get_icon()
|
||||
|
||||
def get_icon_color(self):
|
||||
"""Retrieve the appropriate icon colour for this activity
|
||||
|
||||
Uses activity_id to index into the PresenceService's
|
||||
set of activity colours, if the PresenceService does not
|
||||
have an entry (implying that this is not a Sugar-shared application)
|
||||
uses the local user's profile.get_color() to determine the
|
||||
colour for the icon.
|
||||
"""
|
||||
pservice = presenceservice.get_instance()
|
||||
activity = pservice.get_activity(self._activity_id)
|
||||
if activity != None:
|
||||
@ -97,28 +131,53 @@ class HomeActivity(gobject.GObject):
|
||||
return profile.get_color()
|
||||
|
||||
def get_activity_id(self):
|
||||
"""Retrieve the "activity_id" passed in to our constructor
|
||||
|
||||
This is a "globally likely unique" identifier generated by
|
||||
sugar.util.unique_id
|
||||
"""
|
||||
return self._activity_id
|
||||
|
||||
def get_xid(self):
|
||||
"""Retrieve the X-windows ID of our root window"""
|
||||
if not self._launched:
|
||||
raise RuntimeError("Activity is still launching.")
|
||||
return self._xid
|
||||
|
||||
def get_window(self):
|
||||
"""Retrieve the X-windows root window of this application
|
||||
|
||||
This was stored by the set_window method, which was
|
||||
called by HomeModel._add_activity, which was called
|
||||
via a callback that looks for all 'window-opened'
|
||||
events.
|
||||
|
||||
HomeModel currently uses a dbus service query on the
|
||||
activity to determine to which HomeActivity the newly
|
||||
launched window belongs.
|
||||
"""
|
||||
if not self._launched:
|
||||
raise RuntimeError("Activity is still launching.")
|
||||
return self._window
|
||||
|
||||
def get_type(self):
|
||||
"""Retrieve bundle's "service_name" for future reference"""
|
||||
return self._bundle.get_service_name()
|
||||
|
||||
def get_shared(self):
|
||||
"""Return whether this activity is using Presence service sharing"""
|
||||
if not self._launched:
|
||||
raise RuntimeError("Activity is still launching.")
|
||||
return self._service.get_shared()
|
||||
|
||||
def get_launch_time(self):
|
||||
"""Return the time at which the activity was first launched
|
||||
|
||||
Format is floating-point time.time() value
|
||||
(seconds since the epoch)
|
||||
"""
|
||||
return self._launch_time
|
||||
|
||||
def get_launched(self):
|
||||
"""Return whether we have bound our top-level window yet"""
|
||||
return self._launched
|
||||
|
@ -28,7 +28,19 @@ _SERVICE_NAME = "org.laptop.Activity"
|
||||
_SERVICE_PATH = "/org/laptop/Activity"
|
||||
|
||||
class HomeModel(gobject.GObject):
|
||||
"""Model of the "Home" view (activity management)
|
||||
|
||||
The HomeModel is basically the point of registration
|
||||
for all running activities within Sugar. It traps
|
||||
events that tell the system there is a new activity
|
||||
being created (generated by the activity factories),
|
||||
or removed, as well as those which tell us that the
|
||||
currently focussed activity has changed.
|
||||
|
||||
The HomeModel tracks a set of HomeActivity instances,
|
||||
which are tracking the window to activity mappings
|
||||
the activity factories have set up.
|
||||
"""
|
||||
__gsignals__ = {
|
||||
'activity-launched': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE,
|
||||
@ -124,6 +136,16 @@ class HomeModel(gobject.GObject):
|
||||
self.emit('activity-added', home_window)
|
||||
|
||||
def _add_activity(self, window):
|
||||
"""Add the window to the set of windows we track
|
||||
|
||||
At the moment this requires that something somewhere
|
||||
have registered a dbus service with the XID of the
|
||||
new window that is used to bind the requested activity
|
||||
to the window.
|
||||
|
||||
window -- gtk.Window instance representing a new
|
||||
normal, top-level window
|
||||
"""
|
||||
bus = dbus.SessionBus()
|
||||
xid = window.get_xid()
|
||||
try:
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""OLPC Sugar User Interface"""
|
||||
ZOOM_MESH = 0
|
||||
ZOOM_FRIENDS = 1
|
||||
ZOOM_HOME = 2
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""Base class for Python-coded activities
|
||||
|
||||
This is currently the only reference for what an
|
||||
activity must do to participate in the Sugar desktop.
|
||||
"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
@ -29,6 +34,26 @@ class Activity(Window, gtk.Container):
|
||||
"""Base Activity class that all other Activities derive from."""
|
||||
__gtype_name__ = 'SugarActivity'
|
||||
def __init__(self, handle):
|
||||
"""Initialise the Activity
|
||||
|
||||
handle -- sugar.activity.activityhandle.ActivityHandle
|
||||
instance providing the activity id and access to the
|
||||
presence service which *may* provide sharing for this
|
||||
application
|
||||
|
||||
Side effects:
|
||||
|
||||
Sets the gdk screen DPI setting (resolution) to the
|
||||
Sugar screen resolution.
|
||||
|
||||
Connects our "destroy" message to our _destroy_cb
|
||||
method.
|
||||
|
||||
Creates a base gtk.Window within this window.
|
||||
|
||||
Creates an ActivityService (self._bus) servicing
|
||||
this application.
|
||||
"""
|
||||
Window.__init__(self)
|
||||
|
||||
self.connect('destroy', self._destroy_cb)
|
||||
@ -105,6 +130,7 @@ class Activity(Window, gtk.Container):
|
||||
return False
|
||||
|
||||
def _destroy_cb(self, window):
|
||||
"""Destroys our ActivityService and sharing service"""
|
||||
if self._bus:
|
||||
del self._bus
|
||||
self._bus = None
|
||||
@ -112,4 +138,6 @@ class Activity(Window, gtk.Container):
|
||||
self._pservice.unregister_service(self._service)
|
||||
|
||||
def get_bundle_path():
|
||||
"""Return the bundle path for the current process' bundle
|
||||
"""
|
||||
return os.environ['SUGAR_BUNDLE_PATH']
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Shell side object which manages request to start activity"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
@ -31,6 +32,7 @@ _ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
|
||||
_ACTIVITY_INTERFACE = "org.laptop.Activity"
|
||||
|
||||
def create_activity_id():
|
||||
"""Generate a new, unique ID for this activity"""
|
||||
pservice = presenceservice.get_instance()
|
||||
|
||||
# create a new unique activity ID
|
||||
@ -52,6 +54,14 @@ def create_activity_id():
|
||||
raise RuntimeError("Cannot generate unique activity id.")
|
||||
|
||||
class ActivityCreationHandler(gobject.GObject):
|
||||
"""Sugar-side activity creation interface
|
||||
|
||||
This object uses a dbus method on the ActivityFactory
|
||||
service to create the new activity. It generates
|
||||
GObject events in response to the success/failure of
|
||||
activity startup using callbacks to the service's
|
||||
create call.
|
||||
"""
|
||||
__gsignals__ = {
|
||||
'success': (gobject.SIGNAL_RUN_FIRST,
|
||||
gobject.TYPE_NONE, ([])),
|
||||
@ -61,6 +71,29 @@ class ActivityCreationHandler(gobject.GObject):
|
||||
}
|
||||
|
||||
def __init__(self, service_name, activity_handle):
|
||||
"""Initialise the handler
|
||||
|
||||
service_name -- used to retrieve the activity bundle
|
||||
from the global BundleRegistry. This is what
|
||||
determines what activity will be run.
|
||||
activity_handle -- stores the values which are to
|
||||
be passed to the service to uniquely identify
|
||||
the activity to be created and the sharing
|
||||
service that may or may not be connected with it
|
||||
|
||||
sugar.activity.activityhandle.ActivityHandle instance
|
||||
|
||||
calls the "create" method on the service for this
|
||||
particular activity type and registers the
|
||||
_reply_handler and _error_handler methods on that
|
||||
call's results.
|
||||
|
||||
The specific service which creates new instances of this
|
||||
particular type of activity is created during the activity
|
||||
registration process in
|
||||
sugar.activity.bundleregistry.BundleRegistry which creates
|
||||
service definition files for each registered bundle type.
|
||||
"""
|
||||
gobject.GObject.__init__(self)
|
||||
self._service_name = service_name
|
||||
self._activity_handle = activity_handle
|
||||
@ -75,16 +108,28 @@ class ActivityCreationHandler(gobject.GObject):
|
||||
factory.create(self._activity_handle.get_dict(),
|
||||
reply_handler=self._reply_handler,
|
||||
error_handler=self._error_handler)
|
||||
|
||||
def get_activity_id(self):
|
||||
"""Retrieve the unique identity for this activity"""
|
||||
return self._activity_handle.activity_id
|
||||
|
||||
def _reply_handler(self, xid):
|
||||
"""Reply from service regarding what window was created
|
||||
|
||||
xid -- X windows ID for the window that was just created
|
||||
|
||||
emits the "success" message (on ourselves)
|
||||
"""
|
||||
logging.debug("Activity created %s (%s)." %
|
||||
(self._activity_handle.activity_id, self._service_name))
|
||||
self.emit('success')
|
||||
|
||||
def _error_handler(self, err):
|
||||
"""Reply from service with an error message (exception)
|
||||
|
||||
err -- exception object describing the error
|
||||
|
||||
emits the "error" message (on ourselves)
|
||||
"""
|
||||
logging.debug("Couldn't create activity %s (%s): %s" %
|
||||
(self._activity_handle.activity_id, self._service_name, err))
|
||||
self.emit('error', err)
|
||||
|
@ -35,9 +35,43 @@ gobject.threads_init()
|
||||
dbus.glib.threads_init()
|
||||
|
||||
class ActivityFactoryService(dbus.service.Object):
|
||||
"""D-Bus service that creates new instances of an activity"""
|
||||
"""D-Bus service that creates instances of Python activities
|
||||
|
||||
The ActivityFactoryService is a dbus service created for
|
||||
each Python based activity type (that is, each activity
|
||||
bundle which declares a "class" in its activity.info file,
|
||||
rather than an "exec").
|
||||
|
||||
The ActivityFactoryService is the actual process which
|
||||
instantiates the Python classes for Sugar interfaces. That
|
||||
is, your Python code runs in the same process as the
|
||||
ActivityFactoryService itself.
|
||||
|
||||
The "service" process is created at the moment Sugar first
|
||||
attempts to create an instance of the activity type. It
|
||||
then remains in memory until the last instance of the
|
||||
activity type is terminated.
|
||||
"""
|
||||
|
||||
def __init__(self, service_name, activity_class):
|
||||
"""Initialize the service to create activities of this type
|
||||
|
||||
service_name -- bundle's service name, this is used
|
||||
to construct the dbus service name used to access
|
||||
the created service.
|
||||
activity_class -- dotted Python class name for the
|
||||
Activity class which is to be instantiated by
|
||||
the service. Assumed to be composed of a module
|
||||
followed by a class.
|
||||
|
||||
if the module specified has a "start" attribute this object
|
||||
will be called on service initialisation (before first
|
||||
instance is created).
|
||||
|
||||
if the module specified has a "stop" attribute this object
|
||||
will be called after every instance exits (note: may be
|
||||
called multiple times for each time start is called!)
|
||||
"""
|
||||
self._activities = []
|
||||
|
||||
splitted_module = activity_class.rsplit('.', 1)
|
||||
@ -60,6 +94,12 @@ class ActivityFactoryService(dbus.service.Object):
|
||||
|
||||
@dbus.service.method("com.redhat.Sugar.ActivityFactory", in_signature="a{ss}")
|
||||
def create(self, handle):
|
||||
"""Create a new instance of this activity
|
||||
|
||||
handle -- sugar.activity.activityhandle.ActivityHandle
|
||||
compatible dictionary providing the instance-specific
|
||||
values for the new instance
|
||||
"""
|
||||
activity_handle = activityhandle.create_from_dict(handle)
|
||||
activity = self._constructor(activity_handle)
|
||||
activity.present()
|
||||
@ -70,6 +110,16 @@ class ActivityFactoryService(dbus.service.Object):
|
||||
return activity.window.xid
|
||||
|
||||
def _activity_destroy_cb(self, activity):
|
||||
"""On close of an instance's root window
|
||||
|
||||
Removes the activity from the tracked activities.
|
||||
|
||||
If our implementation module has a stop, calls
|
||||
that.
|
||||
|
||||
If there are no more tracked activities, closes
|
||||
the activity.
|
||||
"""
|
||||
self._activities.remove(activity)
|
||||
|
||||
if hasattr(self._module, 'stop'):
|
||||
|
@ -18,13 +18,47 @@
|
||||
from sugar.presence import presenceservice
|
||||
|
||||
class ActivityHandle(object):
|
||||
def __init__(self, activity_id):
|
||||
"""Data structure storing simple activity metadata"""
|
||||
def __init__(
|
||||
self, activity_id, pservice_id=None,
|
||||
object_id=None,uri=None
|
||||
):
|
||||
"""Initialise the handle from activity_id
|
||||
|
||||
activity_id -- unique id for the activity to be
|
||||
created
|
||||
pservice_id -- identity of the sharing service
|
||||
for this activity in the PresenceService
|
||||
object_id -- identity of the journal object
|
||||
associated with the activity. It was used by
|
||||
the journal prototype implementation, might
|
||||
change when we do the real one.
|
||||
|
||||
When you resume an activity from the journal
|
||||
the object_id will be passed in. It's optional
|
||||
since new activities does not have an
|
||||
associated object (yet).
|
||||
|
||||
XXX Not clear how this relates to the activity
|
||||
id yet, i.e. not sure we really need both. TBF
|
||||
uri -- URI associated with the activity. Used when
|
||||
opening an external file or resource in the
|
||||
activity, rather than a journal object
|
||||
(downloads stored on the file system for
|
||||
example or web pages)
|
||||
"""
|
||||
self.activity_id = activity_id
|
||||
self.pservice_id = None
|
||||
self.object_id = None
|
||||
self.uri = None
|
||||
self.pservice_id = pservice_id
|
||||
self.object_id = object_id
|
||||
self.uri = uri
|
||||
|
||||
def get_presence_service(self):
|
||||
"""Retrieve the "sharing service" for this activity
|
||||
|
||||
Uses the PresenceService to find any existing dbus
|
||||
service which provides sharing mechanisms for this
|
||||
activity.
|
||||
"""
|
||||
if self.pservice_id:
|
||||
pservice = presenceservice.get_instance()
|
||||
return pservice.get_activity(self.pservice_id)
|
||||
@ -32,6 +66,7 @@ class ActivityHandle(object):
|
||||
return None
|
||||
|
||||
def get_dict(self):
|
||||
"""Retrieve our settings as a dictionary"""
|
||||
result = { 'activity_id' : self.activity_id }
|
||||
if self.pservice_id:
|
||||
result['pservice_id'] = self.pservice_id
|
||||
@ -43,12 +78,11 @@ class ActivityHandle(object):
|
||||
return result
|
||||
|
||||
def create_from_dict(handle_dict):
|
||||
result = ActivityHandle(handle_dict['activity_id'])
|
||||
if handle_dict.has_key('pservice_id'):
|
||||
result.pservice_id = handle_dict['pservice_id']
|
||||
if handle_dict.has_key('object_id'):
|
||||
result.object_id = handle_dict['object_id']
|
||||
if handle_dict.has_key('uri'):
|
||||
result.uri = handle_dict['uri']
|
||||
|
||||
"""Create a handle from a dictionary of parameters"""
|
||||
result = ActivityHandle(
|
||||
handle_dict['activity_id'],
|
||||
pservice_id = handle_dict.get( 'pservice_id' ),
|
||||
object_id = handle_dict.get('object_id'),
|
||||
uri = handle_dict.get('uri'),
|
||||
)
|
||||
return result
|
||||
|
@ -29,6 +29,21 @@ class ActivityService(dbus.service.Object):
|
||||
tightly control what stuff passes through the dbus python bindings."""
|
||||
|
||||
def __init__(self, activity):
|
||||
"""Initialise the service for the given activity
|
||||
|
||||
activity -- sugar.activity.activity.Activity instance,
|
||||
must have already bound it's window (i.e. it must
|
||||
have already initialised to the point of having
|
||||
the X window available).
|
||||
|
||||
Creates dbus services that use the xid of the activity's
|
||||
root window as discriminants among all active services
|
||||
of this type. That is, the services are all available
|
||||
as names/paths derived from the xid for the window.
|
||||
|
||||
The various methods exposed on dbus are just forwarded
|
||||
to the client Activity object's equally-named methods.
|
||||
"""
|
||||
xid = activity.window.xid
|
||||
service_name = _ACTIVITY_SERVICE_NAME + '%d' % xid
|
||||
object_path = _ACTIVITY_SERVICE_PATH + "/%s" % xid
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Metadata description of a given application/activity"""
|
||||
import logging
|
||||
import locale
|
||||
import os
|
||||
@ -8,7 +9,17 @@ from sugar import env
|
||||
_PYTHON_FACTORY='sugar-activity-factory'
|
||||
|
||||
class Bundle:
|
||||
"""Info about an activity bundle. Wraps the activity.info file."""
|
||||
"""Metadata description of a given application/activity
|
||||
|
||||
The metadata is normally read from an activity.info file,
|
||||
which is an INI-style configuration file read using the
|
||||
standard Python ConfigParser module.
|
||||
|
||||
The format reference for the Bundle definition files is
|
||||
available for further reference:
|
||||
|
||||
http://wiki.laptop.org/go/Activity_bundles
|
||||
"""
|
||||
def __init__(self, path):
|
||||
self._name = None
|
||||
self._icon = None
|
||||
|
@ -15,8 +15,25 @@ def _get_data_dirs():
|
||||
return [ '/usr/local/share/', '/usr/share/' ]
|
||||
|
||||
class _ServiceManager(object):
|
||||
"""Internal class responsible for creating dbus service files
|
||||
|
||||
DBUS services are defined in files which bind a service name
|
||||
to the name of an executable which provides the service name.
|
||||
|
||||
In Sugar, the service files are automatically generated from
|
||||
the activity registry (by this class). When an activity's
|
||||
dbus launch service is requested, dbus will launch the
|
||||
specified executable in order to allow it to provide the
|
||||
requested activity-launching service.
|
||||
|
||||
In the case of activities which provide a "class", instead of
|
||||
an "exec" attribute in their activity.info, the
|
||||
sugar-activity-factory script is used with an appropriate
|
||||
argument to service that bundle.
|
||||
"""
|
||||
SERVICE_DIRECTORY = '~/.local/share/dbus-1/services'
|
||||
def __init__(self):
|
||||
service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
|
||||
service_dir = os.path.expanduser(self.SERVICE_DIRECTORY)
|
||||
if not os.path.isdir(service_dir):
|
||||
os.makedirs(service_dir)
|
||||
|
||||
|
@ -1,10 +1,25 @@
|
||||
"""Simple date-representation model"""
|
||||
import datetime
|
||||
|
||||
class Date(object):
|
||||
"""Date-object storing a simple time.time() float
|
||||
|
||||
XXX not sure about the rationale for this class,
|
||||
possibly it makes transfer over dbus easier?
|
||||
"""
|
||||
def __init__(self, timestamp):
|
||||
"""Initialise via a timestamp (floating point value)"""
|
||||
self._timestamp = timestamp
|
||||
|
||||
def __str__(self):
|
||||
"""Produce a formatted date representation
|
||||
|
||||
Eventually this should produce a localised version
|
||||
of the date. At the moment it always produces English
|
||||
dates in long form with Today and Yesterday
|
||||
special-cased and dates from this year not presenting
|
||||
the year in the date.
|
||||
"""
|
||||
date = datetime.date.fromtimestamp(self._timestamp)
|
||||
today = datetime.date.today()
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Calculates file-paths for the Sugar working environment"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Logging module configuration for Sugar"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""User settings/configuration loading"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@ -23,6 +24,30 @@ from sugar import util
|
||||
from sugar.graphics.xocolor import XoColor
|
||||
|
||||
class _Profile(object):
|
||||
"""Local user's current options/profile information
|
||||
|
||||
User settings are stored in an INI-style configuration
|
||||
file. This object uses the ConfigParser module to load
|
||||
the settings. At the moment the only storage mechanism
|
||||
is in the set_server_registered method, which loads the
|
||||
file directly from disk, then dumps it back out again
|
||||
immediately, rather than using the class.
|
||||
|
||||
The profile is also responsible for loading the user's
|
||||
public and private ssh keys from disk.
|
||||
|
||||
Attributes:
|
||||
|
||||
name -- child's name
|
||||
color -- XoColor for the child's icon
|
||||
server -- school server with which the child is
|
||||
associated
|
||||
server_registered -- whether the child has registered
|
||||
with the school server or not
|
||||
|
||||
pubkey -- public ssh key
|
||||
privkey_hash -- SHA has of the child's public key
|
||||
"""
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
self.color = None
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Various utility functions"""
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
@ -38,6 +39,19 @@ def _sha_data(data):
|
||||
return sha_hash.digest()
|
||||
|
||||
def unique_id(data = ''):
|
||||
"""Generate a likely-unique ID for whatever purpose
|
||||
|
||||
data -- suffix appended to working data before hashing
|
||||
|
||||
Returns a 40-character string with hexidecimal digits
|
||||
representing an SHA hash of the time, a random digit
|
||||
within a constrained range and the data passed.
|
||||
|
||||
Note: these are *not* crypotographically secure or
|
||||
globally unique identifiers. While they are likely
|
||||
to be unique-enough, no attempt is made to make
|
||||
perfectly unique values.
|
||||
"""
|
||||
data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
|
||||
return printable_hash(_sha_data(data_string))
|
||||
|
||||
@ -49,7 +63,7 @@ def is_hex(s):
|
||||
|
||||
def validate_activity_id(actid):
|
||||
"""Validate an activity ID."""
|
||||
if not isinstance(actid, str) and not isinstance(actid, unicode):
|
||||
if not isinstance(actid, (str,unicode)):
|
||||
return False
|
||||
if len(actid) != ACTIVITY_ID_LEN:
|
||||
return False
|
||||
@ -62,6 +76,23 @@ class _ServiceParser(ConfigParser):
|
||||
return option
|
||||
|
||||
def write_service(name, bin, path):
|
||||
"""Write a D-BUS service definition file
|
||||
|
||||
These are written by the bundleregistry when
|
||||
a new activity is registered. They bind a
|
||||
D-BUS bus-name with an executable which is
|
||||
to provide the named service.
|
||||
|
||||
name -- D-BUS service name, must be a valid
|
||||
filename/D-BUS name
|
||||
bin -- executable providing named service
|
||||
path -- directory into which to write the
|
||||
name.service file
|
||||
|
||||
The service files themselves are written using
|
||||
the _ServiceParser class, which is a subclass
|
||||
of the standard ConfigParser class.
|
||||
"""
|
||||
service_cp = _ServiceParser()
|
||||
section = 'D-BUS Service'
|
||||
service_cp.add_section(section)
|
||||
|
Loading…
Reference in New Issue
Block a user