Amarok logoAvevo scritto questo articolo su come installare Amarok 1.4.10 su recenti versioni di Debian, per chi preferisce la vecchia versione alla nuova. Visto che sono cambiate un po’ di cose nei pacchetti disponibili, questo articolo è un aggiornamento della precedente guida.

Si cominci sempre con installare un po’ di pacchetti necessari e che dovrebbero essere disponibili a prescindere dalla versione di Debian in uso:

aptitude install libqt3-mt libifp4 libkarma0 libnjb5 libpq5 liblua50 liblualib50

Fatto questo, abbiamo bisogno dei seguenti pacchetti:

amarok
amarok-common
amarok-engine-xine
kdelibs4c2a
kdelibs-data
libarts1c2a
libartsc0
libaudiofile0
libavahi-qt3-1
libgpod3-nogtk
libmtp7
libmysqlclient15off
libtunepimp5

Notare che:

  1. i primi tre pacchetti (amarok, amarok-common e amarok-engine-xine) devono essere alla versione 1.4.x;
  2. alcuni di questi pacchetti sono disponibili solo per Debian Lenny (oldstable), altri anche se Debian Squeeze (attuale stable) e/o su Debian Sid (unstable).

Se volete, quindi, potete procedere tramite pinning (guida), almeno per i pacchetti presenti su Squeeze e/o Unstable. Ma per agevolarvi il lavoro, ho creato due comodi archivi .tar.gz, uno per Debian a 32bit (qui) e uno per Debian a 64bit (qui).

Scaricate quello corrispondente alla vostra architettura. Per 32bit:

http://docs.mirkopagliai.it/packages/amarok_32bit.tar.gz

Per 64bit:

http://docs.mirkopagliai.it/packages/amarok_64bit.tar.gz

Decomprimete l’archivio:

tar -zxvf amarok*.tar.gz

Quindi portatevi all’interno della directory estratta e procedete all’installazione di tutti i file .deb tramite dpkg:

cd amarok*
dpkg -i *.deb

Ricordatevi, alla fine, di bloccare i pacchetti amarok e amarok-common, altrimenti vi chiederà continuamente di aggiornarli:

aptitude hold amarok amarok-common

(la stessa cosa va fatta all’interno di Synaptic, selezionando i pacchetti e poi scegliendo dal menù “Pacchetto” l’opzione “Blocca versione”)

Enjoy Amarok 1.4.10 ;-)

Oggi è apparso questo articolo su La Repubblica. Da quanto riportato, sembrerebbe che Facebook offrirà ai suoi utenti licenze antivirus gratuite che vanno da sei mesi fino ad un anno. Nell’articolo si legge che

Gli obbiettivi sono almeno due: rendere educare gli utenti alla protezione del computer, e rendere il social network più sicuro e gli iscritti meno vulnerabili agli attacchi di spam.

Primo, un antivirus non protegge e non può proteggere dallo spam, tanto meno dalla spam presente su Facebook: se un altro utente vuole postare della pubblicità sulla vostra bacheca o se ricevete messaggi privati dagli stessi contenuti, un antivirus nulla può fare. Semmai dovrebbe essere Facebook a prevenire (a livello di codice della propria piattaforma) questi episodi, piuttosto che consigliare “soluzioni terze” di scarsa utilità.
Secondo, si parla di “educazione”, ma non si capisce perché l’educazione debba passare tramite la prova gratuita di un prodotto commerciale (e semmai non fosse chiaro: vi regalano dai 6 ai 12 mesi di utilizzo gratuito, poi dovrete pagare), cosa che sembra piuttosto marketing – appunto – commerciale.

Ed è proprio di marketing che si parla: le case produttrici di software antivirus pagano Facebook, in cambio Facebook vi offre per inter-tramite i loro prodotti in prova gratuita, consigliando e suggerendo (e non è cosa da poco, perché ormai è fin dentro la nostra vita e molti si fidano); quando la prova gratuita termina, dovete procedere al pagamento della licenza annuale.
Insomma, Facebook e le case produttrici (l’articolo riporta Symantec, McAfee, Trend Micro, Sophos e Microsoft) guadagno, voi intanto venite “educati”. Sì, educati all’acquisto acritico e di massa.

Diffidate di questi articoli, diffidate anche delle rubriche informatiche e tecnologiche dei vari quotidiani italiani, che sono di una superficialità spaventosa e si limitano soltanto a fare da vetrina per prodotti, diffidate soprattutto delle relative rubriche su La Repubblica, che in questo senso detiene un vero e proprio record. Diffidate anche degli “acquisti suggeriti” e dagli acquisti suggeriti in particolare da Facebook. Ma fin qui spero siate capaci di arrivarci anche da soli.

