Biblioteca Happstack

De Wikihaskell
Saltar a: navegación, buscar
Framework programación Web con Haskell
Programación servicios Web con Haskell
Lenguaje Haskell
Biblioteca Happstack
Autores Manuel López Urbina
Juan Luis Barrios Reina
Luis Calvo Notario


Contenido

Introducción

Happstack es un framework para la creación ágil de servicios web. Está especialmente indicado para crear prototipos rápidamente, implementarlos sin dificultad y de forma segura sin preocuparse de las capas más internas. Está disponible para los sistemas operativos GNU/Linux, OS X, FreeBSD y Windows.

Happstack incluye un servidor Web integrado. Es un servidor rápido y seguro que nos permite integrarlo en nuestras aplicaciones autónomas realizando los ajustes necesarios para cada una de ellas.

Happstack permite el uso libre de paquete generadores de código HTML integradas dentro del framework. Las plantillas soportadas son HSP (Haskell Server Page), HStringTemplate, Hamlet, Text.XHtml, BlazeHTML. Entre estas utilizaremos la librería Text.XHTML

Happstack incluye una serie de características opcionales que permiten aumentar la seguridad de su aplicación web. Esto significa una mayor seguridad de que su sitio esta libre de URL rotas y libre de ataques de inyección de JavaScript.

Happstack es la continuación del proyecto HAppS. El nombre del proyecto fue modificado para resaltar la transición a un modelo de desarrollo más abierto y un cambio en el liderazgo del proyecto. La transición se hizo con la bendición de Alex Jacobson, y los desarrolladores HAppS todavía están involucrados en la codificación.

Instalación

La instalación, desarrollo y pruebas la realizaremos sobre la distribución Ubuntu 10.04 de Linux. Hemos tomado esta decisión porque es la distribución que menos inconveniente hemos detectado. A continuación mostramos los pasos que debemos seguir para realizar la instalación del framework así como, los paquetes necesarios para su funcionamiento. Sería recomendable realizarlo con el usuario root, aunque se podría instalar anteponiendo el comando sudo.

  1. Instalación del compilador ghc
    Realizaremos la instalación a través de los repositorios oficiales de Ubuntu con el siguiente comando.
    $ sudo apt-get install ghc
  2. Instalación de la utilidad curl para realizar consultas a URL desde la línea de comandos
    $ sudo apt-get install curl
  3. Instalación de la librería de desarrollo zlib para ghc libghc6-zlib-dev. Necesario para compilar cabal si fuera necesario. También puede requerirlo algún paquete que necesite Happstack
    $ sudo apt-get install libghc6-zlib-dev
  4. Instalación de la herramienta cabal.
    Esta herramienta se utiliza para instalar librerías que están almacenadas en el repositorio de HackageDB y que están empaquetadas con cabal.
    $ sudo apt-get install cabal-install
    export PATH=~/.cabal/bin:$PATH
    $sudo cabal update
    $sudo cabal install cabal-install
  5. Instalación de la librería happy
    $sudo cabal install happy
  6. Instalación del framework happstack
    $sudo cabal install happstack-server

Nuestro primer ejemplo

A continuación vamos a mostrar un ejemplo para comprobar la instalación. Esta aplicación es un simple servidor que responde a todas las peticiones con la cadena Hola Mundo.
Con el siguiente comando compilamos el código y generamos el ejecutable.
Podemos ver el resultado a través de un navegador web con la URL http://localhost:8000. También podemos hacerlo con el comando curl.

import Happstack.Server 
main :: IO ()
main = simpleHTTP nullConf $ ok "Hola Mundo!"


  $ ghc --make -threaded holaMundo.hs -o holaMundo
 $ ./holaMundo


  $ curl http://localhost:8000
 Hola Mundo


Detalle del código

Comenzando la ejecución del programa tenemos la función simpleHTTP que es la encargada de recibir las peticiones HTTP en el puerto configurado, por defecto el 8000. Podemos cambiar a nuestras necesidades el puerto por donde nuestra aplicación recibe las peticiones HTTP. Para ello tenemos el siguiente tipo Conf que contiene la siguiente información. En nuestro ejemplo la función simpleHTTP recibe un parámetro, nullconf, de tipo Conf con los siguientes valores por defecto. El elemento validator nos puede servir para formatear la salida. No se establece validadores por defecto en estos momentos.

     simpleHTTP :: (ToMessage a) => Conf -> ServerPartT IO a -> IO ()


     data Conf = Conf { port :: Int
        , validator :: Maybe (Response -> IO Response) 
        }


     nullConf :: Conf
