Visualizzazione post con etichetta Ambienti di sviluppo. Mostra tutti i post
Visualizzazione post con etichetta Ambienti di sviluppo. Mostra tutti i post

giovedì 4 maggio 2017

Docker…Buzzword o nuovo strumento nella nostra cassetta degli utensili?

Tutti quelli che come me sono sempre incuriositi alle novità si sono sicuramente imbattuti in un articolo che, a dir poco, osanna le virtù derivanti dall’utilizzo dei container per lo sviluppo e la distribuzione del software. La tecnologia dei container non è nuova. Disponibile in ambiente linux dalla versione 2.6.4 (intorno al 2004) la tecnologia nota con l’acronimo LXC, sta venendo alla ribalta negli ultimi anni grazie soprattutto alla piattaforma Docker.
Docker
Volendo semplificare all’estremo il concetto si può pensare che la containerizzazione avrà un’impatto in ambito ITC pari almeno a quello avuto dall’introduzione delle macchine virtuali.

In origine erano le Virtual Machines…

Nella mia esperienza l’introduzione tra i miei strumenti del VMWare Player ha portato una piccola rivoluzione nel mio modo di lavorare. All’epoca ero impegnato nello sviluppo di un sistema di visione artificiale integrato nel sistema di controllo di un robot. Il sistema di controllo era implementato su una piattaforma Linux Debian, il che mi obbligava ad avere lo stesso sistema operativo sulla macchina di sviluppo e quindi o avere due computer o, più realisticamente, installare un secondo sistema operativo ed avviare il computer a seconda del progetto al quale stavo lavorando. La possibilità di avere una macchina virtuale che mi consentiva di avere contemporanemante sotto mano sia KDevelop e Debian che Visual Studio e Windows Xp era il massimo in termini di comodità ed efficienza.
Un altro vantaggio derivante dall’utilizzo delle macchine virtuali, è stato quello di poter creare delle macchine di sviluppo molto simili, se non identiche, alle macchine in produzione in termini di pacchetti software installati, versioni particolari di driver di periferica, ecc.. Macchine di sviluppo che, in quanto virtualizzate ho la possibilità mettere da parte al termine della fase di sviluppo e tirar fuori al bisogno nel caso di un aggiornamento, di un bug fix, o di una semplice assistenza.
Last but not Least ora sono in grado di lavorare con qualunque sistema operativo a prescindere da quello installato sull’host (negli ultimi anni macOS su un Macbook Pro).
Il problema di fondo legato all’utilizzo delle macchine virtuali è dato dal peso che ognuna di esse ha in termini di risorse hardware cosa molto evidente se poi parliamo di un laptop. Avere a disposizione più macchine virtuale, o, peggio ancora, mandarne in esecuzione più di una allo stesso momento è un impresa ardua se si dispone di ‘soli’ 16GB di RAM ed un disco SSD da 256GB. E se poi volessimo creare un sistema di sviluppo per SharePoint? IMPOSSIBILE!…o No…?

… E poi arrivò Docker™

A rendere ancora più interessante la faccenda c’è la comunità di utenti pronti a condividere le proprie esperienze su piattaforme come Docker Hub.
Ok, di documentazione e di tutorial on line ce ne sono un’infinità ed in continuo aggironamento, quindi mi asterrò dal ripetere ci che è egregiamente illustrato da persone più esperte di me nel settore. Un buon punto di partenza è la documentazione ufficiale (DOCKER 101: GETTING TO KNOW DOCKER).

Un caso pratico

Un esempio per dare un’idea della semplicità e dell’efficacia dello strumento però è il caso di farlo se non altro per invogliare qualcun altro ad approfondire l’argomento. A tal fine utilizzerò proprio un’esperienza che ho fatto poco tempo fà, per risolvere un problema ad un cliente il cui sito web, a seguito di un attacco informatico, era stato accidentalmente cancellato, e l’ultimo backup disponibile era molto differente nei contenuti dalla versione persa. Il CMS utilizzato per creare il sito era Joomla! nella versione 2.5, ed il database era MySql. La procedura standard per predisporre un ambiente di sviluppo (LAMP, MAMP o WAMP a seconda del sistema operativo) sarebbe, in linea di principio:
- predisporre un server Apache o nginx;
- installare la versione corretta di php;
- installare la versione corretta di MySql;
In alternativa possiamo installare la versione di WAMPServer o MAMP.

