Перезапуск самообновляющегося скрипта Python
Я написал скрипт, который будет обновляться, загружая последнюю версию с веб-сайта и перезаписывая работающий скрипт.
Я не уверен, что лучший способ перезапустить скрипт после его обновления.
Есть идеи?
Я действительно не хочу иметь отдельный скрипт обновления. о, и это должно работать на обоих linux/windows тоже.
8 ответов
В Linux или любой другой форме unix, os.execl и друзья - хороший выбор для этого - вам просто нужно повторно выполнить sys.executable с теми же параметрами, которые были выполнены в прошлый раз (sys.argv
(более или менее) или любой другой вариант, если вам нужно сообщить вашему следующему воплощению, что это на самом деле перезапуск. В Windows os.spawnl (и друзья) - это лучшее, что вы можете сделать (хотя на переходный период это займет больше времени и памяти, чем os.execl и друзья).
Проект CherryPy имеет код, который перезапускается сам. Вот как они это делают:
args = sys.argv[:]
self.log('Re-spawning %s' % ' '.join(args))
args.insert(0, sys.executable)
if sys.platform == 'win32':
args = ['"%s"' % arg for arg in args]
os.chdir(_startup_cwd)
os.execv(sys.executable, args)
Я использовал эту технику в своем собственном коде, и она прекрасно работает. (Я не удосужился выполнить шаг цитирования аргументов в окнах выше, но, вероятно, это необходимо, если аргументы могут содержать пробелы или другие специальные символы.)
Я думаю, что лучшим решением будет что-то вроде этого:
Ваша обычная программа:
...
# ... part that downloaded newest files and put it into the "newest" folder
from subprocess import Popen
Popen("/home/code/reloader.py", shell=True) # start reloader
exit("exit for updating all files")
Сценарий обновления: (например, home/code/reloader.py)
from shutil import copy2, rmtree
from sys import exit
# maybie you could do this automatic:
copy2("/home/code/newest/file1.py", "/home/code/") # copy file
copy2("/home/code/newest/file2.py", "/home/code/")
copy2("/home/code/newest/file3.py", "/home/code/")
...
rmtree('/home/code/newest') # will delete the folder itself
Popen("/home/code/program.py", shell=True) # go back to your program
exit("exit to restart the true program")
Я надеюсь, что это поможет вам.
Самое чистое решение - это отдельный скрипт обновления!
Запустите вашу программу внутри нее, сообщите (при выходе), что доступна новая версия. Это позволяет вашей программе сохранить все свои данные, средство обновления применяет обновление и запускает новую версию, которая затем загружает сохраненные данные и продолжает работу. Для пользователей это может быть абсолютно прозрачно, поскольку они просто запускают оболочку обновления, которая запускает настоящую программу.
У команды pocoo есть очень хороший перегрузчик для своего сервера разработки внутри werkzueg. Проверьте код здесь (это к нижней части файла).
Для дополнительной поддержки вызовов сценариев с параметром Python "-m" может использоваться следующее (в зависимости от ответа Алекса; версия для Windows):
os.spawnl(os.P_WAIT, sys.executable, *([sys.executable] +
(sys.argv if __package__ is None else ["-m", __loader__.name] + sys.argv[1:])))
sys.exit()
Разве не было бы проще сделать что-то вроде очень простого, без необходимости в дополнительном импорте и совместимого с любой ОС в зависимости от того, что вы вводите в поле os.system
def restart_program():
print("Restarting Now...")
os.system('your program here')
Основной файл:
if __name__ == '__main__':
if os.path.isfile('__config.py'):
print 'Development'
push.update_server()
else:
e = update.check()
if not e: sys.exit()
Обновить файл:
def check():
e = 1.....perform checks, if something needs updating, e=0;
if not e:
os.system("python main.pyw")
return e
Вот логика:
Основная программа вызывает функцию обновления
1) Если функция обновления требует обновления, то она обновляет и вызывает новые экземпляры "main"
Затем исходный экземпляр "основного" выхода.
2) Если функция обновления не нуждается в обновлении, то "основной" продолжает работать
Вы можете использовать перезагрузку (модуль) для перезагрузки модуля.