nullConf = Conf { port      = 8000
        , validator  = Nothing
        }


El segundo argumento, ServerPartT IO, es el encargado de recibir y procesar las peticiones HTTP y componer una respuesta. SimpleHTTP procesa cada petición HTTP en su propio hilo de ejecución. A continuación parsea la petición se ejecuta el callback ServerPartT IO y se devuelve la petición. ServerPartT IO se define como una mónada que nos permite definir y escribir funciones de la forma. Podíamos pensar que el flujo de ejecución sería recibir una petición, procesarla y enviar una respuesta. Pero tenemos que pensar que en procesos donde están implicados operaciones de E/S establecer un diseño con varios hilos de ejecución.

     Request -> IO Response


Finalmente establecemos el código de respuesta a nuestra petición. En nuestro ejemplo siempre devolvemos un código de correcto, 200, establecido con el combinador ok. En la librería existen distintos combinadores para las diferentes respuestas que puede establecerse. Se puede consultar en la documentación de la librería Happstack.Server.SimpleHTTP. Incluye otros combinadores como notfound, seeOther, badRequest, que son códigos de retorno del servidor.

En este ejemplo establecemos un tipo de repuesta concreto de tipo String. Podemos crear otros tipos y utilizar para ello plantillas u otras librerías que compongan código HTML. En este caso se realiza una llamada implícita toResponse desde la clase ToMessage. Podemos establecer una llamada explícita de la siguiente forma. Como hemos dicho la clase ToMessage llega con instancias para las distintas tipo de respuesta que queremos establecer y utilizar con Text.Html, Text.XHtml, String, HSP, etc.

     main :: IO ()
main = simpleHTTP nullConf $ ok (toResponse "Hola, Mundo!")


Filtros de salida

Happstack proporciona una variedad de modos de relacionar las peticiones y las respuestas apropiadamente, consiguiendo responder a diferentes rutas. Esto se consigue mediante funciones guarda en SimpleHTTP.

Eligiendo entre múltiples ServerPartTs

En el primer ejemplo, solo había un ServerPartTs. Todas lasRequestS eran entregadas por la misma parte y devueltas por la misma Response.

En general, nuestras aplicaciones tendrán muchos ServerPartTs. Las combinaremos en un único ServerPartT de nivel superior usando MonadPlus, mediante la función msum.

msum :: (MonadPlus m) => [m a] -> m a

En el siguiente ejemplo se combinan 3 ServerPartTs juntos:

module Main where

import Control.Monad
import Happstack.Server (nullConf, simpleHTTP, ok, dir)

main :: IO ()
main = simpleHTTP nullConf $ msum [ mzero
                                 , ok "Hola, Mundo"
                                 , ok "Imposible ServerPartT"
                                 ]

El comportamiento de MonadPlus es probar cada ServerPartT en sucesión, hasta que uno tenga éxito.

En el ejemplo de arriba, la primera parte es mzero, por lo tanto siempre falla. La segunda parte sera exitosa, por lo que la tercera nunca se alcanzará.

Direccionando segmentos de rutas estáticos

Usando dir para direccionar componentes de rutas estáticos

Podemos usar dir para manejar componentes de rutas URI, las cuales son estáticos. Por ejemplo, podríamos tener un site con dos URLS /hola y /adios.

module Main where

import Control.Monad
import Happstack.Server (nullConf, simpleHTTP, ok, dir)

main :: IO ()
main = simpleHTTP nullConf $ msum [ dir "hola"    $ ok "Hola, mundo!"
                               , dir "adios"  $ ok "Adios"
                               ]

Compilando y ejecutando el archivo, tal y como el primer ejemplo, y escribiendo en nuestro navegador http://localhost:8000/hola obtendremos, el mensaje de hello y si escribimos http://localhost:8000/adios, obtendremos el mensaje goodbye. Si ejecutamos el comando curl, desde nuestra terminal:

$curl http://localhost:8000/hola
Hola, mundo!