WAMP MAMP

Qualunque strada si decida di intraprendere, al termine, il nostro pc sarà configurato per far girare un server Apache, avremo un database MySql ed una versione di php compatibile con la versione del cms del nostro sito web. Non ci resta che copiare il backup nella directory htdocs (o qualunque sia la cartella servita da Apache), modificare il file di configurazione in modo che possa puntare all’istanza di MySql ed al database, aprire il browser, navigare all’indirizzo http://localhost:8080 ed il gioco è fatto, abbiamo una copia del sito web che gira sulla macchina di sviluppo sulla quale fare considerazioni e/o modifiche. Fin qui la procedura classica, e per il mio caso, un intervento su un sito web in particolare può andare più che bene. In fondo, non essendo il mio mestiere, quanti siti web dovrò mai far girare sul mio laptop? Ma se così non fosse? Se arrivasse una richiesta d’intervento su un sito implementato con un cms diverso, con una diversa versione di php, o con un database diverso database? E questo sempre rimanendo nell’area dei cms che girano su server Apache, Php e MySql. Cosa dire poi se al posto di Apache fosse richiesto nginx, se al posto di MySql avessimo bisogno di PostgreSQL o SQL Server, ed al posto di php volessimo Ruby on Rails, o .NET o Java, o python o nodejs. E via dicendo verso l’infinito ed oltre…. Ok possiamo installare tutto (o almeno provarci) sulla nostra macchina e tentare di creare un ambiente di sviluppo simile, per quanto possibile, all’ambiente di produzione…. SIMILE ma certamente NON UGUALE. E anche se ci accontentiamo di SIMILE dobbiamo sempre sperare che nessuno dei pacchetti installati vada in conflitto con qualcos’altro…. Ok, proviamo un’altra strada.
Torniamo al caso di partenza, ovvero Joomla! in una particolare versione.
Una possibilità è quella di creare il nostro container a partire da una versione vanilla di una distribuzione di Linux, e, seguendo il manuale per la creazione di un container custom, installare tutti i componenti di cui abbiamo bisogno. Oppure possiamo ricorrere alle risorse messe a disposizione da altri sviluppatori su repositories come il già citato Docker Hub. Facendo una ricerca con la parola chiave Joomla troviamo ben 158 risultati, cercando, invece mysql, di risultati ne abbiamo 6418!

docker-hub-joomla docker-hub-mysql

Per far girare docker sul nostro sistema di sviluppo, è sufficiente raggiungere la pagina Download Docker Community Edition, selezionare il sistema operativo e scaricare la versione adatta al nostro sistema operativo. Ora, Docker è un sistema che gira in ambiente Linux, ma, con un piccolo accorgimento (in pratica l’installazione di una macchina virtuale) è possibile far girare Docker anche su sistemi Windows o macOS (o OsX).
Portata a termine l’installazione di docker torniamo su Docker Hub, o un altro Registry Docker, e scarichiamo in locale le immagini di nostro interesse lanciando da un prompt dei comandi

$ docker pull joomla

per scaricare l’immagine del container ufficiale di Joomla!, e

$ docker pull mysql

per l’immagine di mysql.

A questo punto abbiamo due possibilità per mandare in esecuzione i due container:
Il primo è quello di mandare in esecuzione i due container lanciando da un prompt dei comandi le due istruzioni opportunamente modificate (per il significato dei parametri si rimanda alle pagine di Docker Hub dedicate ai due container):
$ docker run -it --link some-mysql:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'

$ docker run --name some-joomla --link some-mysql:mysql -p 8080:80 -d joomla
La seconda possibilità è quella di utilizzare Docker Compose e quindi:
- creare una cartella dedicata al nostro progetto, all’interno della quale creeremo un file YAML denominato docker-compose.yml (il nome deve essere questo), che conterrà le seguenti istruzioni:

########################### 
# Joomla! CMS Container 
joomla: 
# nome univoco del container 
container_name: my_web_site

