1
// Copyright 2012 Giovanni Campagna
3
// Permission is hereby granted, free of charge, to any person obtaining a copy
4
// of this software and associated documentation files (the "Software"), to
5
// deal in the Software without restriction, including without limitation the
6
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
// sell copies of the Software, and to permit persons to whom the Software is
8
// furnished to do so, subject to the following conditions:
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
* This module provides a set of convenience APIs for building packaged
26
const GLib = imports.gi.GLib;
27
const GIRepository = imports.gi.GIRepository;
28
const Gio = imports.gi.Gio;
29
const System = imports.system;
31
const Gettext = imports.gettext;
48
function _findEffectiveEntryPointName() {
49
let entryPoint = System.programInvocationName;
50
while (GLib.file_test(entryPoint, GLib.FileTest.IS_SYMLINK))
51
entryPoint = GLib.file_read_link(entryPoint);
53
return GLib.path_get_basename(entryPoint);
56
function _runningFromSource() {
57
let binary = Gio.File.new_for_path(System.programInvocationName);
58
let sourceBinary = Gio.File.new_for_path('./src/' + name);
59
return binary.equal(sourceBinary);
62
function _makeNamePath(name) {
63
return '/' + name.replace('.', '/', 'g');
68
* @params: package parameters
70
* Initialize directories and global variables. Must be called
71
* before any of other API in Package is used.
72
* @params must be an object with at least the following keys:
73
* - name: the package name ($(PACKAGE_NAME) in autotools,
75
* - version: the package version
76
* - prefix: the installation prefix
78
* init() will take care to check if the program is running from
79
* the source directory or not, by looking for a 'src' directory.
81
* At the end, the global variable 'pkg' will contain the
82
* Package module (imports.package). Additionally, the following
83
* module variables will be available:
84
* - name: the base name of the entry point (eg. org.foo.Bar.App)
85
* - version: same as in @params
86
* - prefix: the installation prefix (as passed in @params)
87
* - datadir, libdir: the final datadir and libdir when installed;
88
* usually, these would be prefix + '/share' and
89
* and prefix + '/lib' (or '/lib64')
90
* - pkgdatadir: the directory to look for private data files, such as
91
* images, stylesheets and UI definitions;
92
* this will be datadir + name when installed and
93
* './data' when running from the source tree
94
* - pkglibdir: the directory to look for private typelibs and C
96
* this will be libdir + name when installed and
97
* './lib' when running from the source tree
98
* - moduledir: the directory to look for JS modules;
99
* this will be pkglibdir when installed and
100
* './src' when running from the source tree
101
* - localedir: the directory containing gettext translation files;
102
* this will be datadir + '/locale' when installed
103
* and './po' in the source tree
105
* All paths are absolute and will not end with '/'.
107
* As a side effect, init() calls GLib.set_prgname().
109
function init(params) {
110
window.pkg = imports.package;
111
_pkgname = params.name;
112
name = _findEffectiveEntryPointName();
113
version = params.version;
115
// Must call it first, because it can only be called
116
// once, and other library calls might have it as a
118
GLib.set_prgname(name);
120
prefix = params.prefix;
121
libdir = params.libdir;
122
datadir = GLib.build_filenamev([prefix, 'share']);
123
let libpath, girpath;
125
if (_runningFromSource()) {
126
log('Running from source tree, using local files');
127
// Running from source directory
128
_base = GLib.get_current_dir();
129
pkglibdir = GLib.build_filenamev([_base, 'lib']);
130
libpath = GLib.build_filenamev([pkglibdir, '.libs']);
132
pkgdatadir = GLib.build_filenamev([_base, 'data']);
133
localedir = GLib.build_filenamev([_base, 'po']);
134
moduledir = GLib.build_filenamev([_base, 'src']);
137
pkglibdir = GLib.build_filenamev([libdir, _pkgname]);
139
girpath = GLib.build_filenamev([pkglibdir, 'girepository-1.0']);
140
pkgdatadir = GLib.build_filenamev([datadir, _pkgname]);
141
localedir = GLib.build_filenamev([datadir, 'locale']);
144
let resource = Gio.Resource.load(GLib.build_filenamev([pkgdatadir,
145
name + '.src.gresource']));
146
resource._register();
148
moduledir = 'resource://' + _makeNamePath(name) + '/js';
150
moduledir = pkgdatadir;
154
imports.searchPath.unshift(moduledir);
155
GIRepository.Repository.prepend_search_path(girpath);
156
GIRepository.Repository.prepend_library_path(libpath);
159
let resource = Gio.Resource.load(GLib.build_filenamev([pkgdatadir,
160
name + '.data.gresource']));
161
resource._register();
167
* @params: see init()
169
* This is a convenience function if your package has a
170
* single entry point.
171
* You must define a main(ARGV) function inside a main.js
172
* module in moduledir.
174
function start(params) {
181
* @module: the module to run
183
* This is the function to use if you want to have multiple
184
* entry points in one package.
185
* You must define a main(ARGV) function inside the passed
186
* in module, and then the launcher would be
188
* imports.package.init(...);
189
* imports.package.run(imports.entrypoint);
191
function run(module) {
192
return module.main([System.programInvocationName].concat(ARGV));
197
* @libs: the external dependencies to import
199
* Mark a dependency on a specific version of one or more
200
* external GI typelibs.
201
* @libs must be an object whose keys are a typelib name,
202
* and values are the respective version. The empty string
203
* indicates any version.
205
function require(libs) {
206
for (let l in libs) {
207
let version = libs[l];
210
imports.gi.versions[l] = version;
215
printerr('Unsatisfied dependency: ' + e.message);
221
function initGettext() {
222
Gettext.bindtextdomain(_pkgname, localedir);
223
Gettext.textdomain(_pkgname);
225
let gettext = imports.gettext;
226
window._ = gettext.gettext;
227
window.C_ = gettext.pgettext;
228
window.N_ = function(x) { return x; }
231
function initFormat() {
232
let format = imports.format;
233
String.prototype.format = format.format;
236
function initSubmodule(name) {
237
if (moduledir != pkgdatadir) {
238
// Running from source tree, add './name' to search paths
240
let submoduledir = GLib.build_filenamev([_base, name]);
241
let libpath = GLib.build_filenamev([submoduledir, '.libs']);
242
GIRepository.Repository.prepend_search_path(submoduledir);
243
GIRepository.Repository.prepend_library_path(libpath);
245
// Running installed, submodule is in $(pkglibdir), nothing to do