$curl http://localhost:8000/adios
Adios

Usando dir como término para relacionar múltiples componentes

Podemos relacionar múltiples componentes encadenando varias llamadas a dir juntas.

module Main where

import Control.Monad (msum)
import Happstack.Server (nullConf, simpleHTTP, ok, dir)

main :: IO ()
main = simpleHTTP nullConf $ msum [ dir "hola"    $ dir "mundo" $ ok "Hola, mundo!"
                              , dir "adios"  $ dir "hermano"  $ ok "Adios, hermano!"
                              ]

Si escribimos en el navegador, tras compilar y ejecutar el programa, http://localhost:8000/hola/mundo, obtendremos el mensaje correspodiente a hola, y si escribimos http://localhost:8000/adios/hermano obtendremos el mensaje correspondiente a adios. Si ejecutamos el comando curl, desde nuestra terminal:

$curl http://localhost:8000/hola/mundo
Hola, mundo!

$curl http://localhost:8000/adios/hermano
Adios, hermano!

Usando dirs como término para relacionar múltiples componentes

Podemos usar el combinador dirs como una forma abreviada para referirnos a múltiples componentes, como en el ejemplo anterior de la siguiente forma

module Main where
import Control.Monad (msum)
import Happstack.Server (nullConf, simpleHTTP, ok, dirs)

main :: IO ()
main = simpleHTTP nullConf $ msum [ dirs "hola/mundo"  $ ok "Hola, Mundo!"
                                 , dirs "adios/hermano" $ ok "Adios, hermano!"
                                 ]

Direccionando segmentos de rutas variables

Path

A menudo, un segmento de ruta contiene un valor de variable que queremos extraer y usar, tales como un número o un string. Podemos usar el combinador path para hacer eso.

path :: (FromReqURI a, MonadPlus m, ServerMonad m) => (a -> m b) -> m b

El combinador path intentará extraer y decodificar una ruta y si resulta con éxito, pasará el valor de decodificado al servidor.

A continuación se muestra un ejemplo básico, extrayendo un valor string. Se trata de una ampliación del ejemplo "hello World" de forma que se pueda decir 'hola' a cualquiera.

module Main where

import Control.Monad (msum)
import Happstack.Server (nullConf, simpleHTTP, ok, dir, path)

main :: IO ()
main = simpleHTTP nullConf $ msum [ dir "hola" $ path $ \s -> ok $ "Hola, " ++ s
                                ]

Ahora si escribimos en el navegador http://localhost:8000/hola/Mundo, obtendremos "Hola, Mundo". Si escribimos http://localhost:8000/hola/Haskell, obtendremos "Hola, Haskell".


Combinando Happstack y Text.Html

Aprovechando que Happstack proporciona una variedad de modos de relacionar las peticiones y las respuestas apropiadamente, y haciendo uso de los combinadores de la biblioteca Text.XHtml para formatear salida html, se puede conseguir que el servidor reciba y responda a peticiones con formato de forma que se consiga un resultado más vistoso.

En el siguiente ejemplo, se ve un programa, en el que se construye una pequeña página en html y se envía al servidor para que se pueda mostrar. Se muestra también la salida en un navegador
Ejemplo1.png
 module Main where

import Happstack.Server
import Text.XHtml


t1 = "Ejemplo para la tarea"

p1 = [
	"Este es un ejemplo para ser usado como caso de prueba para."
 ]

p2 = [	"Este es el segundo parrafo. Y no queda otra cosa por decir." ]

t2 = "Segundo titulo"

p3 = [	"Vemos ahora ejemplos de algunos elementos que pueden aparecer" 
]

t21 ="Listas numeradas"

lista1 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior." ]

t22 = "Listas no numeradas"

lista2 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior. "]

t223 = "Que hace este titulo aqui?"

p4 = "        El anterior es un titulo de tercer nivel"

t3 = "El tercer titulo"

p5 =	["Aqui vamos a ver un ejemplo de texto pre formateado. Este"
	,"comienza en la columna 14"
	]

pref =   ["       elem :: Eq a -> [a] -> Bool"
	, "        elem = any . (=)"
	]

t4 ="El ultimo capitulo"
p6 =	[ "        Aqui vemos un parrafo que tiene alguna palabra"
	, "*enfatizada* . Tambien tenemos palabras en _negrita_      "]