Se utilizzate Windows, guardate a soluzioni gratuite come Avast e Avg. È dimostrato, informaticamente parlando, come ad oggi queste soluzioni gratuite siano pari se non superiori a quelle a pagamento, quindi non si capisce perché scegliere diversamente, soprattutto perché dover essere educati diversamente, per giunta tramite metodi subdoli.
Se volete fare cosa ancora migliore, allora passate a Linux e dormite sonni tranquilli.

Sulle mie Debian non manca mai localepurge, un ottimo tool per mantenere pulito il sistema e rimuovere file non necessari.

Questo è uno script per recuperare lo spazio su disco sprecato per file locale, localizzazioni di Gnome/KDE e pagine di manuale localizzate non necessari. In base all’installazione, è possibile recuperare qualcosa come 200, 300 o più mega byte di spazio su disco dedicato alle localizzazioni che molto probabilmente non avrebbero nessun utilizzo. Sarà invocato automagicamente al termine di ogni processo di installazione di apt.

Notare che questo strumento è un trucco che *non* è integrato nel sistema di gestione dei pacchetti di Debian e perciò non è adatto ai deboli di cuore. Questo programma interferisce con la gestione dei pacchetti di Debian e provoca strani, ma di solito innocui, comportamenti nei programmi correlati ad apt/dpkg, come dpkg-repack, reportbug, ecc. La responsabilità e i possibili danni al sistema derivanti dal suo uso ricadono perciò nelle mani dell’amministratore di sistema (le vostre).

Ci si astenga categoricamente dal riportare uno qualsiasi di questi malfunzionamenti incolpando localepurge se il proprio sistema è stato danneggiato dal suo uso. Se non si sa quello che si sta facendo e non si possono risolvere autonomamente i danni derivanti dall’uso, allora semplicemente non si usi questo pacchetto.

Tuttavia, se lo utilizzate avrete sicuramente notato come venga lanciato ogni qualvolta andiamo compiere una qualsiasi operazione con i pacchetti di sistema (con apt-get e aptitude, ma anche con synaptic). Comportamento – almeno per quanto mi riguarda – fastidioso e dispendioso, ma che può ovviamente essere disabilitato.

Durante la sua installazione, infatti, localepurge crea il file /etc/apt/apt.conf.d/99-localepurge, che si occupa appunto dell’autostart ogni volta che viene compiuta un’operazione inerente apt. Il contenuto del file:

// Get rid of unneeded locale files after each package installation

DPkg
{
Post-Invoke {"if [ -x /usr/sbin/localepurge ] && [ $(ps w -p $PPID | grep -c remove) != 1 ]; then /usr/sbin/localepurge; else exit 0; fi";};
};

