2014-03-10 01:18:05 -04:00
# Author: Nic Wolfe <nic@wolfeden.ca>
# URL: http://code.google.com/p/sickbeard/
#
2014-05-23 08:37:22 -04:00
# This file is part of SickRage.
2014-03-10 01:18:05 -04:00
#
2014-05-23 08:37:22 -04:00
# SickRage is free software: you can redistribute it and/or modify
2014-03-10 01:18:05 -04:00
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
2014-05-23 08:37:22 -04:00
# SickRage is distributed in the hope that it will be useful,
2014-03-10 01:18:05 -04:00
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
2014-05-23 08:37:22 -04:00
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
2014-03-10 01:18:05 -04:00
import os
import platform
import shutil
import subprocess
import re
import urllib
import zipfile
import tarfile
import stat
import traceback
import gh_api as github
2014-05-13 07:16:32 -04:00
import threading
2014-03-10 01:18:05 -04:00
import sickbeard
from sickbeard import helpers
from sickbeard import version , ui
from sickbeard import logger
from sickbeard . exceptions import ex
from sickbeard import encodingKludge as ek
class CheckVersion ( ) :
"""
Version check class meant to run as a thread object with the SB scheduler .
"""
def __init__ ( self ) :
self . install_type = self . find_install_type ( )
if self . install_type == ' win ' :
self . updater = WindowsUpdateManager ( )
elif self . install_type == ' git ' :
self . updater = GitUpdateManager ( )
elif self . install_type == ' source ' :
self . updater = SourceUpdateManager ( )
else :
self . updater = None
2014-05-19 13:40:25 -04:00
def run ( self , force = False ) :
2014-04-23 03:47:42 -04:00
if self . check_for_new_version ( ) :
2014-05-11 09:25:12 -04:00
if sickbeard . AUTO_UPDATE :
logger . log ( u " New update found for SickRage, starting auto-updater ... " )
2014-05-29 02:24:23 -04:00
if sickbeard . versionCheckScheduler . action . update ( ) :
2014-05-11 09:25:12 -04:00
logger . log ( u " Update was successfull, restarting SickRage ... " )
2014-05-13 07:16:32 -04:00
threading . Timer ( 2 , sickbeard . invoke_restart , [ False ] ) . start ( )
2014-03-10 01:18:05 -04:00
def find_install_type ( self ) :
"""
Determines how this copy of SB was installed .
returns : type of installation . Possible values are :
' win ' : any compiled windows build
' git ' : running from source using git
' source ' : running from source without git
"""
# check if we're a windows build
if sickbeard . version . SICKBEARD_VERSION . startswith ( ' build ' ) :
install_type = ' win '
elif os . path . isdir ( ek . ek ( os . path . join , sickbeard . PROG_DIR , u ' .git ' ) ) :
install_type = ' git '
else :
install_type = ' source '
return install_type
2014-04-23 03:47:42 -04:00
def check_for_new_version ( self , force = False ) :
2014-03-10 01:18:05 -04:00
"""
Checks the internet for a newer version .
returns : bool , True for new version or False for no new version .
force : if true the VERSION_NOTIFY setting will be ignored and a check will be forced
"""
2014-04-23 03:47:42 -04:00
if not sickbeard . VERSION_NOTIFY and not sickbeard . AUTO_UPDATE and not force :
2014-03-10 01:18:05 -04:00
logger . log ( u " Version checking is disabled, not checking for the newest version " )
return False
2014-04-23 03:47:42 -04:00
if not sickbeard . AUTO_UPDATE :
2014-04-23 03:12:51 -04:00
logger . log ( u " Checking if " + self . install_type + " needs an update " )
2014-03-10 01:18:05 -04:00
if not self . updater . need_update ( ) :
sickbeard . NEWEST_VERSION_STRING = None
2014-04-23 03:47:42 -04:00
if not sickbeard . AUTO_UPDATE :
2014-04-23 03:12:51 -04:00
logger . log ( u " No update needed " )
2014-03-10 01:18:05 -04:00
2014-05-23 01:43:53 -04:00
if force :
2014-03-10 01:18:05 -04:00
ui . notifications . message ( ' No update needed ' )
return False
self . updater . set_newest_text ( )
return True
def update ( self ) :
if self . updater . need_update ( ) :
return self . updater . update ( )
class UpdateManager ( ) :
def get_github_repo_user ( self ) :
return ' echel0n '
def get_github_repo ( self ) :
2014-05-05 05:06:15 -04:00
return ' SickRage '
2014-03-10 01:18:05 -04:00
def get_update_url ( self ) :
return sickbeard . WEB_ROOT + " /home/update/?pid= " + str ( sickbeard . PID )
class WindowsUpdateManager ( UpdateManager ) :
def __init__ ( self ) :
self . github_repo_user = self . get_github_repo_user ( )
self . github_repo = self . get_github_repo ( )
self . branch = ' windows_binaries '
self . _cur_version = None
self . _cur_commit_hash = None
self . _newest_version = None
self . gc_url = ' http://code.google.com/p/sickbeard/downloads/list '
self . version_url = ' https://raw.github.com/ ' + self . github_repo_user + ' / ' + self . github_repo + ' / ' + self . branch + ' /updates.txt '
def _find_installed_version ( self ) :
2014-05-29 02:24:23 -04:00
version = ' '
2014-03-10 01:18:05 -04:00
try :
version = sickbeard . version . SICKBEARD_VERSION
return int ( version [ 6 : ] )
except ValueError :
2014-05-23 08:37:22 -04:00
logger . log ( u " Unknown SickRage Windows binary release: " + version , logger . ERROR )
2014-03-10 01:18:05 -04:00
return None
def _find_newest_version ( self , whole_link = False ) :
"""
Checks git for the newest Windows binary build . Returns either the
build number or the entire build URL depending on whole_link ' s value.
whole_link : If True , returns the entire URL to the release . If False , it returns
only the build number . default : False
"""
2014-05-23 08:37:22 -04:00
regex = " .*SickRage \ -win32 \ -alpha \ -build( \ d+)(?: \ . \ d+)? \ .zip "
2014-03-10 01:18:05 -04:00
version_url_data = helpers . getURL ( self . version_url )
if version_url_data is None :
return None
else :
for curLine in version_url_data . splitlines ( ) :
logger . log ( u " checking line " + curLine , logger . DEBUG )
match = re . match ( regex , curLine )
if match :
logger . log ( u " found a match " , logger . DEBUG )
if whole_link :
return curLine . strip ( )
else :
return int ( match . group ( 1 ) )
return None
def need_update ( self ) :
self . _cur_version = self . _find_installed_version ( )
self . _newest_version = self . _find_newest_version ( )
logger . log ( u " newest version: " + repr ( self . _newest_version ) , logger . DEBUG )
if self . _newest_version and self . _newest_version > self . _cur_version :
return True
return False
def set_newest_text ( self ) :
sickbeard . NEWEST_VERSION_STRING = None
if not self . _cur_version :
2014-05-23 08:37:22 -04:00
newest_text = " Unknown SickRage Windows binary version. Not updating with original version. "
2014-03-10 01:18:05 -04:00
else :
2014-03-25 01:57:24 -04:00
newest_text = ' There is a <a href= " ' + self . gc_url + ' " onclick= " window.open(this.href); return false; " >newer version available</a> (build ' + str (
self . _newest_version ) + ' ) '
2014-03-10 01:18:05 -04:00
newest_text + = " — <a href= \" " + self . get_update_url ( ) + " \" >Update Now</a> "
sickbeard . NEWEST_VERSION_STRING = newest_text
def update ( self ) :
zip_download_url = self . _find_newest_version ( True )
logger . log ( u " new_link: " + repr ( zip_download_url ) , logger . DEBUG )
if not zip_download_url :
logger . log ( u " Unable to find a new version link on google code, not updating " )
return False
try :
# prepare the update dir
sb_update_dir = ek . ek ( os . path . join , sickbeard . PROG_DIR , u ' sb-update ' )
if os . path . isdir ( sb_update_dir ) :
logger . log ( u " Clearing out update folder " + sb_update_dir + " before extracting " )
shutil . rmtree ( sb_update_dir )
logger . log ( u " Creating update folder " + sb_update_dir + " before extracting " )
os . makedirs ( sb_update_dir )
# retrieve file
logger . log ( u " Downloading update from " + zip_download_url )
zip_download_path = os . path . join ( sb_update_dir , u ' sb-update.zip ' )
urllib . urlretrieve ( zip_download_url , zip_download_path )
if not ek . ek ( os . path . isfile , zip_download_path ) :
logger . log ( u " Unable to retrieve new version from " + zip_download_url + " , can ' t update " , logger . ERROR )
return False
if not ek . ek ( zipfile . is_zipfile , zip_download_path ) :
logger . log ( u " Retrieved version from " + zip_download_url + " is corrupt, can ' t update " , logger . ERROR )
return False
# extract to sb-update dir
logger . log ( u " Unzipping from " + str ( zip_download_path ) + " to " + sb_update_dir )
update_zip = zipfile . ZipFile ( zip_download_path , ' r ' )
update_zip . extractall ( sb_update_dir )
update_zip . close ( )
# delete the zip
logger . log ( u " Deleting zip file from " + str ( zip_download_path ) )
os . remove ( zip_download_path )
# find update dir name
2014-03-25 01:57:24 -04:00
update_dir_contents = [ x for x in os . listdir ( sb_update_dir ) if
os . path . isdir ( os . path . join ( sb_update_dir , x ) ) ]
2014-03-10 01:18:05 -04:00
if len ( update_dir_contents ) != 1 :
2014-03-25 01:57:24 -04:00
logger . log ( u " Invalid update data, update failed. Maybe try deleting your sb-update folder? " ,
logger . ERROR )
2014-03-10 01:18:05 -04:00
return False
content_dir = os . path . join ( sb_update_dir , update_dir_contents [ 0 ] )
old_update_path = os . path . join ( content_dir , u ' updater.exe ' )
new_update_path = os . path . join ( sickbeard . PROG_DIR , u ' updater.exe ' )
logger . log ( u " Copying new update.exe file from " + old_update_path + " to " + new_update_path )
shutil . move ( old_update_path , new_update_path )
except Exception , e :
logger . log ( u " Error while trying to update: " + ex ( e ) , logger . ERROR )
return False
return True
class GitUpdateManager ( UpdateManager ) :
def __init__ ( self ) :
self . _git_path = self . _find_working_git ( )
self . github_repo_user = self . get_github_repo_user ( )
self . github_repo = self . get_github_repo ( )
self . branch = self . _find_git_branch ( )
self . _cur_commit_hash = None
self . _newest_commit_hash = None
self . _num_commits_behind = 0
self . _num_commits_ahead = 0
def _git_error ( self ) :
2014-05-29 02:24:23 -04:00
error_message = ' Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates. '
2014-03-10 01:18:05 -04:00
sickbeard . NEWEST_VERSION_STRING = error_message
def _find_working_git ( self ) :
test_cmd = ' version '
if sickbeard . GIT_PATH :
main_git = ' " ' + sickbeard . GIT_PATH + ' " '
else :
main_git = ' git '
logger . log ( u " Checking if we can use git commands: " + main_git + ' ' + test_cmd , logger . DEBUG )
output , err , exit_status = self . _run_git ( main_git , test_cmd )
if exit_status == 0 :
logger . log ( u " Using: " + main_git , logger . DEBUG )
return main_git
else :
logger . log ( u " Not using: " + main_git , logger . DEBUG )
# trying alternatives
alternative_git = [ ]
# osx people who start SB from launchd have a broken path, so try a hail-mary attempt for them
if platform . system ( ) . lower ( ) == ' darwin ' :
alternative_git . append ( ' /usr/local/git/bin/git ' )
if platform . system ( ) . lower ( ) == ' windows ' :
if main_git != main_git . lower ( ) :
alternative_git . append ( main_git . lower ( ) )
if alternative_git :
logger . log ( u " Trying known alternative git locations " , logger . DEBUG )
for cur_git in alternative_git :
logger . log ( u " Checking if we can use git commands: " + cur_git + ' ' + test_cmd , logger . DEBUG )
output , err , exit_status = self . _run_git ( cur_git , test_cmd )
if exit_status == 0 :
logger . log ( u " Using: " + cur_git , logger . DEBUG )
return cur_git
else :
logger . log ( u " Not using: " + cur_git , logger . DEBUG )
# Still haven't found a working git
2014-05-29 02:24:23 -04:00
error_message = ' Unable to find your git executable - Shutdown SickRage and EITHER set git_path in your config.ini OR delete your .git folder and run from source to enable updates. '
2014-03-10 01:18:05 -04:00
sickbeard . NEWEST_VERSION_STRING = error_message
return None
def _run_git ( self , git_path , args ) :
output = err = exit_status = None
if not git_path :
logger . log ( u " No git specified, can ' t use git commands " , logger . ERROR )
exit_status = 1
return ( output , err , exit_status )
cmd = git_path + ' ' + args
try :
logger . log ( u " Executing " + cmd + " with your shell in " + sickbeard . PROG_DIR , logger . DEBUG )
2014-03-25 01:57:24 -04:00
p = subprocess . Popen ( cmd , stdin = subprocess . PIPE , stdout = subprocess . PIPE , stderr = subprocess . STDOUT ,
shell = True , cwd = sickbeard . PROG_DIR )
2014-03-10 01:18:05 -04:00
output , err = p . communicate ( )
exit_status = p . returncode
if output :
output = output . strip ( )
logger . log ( u " git output: " + output , logger . DEBUG )
except OSError :
logger . log ( u " Command " + cmd + " didn ' t work " )
exit_status = 1
if exit_status == 0 :
logger . log ( cmd + u " : returned successful " , logger . DEBUG )
exit_status = 0
elif exit_status == 1 :
logger . log ( cmd + u " returned : " + output , logger . ERROR )
exit_status = 1
elif exit_status == 128 or ' fatal: ' in output or err :
logger . log ( cmd + u " returned : " + output , logger . ERROR )
exit_status = 128
else :
logger . log ( cmd + u " returned : " + output + u " , treat as error for now " , logger . ERROR )
exit_status = 1
return ( output , err , exit_status )
def _find_installed_version ( self ) :
"""
2014-05-23 08:37:22 -04:00
Attempts to find the currently installed version of SickRage .
2014-03-10 01:18:05 -04:00
Uses git show to get commit version .
Returns : True for success or False for failure
"""
output , err , exit_status = self . _run_git ( self . _git_path , ' rev-parse HEAD ' ) # @UnusedVariable
if exit_status == 0 and output :
cur_commit_hash = output . strip ( )
if not re . match ( ' ^[a-z0-9]+$ ' , cur_commit_hash ) :
logger . log ( u " Output doesn ' t look like a hash, not using it " , logger . ERROR )
return False
self . _cur_commit_hash = cur_commit_hash
2014-05-17 15:18:05 -04:00
sickbeard . CUR_COMMIT_HASH = str ( cur_commit_hash )
2014-03-10 01:18:05 -04:00
return True
else :
return False
def _find_git_branch ( self ) :
2014-03-25 01:57:24 -04:00
branch_info , err , exit_status = self . _run_git ( self . _git_path , ' symbolic-ref -q HEAD ' ) # @UnusedVariable
2014-03-10 01:18:05 -04:00
if exit_status == 0 and branch_info :
branch = branch_info . strip ( ) . replace ( ' refs/heads/ ' , ' ' , 1 )
if branch :
sickbeard . version . SICKBEARD_VERSION = branch
return sickbeard . version . SICKBEARD_VERSION
def _check_github_for_update ( self ) :
"""
Uses git commands to check if there is a newer version that the provided
commit hash . If there is a newer version it sets _num_commits_behind .
"""
self . _newest_commit_hash = None
self . _num_commits_behind = 0
self . _num_commits_ahead = 0
# get all new info from github
output , err , exit_status = self . _run_git ( self . _git_path , ' fetch origin ' )
if not exit_status == 0 :
logger . log ( u " Unable to contact github, can ' t check for update " , logger . ERROR )
return
# get latest commit_hash from remote
output , err , exit_status = self . _run_git ( self . _git_path , ' rev-parse --verify --quiet " @ {upstream} " ' )
if exit_status == 0 and output :
cur_commit_hash = output . strip ( )
if not re . match ( ' ^[a-z0-9]+$ ' , cur_commit_hash ) :
logger . log ( u " Output doesn ' t look like a hash, not using it " , logger . DEBUG )
return
else :
self . _newest_commit_hash = cur_commit_hash
else :
logger . log ( u " git didn ' t return newest commit hash " , logger . DEBUG )
return
# get number of commits behind and ahead (option --count not supported git < 1.7.2)
output , err , exit_status = self . _run_git ( self . _git_path , ' rev-list --left-right " @ {upstream} " ...HEAD ' )
if exit_status == 0 and output :
try :
self . _num_commits_behind = int ( output . count ( " < " ) )
self . _num_commits_ahead = int ( output . count ( " > " ) )
except :
logger . log ( u " git didn ' t return numbers for behind and ahead, not using it " , logger . DEBUG )
return
logger . log ( u " cur_commit = " + str ( self . _cur_commit_hash ) + u " , newest_commit = " + str ( self . _newest_commit_hash )
2014-03-25 01:57:24 -04:00
+ u " , num_commits_behind = " + str ( self . _num_commits_behind ) + u " , num_commits_ahead = " + str (
self . _num_commits_ahead ) , logger . DEBUG )
2014-03-10 01:18:05 -04:00
def set_newest_text ( self ) :
# if we're up to date then don't set this
sickbeard . NEWEST_VERSION_STRING = None
if self . _num_commits_ahead :
logger . log ( u " Local branch is ahead of " + self . branch + " . Automatic update not possible. " , logger . ERROR )
newest_text = " Local branch is ahead of " + self . branch + " . Automatic update not possible. "
elif self . _num_commits_behind > 0 :
base_url = ' http://github.com/ ' + self . github_repo_user + ' / ' + self . github_repo
if self . _newest_commit_hash :
url = base_url + ' /compare/ ' + self . _cur_commit_hash + ' ... ' + self . _newest_commit_hash
else :
url = base_url + ' /commits/ '
newest_text = ' There is a <a href= " ' + url + ' " onclick= " window.open(this.href); return false; " >newer version available</a> '
newest_text + = " (you ' re " + str ( self . _num_commits_behind ) + " commit "
if self . _num_commits_behind > 1 :
newest_text + = ' s '
newest_text + = ' behind) ' + " — <a href= \" " + self . get_update_url ( ) + " \" >Update Now</a> "
else :
return
sickbeard . NEWEST_VERSION_STRING = newest_text
def need_update ( self ) :
self . _find_installed_version ( )
if not self . _cur_commit_hash :
return True
else :
try :
self . _check_github_for_update ( )
except Exception , e :
logger . log ( u " Unable to contact github, can ' t check for update: " + repr ( e ) , logger . ERROR )
return False
if self . _num_commits_behind > 0 :
return True
return False
def update ( self ) :
"""
2014-05-23 08:37:22 -04:00
Calls git pull origin < branch > in order to update SickRage . Returns a bool depending
2014-03-10 01:18:05 -04:00
on the call ' s success.
"""
output , err , exit_status = self . _run_git ( self . _git_path , ' pull origin ' + self . branch ) # @UnusedVariable
if exit_status == 0 :
return True
2014-03-20 14:03:22 -04:00
return False
2014-03-10 01:18:05 -04:00
class SourceUpdateManager ( UpdateManager ) :
def __init__ ( self ) :
self . github_repo_user = self . get_github_repo_user ( )
self . github_repo = self . get_github_repo ( )
self . branch = sickbeard . version . SICKBEARD_VERSION
self . _cur_commit_hash = None
self . _newest_commit_hash = None
self . _num_commits_behind = 0
def _find_installed_version ( self ) :
version_file = ek . ek ( os . path . join , sickbeard . PROG_DIR , u ' version.txt ' )
if not os . path . isfile ( version_file ) :
self . _cur_commit_hash = None
return
2014-03-25 01:57:24 -04:00
2014-03-10 01:18:05 -04:00
try :
with open ( version_file , ' r ' ) as fp :
self . _cur_commit_hash = fp . read ( ) . strip ( ' \n \r ' )
except EnvironmentError , e :
logger . log ( u " Unable to open ' version.txt ' : " + ex ( e ) , logger . DEBUG )
if not self . _cur_commit_hash :
self . _cur_commit_hash = None
2014-05-10 18:46:29 -04:00
sickbeard . CUR_COMMIT_HASH = str ( self . _cur_commit_hash )
2014-03-10 01:18:05 -04:00
def need_update ( self ) :
self . _find_installed_version ( )
try :
self . _check_github_for_update ( )
except Exception , e :
logger . log ( u " Unable to contact github, can ' t check for update: " + repr ( e ) , logger . ERROR )
return False
if not self . _cur_commit_hash or self . _num_commits_behind > 0 :
return True
return False
def _check_github_for_update ( self ) :
"""
Uses pygithub to ask github if there is a newer version that the provided
2014-05-23 08:37:22 -04:00
commit hash . If there is a newer version it sets SickRage ' s version text.
2014-03-10 01:18:05 -04:00
commit_hash : hash that we ' re checking against
"""
self . _num_commits_behind = 0
self . _newest_commit_hash = None
gh = github . GitHub ( self . github_repo_user , self . github_repo , self . branch )
# try to get newest commit hash and commits behind directly by comparing branch and current commit
if self . _cur_commit_hash :
branch_compared = gh . compare ( base = self . branch , head = self . _cur_commit_hash )
if ' base_commit ' in branch_compared :
self . _newest_commit_hash = branch_compared [ ' base_commit ' ] [ ' sha ' ]
if ' behind_by ' in branch_compared :
self . _num_commits_behind = int ( branch_compared [ ' behind_by ' ] )
# fall back and iterate over last 100 (items per page in gh_api) commits
if not self . _newest_commit_hash :
for curCommit in gh . commits ( ) :
if not self . _newest_commit_hash :
self . _newest_commit_hash = curCommit [ ' sha ' ]
if not self . _cur_commit_hash :
break
if curCommit [ ' sha ' ] == self . _cur_commit_hash :
break
# when _cur_commit_hash doesn't match anything _num_commits_behind == 100
self . _num_commits_behind + = 1
logger . log ( u " cur_commit = " + str ( self . _cur_commit_hash ) + u " , newest_commit = " + str ( self . _newest_commit_hash )
+ u " , num_commits_behind = " + str ( self . _num_commits_behind ) , logger . DEBUG )
def set_newest_text ( self ) :
# if we're up to date then don't set this
sickbeard . NEWEST_VERSION_STRING = None
if not self . _cur_commit_hash :
logger . log ( u " Unknown current version number, don ' t know if we should update or not " , logger . DEBUG )
2014-05-23 08:37:22 -04:00
newest_text = " Unknown current version number: If you ' ve never used the SickRage upgrade system before then current version is not set. "
2014-03-10 01:18:05 -04:00
newest_text + = " — <a href= \" " + self . get_update_url ( ) + " \" >Update Now</a> "
elif self . _num_commits_behind > 0 :
2014-03-25 01:57:24 -04:00
base_url = ' http://github.com/ ' + self . github_repo_user + ' / ' + self . github_repo
if self . _newest_commit_hash :
url = base_url + ' /compare/ ' + self . _cur_commit_hash + ' ... ' + self . _newest_commit_hash
else :
url = base_url + ' /commits/ '
2014-03-10 01:18:05 -04:00
2014-03-25 01:57:24 -04:00
newest_text = ' There is a <a href= " ' + url + ' " onclick= " window.open(this.href); return false; " >newer version available</a> '
newest_text + = " (you ' re " + str ( self . _num_commits_behind ) + " commit "
if self . _num_commits_behind > 1 :
newest_text + = " s "
newest_text + = " behind) " + " — <a href= \" " + self . get_update_url ( ) + " \" >Update Now</a> "
2014-03-10 01:18:05 -04:00
else :
return
sickbeard . NEWEST_VERSION_STRING = newest_text
def update ( self ) :
"""
Downloads the latest source tarball from github and installs it over the existing version .
"""
base_url = ' https://github.com/ ' + self . github_repo_user + ' / ' + self . github_repo
tar_download_url = base_url + ' /tarball/ ' + self . branch
version_path = ek . ek ( os . path . join , sickbeard . PROG_DIR , u ' version.txt ' )
try :
# prepare the update dir
sb_update_dir = ek . ek ( os . path . join , sickbeard . PROG_DIR , u ' sb-update ' )
if os . path . isdir ( sb_update_dir ) :
logger . log ( u " Clearing out update folder " + sb_update_dir + " before extracting " )
shutil . rmtree ( sb_update_dir )
logger . log ( u " Creating update folder " + sb_update_dir + " before extracting " )
os . makedirs ( sb_update_dir )
# retrieve file
logger . log ( u " Downloading update from " + repr ( tar_download_url ) )
tar_download_path = os . path . join ( sb_update_dir , u ' sb-update.tar ' )
urllib . urlretrieve ( tar_download_url , tar_download_path )
if not ek . ek ( os . path . isfile , tar_download_path ) :
logger . log ( u " Unable to retrieve new version from " + tar_download_url + " , can ' t update " , logger . ERROR )
return False
if not ek . ek ( tarfile . is_tarfile , tar_download_path ) :
logger . log ( u " Retrieved version from " + tar_download_url + " is corrupt, can ' t update " , logger . ERROR )
return False
# extract to sb-update dir
logger . log ( u " Extracting file " + tar_download_path )
tar = tarfile . open ( tar_download_path )
tar . extractall ( sb_update_dir )
tar . close ( )
# delete .tar.gz
logger . log ( u " Deleting file " + tar_download_path )
os . remove ( tar_download_path )
# find update dir name
2014-03-25 01:57:24 -04:00
update_dir_contents = [ x for x in os . listdir ( sb_update_dir ) if
os . path . isdir ( os . path . join ( sb_update_dir , x ) ) ]
2014-03-10 01:18:05 -04:00
if len ( update_dir_contents ) != 1 :
logger . log ( u " Invalid update data, update failed: " + str ( update_dir_contents ) , logger . ERROR )
return False
content_dir = os . path . join ( sb_update_dir , update_dir_contents [ 0 ] )
# walk temp folder and move files to main folder
logger . log ( u " Moving files from " + content_dir + " to " + sickbeard . PROG_DIR )
for dirname , dirnames , filenames in os . walk ( content_dir ) : # @UnusedVariable
dirname = dirname [ len ( content_dir ) + 1 : ]
for curfile in filenames :
old_path = os . path . join ( content_dir , dirname , curfile )
new_path = os . path . join ( sickbeard . PROG_DIR , dirname , curfile )
#Avoid DLL access problem on WIN32/64
#These files needing to be updated manually
#or find a way to kill the access from memory
if curfile in ( ' unrar.dll ' , ' unrar64.dll ' ) :
try :
os . chmod ( new_path , stat . S_IWRITE )
os . remove ( new_path )
os . renames ( old_path , new_path )
except Exception , e :
logger . log ( u " Unable to update " + new_path + ' : ' + ex ( e ) , logger . DEBUG )
os . remove ( old_path ) # Trash the updated file without moving in new path
continue
if os . path . isfile ( new_path ) :
os . remove ( new_path )
os . renames ( old_path , new_path )
# update version.txt with commit hash
try :
with open ( version_path , ' w ' ) as ver_file :
ver_file . write ( self . _newest_commit_hash )
except EnvironmentError , e :
logger . log ( u " Unable to write version file, update not complete: " + ex ( e ) , logger . ERROR )
return False
except Exception , e :
logger . log ( u " Error while trying to update: " + ex ( e ) , logger . ERROR )
logger . log ( u " Traceback: " + traceback . format_exc ( ) , logger . DEBUG )
return False
return True