Skip to content

Instantly share code, notes, and snippets.

@jinie
Last active December 25, 2015 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jinie/7033687 to your computer and use it in GitHub Desktop.
Save jinie/7033687 to your computer and use it in GitHub Desktop.
Script to update WoW packages installed by Curse Client. usage : "curse_update.py Warcraft/Interface/Addons"
#!/usr/bin/env python
import os
import re
import logging
import fnmatch
try:
# For Python 3.0 and later
from urllib.request import urlopen
except ImportError:
# Fall back to Python 2's urllib2
from urllib2 import urlopen
import argparse
import tempfile
from zipfile import ZipFile
from threading import Thread
packages = {}
addon_dir = ""
toc_project_pattern = re.compile("^## X-Curse-Project-Name:\s?(.*)$")
toc_repository_pattern = re.compile("^## X-Curse-Repository-ID:\s?(.*)$")
redirect_pattern = re.compile('data-href=\"(.*)\"\sclass="download-link"')
def get_args():
argparser = argparse.ArgumentParser()
argparser.add_argument('ADDON_DIRECTORY',help="Addon Direction",type=str)
argparser.add_argument('-n','--dry-run',help="Don't update anything, just list packages", action="store_true")
args = argparser.parse_args()
if 'ADDON_DIRECTORY' not in args:
argparser.print_help()
exit(-1)
return args
def read_toc(name):
project_name = None
project_repo = None
with open(name,"r") as f:
for l in iter(f.readline,''):
if project_name is None:
m = toc_project_pattern.match(l)
if m is not None:
project_name = m.group(1).rstrip('\r\n')
if project_repo is None:
m = toc_repository_pattern.match(l)
if m is not None:
project_repo = m.group(1).rstrip('\r\n')
if project_name is not None and project_repo is not None:
break
return (project_name,project_repo)
def update_package(package_name, package_path, addon_directory):
repo = "http://www.curse.com/addons/"+package_path[:package_path.rfind("/")]+"/download"
logging.info(repo)
try:
package = urlopen(repo)
redirect = redirect_pattern.search(package.read().decode('utf-8'))
if redirect is None:
logging.error("Error downloading package : %s" % k)
remote_file = redirect.group(1)
local_file_name = os.path.join(tempfile.gettempdir(),(remote_file.split("/")[-1]))
remote = urlopen(remote_file)
logging.debug("remote_file %s, local_file_name %s" %(remote_file, local_file_name))
with open(local_file_name,"wb") as f:
f.write(remote.read())
logging.debug("unzipping %s into %s" % (local_file_name, addon_directory))
#Extract ZIP file to Addon directory
with ZipFile(local_file_name,"r") as f:
f.extractall(addon_directory)
logging.debug("deleting %s" % local_file_name)
#Delete downloaded ZIP file
os.unlink(local_file_name)
except Exception as e:
logging.exception(e)
def update_packages(addon_directory):
threads = []
for k in packages:
t = Thread(target=update_package, args=(k, packages[k], addon_directory))
t.start()
threads.append(t)
for t in threads:
t.join()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
args= get_args()
for root, dirs, files in os.walk(args.ADDON_DIRECTORY, topdown=True):
depth = root[len(args.ADDON_DIRECTORY)+len(os.path.sep):].count(os.path.sep)
if depth == 1:
dirs[:] = []
for n in files:
fname = os.path.join(root, n)
if os.path.isfile(fname):
if fnmatch.fnmatch(n, "*.toc"):
project_name, project_repo = read_toc(fname)
if project_name is not None and project_repo is not None:
logging.debug(root+"=>"+project_name)
packages[project_name] = project_repo
dirs[:] = []
continue
if args.dry_run:
for k in packages:
print("%s => %s" % (k,packages[k]))
else:
update_packages(args.ADDON_DIRECTORY)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment