#include #include #include #include #include #include "projet.h" #include "projetx.m" #if 0 static void diff_getsubdirs( MAKEFILE &mkf, SSTRINGS &tb) { mkf.setiter(); MAKEFILE_FILE *file; while ((file=mkf.iter("*/makefile.dat"))!=NULL){ char dir[MAXSIZ_PATH]; path_splitlex (file->getnom(),dir,NULL); tb.add (new SSTRING(dir)); } } #endif /* Set the absolute path in the archive of a revision of a given file in a project */ static void diff_setrevpath ( const USERINFO &user, const char *projet, const REVISION *rev, const char *name, char path[MAXSIZ_PATH]) { if (rev == NULL){ // The file does not exist, we help diff a bit here strcpy (path,"/dev/null"); }else{ user.makombpath(projet,path); char revstr[MAXSIZ_REVISION+1]; rev->formatpath(revstr); path_make (path,revstr,path); strcat (path,".s"); path_make (path,name,path); } } struct DIFFCONTEXT { const USERINFO *user; const char *cmd; // diff command and options const char *version1; // Version of the root project (start) const char *version2; // Version of the root project (end) FILE *fileout; // Output FILE *filecmd; // Will contain script commands to make // sure the patch is complete const SSTRINGS *subdirs; // Subdir to diff. By default, diff all void (*log) (const char *ctl, ...); }; static bool diff_issymlink (const char *path) { struct stat st; return lstat(path,&st)!=-1 && S_ISLNK(st.st_mode); } /* Format the revision date of the file if it exists */ static void pdiff_setcomment ( bool exist, const char *path, char *comment) { comment[0] = '\0'; struct stat st; if (exist && stat(path,&st)!=-1){ struct tm *t = localtime (&st.st_mtime); strcpy (comment,asctime(t)); strip_end (comment); } } /* Execute la commande diff en corrigeant le resultat, camouflant le système d'archivage de /kit/ombre */ static void diff_cmd ( DIFFCONTEXT &ctx, const char *projet, const char *name, const REVISION *rev1, // May be NULL if the file does not exist const REVISION *rev2) { char path1[MAXSIZ_PATH],path2[MAXSIZ_PATH]; diff_setrevpath (ctx.user,projet,rev1,name,path1); diff_setrevpath (ctx.user,projet,rev2,name,path2); const char *slash = projet[0] != '\0' ? "/" : ""; bool symlink1 = diff_issymlink(path1); bool symlink2 = diff_issymlink(path2); if (!symlink1 && !symlink2){ char comment1[1000],comment2[1000]; pdiff_setcomment (rev1 != NULL,path1,comment1); pdiff_setcomment (rev2 != NULL,path2,comment2); char tmp[2000]; snprintf (tmp,sizeof(tmp)-1 ,"%s -L\"%s/%s%s%s\t%s\" -L\"%s/%s%s%s\t%s\" %s %s" ,ctx.cmd ,ctx.version1,projet,slash,name,comment1 ,ctx.version2,projet,slash,name,comment2 ,path1,path2); POPEN pop (tmp); if (pop.isok()){ int skip = 0; // Skip the first two line while (pop.wait(1)>=0){ char line[1000]; while (pop.readout(line,sizeof(line)-1)!=-1){ if (skip == 2){ line[4] = '\0'; fprintf (ctx.fileout,"%s%s%c%s/%s\n",line ,ctx.version1 ,projet[0] != '\0' ? '/' : '\0' ,projet,name); skip--; }else if (skip == 1){ skip--; line[4] = '\0'; fprintf (ctx.fileout,"%s%s%c%s/%s\n",line ,ctx.version2 ,projet[0] != '\0' ? '/' : '\0' ,projet,name); }else{ fputs (line,ctx.fileout); } } while (pop.readerr(line,sizeof(line)-1)!=-1){ fputs (line,stderr); } } } } if (ctx.filecmd != NULL){ if (rev2 == NULL){ // The file does not exist in the new version fprintf (ctx.filecmd,"UNLINK %s%s%s\n",projet,slash,name); }else if (symlink2 && (rev1 == NULL || !symlink1)){ char val[MAXSIZ_PATH]; int len = readlink (path2,val,sizeof(val)-1); if (len !=-1){ val[len] = '\0'; fprintf (ctx.filecmd,"LINK %s%s%s %s\n",projet,slash,name ,val); } } } } static int diff_iterfile ( DIFFCONTEXT &ctx, const char *projet, MAKEFILE &mkf1, MAKEFILE &mkf2) { mkf1.setiter(); mkf2.setmark(0); MAKEFILE_FILE *file1; while ((file1=mkf1.iter(WILD_ALLFILE))!=NULL){ const char *name = file1->getnom(); if (strcmp(name,"makefile.dat")!=0){ MAKEFILE_FILE *file2 = mkf2.locate(name); if (file2 == NULL){ diff_cmd (ctx,projet,name,file1->getrev(),NULL); // printf ("Nouveau manque %s\n",name); }else{ file2->setmark (1); if (file1->getrev()->cmp(file2->getrev())!=0){ // printf ("Differe %s\n",name); diff_cmd (ctx,projet,name,file1->getrev() ,file2->getrev()); } } } } // Look for new file in mkf2 (not marked by the previous loop) mkf2.setiter(); MAKEFILE_FILE *file2; while ((file2=mkf2.iter(WILD_ALLFILE,0))!=NULL){ const char *name = file2->getnom(); if (strcmp(name,"makefile.dat")!=0){ // printf ("Nouveau fichier %s\n",file2->getnom()); diff_cmd (ctx,projet,name,NULL,file2->getrev()); } } return 0; } static int diff_recur ( DIFFCONTEXT &ctx, const char *projet, const REVISION &rv1, const REVISION &rv2); static int diff_recursubdir ( DIFFCONTEXT &ctx, const char *projet, // parent project const char *dirmkf, // subdir/makefile.dat const REVISION &rv1, const REVISION &rv2) { char dir[MAXSIZ_PATH]; path_splitlex (dirmkf,dir,NULL); char subprj[MAXSIZ_PATH]; if (projet[0] != '\0'){ sprintf (subprj,"%s/%s",projet,dir); }else{ strcpy (subprj,dir); } return diff_recur (ctx,subprj,rv1,rv2); } static int diff_itersubdir ( DIFFCONTEXT &ctx, const char *projet, MAKEFILE &mkf1, MAKEFILE &mkf2, const REVISION &rv1, const REVISION &rv2) { mkf1.setiter(); mkf2.setmark(0); MAKEFILE_FILE *file1; while ((file1=mkf1.iter("*/makefile.dat"))!=NULL){ const char *name = file1->getnom(); MAKEFILE_FILE *file2 = mkf2.locate(name); if (file2 == NULL){ // printf ("Nouveau subdir manque %s\n",name); diff_recursubdir (ctx,projet,name,*file1->getrev(),rv2); }else{ file2->setmark (1); if (file1->getrev()->cmp(file2->getrev())!=0){ // printf ("dir Differe %s\n",name); diff_recursubdir (ctx,projet,name,*file1->getrev() ,*file2->getrev()); } } } // Look for new file in mkf2 (not marked by the previous loop) mkf2.setiter(); MAKEFILE_FILE *file2; while ((file2=mkf2.iter("*/makefile.dat",0))!=NULL){ // fprintf (stderr,"Nouveau dir %s\n",file2->getnom()); // We are using the revision of the parent for the first // directory. We know that it does not exist, but // diff_recur() will manage an empty (missing) makefile.dat // properly, showing all new files in sub-directories diff_recursubdir (ctx,projet,file2->getnom(),rv1 ,*file2->getrev()); } return 0; } enum PDIFF_VIEW { PDIFF_AVOID, // We have no work in this directory PDIFF_SHOW, // We must compute the difference in this // directory PDIFF_PARENT // We have nothing to show in this directory // but in some childs }; static PDIFF_VIEW diff_checkvisible ( const char *projet, const SSTRINGS *subdirs) { PDIFF_VIEW ret = PDIFF_SHOW; if (subdirs != NULL && subdirs->getnb()>0){ int len = strlen(projet); if (len == 0){ ret = PDIFF_PARENT; }else{ int n = subdirs->getnb(); ret = PDIFF_AVOID; for (int i=0; igetitem(i)->get(); // fprintf (stderr,"Compare dirs :%s: :%s:\n",dir,projet); if (strncmp(dir,projet,len)==0){ // projet is maybe a parent of dir if (dir[len] == '\0'){ ret = PDIFF_SHOW; break; }else if (dir[len] == '/'){ ret = PDIFF_PARENT; break; } }else{ // dir is maybe a parent of projet int lendir = strlen(dir); if (strncmp(dir,projet,lendir)==0){ if (projet[lendir] == '\0' || projet[lendir] == '/'){ ret = PDIFF_SHOW; break; } } } } } } return ret; } static int diff_recur ( DIFFCONTEXT &ctx, const char *projet, const REVISION &rv1, const REVISION &rv2) { int ret = 0; PDIFF_VIEW visible = diff_checkvisible (projet,ctx.subdirs); if (visible != PDIFF_AVOID){ char path1[MAXSIZ_PATH],path2[MAXSIZ_PATH]; diff_setrevpath (ctx.user,projet,&rv1,"makefile.dat",path1); diff_setrevpath (ctx.user,projet,&rv2,"makefile.dat",path2); MAKEFILE mkf1 (path1,true,projet,ctx.user); MAKEFILE mkf2 (path2,true,projet,ctx.user); if (visible == PDIFF_SHOW){ MAKEFILE_FILE *dat1 = mkf1.locate ("makefile.dat"); MAKEFILE_FILE *dat2 = mkf2.locate ("makefile.dat"); if (ctx.log != NULL) ctx.log (MSG_U(L_DIRECTORY,"Répertoire %s\n"),projet); if (dat1 != NULL && dat2 != NULL){ // Check if this is the same version const REVISION *rev1 = dat1->getrev(); const REVISION *rev2 = dat2->getrev(); if (rev1->cmp(rev2)!=0){ diff_iterfile (ctx,projet,mkf1,mkf2); } }else{ diff_iterfile (ctx,projet,mkf1,mkf2); } } diff_itersubdir (ctx,projet,mkf1,mkf2,rv1,rv2); } return ret; } /* Find all the files different between version ver1 and ver2 List new files as well as removed file */ int diff_findfiles ( const USERINFO *user, const char *diffcmd, // diff command and options const char *ver1, // Reference version const char *ver2, // Target version of the diff const SSTRINGS &subdirs, // Which subdirs to diff or all FILE *fout, FILE *fcmd, void (*fctlog)(const char *, ...)) { int ret = -1; DIFFCONTEXT ctx; ctx.user = user; ctx.cmd = diffcmd; ctx.version1 = ver1; ctx.version2 = ver2; ctx.fileout = fout; ctx.filecmd = fcmd; ctx.subdirs = &subdirs; ctx.log = fctlog; REVISION rv1 (ver1); REVISION rv2 (ver2); VERSION_DAT v (user); VERSION_ONE *one1 = v.get(&rv1); VERSION_ONE *one2 = v.get(&rv2); if (one1 == NULL){ fprintf (stderr,MSG_U(E_MISSVER,"La révision %s n'existe pas\n") ,ver1); }else if (one2 == NULL){ fprintf (stderr,MSG_R(E_MISSVER),ver2); }else{ ctx.version1 = one1->getversion(); ctx.version2 = one2->getversion(); ret = diff_recur (ctx,"",rv1,rv2); } return ret; }