/* controle interactif des transfert de fichier entre l'espace d'int‚gration et la r‚f‚rence de groupe */ #include #include #include "projet.h" /* D‚crit une r‚vision d'un r‚pertoire */ class PROJET_CONTEXTE{ public: USERINFO *info; MAKEFILE mkf; // makefile.dat du projet FILE_REV_SPEC rev; PROJET_CONTEXTE ( // AccŠde info dans environnement d‚crit par _info USERINFO *_info, const char *projet) : info(_info),mkf (NULL,true,projet,_info) { rev.fichier = NULL; rev.dir = _info->getrevsrc(); rev.root = rev.dir; } PROJET_CONTEXTE ( // Accede info directement dans /kit/ombre USERINFO *_info, const REVISION *_revdir, const char *projet) : info(_info),mkf (NULL,true,_revdir,projet,_info) { rev.fichier = NULL; rev.dir = _revdir; rev.root = _info->getrevsrc(); } }; class FUSION_CONTEXTE{ PROJET_CONTEXTE &c_extr; PROJET_CONTEXTE &c_ref; PROJET_CONTEXTE &c_intg; INTEGRE_DAT &integre; const char *projet; public: FUSION_CONTEXTE ( PROJET_CONTEXTE &_extr, PROJET_CONTEXTE &_ref, PROJET_CONTEXTE &_intg, const char *_projet, INTEGRE_DAT &_integre) : c_extr(_extr), c_ref(_ref), c_intg(_intg), integre(_integre),projet(_projet){ } int addtrans (MAKEFILE_FILE *intg_file, MAKEFILE_FILE *extr_file , MAKEFILE_FILE *ref_file, int isdir); int addnew (MAKEFILE_FILE *extr_file, MAKEFILE_FILE *ref_file); int subdir (MAKEFILE_FILE *extr_file, MAKEFILE_FILE *ref_file ,PROJET_LOG *log); int mksubdir (const char *subprj); }; /* Cr‚ation d'un sous-r‚pertoire dans un projet de kit/build */ PRIVATE int FUSION_CONTEXTE::mksubdir(const char *subprj) { char newprojet[MAXSIZ_PATH]; path_make (projet,subprj,newprojet); char path[MAXSIZ_PATH]; c_intg.info->makbldpath (newprojet,path); return file_mkdir (path,-1,-1,-1,NULL); } /* Compare la r‚vision de base, de r‚f‚rence et la nouvelle et d‚termine information requise pour fusion. Retourne != 0 si une transaction a ‚t‚ ajout‚ (donc il y a diff‚rence de r‚vision). Bien qu'il n'y ait pas de transaction ajout‚e pour les sous-r‚pertoires, retourne != 0 si pour les sous-r‚pertoires aussi. */ PUBLIC int FUSION_CONTEXTE::addtrans ( MAKEFILE_FILE *intg_file, MAKEFILE_FILE *extr_file, MAKEFILE_FILE *ref_file, int isdir) { int ret = 0; const char *nom = intg_file->getnom(); if (extr_file == NULL && ref_file == NULL){ // Le fichier n'existait pas ni dans ref // ni dans extr }else if(extr_file != NULL && ref_file != NULL && extr_file->getrev()->cmp(ref_file->getrev())==0){ // Mˆme r‚vision dans ref et dans extr. extr_file->setmark(1); }else{ /* #Sp‚cification: fusion / integre.dat / path relatif Les paths plac‚s dans integre.dat sont souvent relatif. Ils sont implicitement relatif a /kit/ombre. Ca rend les fichiers integre.dat deplacables. */ const char *baseombpath = intg_file->getrelpath(); const REVISION *intg_rev = intg_file->getrev(); c_intg.rev.fichier = intg_rev; if (extr_file == NULL){ // Le fichier n'existe plus pour cette r‚vision c_extr.rev.fichier = NULL; integre.addtrans (nom ,c_intg.rev,baseombpath ,'-' ,c_extr.rev,NULL); }else{ /* #Sp‚cification: fusion / integre.dat / sous-projets Il n'est pas utiles de mentionner les variations des sous-makefile.dat dans le integre.dat, sauf pour mentionner que le sous-r‚pertoire a ‚t‚ ajout‚s ou ‚limin‚s. */ // V‚rifie si c'est la mˆme r‚vision. const REVISION *extr_rev = extr_file->getrev(); if (!isdir && intg_rev->cmp(extr_rev) != 0){ /* #Sp‚cification: fusion / s‚lection complexe / ref‚rence Si la r‚vision r‚f‚rence n'est pas la mˆme que la r‚vision de base, il faut ajouter les sp‚cifications du fichier pour cette r‚vision. Ca permettra … l'usager de comparer la r‚vision a fusionner avec sa r‚f‚rence et aussi avec la r‚vision de base. */ const REVISION *ref_rev = ref_file->getrev(); if (ref_file != NULL && intg_rev->cmp(ref_rev)!= 0){ // Assure que le fichier est unzip c_ref.mkf.extract (ref_file,0); c_ref.rev.fichier = ref_rev; integre.addtrans (nom ,c_intg.rev ,baseombpath,'+' ,c_ref.rev ,ref_file->getrelpath()); } c_extr.mkf.extract (extr_file,0); c_extr.rev.fichier = extr_rev; integre.addtrans (nom ,c_intg.rev ,baseombpath,'+' ,c_extr.rev ,extr_file->getrelpath()); } // Permettra de d‚tecter les nouveaux fichiers dans // une seconde passe. extr_file->setmark(1); ret = 1; } } return ret; } /* Ajoute information dans integre.dat si extr_file est diff‚rent de ref_file (r‚vision diff‚rente). Cette fonction est appel‚ lorsque extr_file n'existe pas dans l'environnement intg. Retourne != 0 si r‚vision de ref_file != revision de extr_file. */ PUBLIC int FUSION_CONTEXTE::addnew ( MAKEFILE_FILE *extr_file, MAKEFILE_FILE *ref_file) { int ret = 0; // Le fichier soit n'existait pas dans ref ou a ‚t‚ chang‚ const REVISION *extr_rev = extr_file->getrev(); if (ref_file == NULL || extr_rev->cmp(ref_file->getrev())!=0){ c_extr.mkf.extract (extr_file,0); FILE_REV_SPEC ref; ref.fichier = NULL; ref.dir = c_intg.rev.dir; ref.root = c_intg.rev.root; FILE_REV_SPEC rev; rev.fichier = extr_rev; rev.dir = c_extr.rev.dir; rev.root = c_extr.rev.root; integre.addtrans (extr_file->getnom() ,ref ,NULL,'?' ,rev ,extr_file->getrelpath()); ret = 1; } return ret; } static int near bfusion_extractdir ( USERINFO *extr, USERINFO *ref, USERINFO *intg, const char *projet, const REVISION *extr_rev, const REVISION *ref_rev, PROJET_LOG *log); /* Traitement des sous-r‚pertoires. file est un sous-r‚pertoire. Retourne -1 si erreur. */ PUBLIC int FUSION_CONTEXTE::subdir ( MAKEFILE_FILE *extr_file, MAKEFILE_FILE *ref_file, PROJET_LOG *log) { /* #Sp‚cification: fusion / nouveau r‚pertoire Quand on d‚tecte qu'un r‚vision ajoute un r‚pertoire, on cr‚e ce r‚pertoire sans makefile.dat. On fait comme si le r‚pertoire existait dans la version de base, mais ‚tait vide. */ char newprojet[MAXSIZ_PATH]; path_splitlex (extr_file->getnom(),newprojet,NULL); mksubdir (newprojet); path_make (projet,newprojet,newprojet); int ret = bfusion_extractdir(c_extr.info,c_ref.info,c_intg.info ,newprojet,extr_file->getrev() ,ref_file==NULL ? c_ref.rev.dir : ref_file->getrev() ,log); /* Comme il y a cr‚ation de sous-r‚pertoire, il faut aussi cr‚ation des r‚pertoires h et doc. Leur absence cause des problŠmes … prjenv_get() (mkextr.addbuild() echoue). */ mksubdir("h"); mksubdir("doc"); return ret; } /* Formatte le num‚ro de r‚vision d'un fichier dans une chaine. Place un '-' si file == NULL. */ static void near format_revstr(const MAKEFILE_FILE *file, char *str) { if (file == NULL){ str[0] = '-'; str[1] = '\0'; }else{ file->getrev()->format(str); } } /* Extrait r‚cursivement tous les sources d'un projet et compare avec les sources de la version de base pour l'integration. Met a jour le fichier integre.dat. */ static int near bfusion_extractdir ( USERINFO *extr, // Description de l'environnement … extraire USERINFO *ref, // R‚f‚rence pour comparaison // Si la r‚vision extr est la mˆme que la r‚vision // ref, on en parle pas. USERINFO *intg, // Environnement pour integration const char *projet, const REVISION *extr_rev, // R‚vision du makefile.dat de extr const REVISION *ref_rev, // R‚vision du makefile.dat de ref PROJET_LOG *log) { int ret = -1; // Le makefile.dat de intg est dans l'environnement d'int‚gration // les deux autres sont localis‚s dans /kit/ombre // C'est pourquoi on doit fournir la r‚vision exacte. PROJET_CONTEXTE c_extr (extr,extr_rev,projet); int is_ok = c_extr.mkf.isok(); log->printf (" %s%s\n",projet,is_ok ? "" : " (makefile.dat invalide)"); if (is_ok){ ret = c_extr.mkf.extract (1); // S'assure que tous les // fichiers sont extraits de RCS if (ret != -1){ PROJET_CONTEXTE c_intg (intg,projet); PROJET_CONTEXTE c_ref (ref,ref_rev,projet); char integre_dat[MAXSIZ_PATH]; intg->makusrpath(projet,integre_dat); path_make (integre_dat,"integre.dat",integre_dat); INTEGRE_DAT integre (integre_dat); FUSION_CONTEXTE fusion (c_extr,c_ref,c_intg,projet,integre); { c_extr.mkf.setmark (0); c_extr.mkf.toi()->setmark(1); char *wild = WILD_ALLFILE; // Fait deux passes, une pour les sous-r‚pertoires // une pour les fichiers, commence par les fichiers for (int i=0; i<2; i++, wild = "*/makefile.dat"){ c_intg.mkf.setiter(); c_intg.mkf.setmark (0); // Evite de mentionner le makefile.dat lui-mˆme c_intg.mkf.toi()->setmark(1); MAKEFILE_FILE *intg_file; while ((intg_file=c_intg.mkf.iter(wild,0))!=NULL){ const char *nom = intg_file->getnom(); MAKEFILE_FILE *extr_file = c_extr.mkf.locate(nom); MAKEFILE_FILE *ref_file = c_ref.mkf.locate(nom); if (fusion.addtrans (intg_file,extr_file,ref_file ,i==1)){ char intg_str[MAXSIZ_REVISION]; char extr_str[MAXSIZ_REVISION]; char ref_str[MAXSIZ_REVISION]; format_revstr(intg_file,intg_str); format_revstr(extr_file,extr_str); format_revstr(ref_file,ref_str); log->printf ("\t\t%s %s %s [%s]\n",nom,ref_str,extr_str ,intg_str); if (i==1 && projet[0] != '\0'){ ret = fusion.subdir (extr_file,ref_file,log); } } } } // D‚termine les fichiers et les r‚pertoires qui // ont ‚t‚ ajout‚ dans la r‚vision. wild = WILD_ALLFILE; for (int i=0; i<2; i++, wild = "*/makefile.dat"){ c_extr.mkf.setiter(); MAKEFILE_FILE *extr_file; while ((extr_file=c_extr.mkf.iter(wild,0))!=NULL){ MAKEFILE_FILE *ref_file = c_ref.mkf.locate( extr_file->getnom()); if (fusion.addnew (extr_file,ref_file) && i==1 && projet[0] != '\0'){ ret = fusion.subdir (extr_file,ref_file,log); } } } } } } return ret; } /* Assure que les sources des projets sont extrait dans /kit/ombre pour une r‚vision donn‚e. Met a jour dans l'environnement d'integration le fichier integre.dat qui indique les diff‚rences entre la version extraite et la version a integrer. Pas d'effet dans l'environnement /kit/build de la version extraite. Retourne -1 si erreur. */ int bfusion_extractrev ( USERINFO *extr, // Une r‚vision … fusionner dans intg. USERINFO *ref, // R‚f‚rence pour s‚lection des diff‚rence // dans extr. // Dans le cas de fusion simple, ref // d‚crit la mˆme r‚vision que intg. USERINFO *intg, // D‚crit l'environnement d'int‚gration. const char *tbprj[], int nbprj, PROJET_LOG *log) { int ret = -1; // Localise et charge le makefile.dat principal MAKEFILE master ((char*)NULL,false,extr->getrevsrc(),"",extr); if (master.isok()){ // mkfref permettra d'optimiser en evitant de traiter // les projets de mˆme r‚vision que la version r‚f‚rence. MAKEFILE mkfref ((char*)NULL,false,ref->getrevsrc(),"",ref); if (mkfref.isok()){ ret = 0; char revstr[MAXSIZ_REVISION]; extr->getrevsrc()->format(revstr); log->printf ("----- Extraction r‚vision %s\n",revstr); for (int i=0; i<=nbprj && ret != -1; i++){ /* #Sp‚cification: fusion / extraction / racine Quelques soit les projets s‚lectionn‚s pour la fusion, la racine est toujours trait‚e. */ char makpath[MAXSIZ_PATH]; const char *projet; if (i==nbprj){ projet = ""; strcpy (makpath,"makefile.dat"); }else{ projet = tbprj[i]; // Obtient le path du makefile.dat appropri‚ pour // le projet. path_make (projet,"makefile.dat",makpath); } MAKEFILE_FILE *file = master.locate (makpath); MAKEFILE_FILE *fref = mkfref.locate (makpath); if (file != NULL){ const REVISION *file_rev = file->getrev(); char revstr[MAXSIZ_REVISION]; file_rev->format(revstr); if (fref != NULL && file_rev->cmp(fref->getrev())==0){ log->printf (" %s [%s == %s]\n" ,projet,revstr,revstr); }else{ log->printf ("Extraction %s [%s]\n",projet,revstr); master.extract (file,0); ret = bfusion_extractdir (extr,ref,intg,projet ,file->getrev() ,fref == NULL ? ref->getrevsrc() : fref->getrev() ,log); } }else{ // Pour cette r‚vision, le projet n'existait pas, ou // n'existe plus. log->printf ("Extraction %s ... absent\n",projet); } } } } return ret; }