Add Vala bindings.

https://bugzilla.gnome.org/show_bug.cgi?id=678846
This commit is contained in:
Evan Nemerson 2012-06-28 02:48:45 -07:00 committed by Stef Walter
parent 3bc89a8971
commit d0df587f08
8 changed files with 577 additions and 10 deletions

7
.gitignore vendored
View File

@ -12,6 +12,7 @@
*.pc
*.tar.gz
*.typelib
*.vapi
.deps
.cproject
.libs
@ -39,7 +40,8 @@ stamp*
.cproject
/build/coverage*
/build/m4
/build/m4/*
!/build/m4/vapigen.m4
/build/valgrind-suppressions
/docs/reference/libsecret/version.xml
@ -67,8 +69,11 @@ stamp*
/library/secret-dbus-generated.[ch]
/library/secret-enum-types.[ch]
/library/tests/test-*
/library/tests/*.metadata
!/library/tests/test-*.c
!/library/tests/test-*.js
!/library/tests/test-*.py
!/library/tests/test-*.vala
/library/tests/test-vala-lang.c
/tool/secret-tool

96
build/m4/vapigen.m4 Normal file
View File

@ -0,0 +1,96 @@
dnl vapigen.m4
dnl
dnl Copyright 2012 Evan Nemerson
dnl
dnl This library is free software; you can redistribute it and/or
dnl modify it under the terms of the GNU Lesser General Public
dnl License as published by the Free Software Foundation; either
dnl version 2.1 of the License, or (at your option) any later version.
dnl
dnl This library is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl Lesser General Public License for more details.
dnl
dnl You should have received a copy of the GNU Lesser General Public
dnl License along with this library; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# VAPIGEN_CHECK([VERSION], [API_VERSION], [FOUND-INTROSPECTION], [DEFAULT])
# --------------------------------------
# Check vapigen existence and version
#
# See http://live.gnome.org/Vala/UpstreamGuide for detailed documentation
AC_DEFUN([VAPIGEN_CHECK],
[
AC_BEFORE([GOBJECT_INTROSPECTION_CHECK],[$0])
AC_BEFORE([GOBJECT_INTROSPECTION_REQUIRE],[$0])
AC_ARG_ENABLE([vala],
[AS_HELP_STRING([--enable-vala[=@<:@no/auto/yes@:>@]],[build Vala bindings @<:@default=]ifelse($4,,auto,$4)[@:>@])],,[
AS_IF([test "x$4" = "x"], [
enable_vala=auto
], [
enable_vala=$4
])
])
AS_CASE([$enable_vala], [no], [enable_vala=no],
[yes], [
AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
AC_MSG_ERROR([Vala bindings require GObject Introspection])
])
], [auto], [
AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
enable_vala=no
])
], [
AC_MSG_ERROR([Invalid argument passed to --enable-vala, should be one of @<:@no/auto/yes@:>@])
])
AS_IF([test "x$2" = "x"], [
vapigen_pkg_name=vapigen
], [
vapigen_pkg_name=vapigen-$2
])
AS_IF([test "x$1" = "x"], [
vapigen_pkg="$vapigen_pkg_name"
], [
vapigen_pkg="$vapigen_pkg_name >= $1"
])
PKG_PROG_PKG_CONFIG
PKG_CHECK_EXISTS([$vapigen_pkg], [
AS_IF([test "$enable_vala" = "auto"], [
enable_vala=yes
])
], [
AS_CASE([$enable_vala], [yes], [
AC_MSG_ERROR([$vapigen_pkg not found])
], [auto], [
enable_vala=no
])
])
AC_MSG_CHECKING([for vapigen])
AS_CASE([$enable_vala],
[yes], [
VAPIGEN=`$PKG_CONFIG --variable=vapigen vapigen`
VAPIGEN_MAKEFILE=`$PKG_CONFIG --variable=datadir vapigen`/vala/Makefile.vapigen
AS_IF([test "x$2" = "x"], [
VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir vapigen`
], [
VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir_versioned vapigen`
])
])
AC_MSG_RESULT([$enable_vala])
AC_SUBST([VAPIGEN])
AC_SUBST([VAPIGEN_VAPIDIR])
AC_SUBST([VAPIGEN_MAKEFILE])
AM_CONDITIONAL(ENABLE_VAPIGEN, test "x$enable_vala" = "xyes")
])

View File

@ -71,6 +71,18 @@ GTK_DOC_CHECK(1.9)
GOBJECT_INTROSPECTION_CHECK([1.29])
AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
# --------------------------------------------------------------------
# Vala
VALA_REQUIRED=0.17.2.12
VAPIGEN_CHECK($VALA_REQUIRED)
if test "$enable_vala" != "no"; then
AC_PATH_PROG([VALAC], [valac], [])
fi
AM_CONDITIONAL(HAVE_VALAC, test "x$VALAC" != "x")
# --------------------------------------------------------------------
# libgcrypt

View File

@ -614,4 +614,172 @@
</chapter>
<chapter id="vala-examples">
<title>Vala examples</title>
<section id="vala-schema-example">
<title>Vala example: Define a password schema</title>
<para>Each stored password has a set of attributes which are later
used to lookup the password. The names and types of the attributes
are defined in a schema. The schema is usually defined once globally.
Here's how to define a schema:</para>
<informalexample><programlisting language="vala"><![CDATA[
var example = new Secret.Schema ("org.example.Password", Secret.SchemaFlags.NONE,
"number", Secret.SchemaAttributeType.INTEGER,
"string", Secret.SchemaAttributeType.STRING,
"even", Secret.SchemaAttributeType.BOOLEAN);
]]></programlisting></informalexample>
<para>See the <link linkend="vala-store-example">other examples</link> for how
to use the schema.</para>
</section>
<section id="vala-store-example">
<title>Vala example: Store a password</title>
<para>Here's how to store a password in the running secret service,
like gnome-keyring or ksecretservice.</para>
<para>Each stored password has a set of attributes which are later
used to lookup the password. The attributes should not contain
secrets, as they are not stored in an encrypted fashion.</para>
<para>These examples use <link linkend="vala-schema-example">the example
schema</link>.</para>
<para>This first example stores a password asynchronously, and is
appropriate for GUI applications so that the UI does not block.</para>
<informalexample><programlisting language="vala"><![CDATA[
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
Secret.password_storev.begin (example_schema, attributes, Secret.COLLECTION_DEFAULT,
"The label", "the password", null, (obj, async_res) => {
bool res = Secret.password_store.end (async_res);
/* ... do something now that the password has been stored */
});
]]></programlisting></informalexample>
<para>If you are already inside of an async function, you can also
use the yield keyword:</para>
<informalexample><programlisting language="vala"><![CDATA[
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
bool res = yield Secret.password_storev (example_schema, attributes,
Secret.COLLECTION_DEFAULT, "The label",
"the password", null);
]]></programlisting></informalexample>
<para>If you would like to avoid creating a hash table for the
attributes you can just use the variadic version:</para>
<informalexample><programlisting language="vala"><![CDATA[
bool res = yield Secret.password_store (example_schema, Secret.COLLECTION_DEFAULT, "The label",
"the password", null, "number", 8, "string", "eight",
"even", true);
]]></programlisting></informalexample>
<para>This next example stores a password synchronously. The function
call will block until the password is stored. So this is appropriate for
non GUI applications.</para>
<informalexample><programlisting language="vala"><![CDATA[
Secret.password_store_sync (example_schema, attributes, Secret.COLLECTION_DEFAULT,
"The label", "the password", null,
"number", 9, "string", "nine", "even", false);
]]></programlisting></informalexample>
</section>
<section id="vala-lookup-example">
<title>Vala example: Lookup a password</title>
<para>Here's how to lookup a password in the running secret service,
like gnome-keyring or ksecretservice.</para>
<para>Each stored password has a set of attributes which are
used to lookup the password. If multiple passwords match the
lookup attributes, then the one stored most recently is returned.</para>
<para>These examples use <link linkend="vala-schema-example">the example
schema</link>.</para>
<para>This first example looks up a password asynchronously, and is
appropriate for GUI applications so that the UI does not block.</para>
<informalexample><programlisting language="vala"><![CDATA[
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
Secret.password_lookupv.begin (example_schema, attributes, null, (obj, async_res) => {
string password = Secret.password_lookup.end (async_res);
});
]]></programlisting></informalexample>
<para>This next example looks up a password synchronously. The function
call will block until the lookup completes. So this is appropriate for
non GUI applications.</para>
<informalexample><programlisting language="vala"><![CDATA[
string password = Secret.password_lookup_sync (example_schema, attributes, null,
"number", 9, "string", "nine", "even", false);
/* password will be null, if no matching password found */
]]></programlisting></informalexample>
</section>
<section id="vala-remove-example">
<title>Vala example: Remove a password</title>
<para>Here's how to remove a password from the running secret service,
like gnome-keyring or ksecretservice.</para>
<para>Each stored password has a set of attributes which are
used to find which password to remove. If multiple passwords match the
attributes, then the one stored most recently is removed.</para>
<para>These examples use <link linkend="vala-schema-example">the example
schema</link>.</para>
<para>This first example removes a password asynchronously, and is
appropriate for GUI applications so that the UI does not block.</para>
<informalexample><programlisting language="vala"><![CDATA[
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
Secret.password_removev.begin (example_schema, attributes, null, (obj, async_res) => {
bool removed = Secret.password_removev.end (async_res);
});
]]></programlisting></informalexample>
<para>This next example removes a password synchronously. The function
call will block until the removal completes. So this is appropriate for
non GUI applications.</para>
<informalexample><programlisting language="vala"><![CDATA[
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
bool removed = Secret.password_remove_sync (example_schema, null,
"number", 8, "string", "eight", "even", true);
/* removed will be true if the password was removed */
]]></programlisting></informalexample>
</section>
</chapter>
</part>

