cpack_repository/commit

First draft of API to server package installation data

authorJan Wielemaker
Wed Nov 17 11:48:53 2010 +0100
committerJan Wielemaker
Wed Nov 17 11:48:53 2010 +0100
commit45c67556cf922cc8e509ba241c8d388fe7eb4133
treef9ded57fdf677a50a63d6e8bf6ec7eb65eb68bbd
parent22261f7d6c7e2f7e780831ececaa15752b065cc1
Diff style: patch stat
diff --git a/api/cpack.pl b/api/cpack.pl
index ee14eb2..a544881 100644
--- a/api/cpack.pl
+++ b/api/cpack.pl
@@ -31,6 +31,10 @@
 :- module(api_cpack,
 	  [
 	  ]).
+:- use_module(library(cpack/dependency)).
+:- use_module(library(semweb/rdf_db)).
+:- use_module(library(semweb/rdf_label)).
+:- use_module(library(http/http_dispatch)).
 
 /** <module> CPACK API for installing packages
 
@@ -61,5 +65,74 @@ To *discover* a package, we will search for
     * Exported predicates (exact)
 */
 
-
-
+:- http_handler(root('cpack/'),	cpack_install_data, [prefix]).
+
+%%	cpack_install_data(+Request)
+%
+%	Return installation info for installing Pack.  The data is
+%	returned as a Prolog term.
+
+cpack_install_data(Request) :-
+	memberchk(path_info(PackName), Request),
+	(   rdf_has(Pack, cpack:packageName, literal(PackName))
+	->  pack_install_data(Pack, Data),
+	    format('Content-type: application/x-prolog~n~n'),
+	    format('% Installation data for CPACK "~w"~n~n', [PackName]),
+	    format('pack(~q, ~q).~n', [PackName, Data])
+	;   format('Content-type: application/x-prolog~n~n'),
+	    format('% Installation data for CPACK "~w"~n~n', [PackName]),
+	    format('no_pack(~q).~n', [PackName])
+	).
+
+
+%%	pack_install_data(+Pack, -Data) is det.
+%
+%	Provides the information to install  Pack.   Data  is  a list of
+%	packages. Each element  is  a   term  pack(Name,  Options).  The
+%	packages are topologically sorted on their dependency.
+%
+%	The  option  list  for  each  package  may  hold  the  following
+%	information:
+%
+%	    * title(Title)
+%	    * license(License)
+%	    * pack_repository(git(URL,Options))
+%	    * author_repository(git(URL,Options))
+%	    Options include:
+%	        - branch(Branch)
+%	        - hash(Hash)
+%	        - tag(Tag)
+%	    * files(ListOfFile)
+%	    Each file is a term file(Path, Options), where options is
+%	        - module(Module)
+
+pack_install_data(Pack, Data) :-
+	cpack_list(Pack, List),
+	maplist(pack_info, List, Data).
+
+pack_info(Pack, pack(Name, Options)) :-
+	rdf_has(Pack, cpack:packageName, literal(Name)),
+	findall(O, pack_option(Pack, O), Options).
+
+pack_option(Pack, title(Title)) :-
+	rdf_has(Pack, dcterms:title, Literal),
+	literal_text(Literal, Title).
+pack_option(Pack, pack_repository(Git)) :-
+	rdf_has(Pack, cpack:mirrorRepository, Mirror),
+	rdf_git_repo(Mirror, Git).
+pack_option(Pack, author_repository(Git)) :-
+	rdf_has(Pack, cpack:clonedRepository, Mirror),
+	rdf_git_repo(Mirror, Git).
+pack_option(Pack, files(FileData)) :-
+	findall(F, rdf_has(F, cpack:inPack, Pack), Files),
+	maplist(file_info, Files, FileData).
+
+rdf_git_repo(URI, git(GitURL,Options)) :-
+	rdf_has(URI, cpack:gitURL, GitURL),
+	findall(O, repo_info(URI,O), Options).
+
+repo_info(URI, branch(Branch)) :-
+	rdf_has(URI, cpack:branch, literal(Branch)).
+
+file_info(URI, module(M)) :-
+	rdf_has(URI, cpack:module, literal(M)).
diff --git a/components/cpack.pl b/components/cpack.pl
index bc4c4f7..2f9d062 100644
--- a/components/cpack.pl
+++ b/components/cpack.pl
@@ -96,7 +96,8 @@ cpack(Pack, _Options) -->
 			   \p_row(Pack, cpack:submittedDate),
 			   \p_row(Pack, cpack:requires),
 			   \p_row(Pack, cpack:clonedRepository),
