Browse Source

added documentation support

Nicolas Cannasse 16 years ago
parent
commit
0651eab9df

+ 4 - 0
std/tools/haxelib/.htaccess

@@ -0,0 +1,4 @@
+<FilesMatch "^([_a-z0-9A-Z-])+$">
+	RewriteEngine On
+	RewriteRule (.*) /index.n
+</FilesMatch>

+ 8 - 0
std/tools/haxelib/Datas.hx

@@ -42,6 +42,7 @@ typedef XmlInfos = {
 class Datas {
 
 	public static var XML = "haxelib.xml";
+	public static var DOCXML = "haxedoc.xml";
 	public static var REPOSITORY = "files";
 	public static var alphanum = ~/^[A-Za-z0-9_.-]+$/;
 	static var LICENSES = ["GPL","LGPL","BSD","Public"];
@@ -81,6 +82,13 @@ class Datas {
 		return safe(lib)+"-"+safe(ver)+".zip";
 	}
 
+	public static function readDoc( zip : List<ZipEntry> ) : String {
+		for( f in zip )
+			if( StringTools.endsWith(f.fileName,DOCXML) )
+				return neko.zip.Reader.unzip(f).toString();
+		return null;
+	}
+
 	public static function readInfos( zip : List<ZipEntry> ) : XmlInfos {
 		var xmldata = null;
 		for( f in zip )

+ 5 - 0
std/tools/haxelib/Main.hx

@@ -331,6 +331,11 @@ class Main {
 				throw "Project "+d.project+" does not have version "+d.version;
 		}
 
+		// check if this version already exists
+		for( v in site.infos(infos.project).versions )
+			if( v.name == infos.version && ask("You're about to overwrite existing version '"+v.name+"', please confirm") == No )
+				throw "Aborted";
+
 		// query a submit id that will identify the file
 		var id = site.getSubmitId();
 

+ 45 - 9
std/tools/haxelib/Site.hx

@@ -1,5 +1,6 @@
 package tools.haxelib;
 import tools.haxelib.SiteDb;
+import haxe.rtti.CType;
 
 class Site {
 
@@ -65,12 +66,13 @@ class Site {
 				return "/"+Datas.REPOSITORY+"/"+Datas.fileName(res(p).name,res(v).name);
 			}
 		};
-		if (fillContent(ctx))
+		if( fillContent(ctx) )
 			neko.Lib.print( page.execute(ctx,macros) );
 	}
 
 	static function fillContent( ctx : Dynamic ) {
 		var uri = neko.Web.getURI().split("/");
+		var error = function(msg) { ctx.error = StringTools.htmlEscape(msg); return true; }
 		if( uri[0] == "" )
 			uri.shift();
 		var act = uri.shift();
@@ -81,10 +83,8 @@ class Site {
 		case "p":
 			var name = uri.shift();
 			var p = Project.manager.search({ name : name }).first();
-			if( p == null ) {
-				ctx.error = "Unknown project '"+name+"'";
-				return true;
-			}
+			if( p == null )
+				return error("Unknown project '"+name+"'");
 			ctx.p = p;
 			ctx.owner = p.owner;
 			ctx.version = p.version;
@@ -94,16 +94,52 @@ class Site {
 		case "u":
 			var name = uri.shift();
 			var u = User.manager.search({ name : name }).first();
-			if( u == null ) {
-				ctx.error = "Unknown user '"+name+"'";
-				return true;
-			}
+			if( u == null )
+				return error("Unknown user '"+name+"'");
 			ctx.u = u;
 			ctx.uprojects = Developer.manager.search({ user : u.id }).map(function(d:Developer) { return d.project; });
 		case "t":
 			var tag = uri.shift();
 			ctx.tag = StringTools.htmlEscape(tag);
 			ctx.tprojects = Tag.manager.search({ tag : tag }).map(function(t) return t.project);
+		case "d":
+			var name = uri.shift();
+			var p = Project.manager.search({ name : name }).first();
+			if( p == null )
+				return error("Unknown project '"+name+"'");
+			var version = uri.shift();
+			var v;
+			if( version == null ) {
+				v = p.version;
+				version = v.name;
+			} else {
+				v = Version.manager.search({ project : p.id, name : version }).first();
+				if( v == null ) return error("Unknown version '"+version+"'");
+			}
+			if( v.documentation == null )
+				return error("Project "+p.name+" version "+version+" has no documentation");
+			var root : TypeRoot = haxe.Unserializer.run(v.documentation);
+			var buf = new StringBuf();
+			var html = new tools.haxedoc.HtmlPrinter("/d/"+p.name+"/"+version+"/","","");
+			html.output = function(str) buf.add(str);
+			var path = uri.join(".").toLowerCase().split(".");
+			if( path.length == 1 && path[0] == "" )
+				path = [];
+			if( path.length == 0 ) {
+				ctx.index = true;
+				html.process(TPackage("root","root",root));
+			} else {
+				var cl = html.find(root,path,0);
+				if( cl == null ) {
+					// we most likely clicked on a class which is part of the haxe core documentation
+					neko.Web.redirect("http://haxe.org/api/"+path.join("/"));
+					return false;
+				}
+				html.process(cl);
+			}
+			ctx.p = p;
+			ctx.v = v;
+			ctx.content = buf.toString();
 		case "index":
 			var vl = Version.manager.latest(10);
 			for( v in vl ) {

+ 44 - 6
std/tools/haxelib/SiteApi.hx

@@ -181,22 +181,60 @@ class SiteApi {
 			return "Project infos updated : submit one more time to send a new version";
 		}
 
-		// check version
-		var vl = Version.manager.search({ project : p.id });
-		for( v in vl )
+		// look for current version
+		var current = null;
+		for( v in Version.manager.search({ project : p.id }) )
 			if( v.name == infos.version ) {
-				neko.FileSystem.deleteFile(path);
-				return "This version is already commited, please change version number";
+				current = v;
+				break;
 			}
 
-		neko.FileSystem.rename(path,Site.REP_DIR+"/"+Datas.fileName(p.name,infos.version));
+		// update documentation
+		var doc = null;
+		var docXML = Datas.readDoc(zip);
+		if( docXML != null ) {
+			var p = new haxe.rtti.XmlParser();
+			p.process(Xml.parse(docXML).firstElement(),null);
+			p.sort();
+			var roots = new Array();
+			for( x in p.root )
+				switch( x ) {
+				case TPackage(name,_,_):
+					switch( name ) {
+					case "flash","flash9","haxe","js","neko","cpp","php","tools": // don't include haXe core types
+					default: roots.push(x);
+					}
+				default:
+					// don't include haXe root types
+				}
+			var s = new haxe.Serializer();
+			s.useEnumIndex = true;
+			s.useCache = true;
+			s.serialize(roots);
+			doc = s.toString();
+		}
+
+		// update file
+		var target = Site.REP_DIR+"/"+Datas.fileName(p.name,infos.version);
+		if( current != null ) neko.FileSystem.deleteFile(target);
+		neko.FileSystem.rename(path,target);
+
+		// update existing version
+		if( current != null ) {
+			current.documentation = doc;
+			current.comments = infos.versionComments;
+			current.update();
+			return "Version "+current.name+" (id#"+current.id+") updated";
+		}
 
+		// add new version
 		var v = new Version();
 		v.project = p;
 		v.name = infos.version;
 		v.comments = infos.versionComments;
 		v.downloads = 0;
 		v.date = Date.now().toString();
+		v.documentation = doc;
 		v.insert();
 
 		p.version = v;

+ 3 - 1
std/tools/haxelib/SiteDb.hx

@@ -63,6 +63,7 @@ class Version extends neko.db.Object {
 	public var date : String; // sqlite does not have a proper 'date' type
 	public var comments : String;
 	public var downloads : Int;
+	public var documentation : Null<String>;
 
 }
 
@@ -149,7 +150,8 @@ class SiteDb {
 				downloads INTEGER NOT NULL,
 				date VARCHAR(19) NOT NULL,
 				name VARCHAR(32) NOT NULL,
-				comments TEXT NOT NULL
+				comments TEXT NOT NULL,
+				documentation TEXT NULL
 			)
 		");
 		db.request("DROP TABLE IF EXISTS Developer");

+ 212 - 0
std/tools/haxelib/haxelib.css

@@ -0,0 +1,212 @@
+
+/* structure */
+
+body {
+	margin : 0;
+	padding : 0;
+	text-align: center;
+	font-family : "trebuchet ms",sans-serif;
+	font-size : 10.5pt;
+	background : #FFFFFF url("http://haxe.org/img/haxe/bg_main.gif") repeat-x;
+}
+
+.page {
+	margin: 10px auto 10px auto;
+	padding : 5px;
+	width : 750px;
+	background-color : #FFFFFF;
+	border : 1px solid #AAA;
+	-moz-border-radius : 10px;
+}
+
+.menu {
+	text-align : left;
+	float : left;
+	width : 150px;
+}
+
+.content {
+	text-align : left;
+	float : left;
+	width : 600px;
+}
+
+.clear {
+	clear : both;
+}
+
+/* style */
+
+a, a:visited {
+	color : #C35700;
+	text-decoration : none;
+}
+
+a:hover {
+	text-decoration : underline;
+}
+
+h1 {
+	text-align : center;
+	margin-top : 20px;
+}
+
+h1 a, h1 a:hover, h1 a:visited {
+	color : #C35700;
+	text-decoration : none;
+}
+
+.content p {
+	text-align : justify;
+	margin : 0px;
+	padding : 0px 10px 0px 10px;
+}
+
+.menu ul {
+	list-style : none;
+	margin : 5px;
+	padding : 0px;
+}
+
+.versions .date, .versions .project, .versions .name {
+	display : inline;
+}
+
+.versions ul, .projects ul {
+	list-style : circle;
+	margin : 25px;
+	padding : 0px;
+}
+
+.date {
+	color : #555;
+	font-size : 12px;
+}
+
+.versions .name {
+	font-weight : bold;
+}
+
+.versions .download {
+	float : right;
+	margin-top : -22px;
+	margin-right : 30px;
+}
+
+.download {
+	padding : 2px 4px 2px 4px;
+	background-color : #eee;
+	display : inline;
+}
+
+.download a {
+	color : #555;
+	font-size : 12px;
+	text-decoration : none;
+}
+
+.download a:visited {
+	color : #555;
+}
+
+.versions .comments {
+	margin-right : 40px;
+	margin-left : 10px;
+	margin-bottom : 5px;
+	text-align : justify;
+}
+
+.pinfos .description {
+	padding : 10px;
+}
+
+.pinfos .download {
+	margin : 200px;
+}
+
+.label {
+	color : #555;
+	width : 80px;
+	float : left;
+}
+
+.tags a {
+	margin-right : 5px;
+}
+
+form {
+	margin-left : 5px;
+	margin-top : 5px;
+}
+
+input {
+	width : 80px;
+}
+
+/* documentation */
+
+.api .title {
+	font-size: 35;
+	font-weight: bold;
+	text-align: center;
+	background-color : #FFD473;
+	color : white;
+}
+
+.api ul.entry {
+	list-style-type: disc;
+	margin-left : 30px;
+	padding-left : 0px;
+}
+
+.api .package_content {
+	display : none;
+}
+
+.api a {
+	text-decoration : none;
+}
+
+.api a:hover {
+	text-decoration : underline;
+}
+
+.api a.package {
+	color : black;
+}
+
+.api .index {
+}
+
+.api .kwd {
+	color : #09598A;
+	font-weight : bold;
+}
+
+.api .classname {
+	font-size : 30;
+	font-weight : bold;
+}
+
+.api .classdoc {
+	border : 1px dashed #666;
+	margin-left : 20px;
+	margin-right : 20px;
+	padding : 5 5 5 5;
+}
+
+.api .importmod, .api .extends, .api .implements, .api .typedef, .api .platforms {
+	color : #777;
+}
+
+.api dd {
+	margin-top : 10px;
+	font-size : 12pt;
+	color : #444;
+}
+
+.api dt {
+	margin-left : 20px;
+	margin-bottom : 5px;
+	text-align : left;
+}

+ 1 - 0
std/tools/haxelib/haxelib.hxp

@@ -3,6 +3,7 @@
   <output name="Command" mode="neko" out="haxelib.n" class="tools.haxelib.Main" lib="" cmd="" main="True" debug="False">-cmd nekotools boot haxelib.n</output>
   <files path="/">
     <file path="Datas.hx" />
+    <file path="haxelib.css" />
     <file path="Main.hx" />
     <file path="Site.hx" />
     <file path="SiteApi.hx" />

+ 24 - 138
std/tools/haxelib/website.mtt

@@ -3,150 +3,15 @@
 <head>
 <title>lib.haxe.org</title>
 <link type="application/rss+xml" rel="alternate" title="RSS feed" href="/rss"/>
-<style type="text/css">
-
-/* structure */
-
-body {
-	margin : 0;
-	padding : 0;
-	text-align: center;
-}
-
-.page {
-	margin: 10px auto 10px auto;
-	width : 750px;
-}
-
-.menu {
-	text-align : left;
-	float : left;
-	width : 150px;
-}
-
-.content {
-	text-align : left;
-	float : left;
-	width : 600px;
-}
-
-/* style */
-
-a {
-	color : #ff8400;
-	text-decoration : none;
-}
-
-a:hover {
-	text-decoration : underline;
-}
-
-a:visited {
-	color : #ff8400;
-}
-
-h1 a, h1 a:hover, h1 a:visited {
-	text-align : center;
-	color : black;
-	text-decoration : none;
-}
-
-.content p {
-	text-align : justify;
-	margin : 0px;
-	padding : 0px 10px 0px 10px;
-}
-
-.menu ul {
-	list-style : none;
-	margin : 5px;
-	padding : 0px;
-}
-
-.versions .date, .versions .project, .versions .name {
-	display : inline;
-}
-
-.versions ul, .projects ul {
-	list-style : circle;
-	margin : 25px;
-	padding : 0px;
-}
-
-.date {
-	color : #555;
-	font-size : 12px;
-}
-
-.versions .name {
-	font-weight : bold;
-}
-
-.versions .download {
-	float : right;
-	margin-top : -22px;
-	margin-right : 30px;
-}
-
-.download {
-	padding : 2px 4px 2px 4px;
-	background-color : #eee;
-	display : inline;
-}
-
-.download a {
-	color : #555;
-	font-size : 12px;
-	text-decoration : none;
-}
-
-.download a:visited {
-	color : #555;
-}
-
-.versions .comments {
-	margin-right : 40px;
-	margin-left : 10px;
-	margin-bottom : 5px;
-	text-align : justify;
-}
-
-.pinfos .description {
-	padding : 10px;
-}
-
-.pinfos .download {
-	margin : 200px;
-}
-
-.label {
-	color : #555;
-	width : 80px;
-	float : left;
-}
-
-.tags a {
-	margin-right : 5px;
-}
-
-form {
-	margin-left : 5px;
-	margin-top : 5px;
-}
-
-input {
-	width : 80px;
-}
-
-</style>
+<link href="/haxelib.css" type="text/css" rel="stylesheet"/>
 </head>
 
 <body>
 
-<div class="page">
-
 <h1><a href="/">lib.haxe.org</a></h1>
 
+<div class="page">
+
 <div class="menu">
 	<div class="title">Search :</div>
 	<form action="/search" method="POST">
@@ -207,6 +72,7 @@ input {
 	<div class="version"><div class="label">Version</div> ::(version.name)::</div>
 	<div class="owner"><div class="label">Owner</div> <a href="/u/::(owner.name)::">::(owner.name)::</a></div>
 	<div class="license"><div class="label">License</div> ::(p.license)::</div>
+	::if (version.documentation)::<div class="doc"><a href="/d/::(p.name)::">Documentation</a></div>::end::
 	<div class="download"><a href="$$download(p,version)">Download</a></div>
 </div>
 
@@ -278,6 +144,23 @@ input {
 </ul>
 </div>
 
+::elseif act_d::
+
+<h2>::(p.name):: ::(v.name):: Documentation</h2>
+
+<script type="text/javascript">
+	function toggle(id) {
+		var e = document.getElementById(id);
+		e.isopen = !e.isopen;
+		e.style.display = e.isopen?"block":"none";
+		return false;
+	}
+</script>
+
+<div class="api">
+::content::
+</div>
+
 ::else::
 
 <p>
@@ -287,6 +170,9 @@ input {
 ::end::
 
 </div>
+
+<div class="clear"></div>
+
 </div>
 
 </body>