# Definisce se il container deve essere riavviato 
#   (i pssibili valori sono no, always e on-failure)
restart: always

# Definisce l'immagine da cui avviare il container
image: joomla

# Collega il container ad un altro servizio
# (in questo caso a quello nel quale gira l'immagine di mysql)
links:
- joomladb:mysql

# Espone la porta, interna al container, all'esterno sulla porta 8080
ports:
- 8080:80

# Esegue il mount di una cartella del container (/var/www/html)
# su una dell'host (./html)        
volumes:
- ./html/:/var/www/html        
# Joomla! CMS Container
###########################

###########################
# MySql Container
joomladb:
container_name: my_web_site_db
restart: always
image: mysql
# Aggiunge alle variabili d'ambiente del container
# la password assegnata all'istanza di mysql (top of security XD)
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
volumes:
- ~/usr/local/var/mysql/:/var/lib/mysql
# MySql Container
###########################

- dalla linea di comando lanciare l’istruzione nella directory contenente il file di sopra:

$ docker-compose up -d 

- Apriamo un browser all’indirizzo http://127.0.0.1:8080/ e otterremo

docker-joomla

ed abbiamo il nostro CMS funzionante e pronto ad essere configurato per una nuova installazione. Se invece abbiamo necessità di operare localmente con il backup di un sito esistente, non ci resta che copiare il backup stesso nella cartella html, sovrascrivendo i files e le cartelle copiate dal container Joomla!, caricare sul server mysql l’ultimo backup del database, ed il gioco è fatto.
- quando finiamo di operare, per terminare i due container, lanciamo il comando:
$ docker-compose down

Conclusione

Quello illustrato è solo uno dei tanti esempi che dimostrano la semplicità con cui è possibile approntare una workstation di sviluppo per un numero enorme di tecnologie.
Ad oggi ho già sperimento le configurazioni ottimali per valutare diversi CMS (Wordpress, prestashop, …), con vari database (MySql, mariadb, mongodb, postgres, …), diversi server (apache, nginx, …), e via dicendo senza aver bisogno di installare niente sulla mia macchina di sviluppo e senza dover creare nuove macchine virtuali.
Forse la tecnologia non è ancora pronta per un utilizzo massivo in ambienti di produzione, anche se tutte le maggiori piattaforme cloud si sono attrezzate per supportare la tecnologia, ma le premesse sono ottime.

Enjoy

domenica 9 ottobre 2016

Visual Studio Dev Essentials

Per chi come me è costantemente alla ricerca di nuovi stimoli per migliorare le proprie conoscenze e di tenersi al passo con lo stato dell’arte, voglio condividere un suggerimento utile a chi vuole implementare soluzioni con il meglio delle tecnologie Microsoft.
Visual Studio Dev Essentials, il cui claim è Everything you need all in one place, ed effettivamente è un po’ un *santo graal* dal quale attingere strumenti di sviluppo, formazione di livello altissimo, e *last but not least*, un credito mensile di 25€ da spendere in servizi Microsoft Azure.


Tra le risorse messe a disposizione, quella, a mio avviso, più preziosa, è proprio l’accesso temporaneo o a tempo indeterminato ai corsi, del quale ho già cominciato ad usufruire, approfondendo gli argomenti relativi allo stato dell’arte del nuovo stack per applicazioni web di Microsoft ASP.Net Core con il corso Building a Web App with ASP.NET Core, MVC 6, EF Core, and Angular.



Enjoy


sabato 29 novembre 2014

Utilizzo di una dll .NET da codice 'nativo' (parte 2)

Nel post precedente, abbiamo visto come realizzare una dll con tecnologia .NET, in grado di consentire ad una qualunque applicazione (sviluppata con tecnologia .NET) di usufruire di un generico servizio web. Tuttavia il problema di partenza era quello di creare un ponte tra il framework .NET ed un’applicazione Win 32.

Il wrapper C++/CLI

Passiamo quindi a descrivere i passi per lo sviluppo del nostro wrapper, ovvero della dll che renderà accessibili i servizi esportati dalla libreria dinamica implementata negli step precedenti.
● Il primo passo è quello di creare un progetto C++ per la creazione di una dll, ed abilitare il Supporto Common Language Runtime (/clr).