-			   \p_row(Pack, cpack:mirrorRepository)
+			   \p_row(Pack, cpack:mirrorRepository),
+			   \install_url_row(Pack)
 			 ]),
 		   br([class('after-ptable')]),
 		   div(class(description),
@@ -110,6 +111,16 @@ cpack(Pack, _Options) -->
 		 ])).
 
 
+%%	install_url_row(+Pack)//
+
+install_url_row(Pack) -->
+	{ rdf_has(Pack, cpack:packageName, literal(Name)),
+	  cpack_uri(pack, Name, URL)
+	},
+	html(tr([th('Install URL:'), td(a(href(URL), URL))])).
+
+
+
 %%	git_shortlog(+Pack, +Options)//
 %
 %	Component that show the top-N most recent changes in Pack.
diff --git a/components/cpack/graphs.pl b/components/cpack/graphs.pl
index e9512c0..84005ac 100644
--- a/components/cpack/graphs.pl
+++ b/components/cpack/graphs.pl
@@ -46,6 +46,7 @@
 %	Show a package and its dependencies
 
 cpack_dependency_graph(URI, _Options) -->
+	{ related(URI, _, _) }, !,
 	html([ h3('Dependency graph'),
 	       \graphviz_graph(dependency_graph(URI),
 			       [ object_attributes([width('100%')]),
@@ -55,6 +56,8 @@ cpack_dependency_graph(URI, _Options) -->
 				 shape_hook(shape(URI))
 			       ])
 	     ]).
+cpack_dependency_graph(_URI, _Options) -->
+	[].
 
 
 %%	shape(+Start, +URI, -Shape) is semidet.
diff --git a/config-available/DEFAULTS b/config-available/DEFAULTS
index ea13ea5..aee3b90 100644
--- a/config-available/DEFAULTS
+++ b/config-available/DEFAULTS
@@ -1 +1,2 @@
 config(cpack_repository, link).
+config(cpack_server, link).
diff --git a/config-available/cpack_server.pl b/config-available/cpack_server.pl
new file mode 100644
index 0000000..52e9529
--- /dev/null
+++ b/config-available/cpack_server.pl
@@ -0,0 +1,5 @@
+:- module(conf_cpack_server, []).
+:- use_module(api(cpack)).
+
+/** <module> Enable CPACK package services
+*/
diff --git a/lib/cpack/dependency.pl b/lib/cpack/dependency.pl
index 84fa509..9c46abe 100644
--- a/lib/cpack/dependency.pl
+++ b/lib/cpack/dependency.pl
@@ -32,10 +32,13 @@
 	  [ file_used_by_file_in_package/3, % +File, -UsedBy, -Package
 	    cpack_requires/3,		% +Package, -Package, -Why
 	    cpack_conflicts/3,		% +Package, -Package, -Why
+	    cpack_list/2,		% +Package, -ListOfImplied
 	    cpack_not_satisfied/2,	% +Package, -Reasons
 	    file_not_satisfied/2,	% +File, -Reasons
 	    file_imports_from/3		% +File, -Imports, -From
 	  ]).
+:- use_module(library(assoc)).
+:- use_module(library(ugraphs)).
 :- use_module(library(semweb/rdf_db)).
 :- use_module(library(semweb/rdfs)).
 :- use_module(repository).
@@ -51,6 +54,7 @@ high-level dependencies between objects. Currently, we keep track of:
   * Conflict reasons
     - Packages holding files that provide the same module
     - Packages holding files with the same path
