From RationalWiki
Jump to: navigation, search
#!/usr/bin/env python3
# encoding: utf8
# Copyright © 2016 Martin Tournoij <>
# See below for full copyright

import re, sys, json, collections

import pywikibot
_site = pywikibot.Site()

# Pages to archive
_wigos = [
	'RationalWiki:What is going on in the blogosphere?',
	'RationalWiki:What is going on in the clogosphere?',
	#'RationalWiki:What is going on with the elections?',

# Find an entry
_start_entry = r'^\s*(?:<vote poll=.*?|<!--)'
_end_entry = r'(?:<\/vote>|-->)\s*$'
_entry = _start_entry + r'.*?' + _end_entry

# Find current section
_section = r'==(.*?)=='

# Find instructions
_config = r'<!-- wigobot: (\d+) -->'

def pp(*ds):
	for d in ds:
		json.dump(d, sys.stdout, sort_keys=True, indent=4)

def main():
	for wigo in _wigos:
		#text = open('test.txt', 'r').read()
		page = pywikibot.Page(_site, wigo)
		text = page.text

		# Extract the number of archives to keep
		m =, text)
		if m is None:
			keep_num = 100
			keep_num = int(m.groups()[0])
			if keep_num == 0:
				print('Archiving has been disabled for {}'.format(wigo))

		# Store everything before the first section
		m =, text, re.MULTILINE)
		head = text[:m.start()]
		text = text[m.start():]

		# ... and the same for everything after the last entry
		m ='.*' + _end_entry, text, re.MULTILINE + re.DOTALL)
		foot = text[m.end():]
		text = text[:m.end()].strip()

		# Split by sections and entries
		sections_tmp = []
		c = re.compile(_section)
		off = 0
		while True:
			m =, off)
			if m is None: break
			off = m.end()
		sections = []
		for i, s in enumerate(sections_tmp):
			if i + 2 > len(sections_tmp):
				end = len(text)
				end = sections_tmp[i + 1].start()

			section_text = text[s.end():end].strip()
				re.findall(_entry, section_text, re.MULTILINE + re.DOTALL)])

		# Split in what we want to keep and archive
		keep = collections.OrderedDict()
		archives = collections.OrderedDict()
		n_archiving = 0
		n = 0
		for section, entries in sections:
			for entry in entries:
				n += 1
				if n > keep_num:
					if archives.get(section) is None: archives[section] = []
					n_archiving += 1
					if keep.get(section) is None: keep[section] = []

		def p(s):
			for l in s.split('\n'): print('|', l[:120])

		page.text = '{}\n{}\n\n{}'.format(
			'\n'.join(['\n=={}==\n{}'.format(k, '\n'.join(v)) for k, v in keep.items()]),

		#print('==> Updating the current page to this:'); p(page.text)'Bot: archiving {} entries'.format(n_archiving))

		archives = list(archives.items())
		for k, v in archives:
			title = '{}/{}'.format(wigo, k)
			page = pywikibot.Page(_site, title, 4)

			if page.text == '':
				page.text = '=={}==\n'.format(k)
				page.text = page.text.strip() + '\n'
			page.text += '\n'.join(v)
			#print('==> Updating {} to this:'.format(k)); p(page.text)'Bot: archiving {} entries'.format(len(v)))

		# Purge cache for the archives
		pywikibot.Page(_site, '{}/Archive_list'.format(wigo), 4).purge()

if __name__ == '__main__':

# The MIT License (MIT)
# Copyright © 2016 Martin Tournoij
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# The software is provided "as is", without warranty of any kind, express or
# implied, including but not limited to the warranties of merchantability,
# fitness for a particular purpose and noninfringement. In no event shall the
# authors or copyright holders be liable for any claim, damages or other
# liability, whether in an action of contract, tort or otherwise, arising
# from, out of or in connection with the software or the use or other dealings
# in the software.