● Aggiungiamo un riferimento alla dll prodotta dal progetto GoogleMapsAPI

● Fatto ciò aggiungeremo due classi CGoogleMapsClientIntefacePrivate e CGoogleMapsClientInteface.
#pragma once

# include <string>

using namespace std;

class CGoogleMapsClientIntefacePrivate;

class CGoogleMapsClientInteface
{
public:
    CGoogleMapsClientInteface();
    ~CGoogleMapsClientInteface();

#pragma region Attributes
private:

    CGoogleMapsClientIntefacePrivate* _private;

#pragma endregion

#pragma region Properties
public:
    __declspec(property(get = GetLatitude)) double Latitude;
    double GetLatitude(void);

    __declspec(property(get = GetLongitude)) double Longitude;
    double GetLongitude(void);

    __declspec(property(put = SetAddress, get = GetAddress)) const char* Address;
    void SetAddress(const char*);
    const char* GetAddress(void) const;
#pragma endregion
};
● La cui implementazione è la seguente:
#include "stdafx.h"
#include "GoogleMapsClientInteface.h"

# include <msclr\auto_gcroot.h>

using namespace System::Runtime::InteropServices;
using namespace GoogleMapsAPI;

class CGoogleMapsClientIntefacePrivate
{
public:
    msclr::auto_gcroot<GoogleMaps^> googleMapsAPI;
};

CGoogleMapsClientInteface::CGoogleMapsClientInteface()
{
    this->_private = new CGoogleMapsClientIntefacePrivate();
    this->_private->googleMapsAPI = gcnew GoogleMaps();
}


CGoogleMapsClientInteface::~CGoogleMapsClientInteface()
{
    if (this->_private)
        delete this->_private;
}

double CGoogleMapsClientInteface::GetLatitude()
{
    return this->_private->googleMapsAPI->Latitude;
}

double CGoogleMapsClientInteface::GetLongitude()
{
    return this->_private->googleMapsAPI->Longitude;
}

void CGoogleMapsClientInteface::SetAddress(const char* value)
{
    this->_private->googleMapsAPI->Address = gcnew System::String(value);

    this->_private->googleMapsAPI->GetCoordinates();
}
const char* CGoogleMapsClientInteface::GetAddress(void) const
{
    return (const char*)Marshal::StringToHGlobalAnsi(this->_private->googleMapsAPI->Address).ToPointer();

}
Il punto focale dell’implementazione è dato dalla classe auto_gcroot, che, citando l’help online di Microsoft, “può essere utilizzato per incapsulare un handle virtuale in un tipo nativo”. In altre parole questa classe ci fornirà il punto d’accesso al mondo .NET, e, ad essa delegheremo gli oneri legati alle differenti modalità di gestione della memoria tra il mondo nativo ed il mondo gestito. Tuttavia, così com’è, la classe auto_gcroot, parte dell’armamentario C++/CLI, non è utilizzabile in una dll C++ nativa. In primo luogo perchè non verrebbe riconosciuta in fase di compilazione, ed anche perchè se venisse compilata altererebbe irrimediabilmente il livello di astrazione che stiamo cercando di dare all’intero progetto seguendo una delle tecniche care allo sviluppo C++ nativo descritte nel PIMPL Idiom. A tale scopo abbiamo nascosto il nostro handle nella classe CGoogleMapsClientIntefacePrivate ottenendo un’interfaccia compatibile con il mondo nativo.

Funzioni esportate

Ottenuto il punto d’accesso, o il wrapper che dir si voglia, non ci resta che implementare la nostra dll nativa. Dando per scontata la parte legata allo sviluppo della dll in sé per sé, focalizzerei l’attenzione sul fatto che non abbiamo esportato direttamente la classe CGoogleMapsClientInteface, cosa del tutto lecita e possibile, ma abbiamo creato un handle verso essa mediante il metodo CGoogleMapsClientInteface_Create(). Il motivo di tale scelta è dato dal fatto che il nostro client non verrà sviluppato in C++ nativo (in tal caso ci saremmo fermati al passo precedente), ma in Delphi 7, linguaggio che ha una gestione della memoria totalmente differente da quella del C++, e che difficilmente riuscirebbe ad utilizzare una classe esportata direttamente dal nostro wrapper.
#ifdef CLIBRIDGE_EXPORTS
#define CLIBRIDGE_API __declspec(dllexport)
#else
#define CLIBRIDGE_API __declspec(dllimport)
#endif