tabla_contenido =
h1 << "Tabla de contenido" +++
ulist << [
        li << (anchor ! [href "#t1"] << t1)
      , li << (anchor ! [href "#t2"] << t2) 
		 +++ ulist <<[ li << (anchor ! [href "#t21"] << t21) 
			  , li << (anchor ! [href "#t21"] << t22) ]
      , li << (anchor ! [href "#t3"] << t3)
	  , li << (anchor ! [href "#t4"] << t4)]

pagina = body <<
	   tabla_contenido +++ hr +++
	   (anchor ! [name "t1"] << h1 << t1) +++
       (p << p1) +++ (p << p2) +++
	   (anchor ! [name "t2"] << h1 << t2) +++ (p << p3) +++
	   (anchor ! [name "t21"] << h2 << t21) +++ 
                      (olist << (map (li<<) lista1)) +++
	   (anchor ! [name "t22"] << h2 << t22) 
                  +++ (ulist << map (li<<) lista2) +++
	   (anchor ! [name "t223"] << h3 << t223) +++ (p << p4) +++
	    anchor ! [name "t3"] << h1 << t3 +++ p << p5 +++ pre << unlines pref +++
	   (anchor ! [name "t4"] << h1 << t4) +++ (p << p6)

page = renderHtml pagina

main :: IO ()
main = simpleHTTP nullConf $ ok pagina

Al igual que si se tratase de la cadena hola mundo, simplemente debemos de construir con los combinadores nuestra página html, para enviarselo al servidor mediante la función simpleHTTP. Compilando y ejecutando el archivo, tal y como el primer ejemplo, y escribiendo en nuestro navegador http://localhost:8000 obtendremos la página con formato. Si ejecutamos el comando curl:

curl http://localhost:8000/

Nos aparecerá el código html correspondiente a la página que se muestra por el navegador.


Filtrando salida formateada

Podemos usar dir para manejar componentes de rutas URI los cuales son estáticos, tal y como vimos en el apartado 4, pero usando combinando también la biblioteca Text.XHtml para tener varios sites a los que direccionar con un estilo más depurado.

En el siguiente ejemplo vemos como hacerlo:

 module Main where

import Control.Monad (msum)
import Happstack.Server (nullConf, simpleHTTP, ok, dir, toResponse,
			ToMessage(..), toContentType ,toMessage, ServerPartT) 
import Text.XHtml
import qualified Happstack.Server as S


t1 = "Programación funcional"

p1 = [
	"Bienvenidos al curso de programación funcional del año 2010-2011."
 ]

p2 = [	"Recordad que todos vamos a aprobar." ]

t21 ="Tema 1: Introducción"

lista1 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior." ]

t22 = "Tema2: "

lista2 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior. "]

t23 = "WikiHaskell"
p4 = ["Enlace a biblioteca Happstack"]

tabla_contenido =
h1 << "Tabla de contenido" +++
ulist << [
        li << (anchor ! [href "#t1"] << t1)
		 +++ ulist <<[ li << (anchor ! [href "#t21"] << t21) 
				, li << (anchor ! [href "#t22"] << t22) 			  
				, li << (anchor ! [href "#t23"] << t23) ]]

pagina1 = body <<
	   tabla_contenido +++ hr +++
	   (anchor ! [name "t1"] << h1 << t1) +++
       (p << p1) +++ (p << p2) +++
	   (anchor ! [name "t21"] << h2 << t21) +++ 
                      (olist << (map (li<<) lista1)) +++
	   (anchor ! [name "t22"] << h2 << t22) 
                  +++ (ulist << map (li<<) lista2) +++
	   (anchor ! [name "t23"] << h3 << t23) +++ (p << p4) 

page = renderHtml pagina

s1 = "Biblioteca Happstack"

q1 = [
	"Bienvenidos a la biblioteca Happstack de haskell."
 ]

q2 = [	"Realizada por Juan Luis Barrios Reina, Manuel López Urbina y Luis Calvo Notario." ]

s21 ="Introducción"

list1 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior." ]

s22 = "Instalación"

list2 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior. "]

s23 = "Ordenes"

q4 = "Algunas ordenes son:"

