// clientloguser.cpp: implementation of the clientloguser class. // ////////////////////////////////////////////////////////////////////// #include <clientapi.h> #include "changesorter.h" #include "filehead.h" #include "filelogcache.h" #include "clientloguser.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// ClientLogUser::ClientLogUser() { doneone = toomany = false; } ClientLogUser::~ClientLogUser() { } /* This is where the magic happens. * Lines of filelog output will have a level of '0', '1', or '2'. * Level '0' is the file name - we can ignore this. * Level '1' is a revision record, looking like this: * #2 change 767 edit on 2001/09/25 by samwise@samwise-luey (binary+k) 'description' * Level '2' is an integ record, looking like this: * branch from //depot/foo/bar#1,#2 */ void ClientLogUser::OutputInfo(char level, const_char *data) { if (toomany) return; //make sure to only process ONE file. /* Get depot path from here in case file arg wasn't in depot syntax. */ if (level == '0') { if (doneone) //this is the second file this CLU has seen! { toomany = true; return; } char* ptr = data; working->name.Clear(); while ( *ptr && *ptr != '\n' ) working->name.Append( ptr++, 1 ); doneone = true; } /* If this is a rev record, create a new FileRev object for it. */ if (level == '1') { StrBuf rev = StrBuf(); //this will be the rev number StrBuf change = StrBuf(); //this will be the change number RevType type; //this will be the revision type char* ptr = data+1; //skip over '#' - we're now pointing at the rev number while (*ptr != ' ') //go until we see the first space { rev.Append(ptr, 1); ptr++; } //rev now contains the rev number. ptr += 8; //skip over ' change ' - we're now pointing at the change number while (*ptr != ' ') { change.Append(ptr, 1); ptr++; } //change now contains the change number. ptr++; //skip the space - now looking at the rev type. switch (*ptr) //We can determine the rev type from the first letter alone unless it's an i. { default: case 'e': type = EDIT; break; // 'edit' case 'a': type = ADD; break; // 'add' case 'b': type = BRANCH; break; // 'branch' case 'd': type = DEL; break; // 'delete' case 'i': type = UNKNOWN_TYPE; break; //indeterminate from first character } if (type == UNKNOWN_TYPE) //Was it an 'i'? { ptr++; if (*ptr == 'm') type = ADD; // 'import' else type = INTEG; // 'integ' } //note: users and clients can have parens, so we have to skip past them while (*ptr != '@') ptr++; //skip up to the "@" before the client while (*ptr != ' ') ptr++; //skip to the space before the ftype ptr += 2; //skip to the first letter of the ftype bool istext = (*ptr == 't' || *(ptr+1) == 't'); working->addRev(rev, change, type, istext); //Tell the FileHead to create a new FileRev. return; //All done with this line of output! } /* Here's where we handle integ records.*/ if (level == '2') { ArrowType atype; //New integ type. char* ptr = data; //ptr is pointing at the first character of the integ type. switch (*ptr) { default: case 'm': atype = merge; break; // 'merge' case 'b': atype = branch; break; // 'branch' case 'e': atype = impure; break; // 'edit' case 'a': atype = impure; break; // 'add' case 'c': atype = copy; break; // 'copy' case 'i': atype = ignore; break; // 'ignored' } while (*ptr != ' ') {ptr++;} //Skip past the rest of that word to the next space. ptr++; //Skip the space - the current word is either 'from' or 'into'. /* A "from" integ record will be indicated by the word "from" in most cases. * For example, "merge from" or "branch from". The exception is the word * "ignored". If this is the case, we'll be looking at a filespec rather * than a "from" or "into". */ if (*ptr == 'f' || *ptr == '/') // 'from' or the beginning of a filespec. { //This is a "from" record, so note this in the appropriate FileRev. StrBuf filepath = StrBuf(); //This will be the "fromfile". StrBuf rev = StrBuf(); //This will be the "fromrev". if (*ptr == 'f') //If this word is "from", skip past it to the file. { while (*ptr != ' ') {ptr++;} ptr++; //now we're at the start of the "from" filespec } //If it wasn't, it was an "ignored" and we're there anyway. while (*ptr != '#') //scan up to the '#' revision marker. { filepath.Append(ptr, 1); ptr++; } ptr ++; //Skip over the '#'. Now looking at a revision number. /* At this point we'll either see a single revision or a revision * range. If it's a revision range it'll be of the form: * #12,#15 * whereas a single revision will just be * #15 * If it's a range, we want to look at the last number in that range. */ while ((*ptr != ',') && (*ptr != '\0')) { rev.Append(ptr, 1); ptr++; } //rev now contains either the single revision, or the first rev in a range. if ( *ptr == '\0' || *ptr == '\n' ) //Single revision - use it. { working->tail->AddFromText(filepath, rev, atype); return; //All done with this line. } rev.Clear(); //This isn't the end of the line, so there must be another rev. ptr+=2; //skip over ",#" to get to the start of the end rev. while ( *ptr != '\0' && *ptr != '\n' ) { rev.Append(ptr, 1); ptr++; } //Now rev contains the end rev of the range. working->tail->AddFromText(filepath, rev, atype); return; //Done. } else // This line is an "into". { StrBuf filepath = StrBuf(); StrBuf rev = StrBuf(); while (*ptr != ' ') {ptr++;} //Skip over this word, be it "into" or "by". ptr++; //Skip the space - now we're at the start of an "into" filespec. while (*ptr != '#') //Go up to the '#' marker. { filepath.Append(ptr, 1); ptr++; } // We now have the "into" file. ptr++; //Skip the '#' and get to the revision. This is not a range. while ( *ptr != '\0' && *ptr != '\n' ) { rev.Append(ptr, 1); ptr++; } working->tail->AddIntoText(filepath, rev, atype); return; //Done! } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#8 | 2944 | Sam Stafford |
Add the ability to read filelog output from a text file. This functionality (if used; it's off by default) causes FLC to try to find required filelog output from a specified file before it queries the server. This can be used to fill in gaps (eg obliterated files), or more importantly, to draw graphs based on filelog output from a server you don't have access to, such as when trying to diagnose an integration problem for a customer. The filelog-parsing code hasn't been changed much, and isn't very fault-tolerant, so it might crash if fed mangled filelogs. Let the user beware. |
||
#7 | 1704 | Sam Stafford |
Change API includes to <*.h> rather than "*.h". No functional change. |
||
#6 | 1684 | Sam Stafford |
Imported new 02.1 p4api headers and libs. MAJOR code cleanup to make it fit without resorting to re-hacking of the API headers. The hacked headers were not L33T. They deserved D34TH. |
||
#5 | 1558 | Sam Stafford |
Finish redoing error checking work - make sure that if phtest is given a file argument with wildcards, it only accepts the first file that the wildcard resolves to and discards the rest. This naturally propagates to client programs which might have to contend with rambunctious users clicking on folders and whatnot, trying to get their version trees. |
||
#4 | 1556 | Sam Stafford |
Undo 1540 and 1552 and do things right. Preliminary tests seem to indicate that everything works, but I've been taught to tread more cautiously in the future. Need to re-implement the error-checking to enforce the "one file per FileHead" rule. |
||
#3 | 1547 | Sam Stafford |
Moved revision type from #defined shorts to an enum, RevType. Infrastructure change. |
||
#2 | 1540 | Sam Stafford |
Quick little change to ensure that a FileHead's name is always in depot syntax. Error checking also put in place to ensure that a FileHead doesn't refer to two files. |
||
#1 | 1417 | Sam Stafford |
Branching backend stuff off for rigorous testing. Grahr. |
||
//guest/sam_stafford/p4hl/src/dlls/clientloguser.cpp | |||||
#6 | 1405 | Sam Stafford |
Phew - this was a big one! New functionality: The rare case in which a revision has multiple parents, due to multiple resolves before submit, is now handled properly. There is no limit on the number of "parents" a revision may have. Integration lines are now always "weighted" to indicate whether they contributed all, some, or none to the target. For example, a "branch" line will be very solid and wide, whereas an "ignore" will be thin and faint. Rearchitecture: Now using low-cost structs to keep track of integration information. Also being just a little more efficient with scanning through large data structures. Quite a bit of general code bloat trimmed off now that some of the kludges are gone. Possible problems: Not sure yet, but it might happen that "duplicate" integration pointers will be created, now that it's not a single variable which would get overwritten in the event of a duplicate. to-do: Trim off obsolete member variables. Use more enums and fewer #defs. |
||
#5 | 1394 | Sam Stafford |
More support for FileRevArrows, including the addition of the FileTextArrow that will replace the ListList. As of right now the old functionality is untouched and I've just been adding stuff on. Submitting now because I've reached the point where I have to start making changes that have a high chance of breaking stuff. *cringe* |
||
#4 | 1008 | Sam Stafford |
Fixed a bug with the whole "istext" thing - wasn't setting the bit on CObjectRevs other than "main", so they'd all default to false. Now it seems to be better. Also cleaned up the style a little bit by including istext in the constructors, rather than setting it after construction. |
||
#3 | 1004 | Sam Stafford |
Different file types are now treated differently - the ObjectFiles have different skins depending on file type of the head rev, and non-text revisions will not attempt to display their contents when expanded. Possible bug: old-style filetypes might be detected wrong (ie "ktext" instead of "text+k"). I'd have to put in some pretty complex logic to make it completely foolproof and backwards-compatible. Right now it just errs on the side of thinking a file is text if there's any confusion. |
||
#2 | 992 | Sam Stafford |
Make sure that any "branch" type revisions are properly marked with a "branch" type integ pointer. In some cases, apparently, the filelog doesn't include that information properly, in which case the integration looks like the default "merge". Not sure why; this phenomenon was observed in the Public Depot. Presumbably it's some kind of artifact of an older server version. |
||
#1 | 937 | Sam Stafford |
Renaming my guest directory to the more conventional sam_stafford. |
||
//guest/samwise/p4hl/src/dlls/clientloguser.cpp | |||||
#1 | 936 | Sam Stafford |
Adding P4HL to the public depot. See relnotes.txt for installation instructions; all relevant files are under p4hl/dist. Source code is under p4hl/src in the form of a VC++ project. |