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