#include #include #include #include #include "projet.h" #include "projetx.m" /* Retourne le type de conflit associ‚ … un fichier. 0 : Fichier existait pas, 1 seule cr‚ation. 1 : Une seule r‚vision, plus r‚cente. 2 : Une seule "r‚vision", le fichier a ‚t‚ ‚limin‚. Cela a ‚t‚ fait lors d'une livraison plus r‚cente. 3 : R‚vision complexe */ PUBLIC int INTEGRE_FILE::conflit() { int ret = 3; if (getnb() == 1){ if (nouveau){ ret = 0; }else{ INTG_TRANS *tra = getitem(0); REVISION revtra(tra->revs.fichier); REVISION baserev(revs.fichier); if (revtra.cmp(&baserev) > 0){ if (tra->oper == INTEGRE_EFFACE){ ret = 2; }else{ ret = 1; } } } } return ret; } /* Ajoute des champs vides dans les sous-pages pour les r‚visions o— le fichier est absent. */ static void near intgdat_addblank( PAGE_EDIT &pselect, PAGE_EDIT &pdiff) { page_setupfixestr0 (&pselect,-1,"-",-1); page_setupfixestr0 (&pdiff ,-1,"-",-1); page_setupfixestr0 (&pdiff ,-1,"-",-1); } /* Fabrique un path pour fichier temporaire. Utilise la pr‚f‚rence prefTempPath. */ static char *intgdat_tmpf(const char *fname_prefix, char *tmpf) { prefTempPath.getval(tmpf, MAXSIZ_PATH); path_make (tmpf,fname_prefix,tmpf); path_tmpname (tmpf,"$$$",tmpf,MAXSIZ_PATH); return tmpf; } static STD_TEXTE * near intgdat2_settexte( const USERINFO *user, const char *fname) { STD_TEXTE *ret; if (!file_exist(fname) && path_ischild (fname,user->getombre())){ /* #Sp‚cification: fusion / archivage / strat‚gie de compaction Lors de l'‚dition d'une transaction (un fichier avec ses diff‚rentes versions), on v‚rifie si le fichier est pr‚sent dans /kit/ombre. On commande l'extraction (unzip) si ce n'est pas le cas. */ char path[MAXSIZ_PATH]; char file[MAXSIZ_PATH]; char sdir[MAXSIZ_NAME]; path_splitlex (fname,path,file); path_splitlex (path,path,sdir); rcs_unzip (user,path,sdir,file); } if (ascii_test(fname)!=-1){ ret = new FILE_TEXTE(fname); }else if (!file_exist(fname)){ ret = new STRING_TEXTE ("",0); }else{ char *msg = MSG_U(I_NOTASCII ,"\n\n\t\t\t\tP A S\n\n\tU N F I C H I E R\n" "\n\t\tA S C I I"); ret = new STRING_TEXTE (msg,strlen(msg)); } return ret; } /* Transforme un path en absolue et retourne une copie allou‚ via strdup. */ static char * near intgdat_setabs ( const USERINFO *user, const char *path) { char *ret = NULL; if (path != NULL){ char tmppath[MAXSIZ_PATH]; if (!path_isabs(path)){ user->makombpath(path,tmppath); path = tmppath; } ret = strdup_err (path); } return ret; } /* Dialogue pour int‚gration de plusieurs r‚visions d'un fichier. Retourne != 0 si int‚gration a ‚t‚ faite, 0 si abandon. */ PUBLIC int INTEGRE_FILE::menu ( long mskwin, EVENT *cmd, BOUTON_FCT *but, MAKEFILE *mkf, const USERINFO *user) { if (getnb()>=20) return 0; PAGE_EDIT page("integre_file"); page_setuptitre (&page,MSGTIT_INTGFILE,fname); /* #Sp‚cification: fusion / dialogue Le dialogue d'‚dition de fusion est assez complexe: Il se divise en deux section verticalement dispos‚es: # 1-S‚lections et op‚rations (section1) 2-Edition (ou pr‚sentation) du fichier (ptexte) # 1-S‚lections et op‚rations Cette section se divise en quatres sous-sections horizontalement dispos‚es: # a-Pr‚sentation de la version b-S‚lection de l'‚dition c-S‚lection de l'op‚ration de diff‚rence d-S‚lection de l'op‚ration de fusion # */ PAGE_EDIT section1(NULL); section1.setboxtype (WINBOX_NO); PAGE_EDIT pversion (NULL); pversion.setboxtype (WINBOX_NO); PAGE_EDIT pdiff (NULL); pdiff.setboxtype (WINBOX_NO); PAGE_EDIT pselect (NULL); pselect.setboxtype (WINBOX_NO); PAGE_EDIT ptexte (NULL); page_setuptitre0 (&ptexte,""); int select = 1; // Permet de s‚lectionner imm‚diatement // C'est g‚n‚ralement la premiŠre r‚vision qui // nous int‚resse. int seldiff1 = 0; int seldiff2 = getnb(); /* tbpath contiennent le path et la r‚vision (format ascii) de chaque fichiers qui participe … la fusion. L'‚l‚ment 0 repr‚sente la r‚f‚rence, les ‚l‚ment 1 @ getnb() (inclus) repr‚sente les getnb() transaction. L'‚l‚ment getnb()+1 (optionnel) repr‚sente le fichier courant dans le r‚pertoire d'int‚gration. */ char *tbpath[20]; const char *tbrev [20]; memset (tbpath,0,sizeof(tbpath)); tbpath[0] = intgdat_setabs (user,path); tbrev [0] = revs.fichier; struct { STD_TEXTE *select[20]; STD_TEXTE *diff[20][20]; STD_TEXTE *tempo[3]; } tbtxt; memset (&tbtxt,0,sizeof(tbtxt)); { //Page affichant les diff‚rentes versions page_setuptitre (&pversion,MSGTIT_VERSIONS); // Page permettant la s‚lection des deux versions pour vdiff page_setuptitre (&pdiff,MSGTIT_DIFF); // Page pour s‚lection des versions … fusionner via patch // Page pour s‚lection d'une seule r‚vision qui deviendra la // r‚vision finale. page_setuptitre (&pselect,MSGTIT_SELECT); page_setupfixestr0 (&pversion,-1,intgdat_rev2prog(revs.root),-1); page_setupfixestr0 (&pversion,-1,revs.root,-1); page_setupfixestr0 (&pversion,-1,revs.dir,-1); page_setupfixestr0 (&pversion,-1,revs.fichier,-1); if (nouveau){ // Le fichier n'existait pas encore, donc ne peut pas // participer au merge. intgdat_addblank(pselect,pdiff); }else{ page_setupradioi (&pselect,-1,&select,0,0); page_setupradioi (&pdiff ,-1,&seldiff1,0,1); page_setupradioi (&pdiff ,-1,&seldiff2,0,0); } int nb = getnb(); for (int i=0; irevs.fichier); int nexti = i+1; tbpath[nexti] = intgdat_setabs(user,tra->path); tbrev[nexti] = tra->revs.fichier; if (revtra.isnull()){ /* #Sp‚cification: fusion / dialogue / r‚vision nulle Lors d'une fusion dans l'espace usager, le fichier qu'on souhaite importer dans la nouvelle r‚vision n'a jamais ‚t‚ livr‚, donc n'a pas de num‚ro de r‚vision (1000.0.0). On le pr‚sente dans le dialogue avec un num‚ro de r‚vision <> permettant de le reconnaitre facilement. */ const char *msg = MSG_U(I_NONLIVRE,"Non livré"); tbrev[nexti] = msg; page_setupfixestr0 (&pversion,-1,msg,-1); page_setupfixestr0 (&pversion,-1,tra->revs.root,-1); page_setupfixestr0 (&pversion,-1,tra->revs.dir,-1); page_setupfixestr0 (&pversion,-1,"",-1); }else{ page_setupfixestr0 (&pversion,-1 ,intgdat_rev2prog(tra->revs.root),-1); page_setupfixestr0 (&pversion,-1,tra->revs.root,-1); page_setupfixestr0 (&pversion,-1,tra->revs.dir,-1); page_setupfixestr0 (&pversion,-1,tra->revs.fichier,-1); } if (tra->oper == INTEGRE_MODIF || tra->oper == INTEGRE_NOUVEAU){ page_setupradioi (&pselect,-1,&select,nexti,0); page_setupradioi (&pdiff ,-1,&seldiff1,nexti,0); page_setupradioi (&pdiff ,-1,&seldiff2,nexti,i==nb-1); }else{ // Le fichier a ‚t‚ effac‚ pour cette r‚vision. // Ou encore, il n'existait pas. intgdat_addblank(pselect,pdiff); if (i==0){ // S'assure que cette r‚vision n'est pas s‚lectionn‚e // par d‚faut. Choisit la r‚f‚rence. Car si le // fichier a ‚t‚ effac‚, la r‚f‚rence existait surement. select = 0; } } } /* #Sp‚cification: fusion / dialogue / fichier pr‚sent Si un fichier est d‚j… pr‚sent dans l'environnement destination, il sera pr‚sent‚ dans le dialogue pour qu'on puisse l'‚diter, faire des diffs ou des fusions. On retrouve cette situation lorsque l'usager fait des fusions dans son environnement. */ if (file_exist (fname)){ page_setupfixestr0 (&pversion,-1 ,message_getstru(MSGETC_COURANT),-1); page_setupfixestr0 (&pversion,-1,"",-1); page_setupfixestr0 (&pversion,-1,"",-1); page_setupfixestr0 (&pversion,-1,"",-1); //merge[i] = 0; int nexti = i+1; page_setupradioi (&pselect,-1,&select,nexti,0); page_setupradioi (&pdiff ,-1,&seldiff1,nexti,0); page_setupradioi (&pdiff ,-1,&seldiff2,nexti,0); tbpath[nexti] = strdup_err(fname); tbrev[nexti] = MSG_U(I_COURANT,"Courant"); } { /* #Sp‚cification: fusion / dialogue / patch / r‚sultat Lorsqu'on applique une diff‚rence sur un source, le r‚sultat est plac‚ dans un des trois fichiers temporaires. */ } bouton_setupuser (&pdiff,MSGBUT_DIFFS,K_NULL,PAGE_VAL_USER8); bouton_setupuser (&pselect,MSGBUT_EDIT,K_NULL,PAGE_VAL_USER12); bouton_setupuser (&pselect,MSGBUT_SELECT,K_NULL,PAGE_VAL_USER11); pversion.linedesign0(4); section1.setup (-1,&pversion,0); section1.setup (-1,&pselect,0); pdiff.linedesign0(2); section1.setup (-1,&pdiff,0); bouton_setupstd (§ion1,"cancel"); bouton_setupuser (§ion1,MSGBUT_EFFACE,K_NULL,PAGE_VAL_USER1); bouton_setupuser (§ion1,MSGBUT_RELOAD,K_NULL,PAGE_VAL_USER13); fuslog_setbutton (§ion1,user); section1.linedesign(); } /* #Sp‚cification: fusion / dialogue Le bas contient le texte d'une des r‚vision, ou encore le r‚sultat de la commande "diff" appliqu‚e … deux r‚visions ou encore le r‚sultat de la commande "merge" appliqu‚ … trois r‚vision. Le titre de cette section identifie le contenu. */ { int size = section1.getsizey(); int reste = vdiinfo.y_max - size - 4*pen_info.std_height; int nbcol = vdiinfo.x_max / pen_info.std_width - 4; if (nbcol > 80) nbcol = 80; // reste/pen_info.std_height-1, ligne de status occupe une ligne page_setupptexte (&ptexte,reste/pen_info.std_height-3,nbcol,1); } tbtxt.select[select] = intgdat2_settexte(user,tbpath[select]); page_setuptitre0 (&ptexte,"%s",tbrev[select]); page_loadptexte (&ptexte,0,tbtxt.select[select]); page.setup (-1,§ion1,0); page.setup (-1,&ptexte,0); page.coldesign(); page.setspec (but); page.draw (); int ret = 0; int done_edit = 0; STD_TEXTE *curtxt = tbtxt.select[0]; char tmpf[MAXSIZ_PATH]; // Buffer pour fabriquer path de fichier // temporaire: voir intgdat_tmpf() do{ PAGE_VAL val = page.edit(mskwin,cmd); pselect.save(); pdiff.save(); if (cmd->is_load || val == PAGE_VAL_ABORT){ done_edit = 1; break; }else{ STD_TEXTE *newtxt = curtxt; switch (val){ case PAGE_VAL_USER1: { /* #Sp‚cification: fusion / Efface un fichier Lorsqu'on choisit d'effacer le fichier de la version fusionn‚, le nom du fichier est simplement ajout‚ au makefile.del du r‚pertoire local. Il est donc tres simple d'annuler un effacement manuellement en ‚ditant makefile.del. */ fuslog_add (user,"Efface %s\n",fname); if (file_exist(fname) && file_unlink (fname) == -1){ xconf_error (MSG_U(E_UNLINK ,"Ne peut pas détruire %s") ,fname); }else{ FILE *fout = fopen_err ("makefile.del","a",1); fprintf (fout,"%s\n",fname); fclose (fout); ret = 1; done_edit = 1; } } break; case PAGE_VAL_USER5: case PAGE_VAL_USER8: case PAGE_VAL_USER9: // Mode imm‚diat, affiche // uniquement si vdiff a d‚j… ‚t‚ fait /* Produit un fichier temporaire contenant la diff‚rence entre deux r‚visions. Le r‚sultat est pr‚sent‚ dans le champs d'‚dition. Chaque combinaison de diff‚rence est plac‚ dans un fichier temporaire unique. Ca ‚vite d'appeler vdiff trop souvent. */ if (seldiff1 != seldiff2){ newtxt = tbtxt.diff[seldiff1][seldiff2]; if (newtxt != NULL || val == PAGE_VAL_USER8){ if (newtxt == NULL){ intgdat_tmpf("diff",tmpf); if (rcs_vdiff (tbpath[seldiff1],tbpath[seldiff2] ,tmpf)!=-1){ newtxt = new FILE_TEXTE (tmpf); tbtxt.diff[seldiff1][seldiff2] = newtxt; } file_unlink (tmpf); } page_setuptitre0 (&ptexte,"vdiff %s <> %s" ,tbrev[seldiff1],tbrev[seldiff2]); } }else{ beep(); } break; case PAGE_VAL_USER11: /* #Sp‚cification: fusion / ‚dition / s‚lection Il y a trois cas de s‚lection: # 1-Une r‚vision de l'archive non modifi‚. 2-Une r‚vision l‚gŠrement corrig‚. 3-La copie locale du fichier (d‚j… dans le r‚pertoire en traitement). # Dans les deux premiers cas, la r‚vision s‚lectionn‚ sera not‚e dans le makefile.dat. Dans le deuxiŠme cas la version corrig‚ sera copi‚e en place. Dans les deux premiers cas, la version locales sera effac‚e. Dans le deuxiŠme cas, on modifie tout de mˆme le makefile.dat parce que ca contribue … l'historique du module. Si on ne le faisait pas, on perdrait un ‚tape d'information. Dans le troisiŠme cas, on laisse simplement le fichier en place. */ { STD_TEXTE *txt = tbtxt.select[select]; int err = 0; if (select == 0){ // On laisse simplement la révision courante // en place. // On signale tout de même que l'usager a pris // une décision. fuslog_add (user,"Conserve %s r‚vision %s\n" ,fname,revs.fichier); done = 1; }else if (select <= getnb()){ // select > getnb() repr‚sente le fichier locale select_tra (user,select-1,mkf); } if (txt != NULL && txt->ismodif()){ fuslog_add (user,"\tavec modification\n"); err = txt->save (fname); } if (err == -1){ xconf_error (MSG_U(E_NOCOPY ,"Ne peut copier\n%s -> %s") ,tbpath[select],fname); }else{ done_edit = 1; ret = 1; } } break; case PAGE_VAL_USER12: // On ‚dite une r‚vision du fichier. newtxt = tbtxt.select[select]; if (newtxt == NULL){ newtxt = intgdat2_settexte(user,tbpath[select]); tbtxt.select[select] = newtxt; } page_setuptitre0 (&ptexte,"%s",tbrev[select]); break; case PAGE_VAL_USER13: // On force un rechargement du texte en ‚dition if (curtxt != NULL){ curtxt->reload(); ptexte.drawitem(0); } break; } if (newtxt != curtxt){ page_loadptexte (&ptexte,0,newtxt); ptexte.drawitem (0); ptexte.drawtitre(); curtxt = newtxt; } } } while (!done_edit); tbstr_free (tbpath,NB_ELM(tbpath)); for (int i=0; i