Skip to content

Commit

Permalink
Merge branch 'master' into plaidml
Browse files Browse the repository at this point in the history
  • Loading branch information
torzdf committed Jun 23, 2019
2 parents dd795ba + 79a6100 commit 68d6862
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 9 deletions.
3 changes: 2 additions & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,11 @@ A desktop shortcut can be added to easily launch straight into the faceswap GUI:

## Updating faceswap
It's good to keep faceswap up to date as new features are added and bugs are fixed. To do so:
- If using the GUI you can go to the Tools Menu and select "Check for Updates...". This will update Faceswap to the latest code and update your dependencies.
- If you are not already in your virtual environment follow [these steps](#entering-your-virtual-environment)
- Enter the faceswap folder: `cd faceswap`
- Enter the following `git pull --all`
- Once the latest version has downloaded, make sure your requirements are up to date: `pip install --upgrade -r requirements.txt`
- Once the latest version has downloaded, make sure your dependencies are up to date. There is a script to help with this: `python update_deps.py`

# General Install Guide
## Installing dependencies
Expand Down
21 changes: 13 additions & 8 deletions lib/gui/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lib.multithreading import MultiThread
from lib.Serializer import JSONSerializer

import update_deps
from .utils import get_config
from .popup_configure import popup_config

Expand Down Expand Up @@ -188,16 +189,20 @@ def output_sysinfo(self):

def update(self):
""" Check for updates and clone repo """
logger.debug("Updating Faceswap")
logger.debug("Updating Faceswap...")
self.root.config(cursor="watch")
self.clear_console()
encoding = locale.getpreferredencoding()
logger.debug("Encoding: %s", encoding)
success = False
if self.check_for_updates(encoding):
self.do_update(encoding)
success = self.do_update(encoding)
update_deps.main(logger=logger)
if success:
logger.info("Please restart Faceswap to complete the update.")
self.root.config(cursor="")

def check_for_updates(self, encoding):
@staticmethod
def check_for_updates(encoding):
""" Check whether an update is required """
# Do the check
logger.info("Checking for updates...")
Expand Down Expand Up @@ -227,7 +232,6 @@ def check_for_updates(self, encoding):
if "have diverged" in line.lower():
msg = "Your branch has diverged from the remote repo. Not updating"
break
self.clear_console()
if not update:
logger.info(msg)
logger.debug("Checked for update. Update required: %s", update)
Expand All @@ -249,7 +253,8 @@ def do_update(encoding):
retcode = cmd.poll()
logger.debug("'%s' returncode: %s", gitcmd, retcode)
if retcode != 0:
msg = "An error occurred during update. return code: {}".format(retcode)
logger.info("An error occurred during update. return code: %s", retcode)
retval = False
else:
msg = "Please restart Faceswap to complete the update."
logger.info(msg)
retval = True
return retval
14 changes: 14 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ def check_missing_dep(self):
if self.env.enable_cuda and self.env.is_macos:
self.env.required_packages.extend(self.env.macos_required_packages)
for pkg in self.env.required_packages:
pkg = self.check_os_requirements(pkg)
key = pkg.split("==")[0]
if key not in self.env.installed_packages:
self.env.missing_packages.append(pkg)
Expand All @@ -550,6 +551,19 @@ def check_missing_dep(self):
self.env.missing_packages.append(pkg)
continue

@staticmethod
def check_os_requirements(package):
""" Check that the required package is required for this OS """
if ";" not in package and "sys_platform" not in package:
return package
package = "".join(package.split())
pkg, tags = package.split(";")
tags = tags.split("==")
sys_platform = tags[tags.index("sys_platform") + 1].replace('"', "").replace("'", "")
if sys_platform == sys.platform:
return pkg
return None

def check_conda_missing_dep(self):
""" Check for conda missing dependencies """
if not self.env.is_conda:
Expand Down
192 changes: 192 additions & 0 deletions update_deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#!/usr/bin/env python3
""" Installs any required third party libs for faceswap.py
Checks for installed Conda / Pip packages and updates accordingly
"""

import locale
import os
import re
import sys
import ctypes

from subprocess import CalledProcessError, run, PIPE, Popen

_LOGGER = None


class Environment():
""" Hold information about the running environment """
def __init__(self):
self.is_conda = "conda" in sys.version.lower()
self.encoding = locale.getpreferredencoding()
self.is_admin = self.get_admin_status()
self.is_virtualenv = self.get_virtualenv
required_packages = self.get_required_packages()
self.installed_packages = self.get_installed_packages()
self.get_installed_conda_packages()
self.packages_to_install = self.get_packages_to_install(required_packages)

@staticmethod
def get_admin_status():
""" Check whether user is admin """
try:
retval = os.getuid() == 0
except AttributeError:
retval = ctypes.windll.shell32.IsUserAnAdmin() != 0
return retval

def get_virtualenv(self):
""" Check whether this is a virtual environment """
if not self.is_conda:
retval = (hasattr(sys, "real_prefix") or
(hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix))
else:
prefix = os.path.dirname(sys.prefix)
retval = (os.path.basename(prefix) == "envs")
return retval

@staticmethod
def get_required_packages():
""" Load requirements list """
packages = list()
pypath = os.path.dirname(os.path.realpath(__file__))
requirements_file = os.path.join(pypath, "requirements.txt")
with open(requirements_file) as req:
for package in req.readlines():
package = package.strip()
if package and (not package.startswith("#")):
packages.append(package)
return packages

def get_installed_packages(self):
""" Get currently installed packages """
installed_packages = dict()
chk = Popen("\"{}\" -m pip freeze".format(sys.executable),
shell=True, stdout=PIPE)
installed = chk.communicate()[0].decode(self.encoding).splitlines()

for pkg in installed:
if "==" not in pkg:
continue
item = pkg.split("==")
installed_packages[item[0]] = item[1]
return installed_packages

def get_installed_conda_packages(self):
""" Get currently installed conda packages """
if not self.is_conda:
return
chk = os.popen("conda list").read()
installed = [re.sub(" +", " ", line.strip())
for line in chk.splitlines() if not line.startswith("#")]
for pkg in installed:
item = pkg.split(" ")
self.installed_packages[item[0]] = item[1]

def get_packages_to_install(self, required_packages):
""" Get packages which need installing, upgrading or downgrading """
to_install = list()
for pkg in required_packages:
pkg = self.check_os_requirement(pkg)
if pkg is None:
continue
key = pkg.split("==")[0]
if key not in self.installed_packages:
to_install.append(pkg)
else:
if (len(pkg.split("==")) > 1 and
pkg.split("==")[1] != self.installed_packages.get(key)):
to_install.append(pkg)
return to_install

@staticmethod
def check_os_requirement(package):
""" Check whether this package is required for this OS """
if ";" not in package and "sys_platform" not in package:
return package
package = "".join(package.split())
pkg, tags = package.split(";")
tags = tags.split("==")
sys_platform = tags[tags.index("sys_platform") + 1].replace('"', "").replace("'", "")
if sys_platform == sys.platform:
return pkg
return None


class Installer():
""" Install packages through Conda or Pip """
def __init__(self, environment):
self.packages = environment.packages_to_install
self.env = environment
self.install()

def install(self):
""" Install required pip packages """
success = True
for pkg in self.packages:
output("Installing {}".format(pkg))
if self.env.is_conda and self.conda_install(pkg):
continue
if not self.pip_install(pkg):
success = False
if not success:
output("There were problems updating one or more dependencies.")
else:
output("Dependencies succesfully updated.")

@staticmethod
def conda_install(package):
""" Install a conda package """
success = True
condaexe = ["conda", "install", "-y", package]
try:
with open(os.devnull, "w") as devnull:
run(condaexe, stdout=devnull, stderr=devnull, check=True)
except CalledProcessError:
output("{} not available in Conda. Installing with pip...".format(package))
success = False
return success

def pip_install(self, package):
""" Install a pip package """
success = True
pipexe = [sys.executable, "-m", "pip"]
# hide info/warning and fix cache hang
pipexe.extend(["install", "-qq", "--no-cache-dir"])
# install as user to solve perm restriction
if not self.env.is_admin and not self.env.is_virtualenv:
pipexe.append("--user")
pipexe.append(package)
try:
run(pipexe, check=True)
except CalledProcessError:
output("Couldn't install {}. Please install this package manually".format(package))
success = False
return success


def output(msg):
""" Output to print or logger """
if _LOGGER is not None:
_LOGGER.info(msg)
else:
print(msg)


def main(logger=None):
""" Check for and update dependencies """
if logger is not None:
global _LOGGER # pylint:disable=global-statement
_LOGGER = logger
output("Updating Dependencies...")
update = Environment()
packages = update.packages_to_install
if not packages:
output("All Dependencies are up to date")
else:
Installer(update)


if __name__ == "__main__":
main()

0 comments on commit 68d6862

Please sign in to comment.