tabla_contenido1 =
h1 << "Tabla de contenido" +++
ulist << [
        li << (anchor ! [href "#s1"] << s1)
		 +++ ulist <<[ li << (anchor ! [href "#s21"] << s21) 
				, li << (anchor ! [href "#s22"] << s22) 			  
				, li << (anchor ! [href "#s23"] << s23) ]]

pagina = body <<
	   tabla_contenido1 +++ hr +++
	   (anchor ! [name "s1"] << h1 << s1) +++
       (p << q1) +++ (p << q2) +++
	   (anchor ! [name "s21"] << h2 << s21) +++ 
                      (olist << (map (li<<) list1)) +++
	   (anchor ! [name "s22"] << h2 << s22) 
                  +++ (ulist << map (li<<) list2) +++
	   (anchor ! [name "s23"] << h3 << s23) +++ (p << q4) 

page1 = renderHtml pagina1

main :: IO ()
main = simpleHTTP nullConf $ msum [ S.dir "funcional"  $ ok pagina1
                              , S.dir "happstack"  $ ok pagina
                              ]


Compilando y ejecutando el archivo, tal y como el ejemplo anterior, y escribiendo en nuestro navegador http://localhost:8000/funcional obtendremos, la página correspondiente a Programación Funcional y si escribimos http://localhost:8000/happstack, obtendremos la página correspondiente a la biblioteca happstack. Si ejecutamos el comando curl, obtendremos los códigos html de las páginas creadas.

curl http://localhost:8000/funcional

curl http://localhost:8000/happstack

Apéndice

Biblioteca XHtml

La biblioteca XHtml provee combinadores para generar documentos en formato HTML.

Para utilizar esta biblioteca debe incluir la siguiente directiva en su programa:

$import Text.XHtml

Conceptos básicos

La biblioteca define un tipo algebraico Html pero no necesita conocer la definición de este tipo para trabajar. Los diferentes elementos de HTML se generan a partir de funciones específicas.

Se define una instancia Show para Html por lo cuál disponemos de la función show para convertir de Html a String.

Generación de títulos

Los títulos de diferentes ordenes se generan por las funciones: h1, h2, h3, etc. Todas ellas tienen el tipo:

 $Html -> Html

Sin embargo, existe un operador de aplicación sobrecargada (<<) que permite aplicar toda función que espera un argumento Html a argumentos de los siguientes tipos:

 Html
[Html]
String
[String] 

Por lo tanto es posible generar un titulo de primer nivel de la siguiente manera:

  
  Html> h1 << “hola”
  
 <H1>
    hola
 </H1>
 

El ejemplo anterior como los siguientes son comandos introducidos interactivamente en hugs con su correspondiente respuesta. Tenga en cuenta que hugs invoca a la función show para mostrar el resultado que es de tipo Html.

Párrafos

Los párrafos se generan con la función p:

 
    Html> map (p<<) $ words “hola que tal”

    <P>
         hola
    </P>
    <P>
        que
    </P>
    <P>
        tal
    </P>
  

Listas

Listas numeradas y no numeradas se obtienen con las funciones olist y ulist respectivamente. Cada ítem de la lista se obtiene con li:

 
       Html> olist << map (li<<) (words “hola que se cuenta”)

       <OL>
         <LI>
           hola
         </LI>
         <LI>
           que
         </LI>
         <LI>
           se
         </LI>
         <LI>
           cuenta
         </LI>
      </OL>
  

Anclas

Para generar un ancla ha de ser apuntado por un hipervínculo usamos la función anchor con un atributo name:

 
        Html> anchor ! [ name “coso” ] << “murcielago”

        <A NAME = “coso”>
           murcielago
        </A>
  

Análogamente se genera un vínculo apuntando al ancla anterior con un atributo href:

         Html> anchor ! [ href “coso” ] << “(Ver murcielago)”

         <A HREF = “coso”>
            (Ver murcielago)
         </A>
 

Concatenación de Html

Para pegar 2 objetos de tipo Html se usa el operador (+++).

    Html> h1 << “hola” +++ p << “que tal”

    <H1> 
      hola
    </H1>
    <P>
        que tal
    </P>
 

Un programa de ejemplo

