P4 wrapper implementations

Migrating this topic from my g+ page, was asking about different ideas behind incorporating P4 functionality into techart tools and APIs. Got some interesting feedback:

From Hamish (macaronikazoo):

I think transparency in p4 interaction is a good thing, but I think you want to keep the callable functionality p4 on a class of its own. Path manipulation should remain separate from p4 integration. IMHO.

So I mean - you could have the delete() method of Path automatically call “p4 -delete” on the file, but you wouldn’t have an add() method on Path. So IF p4 integration is turned on, it just magically works when using Path objects. But if you want to do a p4 transaction, you have to pass a Path instance to some p4 class.

I made the mistake of having p4 specific methods on my Path class. It caused headaches for me…

This makes good sense, got a few more followups to this effect:
From Rob (needs no intro):

Having seen a dozen different p4 wrappers, including those I’ve written myself, I prefer ones that mirror p4 as closely as possible (with as little magic as possible behind the scenes). A wrapper should help to object-orientize the p4 interaction, not reinvent the API (which is pretty good once you’re familiar with it and seems difficult, complex, and cumbersome when you’re not).

From my buddy Stephen (who’s actually an audio programmer, but a damn fine engineer overall):

I have a class that wraps file operations (Delete, WriteAllText,…) that has a set of delegates that get called before/after file operations (BeforeWriteText, AfterWriteText, BeforeDelete). The app can add relevant callbacks if it wants p4 automation (or not if it doesn’t, or even modify the callbacks during runtime). The p4 class is very close to matching the p4 commands. (P4.Edit(“c:\myfile.txt”). This is C# but such a structure is trivial in python. Using callbacks nicely isolates p4 entirely from the tool code but gives the ability to punch it in whenever you like.

Wondering if anyone else had any thoughts about this…Rob.

That’s a tricky one, I’ve seen it swing both ways. Some people think artists should learn p4 and work directly on it, while other people want it to work like dropbox.

I like the integrations where it’s meant to help the user, like when they’re trying to save a file that’s not checked out, it will prompt the user to check it out. But it also depends on the tool, I’ve done tools that check stuff in and then back out every so often (for concept art). But if you have an asset manager type tool, it should tightly integrate with P4, so people can one stop shop.

One nice thing that I would throw in, is the ability to see what you can do to the file, basically run a p4 stat on the file and determine what options the user has, to check-in, check-out, revert. It’s something I used over and over again in tools by just returning an array of possible options and then building my UI based on that.

Upon saving a file from any DCC app, we try to auto-checkout from p4. In my opinion, this is one of the lowest hanging fruits for a tech artist to save a huge amount of time for all of your artists. Also, MarkForAdd into a new changelist, for specific filetypes, if the asset is not yet in perforce. We never checkIn via script, though, for obvious reasons.

This way users just check their Pending tab in their Perforce client often and submit whenever they like. Clever naming of changelists can help organize the assets they’re working on as well.

I love Hamish’s idea of expanding my favorite path() class to have some perforce methods as well.

P.S. Rob needs to change your guys’ company logos. :-]

[QUOTE=Count_Zr0;11350]
I love Hamish’s idea of expanding my favorite path() class to have some perforce methods as well.[/QUOTE]

I agree, and i’m definitely on board with being selective about what you implement. Our implementation at 343 i think was just a blanket injection of VCS functionality into the path() class, i’m still going to go that route, but yeah i think just the “less dangerouse” functionality is going to be on the path() class.