+  * Satisfied status
 
 @tbd	Extend reasoning
 */
@@ -125,6 +129,54 @@ cpack_conflicts_by(Package, Conflict, same_file(Path,File1,File2)) :-
 	rdf_has(Package, cpack:in_file, File1),
 	rdf_has(Conflict, cpack:in_file, File2).
 
+
+		 /*******************************
+		 *	      GRAPH		*
+		 *******************************/
+
+%%	cpack_list(+Pack, -PackList) is det.
+%
+%	PackList is a list of all packages  that need to be installed to
+%	get Pack working. This list is ensured to contain Pack.
+%
+%	@tbd	Toplogical sorting may not be possible.  As ordering is
+%		not always necessary, we should try to relax
+%		dependencies if a topological sort is not possible due
+%		to cycles.  There are two heuristics here.  First of
+%		all, explicit (token) dependencies may be removed and
+%		second, libraries must be loaded before applications.
+
+cpack_list(Pack, Packs) :-
+	dependency_ugraph(Pack, Ugraph),
+	(   top_sort(Ugraph, Packs)
+	->  true
+	;   domain_error(non_cyclic_dependency_structure, Ugraph)
+	).
+
+
+%%	dependency_ugraph(+Pack, -Ugraph) is det.
+%
+%	Create a full dependency graph for pack as a ugraph.
+
+dependency_ugraph(Pack, Ugraph) :-
+	empty_assoc(Visited),
+	dependency_ugraph([Pack], Visited, Ugraph).
+
+dependency_ugraph([], _, []).
+dependency_ugraph([H|T], Visited, Graph) :-
+	(   get_assoc(H, Visited, _)
+	->  dependency_ugraph(T, Visited, Graph)
+	;   findall(Required, cpack_requires(H, Required, _), RList),
+	    Graph = [H-RList|More],
+	    put_assoc(H, Visited, true, Visited2),
+	    dependency_ugraph(T, Visited2, More)
+	).
+
+
+		 /*******************************
+		 *	     SATISFIED		*
+		 *******************************/
+
 %%	cpack_not_satisfied(+Package, -WhyNot) is semidet.
 %
 %	True when WhyNot describes why Package is not satisfied.
diff --git a/lib/cpack/repository.pl b/lib/cpack/repository.pl
index eb43dc3..c3d1a31 100644
--- a/lib/cpack/repository.pl
+++ b/lib/cpack/repository.pl
@@ -41,6 +41,7 @@
 :- use_module(library(lists)).
 :- use_module(library(record)).
 :- use_module(library(git)).
+:- use_module(library(uri)).
 :- use_module(library(settings)).
 :- use_module(library(semweb/rdf_db)).
 :- use_module(library(semweb/rdf_turtle)).
@@ -296,14 +297,22 @@ cpack_uri(Type, Name, URI) :-
 	http_current_host(Request, Host, Port,
 			  [ global(true)
 			  ]),
-	format(atom(URI), 'http://~w:~w/cpack/~w~w',
-	       [ Host, Port, Root, Name ]).
-
-type_root(package,    'packs/').
-type_root(file_ref,   'file_ref/').
-type_root(graph,      'graph/').
-type_root(prolog,     'prolog/').
-type_root(cliopatria, 'cliopatria/').
+	uri_authority_data(host, AD, Host),
+	uri_authority_data(port, AD, Port),
+	uri_authority_components(Authority, AD),
+	uri_data(scheme, Data, http),
+	uri_data(authority, Data, Authority),
+	uri_data(path, Data, Root),
+	uri_components(Start, Data),
+	atom_concat(Start, Name, URI).
+
+
+type_root(package,    '/packs/').
+type_root(pack,	      '/cpack/').	% Sync with api(cpack)!
+type_root(file_ref,   '/file_ref/').
+type_root(graph,      '/graph/').
+type_root(prolog,     '/prolog/').
+type_root(cliopatria, '/cliopatria/').
 
 package_graph(Package, Graph) :-
 	cpack_uri(package, Package, Graph).