A continuación se muestra como crear y desplegar un documento html usando los combinadores de la biblioteca XHtml.

 module Main where

 import Text.XHtml


 t1 = "Ejemplo para la tarea"

 p1 = [
	 "	Este es un ejemplo para ser usado como caso de prueba para"
	,"	probar la conversión de texto a html."
	,"	Esta primera sección esta formada unicamente por 2 parrafos."
     ]

 p2 = [	"	Este es el segundo parrafo. Y no queda otra cosa por decir." ]

 t2 = "Segundo titulo"

 p3 = [	"	Vemos ahora ejemplos de algunos elementos que pueden aparecer" 
     ]

 t21 ="Listas numeradas"

 lista1 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior." ]

 t22 = "Listas no numeradas"

 lista2 = [
	  "Primer item de la lista."
	 ,"Este es el segundo."
	 ,"Este no es el cuarto item, sino el anterior. "]

 t223 = "Que hace este titulo aqui?"

 p4 = "        El anterior es un titulo de tercer nivel"

 t3 = "El tercer titulo"

 p5 =	["      Aqui vamos a ver un ejemplo de texto pre formateado. Este"
	,"	comienza en la columna 14"
	]

 pref =   ["        elem :: Eq a -> [a] -> Bool"
	, "        elem = any . (=)"
	]

 t4 ="El ultimo capitulo"

 p6 =	[ "        Aqui vemos un parrafo que tiene alguna palabra"
	, "	*enfatizada* . Tambien tenemos palabras en _negrita_      "]

 tabla_contenido =
    h1 << "Tabla de contenido" +++
    ulist << [
            li << (anchor ! [href "#t1"] << t1)
          , li << (anchor ! [href "#t2"] << t2) 
		 +++ ulist <<[ li << (anchor ! [href "#t21"] << t21) 
			  , li << (anchor ! [href "#t21"] << t22) ]
          , li << (anchor ! [href "#t3"] << t3)
	  , li << (anchor ! [href "#t4"] << t4)]

 pagina = body <<
	   tabla_contenido +++ hr +++
	   (anchor ! [name "t1"] << h1 << t1) +++
           (p << p1) +++ (p << p2) +++
	   (anchor ! [name "t2"] << h1 << t2) +++ (p << p3) +++
	   (anchor ! [name "t21"] << h2 << t21) +++ 
                          (olist << (map (li<<) lista1)) +++
	   (anchor ! [name "t22"] << h2 << t22) 
                      +++ (ulist << map (li<<) lista2) +++
	   (anchor ! [name "t223"] << h3 << t223) +++ (p << p4) +++
	    anchor ! [name "t3"] << h1 << t3 +++ p << p5 +++ pre << unlines pref +++
	   (anchor ! [name "t4"] << h1 << t4) +++ (p << p6)


 main :: IO ()
 main = putStr  $ renderHtml pagina

 

Si compilamos y ejecutamos nos muestra en pantalla la salida en formato HTML que lo interpretaría el navegador de internet

$ghc --make -threaded ejemplo_html.hs -o ejemplo_html
$./ejemplo_html

Aplicación práctica. Gitit, wiki usando Happstack

Básicamente Gitit es una wiki de apoyo para las herramientas de control de versiones darcs, git. Los ficheros que componen el proyecto pueden ser modificados directamente desde la línea de comando o desde la wiki directamente. Para escribir dentro de la wiki se utilizan distintos formatos basados en etiquetas. Para ello hace uso de Pandoc, así que se puede escribir siguiendo los formatos de markdown extendido, reStructuredText, LaTeX, HTML, o Haskell. A su vez se puede exportar el contenido en distintos formatos como LaTeX, ConTeXt, DocBook, RTF, OpenOffice ODT y MediaWiki.


Instalación

Como viene siendo usado en esta wiki, vamos a realizar la instalación dentro de Ubuntu en su versión 10.04 TLS y con la plataforma de Haskell instalada como hemos comentado en esta misma wiki
Gitit.png
  1. Instalar pandoc.
    $sudo apt-get install pandoc
  2. Instalar git si no está instalado.
    $sudo apt-get install git
  3. Instalar gitit.
    $sudo cabal update
    $sudo cabal install gitit
  4. Arrancar gitit.
    $mkdir mywiki
    $cd mywiki
    $gitit
  5. Podemos ver el resultado en http://localhost:5001

Referencias

Herramientas personales