View File

@ -94,6 +94,8 @@ secret-enum-types.h: secret-enum-types.h.template $(HEADER_FILES)
secret-enum-types.c: secret-enum-types.c.template $(HEADER_FILES)
$(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > $@
CLEANFILES =
# ------------------------------------------------------------------
# INTROSPECTION
@ -121,7 +123,24 @@ gir_DATA = $(INTROSPECTION_GIRS)
typelibsdir = $(libdir)/girepository-1.0
typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
endif
if ENABLE_VAPIGEN
include $(VAPIGEN_MAKEFILE)
libsecret-@SECRET_MAJOR@.vapi: Secret-@SECRET_MAJOR@.gir Secret-@SECRET_MAJOR@.metadata
VAPIGEN_VAPIS = libsecret-@SECRET_MAJOR@.vapi
libsecret_@SECRET_MAJOR@_vapi_DEPS = gio-2.0
libsecret_@SECRET_MAJOR@_vapi_METADATADIRS = $(srcdir)
libsecret_@SECRET_MAJOR@_vapi_FILES = Secret-@SECRET_MAJOR@.gir
vapidir = $(datadir)/vala/vapi
vapi_DATA = $(VAPIGEN_VAPIS)
CLEANFILES += $(VAPIGEN_VAPIS)
endif # ENABLE_VAPIGEN
endif # HAVE_INTROSPECTION
# ------------------------------------------------------------------
# PKG CONFIG
@ -139,9 +158,10 @@ EXTRA_DIST = \
secret-enum-types.h.template \
secret-enum-types.c.template \
org.freedesktop.Secrets.xml \
Secret-@SECRET_MAJOR@.metadata \
$(NULL)
CLEANFILES = \
CLEANFILES += \
$(pkgconfig_DATA) \
$(gir_DATA) \
$(typelibs_DATA) \

26
library/Secret-0.metadata Normal file
View File

@ -0,0 +1,26 @@
// Metadata file for Vala API generation.
// See https://live.gnome.org/Vala/UpstreamGuide for more information
Service
.lookup skip=false
.lookupv finish_name="secret_service_lookup_finish"
.remove skip=false
.removev finish_name="secret_service_remove_finish"
.store skip=false
.storev finish_name="secret_service_store_finish"
Schema
.new skip=false
password_lookup skip=false
password_lookup_sync skip=false throws="GLib.Error"
.error skip
password_lookupv finish_name="secret_password_lookup_finish"
password_remove skip=false
password_remove_sync skip=false throws="GLib.Error"
.error skip
password_removev finish_name="secret_password_remove_finish"
password_store skip=false
password_store_sync skip=false throws="GLib.Error"
.error skip
password_storev finish_name="secret_password_store_finish"

View File

@ -10,7 +10,8 @@ INCLUDES = \
noinst_LTLIBRARIES = libmock_service.la
libmock_service_la_SOURCES = \
mock-service.c mock-service.h \
mock-service.c \
mock-service.h \
$(NULL)
libmock_service_la_CFLAGS = \
@ -30,7 +31,7 @@ LDADD = \
libmock_service.la \
$(NULL)
TEST_PROGS = \
C_TESTS = \
test-value \
test-prompt \
test-service \
@ -41,6 +42,10 @@ TEST_PROGS = \
test-collection \
$(NULL)
TEST_PROGS = \
$(C_TESTS) \
$(NULL)
check_PROGRAMS = \
$(TEST_PROGS)
@ -63,8 +68,36 @@ PY_TESTS = \
PY_ENV = $(JS_ENV)
test-c: $(TEST_PROGS)
@gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(TEST_PROGS)
if HAVE_VALAC
VALA_V = $(VALA_V_$(V))
VALA_V_ = $(VALA_V_$(AM_DEFAULT_VERBOSITY))
VALA_V_0 = @echo " VALAC " $^;
VALA_TESTS = \
test-vala-lang \
$(NULL)
test-vala-lang.c: test-vala-lang.vala libsecret-@SECRET_MAJOR@.vapi mock-service-0.vapi
$(VALA_V)$(VALAC) -C --pkg gio-2.0 $^
TEST_PROGS += $(VALA_TESTS)
test_vala_lang_CFLAGS = -w
DISTCLEANFILES = test-vala-lang.c
test-vala: $(VALA_TESTS)
@gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(VALA_TESTS)
else
test-vala:
endif # HAVE_VALAC
test-c: $(C_TESTS)
@gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(C_TESTS)
test-js:
@for js in $(JS_TESTS); do echo "TEST: $$js"; $(JS_ENV) gjs $(srcdir)/$$js; done
@ -72,7 +105,7 @@ test-js:
test-py:
@for py in $(PY_TESTS); do echo "TEST: $$py"; $(PY_ENV) python $(srcdir)/$$py; done
test: test-c test-py test-js
test: test-c test-py test-js test-vala
# ------------------------------------------------------------------
# INTROSPECTION
@ -91,7 +124,7 @@ MockService_0_gir_PACKAGES = gobject-2.0 gio-2.0
MockService_0_gir_EXPORT_PACKAGES = mock-service-0
MockService_0_gir_INCLUDES = GObject-2.0 Gio-2.0
MockService_0_gir_LIBS = libmock_service.la
MockService_0_gir_CFLAGS = -I$(top_srcdir) -I$(top_builddir)
MockService_0_gir_CFLAGS = -I$(top_srcdir) -I$(top_builddir) -I$(srcdir)
MockService_0_gir_FILES = $(libmock_service_la_SOURCES)
MockService_0_gir_SCANNERFLAGS = --c-include "mock-service.h"
@ -99,7 +132,40 @@ noinst_DATA = \
$(INTROSPECTION_GIRS) \
$(INTROSPECTION_GIRS:.gir=.typelib)
endif
if ENABLE_VAPIGEN
include $(VAPIGEN_MAKEFILE)
mock-service-0.vapi: MockService-0.gir libsecret-@SECRET_MAJOR@.vapi
VAPIGEN_VAPIS = mock-service-0.vapi
mock_service_0_vapi_DEPS = gio-2.0 libsecret-@SECRET_MAJOR@
mock_service_0_vapi_METADATADIRS = $(builddir)
mock_service_0_vapi_VAPIDIRS = $(builddir)
mock_service_0_vapi_FILES = MockService-0.gir
vapidir = $(datadir)/vala/vapi
vapi_DATA = mock-service-0.vapi
# We have to make a version of the VAPI which references the
# uninstalled C headers.
VAPIGEN_VAPIS += libsecret-@SECRET_MAJOR@.vapi
Secret-@SECRET_MAJOR@.metadata: $(top_srcdir)/library/Secret-@SECRET_MAJOR@.metadata
$(AM_V_GEN) echo "* cheader_filename=\"secret-collection.h,secret-item.h,secret-password.h,secret-prompt.h,secret-schema.h,secret-schemas.h,secret-service.h,secret-types.h,secret-value.h\"" > $@ && \
cat < $^ >> $@
libsecret-@SECRET_MAJOR@.vapi: Secret-@SECRET_MAJOR@.metadata $(top_builddir)/library/Secret-@SECRET_MAJOR@.gir
libsecret_@SECRET_MAJOR@_vapi_DEPS = gio-2.0
libsecret_@SECRET_MAJOR@_vapi_METADATADIRS = $(srcdir)
libsecret_@SECRET_MAJOR@_vapi_FILES = $(top_builddir)/library/Secret-@SECRET_MAJOR@.gir
noinst_DATA += $(VAPIGEN_VAPIS)
endif # ENABLE_VAPIGEN
endif # HAVE_INTROSPECTION
#--------------------------------------------------------------------
@ -110,6 +176,8 @@ EXTRA_DIST = \
mock-service-normal.py \
mock-service-only-plain.py \
mock-service-prompt.py \
Secret-@SECRET_MAJOR@.metadata \
test-vala-lang.vala \
$(JS_TESTS) \
$(PY_TESTS) \
$(NULL)

View File

@ -0,0 +1,172 @@
Secret.Schema schema;
Secret.Schema no_name_schema;
private void test_lookup_sync () {
try {
string? password = Secret.password_lookup_sync (schema, null, "even", false, "string", "one", "number", 1);
GLib.assert (password == "111");
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
public async void test_lookup_async_ex () {
try {
string? password = yield Secret.password_lookup (schema, null, "even", false, "string", "one", "number", 1);
GLib.assert (password == "111");
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private void test_lookup_async () {
var loop = new GLib.MainLoop ();
test_lookup_async_ex.begin ((obj, async_res) => {
loop.quit ();
});
loop.run ();
}
private void test_lookup_no_name () {
try {
string? password = Secret.password_lookup_sync (schema, null, "number", 5);
GLib.assert (password == null);
password = Secret.password_lookup_sync (no_name_schema, null, "number", 5);
GLib.assert (password == "555");
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private void test_store_sync () {
try {
var attributes = new GLib.HashTable<string,string> (GLib.str_hash, GLib.str_equal);
attributes["even"] = "false";
attributes["string"] = "nine";
attributes["number"] = "9";
string? password = Secret.password_lookupv_sync (schema, attributes);
GLib.assert (password == null);
bool stored = Secret.password_storev_sync (schema, attributes, Secret.COLLECTION_DEFAULT, "The number ", "999");
GLib.assert (stored);
password = Secret.password_lookupv_sync (schema, attributes);
GLib.assert (password == "999");
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private async void test_store_async_ex () {
var attributes = new GLib.HashTable<string,string> (GLib.str_hash, GLib.str_equal);
attributes["even"] = "true";
attributes["string"] = "eight";
attributes["number"] = "8";
try {
string? password = yield Secret.password_lookupv (schema, attributes, null);
GLib.assert (password == null);
bool stored = yield Secret.password_storev (schema, attributes, Secret.COLLECTION_DEFAULT, "The number nine", "999", null);
GLib.assert (stored);
password = yield Secret.password_lookupv (schema, attributes, null);
GLib.assert (password == "999");
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private void test_store_async () {
var loop = new GLib.MainLoop ();
test_store_async_ex.begin ((obj, async_res) => {
loop.quit ();
});
loop.run ();
}
private void test_remove_sync () {
try {
var attributes = new GLib.HashTable<string,string> (GLib.str_hash, GLib.str_equal);
attributes["even"] = "false";
attributes["string"] = "nine";
attributes["number"] = "9";
string? password = Secret.password_lookupv_sync (schema, attributes);
GLib.assert (password == "999");
bool removed = Secret.password_removev_sync (schema, attributes, null);
GLib.assert (removed);
password = Secret.password_lookupv_sync (schema, attributes);
GLib.assert (password == null);
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private async void test_remove_async_ex () {
var attributes = new GLib.HashTable<string,string> (GLib.str_hash, GLib.str_equal);
attributes["even"] = "true";
attributes["string"] = "eight";
attributes["number"] = "8";
try {
string? password = yield Secret.password_lookupv (schema, attributes, null);
GLib.assert (password == "999");
bool removed = yield Secret.password_removev (schema, attributes, null);
GLib.assert (removed);
password = yield Secret.password_lookupv (schema, attributes, null);
GLib.assert (password == null);
} catch ( GLib.Error e ) {
GLib.error (e.message);
}
}
private void test_remove_async () {
var loop = new GLib.MainLoop ();
test_remove_async_ex.begin ((obj, async_res) => {
loop.quit ();
});
loop.run ();
}
private static int main (string[] args) {
GLib.Test.init (ref args);
try {
MockService.start ("mock-service-normal.py");
} catch ( GLib.Error e ) {
GLib.error ("Unable to start mock service: %s", e.message);
}
{
schema = new Secret.Schema ("org.mock.Schema", Secret.SchemaFlags.NONE,
"number", Secret.SchemaAttributeType.INTEGER,
"string", Secret.SchemaAttributeType.STRING,
"even", Secret.SchemaAttributeType.BOOLEAN);
no_name_schema = new Secret.Schema ("unused.Schema.Name", Secret.SchemaFlags.DONT_MATCH_NAME,
"number", Secret.SchemaAttributeType.INTEGER,
"string", Secret.SchemaAttributeType.STRING);
}
GLib.Test.add_data_func ("/vala/lookup/sync", test_lookup_sync);
GLib.Test.add_data_func ("/vala/lookup/async", test_lookup_async);
GLib.Test.add_data_func ("/vala/lookup/no-name", test_lookup_no_name);
GLib.Test.add_data_func ("/vala/store/sync", test_store_sync);
GLib.Test.add_data_func ("/vala/store/async", test_store_async);
GLib.Test.add_data_func ("/vala/remove/sync", test_remove_sync);
GLib.Test.add_data_func ("/vala/remove/async", test_remove_async);
var res = GLib.Test.run ();
MockService.stop ();
schema = null;
return res;
}