#include #include #include #include "projet.h" #include "projetx.m" /* #Sp‚cification: Fusion / Espace usager Un usager peut continuer … d‚velopper pendant qu'une int‚gration a lieu. AprŠs l'int‚gration, il souhaitera rappatrier ces changements dans la nouvelle r‚vision. (histoire de travailler avec des bits frais: Il est reconnue que la fraicheur des bits est inversement proportionnelle … l'age du capitaine. C'est pourquoi il faudra voter non le 26 octobre prochain) Voici un exemple: L'exemple suivant est purement fictif et toute ressemblance avec la r‚alit‚ est purement le fruit du hasard. Dans une compagnie fictive MSK, il y a trois programmeurs: Woodbang dit mosart, Jambon dit bambin, et louis dit le casseur de r‚seau. Tous trois sont occup‚s … am‚liorer la version 4.2 du programme 69/69. Et soudain avant mˆme que l'automne ne fut venue, chacun fait une livraison. Et il continue ensuite … travailler dans leur version respective. Woodbang livre la version 4.2.4.1 Jambon livre la version 4.2.3.1 Louis livre la version 4.2.6.1 Pierrot le loup fait une int‚gration … partir des versions 4.2 4.2.3.1 4.2.4.1 4.2.6.1. Cela donne la version 4.3. Elle se compose de: Majoritairement des fichiers de 4.2. Des fichiers provenant d'une des 3 r‚visions. Des fichiers provenant de la combinaison des 3 r‚visions. Lorsque Woodbang d‚cide de travailler sur la version 4.3 et ainsi profiter des nouvelles options auto-reboot de louis le casseur et Jambon, quelques minutes se sont pass‚ depuis qu'il a livr‚ sa version 4.2.4.1. Entre temps, il a ajout‚ 25 nouvelles options au programme. Ces options ont ‚t‚ ajout‚s … la r‚vision 4.2.4.1. Il ne peut pas simplement copier les fichiers modifi‚s dans sa copie de la version 4.3. La r‚vision dans laquelle il a continu‚ … travailler est la r‚vision "temporaire". La r‚vision dans laquelle il souhaite incorporer ses changement est la r‚vision destination. */ # /* Enregistre conditionnellement les transactions pour faire l'int‚gration d'un fichier. */ static void ufusion_settrans( INTEGRE_DAT &intg, USERINFO *userref, MAKEFILE &mkfref, // R‚f‚rence commune approxim‚. USERINFO *usersrc, MAKEFILE &mkfsrc, // Provenance imm‚diate du fichier r‚vis‚. USERINFO *userdst, MAKEFILE &mkfdst, // Destination de l'int‚gration. const char *dirsrc, // Path du r‚pertoire projet qui contient // fichier. const char *fichier, int efface) // Ce fichier a ‚t‚ effac‚ de la r‚vision source { /* #Sp‚cification: fusion / espace usager / r‚vision bidon Les fichiers qui sont dans l'espace usager n'ont pas encore ‚t‚ livr‚s. On va leur attribu‚ une r‚vision bidon facile … reconnaitre lors de l'int‚gration. On placera simplement comme r‚vision dans integre.dat le num‚ro 1000.0.0.0. Le module d'‚dition de la fusion fera un cas sp‚cial pour ce num‚ro de r‚vision. */ REVISION spcrev; // Le constructeur assure // spcrev.isnull() != 0 const REVISION *revroot_src = usersrc->getrevsrc(); const REVISION *revroot_dst = userdst->getrevsrc(); MAKEFILE_FILE *fsrc = mkfsrc.locate(fichier); MAKEFILE_FILE *fdst = mkfdst.locate(fichier); MAKEFILE_FILE *fref = mkfref.locate(fichier); char srcpath[MAXSIZ_PATH]; // Path du fichier non livr‚ path_make (dirsrc,fichier,srcpath); if (fsrc != NULL && fdst != NULL && fsrc->getrev()->cmp(fdst->getrev()) == 0){ // ICI on est certain que la r‚vision usersrc est l'ancˆtre // de userdst et ‚videmment de la r‚vision … fusionner. char pathref[MAXSIZ_PATH]; fsrc->getombpath(usersrc,pathref); FILE_REV_SPEC ref; ref.fichier = fsrc->getrev(); ref.dir = mkfsrc.getrev(); ref.root = revroot_src; /* #Sp‚cification: Fusion / Espace usager / automatique Pour importer sans intervention un fichier d'une r‚vision temporaire vers la r‚vision destination, il faut que les deux r‚visions possŠdent la mˆme version de ce fichier. */ FILE_REV_SPEC rev; rev.fichier = &spcrev; rev.dir = ref.dir; rev.root = ref.root; intg.addtrans(fichier,ref ,pathref,efface ? '-' : '+' ,rev,srcpath); }else{ // ICI, on prend userref comme r‚vision ancˆtre. C'est une // approximation. Se referer … la spec plus bas pour comprendre // les noms des variables ref, tmp et dst FILE_REV_SPEC ref; ref.fichier = NULL; ref.dir = mkfref.getrev(); ref.root = userref->getrevsrc(); FILE_REV_SPEC tmp; tmp.fichier = NULL; tmp.dir = mkfsrc.getrev(); tmp.root = revroot_src; FILE_REV_SPEC dst; dst.fichier = NULL; dst.dir = mkfdst.getrev(); dst.root = revroot_dst; /* #Sp‚cification: Fusion / Espace usager / manuelle Voici un exemple, o— une fusion interactive est requise. Soit le fichier A et ses diff‚rentes r‚visions: # ---> 4.2.3.1 ------- | |--> 4.3 ..................... 4.2--| --- (R‚vision destination) . | | . ---> 4.2.4.1 -->| . --- R‚vision temporaire ........ (4.2.4.2) 4.2 est la r‚vision r‚f‚rence # Pour simplifier la fusion, l'usager doit pouvoir visualiser les diff‚rences suivantes: # 4.2.4.1 vs 4.2 4.2.3.1 vs 4.2 4.3 vs 4.2 4.2.4.2 vs 4.2.4.1 (Probablement la plus importante). # La version 4.3 a ‚t‚ construites manuellement … partir de diff‚rentes versions (4.1.3.1 et 4.1.4.1). De plus l'int‚grateur a pu ajout‚ d'autre chose (l'ivresse du moment). La provenance de la version 4.3 ne peut pas ˆtre d‚montr‚ absoluement. C'est pourquoi, il faut permettrent … peu prŠs toutes les combinaisons de diff‚rences imaginables. */ char *pathref = NULL; char tmppath[MAXSIZ_PATH]; if (fref != NULL){ ref.fichier = fref->getrev(); fref->getombpath(userref,tmppath); pathref = tmppath; } if (efface){ intg.addtrans(fichier,ref,pathref ,'-' ,tmp,srcpath); }else{ tmp.fichier = &spcrev; intg.addtrans(fichier,ref,pathref ,fsrc == NULL && fdst == NULL ? '?' : '+' ,tmp,srcpath); } if (fsrc != NULL){ char tmppath[MAXSIZ_PATH]; fsrc->getombpath(usersrc,tmppath); tmp.fichier = fsrc->getrev(); intg.addtrans (fichier,ref ,pathref,'+' ,tmp,tmppath); }else{ intg.addtrans (fichier,ref ,pathref,'-' ,tmp,NULL); } if (fdst != NULL){ char tmppath[MAXSIZ_PATH]; fdst->getombpath(userdst,tmppath); dst.fichier = fdst->getrev(); intg.addtrans (fichier,ref ,pathref,'+' ,dst,tmppath); }else{ intg.addtrans (fichier,ref ,pathref,'-' ,dst,NULL); } } } /* Balaye les deux r‚pertoires r‚cursivement et construit un integre.dat dans chaque r‚pertoire. Ces integre.dat agira comme guide pour la fusion. Mˆme format que pour les fusions dans /kit/build. */ static int ufusion_scan ( USERINFO *usersrc, // Environnement … int‚grer dans userdst USERINFO *userdst, USERINFO *userref, // Racine des deux environnement pr‚c‚dant PRJCTRL *ctrl, const char *projet, PROJET_LOG *log, MAKEFILE *mkrefanc, // makefile.dat du projet ancˆtre de celui-ci // obtenue … partir de userref. // == NULL si projet == "" MAKEFILE *mksrcanc) // makefile.dat du projet ancˆtre de celui-ci // obtenue … partir de usersrc. // == NULL si projet == "" { char dirdst[MAXSIZ_PATH]; userdst->makusrpath(projet,dirdst); /* #Sp‚cification: fusion / Espace usager / s‚lection des r‚pertoires. La fusion est faite uniquement pour les projets que l'usager a import‚ pour la r‚vision cible. */ if (file_type(dirdst)==1){ char dirsrc[MAXSIZ_PATH]; usersrc->makusrpath(projet,dirsrc); SSTRINGS tb; int nb = ctrl->dirsource (dirsrc,WILD_ALLFILE,tb); log->printf ("R‚pertoire %s [%d]\n",dirsrc,nb); if (nb > 0){ /* #Sp‚cification: fusion / espace usager / r‚vision r‚f‚rence La r‚vision r‚f‚rence n'est probablement pas disponible dans l'espace usager. Pour un projet ou sous-projet, on doit retrouver la r‚vision correspondante. En effet la r‚vision X est une combinaison de r‚visions diff‚rentes de sous-projet. */ const REVISION *revision_ref = userref->getrevsrc(); const REVISION *revision_src = usersrc->getrevsrc(); if (projet[0] != '\0'){ // Sous-projet, il faut consulter mkrefanc et mksrcanc pour // d‚terminer la bonne r‚vision r‚f‚rence et source. char nom[MAXSIZ_NAME*2]; path_splitlex (projet,NULL,nom); strcat (nom,"/makefile.dat"); MAKEFILE_FILE *file = mkrefanc->locate(nom); if (file == NULL){ // Nouveau r‚pertoire. log->printf ("Nouveau r‚pertoire %s\n",projet); /* #Sp‚cification: fusion / espace usager / nouveaux r‚pertoires Le traitement … r‚aliser n'est pas clair dans le cas ou un nouveau r‚pertoire ou projet a ‚t‚ cr‚‚. En ce moment, on signale simplement … l'usager qui devra fusionner manuellement le r‚pertoire en question. */ // On laisse revision_ref comme il est. // En utilisant la r‚vision de la racine // ca va charger un makefile.dat vide. }else{ revision_ref = file->getrev(); } // Mˆme traitement pour la r‚vision source file = mksrcanc->locate(nom); if (file == NULL){ // Nouveau r‚pertoire. log->printf ("Nouveau r‚pertoire %s : environnement tmp\n",projet); // On laisse revision_src comme il est. // En utilisant la r‚vision de la racine // ca va charger un makefile.dat vide. }else{ revision_src = file->getrev(); } } MAKEFILE mkfref(NULL,true,revision_ref,projet,userref); // Pour le r‚pertoire source, on obtient le makefile.dat // de /kit/ombre, pour eviter le makefile.del locale. // Voir MAKEFILE::MAKEFILE MAKEFILE mkfsrc(NULL,1,revision_src,projet,usersrc); // Scan les sous-r‚pertoires for (int i=0; iget(); if (ctrl->isdir(fichier)){ char sub_projet[MAXSIZ_PATH]; path_make (projet,fichier,sub_projet); path_stripsep(sub_projet,sub_projet); ufusion_scan (usersrc,userdst,userref,ctrl ,sub_projet,log,&mkfref,&mkfsrc); } } MAKEFILE mkfdst(NULL,true,projet,userdst); INTEGRE_DAT intg(dirdst); for (int i=0; iget(); if (!ctrl->isdir(fichier)){ ufusion_settrans (intg,userref,mkfref,usersrc,mkfsrc ,userdst,mkfdst,dirsrc,fichier,0); } } /* #Sp‚cification: Fusion / espace usager / makefile.del Les fichiers makefile.del sont interprŠter lors de la fusion et pr‚senter interactivement lors de l'‚dition de la fusion. */ char delpath[MAXSIZ_PATH]; // Path du fichier makefile.del path_make (dirsrc,"makefile.del",delpath); FILE *fdel = fopen (delpath,"r"); // Le fichier makefile.del est optionnel. if (fdel != NULL){ char buf[MAXSIZ_PATH]; while (fgets(buf,sizeof(buf)-1,fdel)!=NULL){ str_strip (buf,buf); if (buf[0] != '\0'){ ufusion_settrans (intg,userref,mkfref,usersrc,mkfsrc ,userdst,mkfdst,dirsrc,buf,1); } } fclose (fdel); } } } return 0; } /* S‚lectionne deux r‚visions … fusionner dans l'environnement usager et produit les fichiers integre.dat pilotant la fusion interactive de integre_do(). */ void ufusion_prepare (USERINFO *user) { char home[MAXSIZ_PATH]; user->gethome(home); char *tbrev[100]; int nb = projet_getrevdir (home,tbrev,100); if (nb < 2){ xconf_error (MSG_U(E_MIN2PRJ ,"Vous devez avoir au moins deux révisions")); }else{ DIALOG dia; char src = 0; char dst = 1; dia.newf_head ("",MSG_U(H_FUSIONSIMPLE ,"Tmp\tDst\tprog/Version/répertoire/source")); for (int i=0; i