typedef void* THandle;

# include "GoogleMapsClientInteface.h"

#ifdef __cplusplus
extern "C"
{
#endif

    inline CLIBRIDGE_API THandle CGoogleMapsClientInteface_Create()
    {
        return (THandle) new CGoogleMapsClientInteface();
    }

    inline CLIBRIDGE_API void CGoogleMapsClientInteface_SetAddress(THandle handle, const char* value)
    {
        if (handle)
        {
            ((CGoogleMapsClientInteface*)handle)->Address = value;

            ((CGoogleMapsClientInteface*)handle)->GetAddress();
        }
    }
    inline CLIBRIDGE_API const char* CGoogleMapsClientInteface_GetAddress(THandle handle)
    {
        return (handle)
            ? ((CGoogleMapsClientInteface*)handle)->Address
            : "";
    }

    inline CLIBRIDGE_API double CGoogleMapsClientInteface_GetLatitude(THandle handle)
    {
        return (handle)
            ? ((CGoogleMapsClientInteface*)handle)->Latitude
            : numeric_limits<double>::signaling_NaN();
    }

    inline CLIBRIDGE_API double CGoogleMapsClientInteface_GetLongitude(THandle handle)
    {
        return (handle)
            ? ((CGoogleMapsClientInteface*)handle)->Longitude
            : numeric_limits<double>::signaling_NaN();
    }

    CLIBRIDGE_API int fnCLIBridge(void);
#ifdef __cplusplus
}
#endif

L’applicazione nativa

A questo punto non ci resta che mettere insieme i blocchi sviluppati finora per creare un programma di test scritto in idioma nativo. Si tratta di una semplice applicazione Console, scritta in C++ e non in Delphi 7 (a tutto c’è un limite ;-)).
// Win32CrashTestDummy.cpp : definisce il punto di ingresso dell'applicazione console.
//

#include "stdafx.h"

# include <iostream>
# include <conio.h>

# include "CLIBridge.h"

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << " ------------------------ " << endl;
    cout << " ---------START---------- " << endl;
    cout << " ------------------------ " << endl;

    cout << endl;

    // cout << "Exported function \'fnCLIBridge()\' returned: " << fnCLIBridge() << endl;

    THandle handle = CGoogleMapsClientInteface_Create();

    const char* address = "Google Building 44, Mountain View, California, Stati Uniti";

    CGoogleMapsClientInteface_SetAddress(handle, address);

    const char* value = CGoogleMapsClientInteface_GetAddress(handle);

    cout << "Address:\t" << value << endl;

    cout << endl;

    cout << "Latitude:\t" << CGoogleMapsClientInteface_GetLatitude(handle) << endl;

    cout << endl;

    cout << "Longitude:\t" << CGoogleMapsClientInteface_GetLongitude(handle) << endl;

    cout << endl;

    cout << " ------------------------ " << endl;
    cout << " ----------END----------- " << endl;
    cout << " ------------------------ " << endl;

    std::cin.get();
    cout << " ------------------------ " << endl;

    return 0;
}
Il risultato finale è illustrato nell’immagine seguente, nella quale si mette a confronto l’output dell’applicazione console con quella WinForm sviluppata nel post precedente.

Conclusione

Lavorando nel mondo della tecnologia, in qualsiasi ambito, l’eterogeneità degli strumenti da utilizzare è la regola e non l’eccezione, e quindi può capitare che una tecnologia datata, ma ancora efficiente e funzionale, debba poter accedere a nuovi strumenti. Quello illustrato è uno dei casi che ci si può trovare a dover affrontare, ed uno dei possibili metodi per risolverlo.
Il link ai sorgenti dell’intero progetto raggiungibili dal link seguente
Git
Enjoy
Creative Commons Quality is not for sale

sabato 1 novembre 2014

Utilizzo di una dll .NET da codice 'nativo' (parte 1)

