Limit Size of Subversion Commits With this Hook
We have experienced some abuse of our subversion repository at work recently. Someone committed 400 MB of data all at once including many object files, libraries, and executables. I did not get very harsh with the person who did this. Because a) I have no objection to binaries in subversion in the first place, b) I don't really know what he's working on, c) disk space is cheap and we are no where near capacity, and d) his commit was still smaller than a few commits we had a long time ago (which were legit). Still, if you just allow people to commit whatever they want to your subversion repository, in the worst case, you could run out of disk space, necessitating an svn dump-and-load onto a new larger drive (pain). It would suck to have to do that just because some people were committing large binaries (without any legitimate reason to). There are other annoying consequences. Our tarball backups of svn currently fit on a DVD, which is cheap and easy, if we allowed this abuse to continue it would complicate our backup process.
What I wanted was a way to limit the commit size for certain users automatically. There did not seem to be any hooks out there to do this, so I wrote one.
Just paste the following into your pre-commit hook:
/svn/repos/hooks/check_txn_size.py "$REPOS" "$TXN" || exit 1
and paste the following into a check_txn_size.py file in your hooks directory and make it executable.
#!/usr/bin/env python import sys,os,popen2 MAX_BYTES = 1024000 DEBUG = False SVNLOOK = '/usr/bin/svnlook' ALLOWED_USERS = ['david', 'ctang', 'vjain', 'mike', 'sbridges', 'tcirip'] ADMIN_EMAIL = 'firstname.lastname@example.org' def printUsage(): sys.stderr.write('Usage: %s "$REPOS" "$TXN" ' % sys.argv) def getTransactionSize(repos, txn): txnRevPath = repos+'/db/transactions'+'/'+txn+'.txn'+'/rev' return os.stat(txnRevPath) def printDebugInfo(repos, txn): for root, dirs, files in os.walk(repos+'/db/transactions', topdown=False): sys.stderr.write(root+", filesize="+str(os.stat(root))+"\n\n") for name in files: sys.stderr.write(name+", filesize="+str(os.stat(root+'/'+name))+"\n") def checkTransactionSize(repos, txn): size = getTransactionSize(repos, txn) if (size > MAX_BYTES): sys.stderr.write("Sorry, you are trying to commit %d bytes, which is larger than the limit of %d.\n" % (size, MAX_BYTES)) sys.stderr.write("If you think you have a good reason to, email %s and ask for permission." % (ADMIN_EMAIL)) sys.exit(1) def getUser(repos, txn): cmd = SVNLOOK + " author " + repos + " -t " + txn out, x, y = popen2.popen3(cmd) cmd_out = out.readlines() return cmd_out[:-1] if __name__ == "__main__": #Check that we got a repos and transaction with this script if len(sys.argv) != 3: printUsage() sys.exit(2) else: repos = sys.argv txn = sys.argv if DEBUG: printDebugInfo(repos, txn) user=getUser(repos, txn) if DEBUG: sys.stderr.write("User:"+user) if DEBUG: if (user in ALLOWED_USERS): sys.stderr.write(user+" in allowed users") else: sys.stderr.write(user+" not in allowed users") if (user not in ALLOWED_USERS): checkTransactionSize(repos, txn)