Created
January 1, 2012 20:32
-
-
Save provegard/1548272 to your computer and use it in GitHub Desktop.
Script for unpacking the contents of a release directory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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