Circa un anno fa, un mio collega si è trovato nella condizione di dover utilizzare una dll sviluppata con tecnologia .NET, all’interno del software di controllo di un sistema di assemblaggio e test di componenti per il mercato automotive, sviluppato con un linguaggio nativo. Ovviamente la dll in questione non era COM-aware, ovvero non poteva essere utilizzata come un ActiveX (troppo facile). Poiché in azienda sono tra i pochi ad avere una certa esperienza sia con la tecnologia .NET che con linguaggi nativi, sono stato coinvolto nella ricerca di una soluzione al problema, e, dopo essermi documentato un po’, tra le varie soluzioni possibili, ho deciso di implementare quella illustrata nell’immagine che segue:
In pratica, si tratta di sfruttare la possibilità di incorporare codice gestito in una dll C++, e creare quindi un wrapper che sia in grado di rendere fruibili metodi e proprietà esposti dalla dll .NET, ad un software legacy. 
Al fine di illustrare tale concetto, il resto del memorandum, che dividerò in due parti, si svilupperà nella scrittura di quanto segue: 
1. una dll C# che che esporti metodi e/o proprietà; 
2. un wrapper C++/CLI che renda visibili le interfacce della dll del punto precedente ad un software nativo; 
3. programma di test, scritto in codice nativo che importi la dll, prodotta allo step 2 e ne usi metodi e/o proprietà. 
Ho già condiviso l’intero progetto su GitHub ed è possibile raggiungerlo dal link che segue CLIWrapperDemo.



La libreria .NET

Il primo passo sarà quello di implementare una libreria di classi .NET attorno alla quale costruiremo il nostro wrapper. Chiameremo la libreria GoogleMapsAPI che, com’è facile capire dal nome, sfrutterà le API di Google Maps, al fine di restituire le coordinate (longitudine e latitudine) dato un indirizzo. Per ulteriori informazioni sul servizio di geolocalizzazione ho fatto riferimento alla documentazione ufficiale Google Maps API Web Services. Il risultato è una classe con tre proprietà ed un metodo.
/// <summary>
/// Returns the location latitude
/// </summary>
public double Latitude { get; private set; }

/// <summary>
/// Returns the location longitude
/// </summary>
public double Longitude { get; private set; }


/// <summary>
/// Set the desired location address
/// </summary>
public string Address { get; set; }

/// <summary>
/// Gets the location coordinates from the Google Maps API Web Service
/// https://developers.google.com/maps/documentation/geocoding/
/// </summary>
/// <returns>true on success, false otherwise</returns>
public bool GetCoordinates()
{
     ...
}

Per testare immediatamente la dll prodotta ho implementato una semplice applicazione WinForm. Il risultato è illustrato nell’immagine che segue:
dotNETCrashTestDummy
Ok, abbiamo una dll .NET e non ci resta che creare il wrapper e provare ad utilizzarlo nel nostro vecchio software legacy. We’ll find out in the next episode!
Enjoy.
Creative Commons Quality is not for sale

giovedì 1 agosto 2013

Utilizzo dei subrepositories di Mercurial

