PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/headphones/versioncheck.py

http://github.com/rembo10/headphones
Python | 252 lines | 171 code | 58 blank | 23 comment | 51 complexity | e5e903f18a334d43fdceb11a21ab0e4e MD5 | raw file
Possible License(s): LGPL-2.0, MIT, GPL-2.0, GPL-3.0, BSD-3-Clause
  1. # This file is part of Headphones.
  2. #
  3. # Headphones is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # Headphones is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with Headphones. If not, see <http://www.gnu.org/licenses/>.
  15. import tarfile
  16. import platform
  17. import subprocess
  18. import re
  19. import os
  20. import headphones
  21. from headphones import logger, version, request
  22. def runGit(args):
  23. if headphones.CONFIG.GIT_PATH:
  24. git_locations = ['"' + headphones.CONFIG.GIT_PATH + '"']
  25. else:
  26. git_locations = ['git']
  27. if platform.system().lower() == 'darwin':
  28. git_locations.append('/usr/local/git/bin/git')
  29. output = err = None
  30. for cur_git in git_locations:
  31. cmd = cur_git + ' ' + args
  32. try:
  33. logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR)
  34. p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
  35. shell=True,
  36. cwd=headphones.PROG_DIR)
  37. output, err = p.communicate()
  38. output = output.strip()
  39. logger.debug('Git output: ' + output)
  40. except OSError as e:
  41. logger.debug('Command failed: %s. Error: %s' % (cmd, e))
  42. continue
  43. if 'not found' in output or "not recognized as an internal or external command" in output:
  44. logger.debug('Unable to find git with command ' + cmd)
  45. output = None
  46. elif 'fatal:' in output or err:
  47. logger.error('Git returned bad info. Are you sure this is a git installation?')
  48. output = None
  49. elif output:
  50. break
  51. return (output, err)
  52. def getVersion():
  53. if version.HEADPHONES_VERSION.startswith('win32build'):
  54. headphones.INSTALL_TYPE = 'win'
  55. # Don't have a way to update exe yet, but don't want to set VERSION to None
  56. return 'Windows Install', 'master'
  57. elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')):
  58. headphones.INSTALL_TYPE = 'git'
  59. output, err = runGit('rev-parse HEAD')
  60. if not output:
  61. logger.error('Couldn\'t find latest installed version.')
  62. cur_commit_hash = None
  63. cur_commit_hash = str(output)
  64. if not re.match('^[a-z0-9]+$', cur_commit_hash):
  65. logger.error('Output doesn\'t look like a hash, not using it')
  66. cur_commit_hash = None
  67. if headphones.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and headphones.CONFIG.GIT_BRANCH:
  68. branch_name = headphones.CONFIG.GIT_BRANCH
  69. else:
  70. branch_name, err = runGit('rev-parse --abbrev-ref HEAD')
  71. branch_name = branch_name
  72. if not branch_name and headphones.CONFIG.GIT_BRANCH:
  73. logger.error(
  74. 'Could not retrieve branch name from git. Falling back to %s' % headphones.CONFIG.GIT_BRANCH)
  75. branch_name = headphones.CONFIG.GIT_BRANCH
  76. if not branch_name:
  77. logger.error('Could not retrieve branch name from git. Defaulting to master')
  78. branch_name = 'master'
  79. return cur_commit_hash, branch_name
  80. else:
  81. headphones.INSTALL_TYPE = 'source'
  82. version_file = os.path.join(headphones.PROG_DIR, 'version.txt')
  83. if not os.path.isfile(version_file):
  84. return None, 'master'
  85. with open(version_file, 'r') as f:
  86. current_version = f.read().strip(' \n\r')
  87. if current_version:
  88. return current_version, headphones.CONFIG.GIT_BRANCH
  89. else:
  90. return None, 'master'
  91. def checkGithub():
  92. headphones.COMMITS_BEHIND = 0
  93. # Get the latest version available from github
  94. logger.info('Retrieving latest version information from GitHub')
  95. url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (
  96. headphones.CONFIG.GIT_USER, headphones.CONFIG.GIT_BRANCH)
  97. version = request.request_json(url, timeout=20, validator=lambda x: type(x) == dict)
  98. if version is None:
  99. logger.warn(
  100. 'Could not get the latest version from GitHub. Are you running a local development version?')
  101. return headphones.CURRENT_VERSION
  102. headphones.LATEST_VERSION = version['sha']
  103. logger.debug("Latest version is %s", headphones.LATEST_VERSION)
  104. # See how many commits behind we are
  105. if not headphones.CURRENT_VERSION:
  106. logger.info(
  107. 'You are running an unknown version of Headphones. Run the updater to identify your version')
  108. return headphones.LATEST_VERSION
  109. if headphones.LATEST_VERSION == headphones.CURRENT_VERSION:
  110. logger.info('Headphones is up to date')
  111. return headphones.LATEST_VERSION
  112. logger.info('Comparing currently installed version with latest GitHub version')
  113. url = 'https://api.github.com/repos/%s/headphones/compare/%s...%s' % (
  114. headphones.CONFIG.GIT_USER, headphones.LATEST_VERSION, headphones.CURRENT_VERSION)
  115. commits = request.request_json(url, timeout=20, whitelist_status_code=404,
  116. validator=lambda x: type(x) == dict)
  117. if commits is None:
  118. logger.warn('Could not get commits behind from GitHub.')
  119. return headphones.LATEST_VERSION
  120. try:
  121. headphones.COMMITS_BEHIND = int(commits['behind_by'])
  122. logger.debug("In total, %d commits behind", headphones.COMMITS_BEHIND)
  123. except KeyError:
  124. logger.info('Cannot compare versions. Are you running a local development version?')
  125. headphones.COMMITS_BEHIND = 0
  126. if headphones.COMMITS_BEHIND > 0:
  127. logger.info(
  128. 'New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND)
  129. elif headphones.COMMITS_BEHIND == 0:
  130. logger.info('Headphones is up to date')
  131. return headphones.LATEST_VERSION
  132. def update():
  133. if headphones.INSTALL_TYPE == 'win':
  134. logger.info('Windows .exe updating not supported yet.')
  135. elif headphones.INSTALL_TYPE == 'git':
  136. output, err = runGit('pull origin ' + headphones.CONFIG.GIT_BRANCH)
  137. if not output:
  138. logger.error('Couldn\'t download latest version')
  139. for line in output.split('\n'):
  140. if 'Already up-to-date.' in line:
  141. logger.info('No update available, not updating')
  142. logger.info('Output: ' + str(output))
  143. elif line.endswith('Aborting.'):
  144. logger.error('Unable to update from git: ' + line)
  145. logger.info('Output: ' + str(output))
  146. else:
  147. tar_download_url = 'https://github.com/%s/headphones/tarball/%s' % (
  148. headphones.CONFIG.GIT_USER, headphones.CONFIG.GIT_BRANCH)
  149. update_dir = os.path.join(headphones.PROG_DIR, 'update')
  150. version_path = os.path.join(headphones.PROG_DIR, 'version.txt')
  151. logger.info('Downloading update from: ' + tar_download_url)
  152. data = request.request_content(tar_download_url)
  153. if not data:
  154. logger.error("Unable to retrieve new version from '%s', can't update", tar_download_url)
  155. return
  156. download_name = headphones.CONFIG.GIT_BRANCH + '-github'
  157. tar_download_path = os.path.join(headphones.PROG_DIR, download_name)
  158. # Save tar to disk
  159. with open(tar_download_path, 'wb') as f:
  160. f.write(data)
  161. # Extract the tar to update folder
  162. logger.info('Extracting file: ' + tar_download_path)
  163. tar = tarfile.open(tar_download_path)
  164. tar.extractall(update_dir)
  165. tar.close()
  166. # Delete the tar.gz
  167. logger.info('Deleting file: ' + tar_download_path)
  168. os.remove(tar_download_path)
  169. # Find update dir name
  170. update_dir_contents = [x for x in os.listdir(update_dir) if
  171. os.path.isdir(os.path.join(update_dir, x))]
  172. if len(update_dir_contents) != 1:
  173. logger.error("Invalid update data, update failed: " + str(update_dir_contents))
  174. return
  175. content_dir = os.path.join(update_dir, update_dir_contents[0])
  176. # walk temp folder and move files to main folder
  177. for dirname, dirnames, filenames in os.walk(content_dir):
  178. dirname = dirname[len(content_dir) + 1:]
  179. for curfile in filenames:
  180. old_path = os.path.join(content_dir, dirname, curfile)
  181. new_path = os.path.join(headphones.PROG_DIR, dirname, curfile)
  182. if os.path.isfile(new_path):
  183. os.remove(new_path)
  184. os.renames(old_path, new_path)
  185. # Update version.txt
  186. try:
  187. with open(version_path, 'w') as f:
  188. f.write(str(headphones.LATEST_VERSION))
  189. except IOError as e:
  190. logger.error(
  191. "Unable to write current version to version.txt, update not complete: %s",
  192. e
  193. )
  194. return