$ cat /dev/random
ripley's miscellanous debris

python Tag Archive

Ruby, XMLRPC e Trac

(2006-06-13)

Io e i miei compari usiamo coordinare e tracciare le nostre attivita’, idee e progetti mediante un software chiamato Trac.

Trac e’ l’insieme di un wiki, un vcs browser e un tracker.

Fornisce quindi alcuni degli strumenti fondamentali per coordinare dei progetti di sviluppo, integrando il tutto in un unico software.

Lo utilizziamo oramai da quasi un anno e’ tranne qualche piccola pecca (l’editing contemporaneo delle pagine wiki… mi sa che se non patch-ano loro ci mettero’ presto le mani io :-P ), ci troviamo benissimo :-)

La componente vcs browser inizialmente era stata pensata semplicemente come un svn browser, il che si e’ rivelato limitante visto il proliferare di varie alternative che prendono sempre piu’ piede (tra cui bzr, git, darcs, mercurial etc.) per cui presto sono venuti fuori dei fork per supportare questo o quel sistemi di revisione.

In particolare noi usavamo il branch sperimentale con il supporto per darcs e bzr (sviluppato tra l’altro da alcuni italiani http://progetti.arstecnica.it/trac+darcs) , il quale funziona piu’ che bene…

ma… c’e’ ovviamente un ma…

una limitazione rispetto al classico utilizzo di Trac+svn e’ rimasta :-(

L'impossibilita' di chiudere automaticamente un bug mediante il semplice commit.

E si… e questo e’ dovuto semplicemente al fatto che subversion esegue gli hook sull’host in cui risiede il repository e in cui e’ plausibile ci sia anche il trac.

Questo non vale invece per bzr (ne per gli altri sistemi di revisione decentralizzati, che prevedono lato repository un comune accesso sftp o equivalente)... in questo caso gli hook vengono richiamati lato client, per cui lo script previsto per subversion non e’ idoneo per bzr :-(

Quindi?

Quindi dobbiamo far in modo di poter chiudere dei ticket da remoto… il modo migliore per farlo sarebbe sicuramente qualcosa tipo XMLRPC.

Su TracHacks troviamo quello che fa al caso nostro:

un bel plugin XMLRPC per Trac :-)

Unico inconveniente… il plugin e’ stato sviluppato sulla versione 0.10 di Trac, cioe’ la versione in sviluppo, per la quale non esiste un branch bzr… ma esiste un plugin per il nuovo strato di virtualizzione della componente vcs di Trac.

Installare Trac 0.10

Trac viene sviluppato utilizzando svn come sistema di revisione, quindi per ottenere l’ultima release di sviluppo:

svn co http://svn.edgewall.com/repos/trac/trunk trac

Per compilare i sorgenti ed installarli nel sistema:

$ cd trac
$ sudo python setup.py install --prefix=/usr/local/

Compilazione dei plugin trac

Trac utilizza per i plugin una tecnologia molto simile ai jar di java, i python egg.

Per generare l’egg di un plugin:

$ python setup.py bdist_egg

Per installare il plugin e’ sufficiente copiare il file .egg ottenuto, contenuto nella directory dist, nella directory plugin dell’istanza trac in cui vogliamo installarlo, ed in alcuni casi aggiungere alcuni parametri in config/trac.ini.

XMLRPC Trac Plugin

Il plugin XMLRPC di trac (compatibile con la versione 0.10 in via di sviluppo) si trova all’indirizzo:

Per installarlo e’ sufficiente generare e copiare l’egg file nell’istanza di trac interessata e modificarne il trac.ini aggiungendo la linea:

[components]
tracrpc.* = enabled

Bzr Trac Plugin

Il plugin XMLRPC di trac (anch’esso compatibile con la versione 0.10) si trova all’indirizzo:

E ad essere precisi il repository (bzr ovviamente) del plugin, che non e’ ancora stato rilasciato ufficialmente:

potere prelevarlo mediante bzr:

  bzr get http://samba.org/~jelmer/bzr/trac-bzr

Analogamente a quanto fatto per il plugin XMLRPC, generiamo l’ egg file e lo copiamo nella directory plugins dell’istanza trac che ci interessa, e aggiungiamo in config/trac.ini le seguenti righe:

[components]
trac-bzr.* = enabled
[trac]
repository_type = bzr
repository_dir = /srv/repos/alcadps/trunk

Primi XMLRPC-passi

Come primo passo verifichiamo che il plugin xmlrpc sia attivo visitando l’indirizzo http://miohost.miodominio/tracname/xmlrpc.

Se il plugin sta funzionando correttamente dovremmo vedere una pagina contenente una descrizione di tutte le funzioni che il plugin XMLRPC ci mette a disposizione.

A questo punto possiamo provare un primo semplice script in ruby…

XMLRPC-Client in ruby

Il primo snippet ha la semplice funzione di elencare le funzioni messe a disposizione da trac:

require "xmlrpc/client"

server = XMLRPC::Client.new("localhost", "/alcadps/xmlrpc", 3000)

system = server.proxy('system')
puts system.listMethods

Il secondo snippet richiede lo stato di un ticket:

require "xmlrpc/client"

server = XMLRPC::Client.new("localhost", "/alcadps/xmlrpc", 3000)

ticket = server.proxy('ticket')
puts ticket.get('9')[3]['status']

La funzione ticket.get ritorna un array in cui il 4 elemento e’ un hash contenente i dettagli del ticket.

E’ importante notare comunque che i due snippet precedenti accedono a trac in modo anonimo, di conseguenza i permessi saranno quelli dell’utente anonymous.

Per avere accesso a tutte le funzionalita’ messe a disposizione ad utenti con permessi aggiuntivi e’ necessario autenticarsi.

Purtroppo questo ha messo in luce un problema dovuto alla tecnica di autenticazione di trac.

Problema di autenticazione su XMLRPC

Il problema e’ dovuto al redirect (Net::HTTPSeeOther) che genera trac dopo aver autenticato un client. In XMLRPC cio’ non ha molto senso e di conseguenza sia l’implementazione python che ruby di xmlrpc non contempla questa risposta da parte del server.

Sono riuscito a bypassare il problema con qualche piccolo hack sulla classe XMLRPC::Client .

Questo hack comunque non credo sia la soluzione migliore…

HTTP See Other Workaround

Il workaround piu’ elegante che mi e’ venuto in mente e’ stato quello di autenticarmi utilizzando direttamente il package Net::HTTP (il quale e’ utilizzato anche dalla classe XMLRPC::Client ), estrarre il cookie dalla risposta del server, e utilizzarlo nell’oggetto XMLRPC::Client creato per comunicare con il server… e per questo dobbiamo ringraziare i lungimirandi sviluppatori di XMLRPC::Client che hanno previsto l’accessor cookie in lettura e scrittura :-)

require "xmlrpc/client"
require 'net/http'

header = {
  "User-Agent"     => "ruby Net::HTTP",
  "Content-Type"   => "text/xml; charset=utf-8",
}

Net::HTTP.start('yourhost.yourdomain',3000) {|http|
   req = Net::HTTP::Post.new('/yourtrac/login/xmlrpc')
   req.basic_auth 'your_login', 'your_password'
   response = http.request(req,header)

   @cookie = response['Set-Cookie']
}


# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new("yourhost.yourdomain", "/yourtrac/xmlrpc", 3000)

server.cookie = @cookie

system = server.proxy('system')
ticket = server.proxy('ticket')
tstatus = server.proxy('ticket.status')

ticket.update(9, 'closed by xml-rpl :-)', { 'status' => 'closed' })

Volendo si puo’ incapsulare la funzionalita’ di autenticazione in una bella funzioncina e riutilizzare il concetto in tutti gli script di automation per trac che potremo sviluppare :-P

Happy Hacking


Full of CC licensed ripley's debris
HTML and CSS Design by Nicolas Fafchamps
Generated with Rote and Rog