Scrivo questa nota con l'intento di riassumere le informazioni, spesso contraddittorie e parziali, sull'argomento raccolte sulla rete. Il fine di tale strumento, o almeno una delle finalità principali, è quella di favorire, a chi già fa uso del DVCS in esame, il riutilizzo in più progetti di componenti già sviluppati in precedenza. Al tal fine,  nel seguito della nota, propongo un esempio concreto dei passi da seguire per integrare un subrepository, contenente uno o più moduli già implementati, in  un nuovo progetto sviluppato, ad esempio, con l'IDE di Microsoft, il Visual Studio 2012. Supponiamo che il subrepository in esame  si chiami XYZ_Core Project.
Il primo passo consiste nella creazione di una struttura di cartelle del tipo:
NEW Project
|_SRC
  1. Nella cartella SRC, creiamo una solution vuota di Visual Studio con il nome del progetto che stiamo creando, ovvero NEW Project.
    A questo punto, la struttura delle cartelle sarà:
    NEW Project
    |--
    SRC
    |----
    NEW Project
  2. Apriamo un prompt dei comandi,  spostiamoci nella sottocartella  _SRC\NEW Project e cloniamo il repository xyz_core-project
    $: hg clone https://bitbucket.org/***/xyz_core-project;
    Ottenuti i progetti del subrepository, non resta che aggiungerli alla nostra solution:
  3. Fatto ciò, torniamo nella cartella root del progetto, ed aggiungiamo il file .hgignore adatto alla versione di Visual Studio utilizzata, ed un nuovo file, denominato .hgsub strutturato come segue:
    _SRC/NEW Project/xyz_core-project=xyz_core-project
    [subpath]
    (https://(?:[^@]+@)?bitbucket\.org/[^/]+)(/[^/]+)/(.*) = \1/\3
    Il file appena aggiunto è quello che indica al nostro DVCS che è presente un subrepository. Spendiamo un attimo per capire il conenuto di tale file:
    - A sinistra del segno di uguaglianza, troviamo il percorso relativo alla root del progetto principale, nel quale intendiamo inserire il subrepository;
    - A destra dell'uguaglianza c'è il nome simbolico del subrepository.
    - Sotto la chiave [subpath] viene specificato, mediante una regular expression, il percorso dal quale ottenere il subrepository, e a destra la stringa che rimpiazzerà il nome simbolico di cui sopra (xyz_core-project). Per una descrizione più dettagliata, e sicuramente meno confusa, si rimanda alla pagina SubrepoRemappingPlan.
  4. A questo punto siamo pronti per consolidare la struttura del nuovo repository, ed a condividerla con il resto del mondo.
    - In primo luogo eseguiamo il commit del nostro repository
    $: hg commit -m "Messaggio di commit" --subrepos
    Notare l'opzione --subrepos che indica al DVCS di estendere il comando in modo ricorsivo ai sottoprogetti indicati da file .hgsub. Al termine del comando, nella root del progetto verrà generato il file .hgsubstate che d'ora in poi avrà il compito di tener traccia della versione del sottoprogetto collegata al nostr repository (Subrepositories).
  5. Non resta che consolidare sul nostro server la nuova struttura del progetto:
    $: hg push
NOTA: I comandi hg pull e hg incoming che ci consentono rispettivamente di aggiornare la copia locale del nostro repository, o più semplicemente di vedere quali e quante sono le differenze tra la copia locale e quella centralizzata, non hanno un'opzione che renda il comando ricorsivo (come l'opzione --subrepos vista per hg pull), il che implica che la sincronizzazione del subrepository con la relativa versione centralizzata è a carico dell'utente. In altre parole, ci si dovrà spostare nella cartella del sotto progetto, e da questa posizione lanciare i comandi

$: hg pull
e
$: hg update
Enjoy

lunedì 22 aprile 2013

Arrivato!!!


In anticipo di un giorno, è appena arrivato l'arduino. Spacchettato, fotografato e condiviso.


giovedì 18 aprile 2013

Acquisto fatto...

A causa di una serie di spiacevoli motivi che non sto qui ad elencare, mi trovo da più di una settimana a casa con un pò di tempo da dedicare ad attività extra lavorative. Sempre a causa delle motivazioni di cui sopra non posso restare troppo tempo davanti al PC, ma in uno di questi brevi intervalli ho fatto l'acquisto, che per un motivo o per l'altro ho rimandato sempre. Ho comprato uno dei gingilli di Massimo Banzi, il creatore di Arduino, la piattaforma open source per la prototipazione rapida (spero che la definizione sia corretta :-) ).  La mia scelta è caduta sull'ultimo nato della famiglia: l' Arduino Due, che a differenza dei precedenti offre un'architettura ARM a 32 bit. 


Ora non resta che attendere l'arrivo del corriere espresso, e spegnere il computer che la mano fa già male.
Ciao

martedì 20 aprile 2010

Visual Studio 2010 RC

OK! un pò in ritardo, ma alla fine ho installato il nuovo aggiornamento dell'IDE di Microsoft.
Dopo aver assistito al lancio ed ascoltato le nuove ceratteristiche (ASP.NET MVC, WCF, e via dicendo). Tempo ed energie permettendo, vediamo se, e soprattutto come, queste novità possono incidere quel che si fa ogni giorno. Prossimo passo...Qt, si quelle di trolltech, oops, nokia.