In questi giorni, dato che la beta di Vista ancora nicchia, per non so bene quale motivo, mi sono preso la briga di impiegare il mio già scarso tempo a disposizione, mettendo il naso nella beta di Monad, cui mi sono iscritto. Monad, per chi non lo sapesse è la nuova shell di Microsoft che dovrebbe debuttare con l'uscita del nuovo sistema operativo Vista, probabilmente entro la fine di quest'anno, sotto il nome di MSH.

Devo dire che sono molto affascinato da Monad, che pur presentandosi con un'interfaccia molto linux-like, dopo una breve esplorazione si rivela un ambiente di una flessibilità e potenza ineguagliabili, tanto da far impallidire facilmente anche il più sfegatato bash-ista. Prima di introdurvi al codice che voglio presentare, che in questi ho scritto per Monad, vale la pena che vi delucidi su cosa rende così potente e singolare un ambiente che a prima vista altro non è che la "solita" linea di comando.

In effetti, dopo aver digerito il primo impatto con la console, la cosa giusta da fare è di rivolgersi alla rete per cercare di capire qual'è il principio attorno cui si impernia il funzionamento di monad, perchè senza averne compreso la logica è del tutto inutile provare a trarne qualcosa di utile, dato che invariabilmente si rimarrà impigliati nell'errata interpretazione che la riga di comando impone. Monad infatti è un ambiente in tutto e per tutto ad oggetti che ha la capacità di estendere il comune concetto di "piping" che molti conoscono grazie alle shell Unix, su una dimensione ulteriore, si potrebbe dire "tridimensionale" quale sono gli oggetti di .NET. Per chiarirlo facciamo subito un piccolo esempio pratico; Aprite una console msh e scrivere quanto segue:

(get-process iexplore).Kill()

Ok, so bene che si tratta di uno scherzo un po' scemo, ma è molto significativo. Vediamo di spiegarlo in due parole; get-process è la cmdlet che restituisce l'elenco dei processi attivi, alla quale è possibile applicare un filtro per nome processo. In questo modo monad troverà tra tutti i processi quello che si chiama "iexplore" e su di esso chiamerà il metodo Kill(), con l'ovvio risultato di chiuderlo.

Converrete con me che questo approccio è davvero fantastico. Se si considera che qualunque cosa venga restituita da Monad è un oggetto di .NET è del tutto evidente che come tale è possibile manipolarlo con la massima libertà. Questo infatti vale allo stesso modo che per i processi attivi, anche per i file e le directory del filesystem che generano degli oggetti di tipo DirectoryInfo e FileInfo che chi ha già usato System.IO conosce bene. Se poi consideriamo che come unix insegna una shell ha sia uno stout che uno stin ecco che appare evidente che i medesimi oggetti che vengono generati da un comando di MSH possono essere passati in input ad un altro comando MSH che li potrà manipolare a piacimento. E' questo il meccanismo del "piping" che mentre in unix/linux si ferma tipicamente al semplice testo ASCII, in monad assume questa consistenza tridimensionale dell'oggetto .NET.

Ma la domanda legittima che ci si dovrebbe porre a questo punto è: ma chi è che genera questi oggetti?

In effetti potrebbe apparire a prima vista che gli oggetti restituiti in output da un comando siano "generati" dal comando stesso, ma non è esattamente così; I comandi di monad infatti sono dei "Verbs", che per essere eseguiti hanno la necessità di un provider che ne interpreti l'input e ne restituisca di conseguenza l'output. Dicendo questo mi sto in effetti muovendo su un terreno un po' scosceso, infatti quanto dico è frutto semplicemente delle mie sperimentazioni e potrebbe essere inficiato dalla limitatezza delle stesse, ma non credo di allontanarmi di molto dalla verità. In effetti i provider in Monad ci sono è sono qualcosa di molto importante, basti pensare che per l'accesso al filesystem esiste un FileSystemProvider che risponde ai comandi più comuni che si possono dare ad un filesystem.

La cosa eccezionale è che questi provider si possono scrivere in .NET con il framework 2.0 è come naturale non appena ne ho scoperto l'esistenza mi ci sono buttato a capofitto per capire come sfruttarli e ho scritto un po' di codice che vi presenterò in un paio di post.

Va detto innanzitutto che un provider per Monad è una classe .NET che estende una classe base, nel mio caso NavigationCmdletProvider e che implementa una serie di interfacce accessorie che consentono di estenderne ulteriormente le funzionalità. Così, nel caso del FileSystemProvider abbiamo che esso eredita dalla NavigationCmdletProvider che gli consente di usare i comandi "cd" e "dir" o per dirla con Monad "set-location" e "get-childitem". Lo stesso provider inoltre implementa l'interfaccia IContentCmdletProvider che gi permette di rispondere ai comandi come "get-content" (type).

Scrivere un provider per Monad quindi significa fare in modo che i comandi che normalmente si impartiscono per navigare nel filesystem possano essere usati anche per navigare in qualsiasi altra struttura gerarchica. La stessa Shell infatti già dispone di altri provider (usare get-provider per avere l'elenco completo) che rispondono a quelli che impropriamente si potrebbero chiamare "device" o "drive". Ad esempio il drive HKLM: consente di navigare all'interno del registry; ENV: nelle variabili di ambiente. E così via.

Appena ho scoperto questa caratteristica ho subito pensato di scrivere un provider e tra tutte le possibili varianti a scopo di esercizio ho deciso di realizzare un provider che risponda al drive "sql:". Come ben potete immaginare questo device consente di navigare all'interno dello schema di un database sql nel quale si abbia accesso con la windows authentication, sfruttando i comuni "cd" e "dir".

Ora è tardi è non mi sembra il caso di continuare, però prometto che a breve tornerò su questo appetitoso argomento presentandovi il codice funzionante che ho realizzato, e magari proverò anche a migliorarlo.

powered by IMHO 1.3


per leggere il post originale o inviare un commento visita il seguente indirizzo: Scrivere un provider per Monad (MSH) #1