Ebbene – incredibile a dirsi :-) – per disabilitare l’autostart di localepurge è sufficiente commentare quelle quattro linee di codice (anteporre il carattere # alle linee 3-6). Viceversa, per ripristinarlo, togliere i commenti.

Oggi mi sono trovato di fronte a un’esigenza un po’ particolare: per un piccolo motore di ricerca di articoli, creare un menù a tendina (select) per scegliere il mese di pubblicazione. La difficoltà sta nel realizzare un array ben curato con i valori da ciclare per poi creare il citato menù a tendina.

Il menù a tendina, ovviamente, di default dovrebbe partire dal momento attuale (cioè mese e anno corrente) e arrivare fino al mese di apertura del sito. Ad esempio, posto che l’eventuale sito abbia aperto a giugno 2010 e visto che ora siamo in aprile 2012, i valori dovrebbero essere questi:

aprile 2012
marzo 2012
febbraio 2012
gennaio 2012
dicembre 2011
...
agosto 2010
luglio 2010
giugno 2010

Dovrebbe tuttavia permettere anche di indicare valori di partenza e/o di arrivo diversi, oltre a quelli di default. Di seguito, la funzione che ho scritto, ben commentata (non dovrebbe necessitare di ulteriori spiegazioni):

/**
* Restituisce un array dei mesi (accompagnati dall'anno) in cui possono essere stati pubblicati degli articoli
* (l'array ha chiavi come "2012-02" e valori come "febbraio 2012")
* @param int $final_month Mese di arrivo. Se non indicato, letto dalla configurazione
* @param int $final_year Anno di arrivo. Se non indica, letto dalla configurazione
* @param int $starting_month Mese di partenza. Se non indicato, impostato all'attuale
* @param int $starting_year Anno di arrivo. Se non indicato, impostato all'attuale
* @return array Array dei mesi
*/
function getPublicationMonths($final_month = null, $final_year = null, $starting_month = null, $starting_year=null) {
	//Se non è stato passato il mese o l'anno di arrivo, imposta dalle constanti di configurazione
	$final_month = !is_null($final_month) ? $final_month : FINAL_MONTH;
	$final_year = !is_null($final_year) ? $final_year : FINAL_YEAR;

	//Se non è stati passato il mese o l'anno di partenza, imposta al momento attuale
	$starting_month = !is_null($starting_month) ? $starting_month : date('n');
	$starting_year = !is_null($starting_year) ? $starting_year : date('Y');

	//Prepara l'array in cui inserire i dati
	$data = array();

	//Cicla i dati. Il ciclo ha fine quando vengono raggiunti mese e anno di arrivo
	while($starting_year != $final_year || $starting_month+1 != $final_month) {
		//Se il mese è valido (>=0), aggiunge i dati all'array
		if($starting_month) {
			$data[$starting_year.'-'.date('m', mktime(0, 0, 0, $starting_month))] = strftime('%B', mktime(0, 0, 0, $starting_month)).' '.$starting_year;
			$starting_month -= 1;
		}
		//Se il mese non è valido, imposta il mese a dodice e decrementa l'anno
		else {
			$starting_month = 12;
			$starting_year -= 1;
		}
	}

	return($data);
}

Giusto un aspetto che potrebbe non essere chiaro: se non viene indicato il mese e/o l’anno finali, utilizza le constanti FINAL_MONTH e/o FINAL_YEAR (che si suppone siano state già state impostate altrove e che riportano appunto mese e anno di apertura del sito. Comunque, nulla di impedisce di fare una query per selezionare l’articolo più vecchio e estrarre i dati da lì); se non viene indicato il mese e/o l’anno di partenza, utilizza mese e anno attuali.

Quindi, lanciandola così:

getPublicationMonths('6', '2010');

(equivale a dire: da oggi (aprile 2012) a giugno 2010)

E utilizzando un altro ciclo per creare l’html del menù a tendina (perché la funzione restituisce solo un array), il risultato è questo:

<select>
	<option value="">-- data --</option>
	<option value="2012-04">aprile 2012</option>
	<option value="2012-03">marzo 2012</option>
	<option value="2012-02">febbraio 2012</option>
	<option value="2012-01">gennaio 2012</option>
	<option value="2011-12">dicembre 2011</option>
	<option value="2011-11">novembre 2011</option>
	<option value="2011-10">ottobre 2011</option>
	<option value="2011-09">settembre 2011</option>
	<option value="2011-08">agosto 2011</option>
	<option value="2011-07">luglio 2011</option>
	<option value="2011-06">giugno 2011</option>
	<option value="2011-05">maggio 2011</option>
	<option value="2011-04">aprile 2011</option>
	<option value="2011-03">marzo 2011</option>
	<option value="2011-02">febbraio 2011</option>
	<option value="2011-01">gennaio 2011</option>
	<option value="2010-12">dicembre 2010</option>
	<option value="2010-11">novembre 2010</option>
	<option value="2010-10">ottobre 2010</option>
	<option value="2010-09">settembre 2010</option>
	<option value="2010-08">agosto 2010</option>
	<option value="2010-07">luglio 2010</option>
	<option value="2010-06">giugno 2010</option>
</select>

Che, graficamente, si traduce in questo:

Menù a tendina con mesi

Come potete vedere dall’output html di cui sopra, il valore selezionato sarà nel formato (formato di date()):

Y-m

Mentre i valori dell’array sono in questo formato (chiave => valore):

Y-m => F Y

In un precedente articolo Tutorial Jquery: menù a tendina ho ricevuto il seguente commento:

Ciao Mirko, ho seguito alla lettera il tuo tutorial… nel mio caso mi servirebbe un menu con una tendina che si aprisse verso l’alto e non verso il basso… sapresti darmi qualche suggerimento su come fare? ti ringrazio!

Si può fare? Sì, vediamo subito di aiutare Paolo.

Il problema che si riscontra è generalmente questo: normalmente, gli elementi html vengono disposti dall’alto verso il basso (oltre che da sinistra verso destra). Noi dobbiamo invertire questo caso, ed è possibile solo utilizzando il posizionamento assoluto.

Partiamo dal precedente esempio. Il codice html era questo:

<ul id="navbar">
	<li><a href="pagina1.html">Pagina 1</a></li>
	<li>
            <a href="#">Pagina 2</a>
            <ul>
               <li><a href="paginaA.html">Pagina A</a></li>
               <li><a href="paginaB.html">Pagina B</a></li>
               <li><a href="paginaC.html">Pagina C</a></li>
            </ul>
        </li>
	<li><a href="pagina3.html">Pagina 3</a></li>
</ul>

Mentre il foglio di stile è disponibile qui.

Bene, la prima cosa da fare, come detto, è dare una posizione assoluta (position: absolute) ai sotto-menù. È però prima necessario indicare qual è l’elemento di riferimento (position: relative): nel nostro caso sarà #navbar, cioè il menù principale.
Quindi la posizione: dal basso, dalla parte inferiore del menù principale (“bottom”) è sufficiente spostare il sotto-menù dello stesso numero di pixel dell’altezza del menù principale (che nel precedente esempio è di 25 pixel). Ovvero (riporto solo le regole che incidono su questo caso, per il resto – come già detto – guardate l’esempio precedente):

#navbar {
	height: 25px;
	position: relative;  /* Necessario perché fa da riferimento alla posizione dei sotto-menù (successiva regola) */
}
#navbar ul {
	bottom: 25px; /* Deve essere uguale all'altezza di #navbar (precedente regola) */
	position: absolute;
}

