Skip to content

Instantly share code, notes, and snippets.

@provegard
Created January 1, 2012 20:32
Show Gist options
  • Save provegard/1548272 to your computer and use it in GitHub Desktop.
Save provegard/1548272 to your computer and use it in GitHub Desktop.
Script for unpacking the contents of a release directory
#!/usr/bin/python -W ignore::DeprecationWarning
"""rel_unpack.py - unpacks the contents of a release directory, optionally
checking SFV check sums prior to unpacking. The script only handles RAR
compressed content, and descends into any CD sub directories as well.
Usage: rel_unpack.py <release directory>
This script relies on the 'unrar' binary being installed. For SFV checking
to take place, the cfv Python module must be present.
Author: Per Rovegard
This code is in the public domain. You may use it for whatever you want,
as long as you do not hold the author responsible for the consequences of
its usage.
"""
import os
import sys
import re
import subprocess
from shutil import move
__version__ = "0.1"
DEBUG = 0
UNRAR = None
CHECK_SFV = True
PROTECTED = ["nfo"]
# The cfv module is perhaps not present, requires cfv
# to be installed for SFV checking to take place.
try:
import cfv
cfv.config.setx("verbose", "q")
except ImportError:
print "Did not find the cfv module, SFV checking is disabled."
CHECK_SFV = False
def check_sfv(dir_path, sfv_file):
print "Checking SFV checksum file '%s'..." % sfv_file
# cfv requires us to set the current directory to where the
# SFV file is.
old_dir = os.getcwd()
os.chdir(dir_path)
cfv.test(sfv_file, "auto")
os.chdir(old_dir)
sfv_err = (cfv.stats.badcrc and 2) | (cfv.stats.badsize and 4) | (cfv.stats.notfound and 8) | (cfv.stats.ferror and 16) | (cfv.stats.unverified and 32) | (cfv.stats.cferror and 64)
if sfv_err > 0:
raise IOError("SFV check of '%s' failed, cfv error = %d." % (os.path.join(dir_path, sfv_file), sfv_err))
def move_files(from_dir, to_dir):
print "Moving contents of '%s' to '%s'..." % (from_dir, to_dir)
files = os.listdir(from_dir)
full_files = [os.path.join(from_dir, file) for file in files]
for f in full_files:
if DEBUG > 0:
print "Moving file '%s' to '%s'..." % (f, to_dir)
move(f, to_dir)
def unpack_rar(dir_path, rarfile):
# Get a list of the files currently in the directory, so that
# we can compare after unpacking.
old_listing = os.listdir(dir_path)
print "Unpacking from archive '%s' in '%s'..." % (rarfile, dir_path)
rar = os.path.join(dir_path, rarfile)
args = [UNRAR]
args.extend("x -c- -o- -p- -y".split(" "))
args.extend([rar, dir_path])
try:
subprocess.check_output(args)
except subprocess.CalledProcessError, e:
raise IOError("Failed to unrar: %s" % e.output)
new_listing = os.listdir(dir_path)
new_files = [file for file in new_listing if not file in old_listing]
if len(new_files) == 0:
# Extraction resulted in no files. Error? Don't know, but
# don't continue.
return
# Delete all the old files (but not directories).
print "Deleting old files in '%s'..." % dir_path
for file in old_listing:
path = os.path.join(dir_path, file)
if os.path.isfile(path) and not path.rsplit(".", 1)[-1] in PROTECTED:
if DEBUG > 0:
print "Deleting file '%s'..." % path
os.unlink(path)
def check_rar(rarpath):
file_type = subprocess.check_output(["file", rarpath])
if not "RAR archive data" in file_type:
raise IOError("File '%s' does not seem to be a RAR file: %s" % (rarpath, line))
# dir_path: full directory path
def unpack_dir(dir_path):
print "Entering directory '%s'." % dir_path
contents = os.listdir(dir_path)
rarfile = None
sfvfiles = []
files = [file for file in contents if os.path.isfile(os.path.join(dir_path, file))]
dirs = [dir for dir in contents if os.path.isdir(os.path.join(dir_path, dir))]
# Find out which RAR file to unpack, and make a note of any
# SFV files in the directory.
for file in files:
if file.lower().endswith(".sfv"):
sfvfiles.append(file)
continue
match = re.search(r"((\.part01)?\.rar)|\.001$", file, re.I)
if not match is None and rarfile is None:
rarfile = file
# If we found any SFV files, check them now provided that we
# have the capability to do so.
if CHECK_SFV and len(sfvfiles):
for sfv in sfvfiles:
check_sfv(dir_path, sfv)
if rarfile:
check_rar(os.path.join(dir_path, rarfile))
unpack_rar(dir_path, rarfile)
elif DEBUG > 0:
print "No RAR file found in '%s', ignoring." % dir_path
# See if there is any CDx directory we can recurse into.
cd_dirs = [d for d in dirs if re.search(r"^CD\d+$", d, re.I)]
for dir in cd_dirs:
cd_dir = os.path.join(dir_path, dir)
unpack_dir(cd_dir)
move_files(cd_dir, dir_path)
print "Deleting directory '%s'..." % cd_dir
os.rmdir(cd_dir)
def init():
# See if we can find unrar, need it for extracting...
global UNRAR
try:
UNRAR = subprocess.check_output(["which", "unrar"]).rstrip()
except subprocess.CalledProcessError:
raise IOError("Cannot find the unrar command.")
def main(argv=None):
if not argv:
argv = sys.argv[1:]
if len(argv) == 0:
raise Exception("Not enough arguments.")
dir = argv[0]
if not os.path.exists(dir) or not os.path.isdir(dir):
raise IOError("%s does not exist or is not a directory." % dir)
init()
unpack_dir(os.path.realpath(dir))
if __name__ == "__main__":
try:
main()
sys.exit(0)
except Exception, inst:
print inst
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment