hgidiocy / idiocy.py

"""Cut down on erroneus check-ins by forcing last-minute sanity checks before checking into named branches."""
import os

def reposetup(ui, repo):
	ui.setconfig("hooks", "pretxncommit", catch_branch)

def _termsize():
	try:
		return tuple(int(x) for x in os.popen("stty size", "r").read().split())	
	except:
		return (40,80)

def catch_branch(ui, repo, **kwargs):
	sensitive_branches = ui.configlist("idiocy", "branches", ["release"])
	# Only do this on sensitive branches
	current_branch = repo[None].branch()
	if current_branch in sensitive_branches:
		o = Output(ui)
		o.start_box();

		o.writeln("You are committing to the %s branch, which is considered a sensitive place to which to commit." % current_branch)
		o.writeln()

		# Output the list of files, prefixed by their status
		o.writeln("The following files will be submitted in this commit:")
		o.writeln()

		# Map the files in the working directory to statuses
		states = 'modified added removed deleted unknown ignored clean'.split()
		chars = 'MAR!?IC'
		changes = zip(states, chars, repo.status())

		# Restrict the list to files in the changeset to be committed
		for state, char, files in changes:
			for f in files:
				if f in repo[kwargs['node']].files():
					o.writeln('%s: %s' % (char, f), label='status.'+state)

		o.end_box()

		# Prompt to see if the user still wants to go ahead
		return (ui.promptchoice("Are you sure you wish to commit (Y/N)?", ("&Yes", "&No"), default=1) > 0)
	return False

class Output(object):
	def __init__(self, ui, char='*', top_padding=1, side_padding=3):
		try:
			size = tuple(int(x) for x in os.popen("stty size", "r").read().split())
		except:
			size = (40,80)

		self.ui = ui
		self.char = char
		self.nl = '\n'
		self.box = False
		self.side_padding = side_padding
		self.top_padding = top_padding
		self.width = size[1]
		self.maxlinelength = self.width - 2 - (self.side_padding * 2)

	def start_box(self):
		self.box = True
		self.ui.status(self.char * self.width + self.nl)
		for i in range(self.top_padding):
			self.ui.status(self.char + (' ' * (self.width - 2)) + self.char + self.nl)

	def end_box(self):
		self.box = False
		for i in range(self.top_padding):
			self.ui.status(self.char + (' ' * (self.width - 2)) + self.char + self.nl)
		self.ui.status(self.char * self.width + self.nl)

	def writeln(self, msg='', label=''):
		if self.box:
				def _write(msg):
					self.ui.status(self.char + (' ' * self.side_padding) + msg + (' ' * (self.maxlinelength - len(msg) + self.side_padding))  + self.char + self.nl, label=label)

				# Special case a blank line
				if not msg:
					_write(msg)

				# Output the string, splitting it into lines
				while msg:
					if len(msg) > self.maxlinelength:
						i = msg.rfind(' ', 0, self.maxlinelength)
						if i < 1:
							i = self.maxlinelength
						_write(msg[:i])
						msg = msg[i:].lstrip()
					elif msg:
						_write(msg)
						break;
		else:
			self.ui.status(msg + self.nl)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.