Graficamente il nuovo menù apparirà così:
jquery_submenu

Anche qui, aggiungiamo ai sotto-menù la regola display: none, così che di default, al caricamento della pagina, non vengano mostrati.

Infine, proprio come nel precedente esempio, possiamo aggiungere lo stesso codice Jquery:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
	$(document).ready(function(){
		$("#navbar li").hover(function (){
			$(this).children("ul").slideToggle();
		});
	});
</script>

Ed ecco il risultato finale:
http://docs.mirkopagliai.it/html/menu-tendina/esempio6_versoalto.html

Notare che:

  1. per praticità, il codice css è nella stessa pagina html, non ho usato un foglio di stile esterno;
  2. al menù principale (#navbar) ho aggiunto un margine superiore semplicemente per distanziarlo e rendere visibile l’effetto.

Riporto qui sul blog l’ottimo suggerimento¹ di xtow sul forum debianizzati.org su come individuare il mirror italiano più veloce.

Innanzitutto è necessario installare netselect e quindi:

apt-get install netselect

Va quindi lanciato col l’opzione -vv (“very verbose mode”), seguito dalla lista dei mirror da testare. Ad esempio:

netselect -vv debian.bononia.it debian.fastweb.it ftp.it.debian.org debian.dynamica.it debian.fastbull.org freedom.dicea.unifi.it giano.com.dist.unige.it mi.mirror.garr.it mirror.units.it

Nel mio caso:

root@mirko-laptop:/home/mirko# netselect -vv debian.bononia.it debian.fastweb.it ftp.it.debian.org debian.dynamica.it debian.fastbull.org freedom.dicea.unifi.it giano.com.dist.unige.it mi.mirror.garr.it mirror.units.it
Running netselect to choose 1 out of 9 addresses.
...............................................................................
freedom.dicea.unifi.it                  82 ms  22 hops   90% ok ( 9/10) [  291]
debian.fastbull.org                     39 ms  16 hops  100% ok (10/10) [  101]
giano.com.dist.unige.it               9999 ms  30 hops    0% ok
debian.fastweb.it                       28 ms  12 hops   90% ok ( 9/10) [   68]
ftp.it.debian.org                       40 ms  17 hops   90% ok ( 9/10) [  121]
mi.mirror.garr.it                       29 ms  16 hops   75% ok ( 6/ 8) [  101]
debian.dynamica.it                      33 ms  14 hops   90% ok ( 9/10) [   88]
debian.bononia.it                     9999 ms  30 hops    0% ok
mirror.units.it                         40 ms  19 hops   90% ok ( 9/10) [  127]
   68 debian.fastweb.it

Modificate il vostro /etc/apt/sources.list di conseguenza.

Per qualsiasi altra cosa, fate sempre riferimento al manuale:

man netselect

netselect

FirefoxCome probabilmente già saprete (soprattutto se giungete a questo post da una ricerca) le ultime versioni di Firefox/Iceweasel non supportano l’ultima versione dell’estensione Silverlight (la 3.99.0.3 del 12 aprile 2011); estensione ahimè necessaria (anche se in rete si possono trovare varie alternative, più o meno funzionanti) per fruire di diversi contenuti multimediali, come quelli sui siti Rai.

Taccio a proposito di:

  1. motivi che portano alla scelta di adottare software proprietario o che si appoggia a software proprietario, software non libero, software non-multipiattaforma o con problemi/scarse prestazioni su alcune piattaforme, software non flessibile e via dicendo. Soprattutto quando (vedi caso della Rai) sono tenuto anche a pagare. Ma è già assodato come ci siano in giro troppi ingegneri, esperti di informatica o sviluppatori che, anche se con laurea alla mano, dovrebbe andare a fare un altro lavoro causa pochezza mentale;
  2. motivi che portano a sviluppare un software, farlo adottare da tanti e in contesti così cruciali da fare in modo che diventi un software essenziale e poi non aggiornarlo regolarmente (l’ultima release stabile risale – lo ripeto – ad aprile 2011).

Vengo a spiegarvi come ho risolto sulla Debian, procedura che dovrebbe essere valida anche su altre distribuzioni GNU/Linux.  Anzitutto dovete sapere che l’estensione funziona benissimo (almeno io la sto usando su Firefox 9), è solo che per ogni estensione viene indicata una versione massima e una minima dei vari browser e presumibilmente la prima sarà l’ultima versione disponibile al momento della versione dell’estensione.

Dunque:

  1. scaricate (non installandola, ma scaricandola effettivamente sul vostro hard disk) l’estensione da qui. Con lo stesso Firefox/Iceweasel dovrebbe essere sufficiente fare click destro sul link e quindi scegliere l’opzione “Salva destinazione con nome…”. Altrimenti, c’è sempre il divino wget:
    wget http://www.go-mono.com/moonlight/downloads/3.99.0.3/novell-moonlight-3.99.0.3-x86_64.xpi
  2. il file scaricato è un archivio, quindi decomprimetelo (assumo sappiate già come fare). In caso di problemi, rinominatelo come un .zip;
  3. entrate nella directory estratta e aprite il file install.rdf, con un qualsiasi editor di testo. Quindi cercate le seguenti righe:
    <em:targetApplication> <!-- Firefox -->
       <Description>
       <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
       <em:minVersion>1.5</em:minVersion>
       <em:maxVersion>4.0.*</em:maxVersion>
       </Description>
    </em:targetApplication>

    Modificate la versione massima, ad esempio così:

    <em:maxVersion>10.*</em:maxVersion>

    Non dovete rimuoverla, deve essere presente, volutamente potete indicare qualsiasi numero (anche 100).
    Quindi salvate il file;

  4. cancellate la directory META-INF;
  5. ricreate l’archivio come file .zip. Fate attenzione a creare un archivio non della directory estratta (altrimenti, al momento dell’installazione, vi dirà che l’estensione risulta danneggiata), ma dei file contenuti nella directory. Il file risultante dovrebbe chiamarsi novell-moonlight-3.99.0.3-x86_64.xpi_FILES.zip, modificatelo affinché abbia il nome come quello originale;
  6. in Firefox andate su “Strumenti”, “Componenti aggiuntivi”, fate click sul pulsante alla sinistra della barra di ricerca e scegliete l’opzione “Installa componente aggiuntivo da file…”. Selezionate il file, attendete il termine dell’installazione e riavviate il browser.

Fatto.

Fonte: http://bit.ly/tM4rS2

Amarok logo

18/05/2012: guida obsoleta. Guardare qui.

Mettiamo che, come il sottoscritto, reputate la vecchia versione di Amarok (Amarok 1.4) come la migliore. Mettiamo che, come il sottoscritto, volete ancora utilizzarla sulla vostra Debian (qualsiasi versione).

Bene, Amarok 1.4 è ancora presente – al momento in cui scrivo – su Debian Lenny, l’attuale old-stable: vediamo come reperirlo, come conservarlo (prima o poi i repository di Debian Lenny andranno off, anche se con un po’ di impegno si può accedere ancora a repository molto più vecchi, che qualcuno conserva qua e là) e come installarlo.

Innanzitutto, se i repository di Debian Lenny sono ancora disponibili, configuriamo il pinning (se non lo abbiamo ancora fatto) come spiegato qui e poi aggiungiamo al nostro sources.list il repository:

deb http://ftp.it.debian.org/debian/ lenny main contrib non-free

Fatto questo, aggiorniamo e poi scarichiamo i pacchetti che ci servono (li scarichiamo proprio per conservarli per il futuro):

aptitude update
aptitude -t lenny download amarok amarok-common amarok-engine-xine libgpod3-nogtk libmtp7 libmysqlclient15off

I pacchetti verranno scaricati nell’attuale directory e dovrebbero essere (può cambiare l’architettura):

amarok_1.4.10-2lenny1_i386.deb
amarok-common_1.4.10-2lenny1_all.deb
amarok-engine-xine_1.4.10-2lenny1_i386.deb
libgpod3-nogtk_0.6.0-6_i386.deb
libmtp7_0.2.6.1-3_i386.deb
libmysqlclient15off_5.0.51a-24+lenny5_i386.deb

Semmai i repository di Lenny non dovessero essere più presenti, ho preparato un archivio con questi pacchetti per 32bit e 64bit. Scaricate e decomprimete.

Fatto questo, è necessario procedere con l’installazione di alcune dipendenze necessarie:

aptitude install kdelibs4c2a libqt3-mt libifp4 libkarma0 libnjb5 libpq5 libtunepimp5

Notate che queste dipendenze dovrebbero essere presenti anche nella vostra versione di Debian, quindi in questo caso non si necessita di pinning. Le dipendenze non più presenti (cioè obsolete) le abbiamo già reperite. Bisogna prima installare queste perché il resto verrà installato tramite dpkg, che non si preoccupa di installare eventuali dipendenze mancanti.

Infatti, a questo punto non resta che installare Amarok e le dipendenze ormai obsolete. Nella cartella in cui abbiamo precedentemente scaricato:

dpkg -i amarok*.deb libgpod3-nogtk*.deb libmtp*.deb libmysqlclient15off*.deb

Ed è fatta. Due accorgimenti:

  1. il lanciatore nel menù è nascosto di default, quindi (in Gnome 2) click destro del mouse sul menù, “Modifica menù”, andate sotto “Audio e video” e mettete la spunta alla relativa opzione;
  2. il nostro gestore dei pacchetti, rilevata una versione più recente di Amarok, insisterà nel farci aggiornare. Per risolvere è sufficiente bloccare i pacchetti amarok e amarok-common. In aptitude:
    aptitude hold amarok amarok-common

    In synaptic cercate (guardate sotto “Installato (aggiornabile)”) i due pacchetti, selezionatene uno alla volta, poi andate sul menù “Pacchetto” e mettete la spunta a “Blocca versione”.
    Notate che dovete seguire entrambe le procedure.

Et voilà:

Amarok

Sometimes we need some dependencies are installed on the operating system to run a bash script. So you can create a script that installs the missing dependencies.

After making a list of required dependencies, there are two ways to do this:

  1. pass the entire list to the package manager. Then the package manager will check which packages are already installed and will proceed with the installation of those that are missing;
  2. check what dependencies are already installed, make a list of dependencies that are missing, then pass to the package manager only missing dependencies list.

The second choice is the best choice, besides being more elegant. First, because it has a better chance of success (by hypothesis, some package managers may not work, if we ask it to install a package that’s already installed); second, ’cause if we were having some problems with the installation (for whatever reason), we can say exactly to the user what are the packages that he has to install manually.

Now let’s see what we have to do. As I have already said, we should:

  1. make a list of required dependencies (it’ll be the DEPENDENCIES array);
  2. check what dependencies are missing and save them in a new list (it’ll be the PKGSTOINSTALL string);
  3. install missing dependencies (from the PKGSTOINSTALL string).

Well, let’s go to the code. We need to create a list of required dependencies, for example foo and bar packages:

DEPENDENCIES=(foo bar)

Now we need to check which of those packages are already installed. The missing packages will be added to the PKGSTOINSTALL string, separated by a space:

# What dependencies are missing?
PKGSTOINSTALL=""
for (( i=0; i /dev/null; then
		if [[ ! `dpkg -l | grep -w "ii  ${DEPENDENCIES[$i]} "` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# OpenSuse, Mandriva, Fedora, CentOs, ecc. (with rpm)
	elif which rpm &> /dev/null; then
		if [[ ! `rpm -q ${DEPENDENCIES[$i]}` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# ArchLinux (with pacman)
	elif which pacman &> /dev/null; then
		if [[ ! `pacman -Qqe | grep "${DEPENDENCIES[$i]}"` ]]; then
			PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
		fi
	# If it's impossible to determine if there are missing dependencies, mark all as missing
	else
		PKGSTOINSTALL=$PKGSTOINSTALL" "${DEPENDENCIES[$i]}
	fi
done

With a loop we will be checked every necessary dependency. Dpkg will be used for the deb-based distros (Debian, Ubuntu and derivatives, as Mint), rpm for the rpm-based (OpenSuse, Mandriva, Fedora, CentOs, etc.) and pacman for ArchLinux. If none of these is available on the system (for whatever reason), all the required dependencies will be marked as missing.

At this point, as I said before, the PKGSTOINSTALL string contains the list of required dependencies that are missing. We can proceed to install them:

# If some dependencies are missing, asks if user wants to install
if [ "$PKGSTOINSTALL" != "" ]; then
	echo -n "Some dependencies are missing. Want to install them? (Y/n): "
	read SURE
	# If user want to install missing dependencies
	if [[ $SURE = "Y" || $SURE = "y" || $SURE = "" ]]; then
		# Debian, Ubuntu and derivatives (with apt-get)
		if which apt-get &> /dev/null; then
			apt-get install $PKGSTOINSTALL
		# OpenSuse (with zypper)
		elif which zypper &> /dev/null; then
			zypper in $PKGSTOINSTALL
		# Mandriva (with urpmi)
		elif which urpmi &> /dev/null; then
			urpmi $PKGSTOINSTALL
		# Fedora and CentOS (with yum)
		elif which yum &> /dev/null; then
			yum install $PKGSTOINSTALL
		# ArchLinux (with pacman)
		elif which pacman &> /dev/null; then
			pacman -Sy $PKGSTOINSTALL
		# Else, if no package manager has been founded
		else
			# Set $NOPKGMANAGER
			NOPKGMANAGER=TRUE
			echo "ERROR: impossible to found a package manager in your sistem. Please, install manually ${DEPENDENCIES[*]}."
		fi
		# Check if installation is successful
		if [[ $? -eq 0 && ! -z $NOPKGMANAGER ]] ; then
			echo "All dependencies are satisfied."
		# Else, if installation isn't successful
		else
			echo "ERROR: impossible to install some missing dependencies. Please, install manually ${DEPENDENCIES[*]}."
		fi
	# Else, if user don't want to install missing dependencies
	else
		echo "WARNING: Some dependencies may be missing. So, please, install manually ${DEPENDENCIES[*]}."
	fi
fi

Now I’ll explain this portion of code. First of all, the script asks the user if he wanna proceed with the installation (else, it will tell the user which packages have to install manually). Then it proceeds by using the package manager avaible on the system: apt-get for Debian, Ubuntu and derivateves, zypper for OpenSuse, urpmi for Mandriva, yum for Fedora and CentOS and pacman for Archlinux.

If none is available, the user indicates which packages have to install manually. Finally it verifies if the installation was successful and in case of problems, again, alerts the user.

Good luck.

(in italiano: Bash scripting: verificare e installare dipendenze mancanti)

CakePHPAs you know, CakePHP can manage flash messages, information messages for the user that are stored by and in session. They are particularly used to notify some operations (result of authentication operations, operations on the database, etc..).

Essentially, flash messages are used whenever you want to say to an user: “hey man, everything is fine, or something went wrong”.

As the CakePHP documentation explains:

Often in web applications, you will need to display a one-time notification message to the user after processing a form or acknowledging data. In CakePHP, these are referred to as “flash messages”. You can set flash messages with the SessionComponent and display them with the SessionHelper::flash(). To set a message, use setFlash.

To store a message inside a controller, you can use the setFlash() method (API) provided by SessionComponent; to show a message inside a view, you can instead use the flash() method (API) provided by SessionHelper.

For example, inside a controller like this:

public function myAction() {
   // do something...
   $this->Session->setFlash("it works!");
   // do something...
}

Inside a view:

Session->flash(); ?>

As my example says, this will work correctly and will produce this html:

<div id="flashMessage" class="message">it works!</div>

This is really nice, especially because flash messages are “one-time messages” and the developer doesn’t have to worry about manage directly the session (Cake’s core will take care of this, not you). But there are problems when you wanna store more messages in a single action of a controller. Indeed this one:

public function myAction() {
   // do something...
   $this->Session->setFlash("does it work?");
   $this->Session->setFlash("it works!");
   // do something...
}

will remember only the second flash message. And the first one? Another problem is: and if I wanted to differentiate between different types of messages (for example: warnings, errors, confirmations, etc..)?
As the documentation explains, “using the $key parameter you can store multiple messages, which can be output separately” (quoting the documentation example):

// set a bad message.
$this->Session->setFlash('Something bad.', 'default', array(), 'bad');
// set a good message.
$this->Session->setFlash('Something good.', 'default', array(), 'good');

These flash messages will be output as html and styled differently:

// in a view.
echo $this->Session->flash('good');
echo $this->Session->flash('bad');

You can also pass a class in $params array using again $this->Session->setFlash:

$this->Session->setFlash('Example message text', 'default', array('class' => 'example_class'));

Using $this->Session->flash(), the output will be:

<div id="flashMessage" class="example_class">Example message text</div>

But all this is very uncomfortable to use and is very difficult to develop using the proposal syntax.
So, how to solve? It’s simple: rewrite component and helper.
First, you need to copy

lib/Cake/Controller/Component/SessionComponent.php

in

app/Controller/Component/

and

lib/Cake/View/Helper/SessionHelper.php

in

app/View/Helper/

This allows you to override the classes of Cake’s core with yours, that will be used first (note: you must not edit directly Cake’s core, never! Just rewrite components, helpers, views, etc.).

Then, in app/Controller/Component/SessionComponent.php replace the setFlash() function with this one:

public function setFlash($message, $type="message") {
	//If flash messages are already stored in session, fetch array
	if(CakeSession::check('flashMessages'))
		$messages = CakeSession::read('flashMessages');
	//Else, create a new empty array
	else
		$messages = array();
	//If the flash message type is not supported (only "error", "notice", "success" and "warning"), set it to "notice"
	if(!in_array($type = strtolower($type), array("error", "notice", "success", "warning")))
		$type = "notice";
	//Add the passed flash message to the array
	$messages[$type][] = $message;
	//Store in sessione
	CakeSession::write('flashMessages', $messages);
}

With this, now you can store flash messages like this (it will store an error):

echo $this->Session->flash('something has gone wrong', 'error');

Again, in app/View/Helper/SessionHelper.php replace the flash() function with this one:

public function flash() {
	//Check if flash messages are stored in session
	if(CakeSession::check('flashMessages')) {
		//Retrieve saved flash messages and deletes them from the session
		$messages = CakeSession::read('flashMessages');
		CakeSession::delete('flashMessages');
		//Prepare the $out variable that will contain the final output
		$out = "";
		//Loop every flash message that is stored in session, appending to the variable $out
		foreach ($messages as $type => $message) {
			foreach ($message as $text)
				$out .= '<div class="'.$type.'">'.$text.'</div>';
		}
		//Return flash messages in html
		return $out;
	}
}

It will return flash messages as:

<div class="$type">$text</div>

Now a new example. Inside your controller:

$this->Session->setFlash("This is just a warning", "warning");
$this->Session->setFlash("It's ok!", "success");
$this->Session->setFlash("Something seems to have gone wrong", "error");
$this->Session->setFlash("A simple, innocent news.", "notice");

It will be displayed like this:

<div class="warning">This is just a warning</div>
<div class="success">It's ok!</div>
<div class="error">Something seems to have gone wrong</div>
<div class="notice">A simple, innocent news.</div>

Wonderful, is not it?

Since we are here, just add a little style for flash messages. In the view, you have to display messages like this:

<div id="flashMessages">
	<?php echo $this->Session->flash(); ?>
</div>

Download these files and move them to app/webroot/img/, then add to your style sheet:

#flashMessages div {
	background: no-repeat 5px 5px;
	border-radius: 5px;
	border-style: solid;
	border-width: 2px;
	box-shadow: 0 5px 5px -5px #555;
	margin-bottom: .5em;
	min-height: 24px;
	padding: 5px 10px 5px 35px;
}

#flashMessages .error {
	background-color: #FFCCCC;
    background-image: url("/img/error.png");
    border-color: #8F0000;
    color: #8F0000;
}

#flashMessages .notice {
	background-color: #e6ecf2;
	background-image: url("/img/notice.png");
	border-color: #314e6c;
	color: #314e6c;
}

#flashMessages .success {
    background-color: #DEFADE;
    background-image: url("/img/success.png");
    border-color: #267726;
    color: #267726;
}

#flashMessages .warning {
    background-color: #FFEEBF;
    background-image: url("/img/warning.png");
    border-color: #B87D00;
    color: #B87D00;
}

This is the result:

flash messages

A great work guys! ;-)