PKG-INFO Format¶
PKG-INFO should be a YAML file with the following key-value items.
entry-point
¶
Entry-point is mandatory.
The value refers to the entry point of the application code from the framework. Value of the entry-point should in the following format
module.path:callable_name
For example, if the entry point callable app_entry(state)
is in
aalam_base.main
module, the entry point will be
aalam_base.main:app_entry
statics-url
¶
statics-url is optional
It is the prefix of the URL on which all the static files are served. The static resource
can be accessed with the prefix followed by the path of the file. The absolute
path of the file be obtained with the help of statics-path
value.
Example, if the prefix is /<provider-code>/<app-code>/s
and the file is installed in <statics-path>/images/static.png
, the
URL to this resource will be like /<provider-code>/<app-code>/s/images/static.png
.
The static resources that are not served through URLs starting with this prefix, has to have a URL route registered for the same.
With this setting, the application need not register explicit URLs to serve static resources. The framework will automatically control the response to the request of these static resources.
statics-path
¶
statics-path
is mandatory when statics-url
is used. Otherwise not required.
It contains the name of the directory under which all the static files are installed. The directory name should be relative to the installed root.
For example, if the static files are all installed in $ROOT/resource/statics/
,
value for this will be resource/statics
The framework derives the path of the resource with the help of the URL.
For example, for a URL /aalam/base/s/contacts/script.js
with the statics-url
as
/aalam/base/s
, the path of the file will be
os.path.join(cfg.CONF.package_dir, statics_path, "contacts/script.js")
permissions
¶
‘permissions’ is optional
The value to this another key-value dictionary. This describes the list of permissions that the application supports.
Every permission name will have a group name.A permission is referred by
provider-code/app-code/group-name/permission-name
.
The permission map should be in the following format
permissions:
permission-groups:
group-name-1: "Group 1's description"
group-name-2: "Group 2's description"
.
.
group-name-n: "Group n's description"
group-name-1:
permission-name-11: "Permission 11's description"
permission-name-12: "Permission 12's description"
.
.
permission-name-1n: "Permission 1n's description"
.
.
group-name-n:
permission-name-n1: "Permission n1's description"
.
.
permission-name-nn: "Permission nn's description"
requires:
provider-1/app-1:
group-name-p1a1-1:
- permission-p1a1-11
- permission-p1a1-22
group-name-p1a1-n:
- permission-pa-nn
provider-2/app-2:
group-name-p2a2-1:
- permission-p2a2-11
- permission-p2a2-22
group-name-p2a2-n:
- permission-pa-nn
The permissions map contains the list of dictionary objects. Out
of all the keys, permission-groups
and requires
are standard. Rest of the
key names are dynamic based on the keys in permission-groups
object.
Here, requires
object contains the list of permissions that are defined in other applications
but required by this application.
Note that ‘group-name’ and ‘permission-name’ should contain only alpha numeric
characters and the special character hyphen -
, however it should not start with a hyphen.
A real world example of the permissions
value can be seen below.
permission-groups:
Journal-Books: "Journal Book management"
Journal-Books:
create: "Create a journal book"
delete: "Delete a journal book"
access: "Access book details"
requires:
aalam/base:
Contacts:
- create
- delete
The application in the above example defines the following set of permissions
Journal-Books/create,
Journal-Books/delete,
Journal-Books/access
It also needs the following permissions from the base application
aalam/base/Contacts/create,
aalam/base/Contacts/delete
messages
¶
messages
is optional
The value of this item is a key-value dictionary object.
This item defines the list of message templates used for sending alerts.
For example,when an app is installed in a server, an alert will be posted to some users with a fixed template.
Each key in the value refers to the name of a message group. Message can be grouped, so that it becomes easier for the users to follow/unfollow all the message in a group.
Each message template is identified by it’s index
value. The index value should be
unique across this message map.
Format of messages
is as below
messages:
MessageGroup-1:
- index: 0
body: Template value 1, {dynamic_variable}
- index: 1
body: Template value 2, {dynamic_variable}
MessageGroup-2
- index: 2
body: Template value 3, a static template
- index: 3
body: Template value 4.
Here ,body
contains the message template. Any dynamic value that needs to formatted
on the template should be put within {}
. The value for the dynamic variables
will be given the application while posting the message.
For example, when an
application is stopped, the template can have the {app_name}
as a dynamic
variable and will supply the value for the {app_name}
which is stopped, at
the time of posting this message.
A real world example will be like
message:
WelcomeMessages:
- index: 0
body: Welcome to this portal. You are the administrator to this portal.
- index: 1
body: Welcome! You can check you permissions here.
AppMessages:
- index: 2
body: New app - {app_name} is installed by {user}
- index: 3
body: '{app_name}' is uninstalled by '{user}'
In the above example, we have two groups.
WelcomeMessages
are the messages that the application sends whenever a new user joins the portal. The index 0 message is used for posting the owner and index 1 is used for posting other users.AppMessages
are the messages sent when any app is installed or uninstalled. Items with{}
will be replaced by relevant values.
settings
¶
settings
is optional
The value to this item is a key-value dictionary object.
This item defines the list of settings
for an application.
settings
are variables for which the user chooses the values.
A settings variable is of two types
- Global
Global settings are variables that is applicable to the entire server and the values of which are same for all users. To modify a global setting, a user needs to haveaalam/base/Settings/modify-globals
permission. Example, date and time format is a global setting.
- Personal
Personal settings are the variables that are user customizable. A user doesn’t need any extra permission to modify personal settings. Example, choice of a theme’s colour is a personal setting.
The settings
format is as below
settings:
- code: short_form_descritpion. See "Code Specification"
name: Detailed name, which will be seen by the user
default: Default value of this setting
property: see "Property Specification"
type: Global/Personal
help: Information on how to input the values
validator: Method name to be invoked for validation. See "Method Specification"
- Similiar to the above format
Code Specification¶
Settings code is a short code for describing for a setting variable. The code
value will not be displayed to the user.It is to identify the setting
by the framework and other applications.
It should abide by the following rules.
- Can contain only alpha numeric and hyphen
-
characters. - Should not start with hyphen character.
- It should be unique for an application.
Property Specification:¶
Every setting can have following property type
- Number
Integer or decimal value
- Text
String
- Choices
Lets the user to choose from a list of choices. If the choice type and method are
- single, dropdown: A listbox will be displayed to choose the value
- single, boxes: A set of radio buttons will be displayed
- multiple, dropdown: List box with support for multiple selection will be displayed
- multiple, boxes: A set of check boxes will be displayed.
Property will be of the following format
property:
type: Ex. number/text/choices(??)
number:
max: Maximum value for a number, applicable only for number. This is optional.
min: Minimum value for a number, applicable only for number. This is optional.
text:
max_len: Maximum length of text, applicable only for text. This is optional.
choices:
type: single/multiple, applicable only for choices. This is mandatory
method: dropdown/boxes, applicable only for choices. This is mandatory.
values:
- value1
- value2
- value3
Method Specification:¶
This is the method that will be invoked by the framework whenever a setting is fed by the user. The method name should be of the format
module.path:method_name
The validator method should accept two parameters
settings_code
The code defined for a setting in the application’s settings map object.input_value
The value that was fed by the user for thissettings_code
.
The validator method should return either of the following
None
When the method finds theinput_value
to be valid for thesettings_code
String message
When the validator finds an error with theinput_value
, this message will be displayed to the user for further assistance.
A sample validator can be seen below
def color_validator(settings_code, input_value) :
if input_value not in ['red', 'green', 'blue']:
# Value is invalid, return an error message.
return "Value should be either 'red', 'green' or 'blue'"
# Value is valid, so return None
return None
hooks
¶
hooks
are optional.
Value should be a key-value dictionary.
‘hooks’ lists the set of hooks that an application is interested in. Please see the python framework documentation for more information on hooks.
Value contains just two keys.
hook
List of URLs in other applications that this application wants to hook.
restrict
List of URLs in this application that it desires to restrict being hooked by other applications. One can include exceptions to the restrictions.
hooks
format is as below.
hook:
- url: Url to be hooked, See "Hook Url Format"
app: App which has this URL in the format provider-code/app-code
method: HTTP Method filter for the url
handler: Hooker's handler to be invoked on hook, see "Hook callback"
type: Before or After or Both (B | A | BA)
- Same as above
restrict:
- url: The url to be restricted, See "Hook Url Format"
method: The method of the url to be restricted
type: (B | A | BA) to be restricted
except:
- provider-code-1/app-code-1
- provider-code-2/app-code-2
- provider-code-3/app-code-3
Hook URL format¶
If the URL needs to be matched statically, then a static url can be used. For
example, if you want to hook GET /aalam/base/user/user@test.test
, you
can input the URL path directly.
But if you want to include a wildcard match) you have to use
/aalam/base/user/*
The asterik *
matches an element with the slashes /<matches-only-this-value/
. For
example, the above will match the following url
/aalam/base/user/user1@test.test
/aalam/base/user/user2@test.test
But will not match
/aalam/base/user/user1@test.test/status
Wherever you want to add a wildcard match, keep an asterik *
. For example,
/aalam/base/*/user1@test.test/*
will match the following urls
/aalam/base/user/user1@test.test/status
/aalam/base/user/user1@test.test/info
/aalam/base/permissions/user1@test.test/assign
Hook Callback¶
Hook callback method name should be like
module.path:method_name
Refer the python framework documentation for more information on the parameters and the return values of the hook callback methods.
libdeps
¶
libdeps
is optional
libdeps contain additional dependencies in the form other than python packages.
For example, if your app depends on some libraries like libjpeg
or libz
, those
dependencies can be listed under libdeps.
libdeps is a listing of a set of commands which fetches or builds some program or library and its artifacts that will be used by your app.
The packager runs on a tiny core linux based distribution. You can use
tce-load
to install .tcz
packages.
For example, let’s say your app has a dependency on a python package ‘Pillow’,
which needs libz.so
and libjpeg.so
. libz.so
is available from the tiny core
linux package zlib_base-dev.tcz
and libjpeg.so
is available from the package
libjpeg-turbo-dev.tcz
. For your app to run properly, you would need these libraries.
In such a case your libdeps should be like the following
libdeps:
-
name: jpeg
actions:
- tce-load -wic libjpeg-turbo-dev
artifacts:
- /usr/local/lib/libjpeg.so.62
-
name: libz
actions:
- tce-load -wic zlib_base-dev
artifacts:
- /usr/lib/libz.so
In the above example, you can just have one action/artifact object to install both the libraries in one command.
Alternatively, you can even build libraries from source using make and gcc. If the building
process needs libraries like autoconf, libtool etc, you can add an action to
install these required .tcz
packages before running the actual command to build the app.
libdeps:
-
actions:
- tce-load -wic cmake
- curl -v https://url.of.the.source.archive | tar -xz -C /tmp/source-path
- cd /tmp/source-path && ./configure && make
artifacts:
- /tmp/source-path/buid-dir/lib.so
properties
¶
This is optional
properties
contains the list of pre-defined properties for an app. It should
be a dictionary with the following keys
public_rootable
By setting this property toTrue
, you mean that this web application can serve the'/' (slash/root)
page for the public (anonymous) users.Server administrators can choose one such public rootable app from the list of their apps to serve it as a website for the public users as home page. Apps that are publicly rootable should have the routes registered for the same.
For example, if your app is public rootable, then you should be having a route for'/'
. These routes work only for the anonymous users. For users who are authenticated, these routes will never be used. For authenticated users, routes starting with/<provider-code>/<app-code>/
alone will work.
eval_rst .. note:: Except `'/'` all other routes should begin with `'/_/'`. Only then the requests will be routed to the public rootable app.
The value should be added to the configuration like
properties:
public_rootable: True
depends
¶
When your application depends on other applications, those dependecies must be listed under this section.
These dependencies are used while installing or updating any application. Each dependency should be given in the following format.
depends:
- provider_code: Provider code of the dependee app
app_code: App code of the dependee app
pattern: The version as is or a regex pattern to match more than one version
You can still use APIs for other apps from your application even without listing them under this section. But there is no guarentee that the API will be successfull.
For example, the Aalam Invoicer app depends on Aalam Stock
app. It should list the Stock app under its depends
section for successful API transaction.
But suppose that the Aaalam invoicer calls the API of a payment service application that is not
listed under depends
section,then there will be no guarentee that the API transaction will be successful.