diff options
Diffstat (limited to 'pyload/setup')
-rw-r--r-- | pyload/setup/Setup.py | 414 | ||||
-rw-r--r-- | pyload/setup/__init__.py | 0 | ||||
-rw-r--r-- | pyload/setup/dependencies.py | 83 | ||||
-rw-r--r-- | pyload/setup/system.py | 30 |
4 files changed, 527 insertions, 0 deletions
diff --git a/pyload/setup/Setup.py b/pyload/setup/Setup.py new file mode 100644 index 000000000..c61a389e2 --- /dev/null +++ b/pyload/setup/Setup.py @@ -0,0 +1,414 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +############################################################################### +# Copyright(c) 2008-2013 pyLoad Team +# http://www.pyload.org +# +# This file is part of pyLoad. +# pyLoad is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Subjected to the terms and conditions in LICENSE +# +# @author: RaNaN +############################################################################### + +import os +import sys +import socket +import webbrowser + +from getpass import getpass +from time import time +from sys import exit + +from pyload.utils import pylgettext as gettext +from pyload.utils.fs import abspath, dirname, exists, join, makedirs +from pyload.utils import get_console_encoding +from pyload.web.ServerThread import WebServer + +from system import get_system_info +from dependencies import deps + +class Setup(): + """ + pyLoads initial setup configuration assistant + """ + + @staticmethod + def check_system(): + return get_system_info() + + + @staticmethod + def check_deps(): + result = { + "core": [], + "opt": [] + } + + for d in deps: + avail, v = d.check() + check = { + "name": d.name, + "avail": avail, + "v": v + } + if d.optional: + result["opt"].append(check) + else: + result["core"].append(check) + + return result + + + def __init__(self, path, config): + self.path = path + self.config = config + self.stdin_encoding = get_console_encoding(sys.stdin.encoding) + self.lang = None + self.db = None + + # We will create a timestamp so that the setup will be completed in a specific interval + self.timestamp = time() + + # TODO: probably unneeded + self.yes = "yes" + self.no = "no" + + def start(self): + import __builtin__ + # set the gettext translation + __builtin__._ = lambda x: x + + web = WebServer(pysetup=self) + web.start() + + error = web.check_error() + + # TODO: start cli in this case + if error: #todo errno 44 port already in use + print error + + url = "http://%s:%d/" % (socket.gethostbyname(socket.gethostname()), web.port) + + print "Setup is running at %s" % url + + opened = webbrowser.open_new_tab(url) + if not opened: + print "Please point your browser to the url above." + + cli = self.ask("Use commandline for configuration instead?", self.no, bool=True) + if cli: + print "Not implemented yet!" + print "Use web configuration or config files" + + raw_input() + + return True + + + def start_cli(self): + + self.ask_lang() + + print _("Welcome to the pyLoad Configuration Assistent.") + print _("It will check your system and make a basic setup in order to run pyLoad.") + print "" + print _("The value in brackets [] always is the default value,") + print _("in case you don't want to change it or you are unsure what to choose, just hit enter.") + print _( + "Don't forget: You can always rerun this assistent with --setup or -s parameter, when you start pyLoadCore.") + print _("If you have any problems with this assistent hit CTRL+C,") + print _("to abort and don't let him start with pyLoadCore automatically anymore.") + print "" + print _("When you are ready for system check, hit enter.") + raw_input() + + + # TODO: new system check + deps + + con = self.ask(_("Continue with setup?"), self.yes, bool=True) + + if not con: + return False + + print "" + print _("Do you want to change the config path? Current is %s") % abspath("") + print _( + "If you use pyLoad on a server or the home partition lives on an internal flash it may be a good idea to change it.") + path = self.ask(_("Change config path?"), self.no, bool=True) + if path: + self.conf_path() + #calls exit when changed + + print "" + print _("Do you want to configure login data and basic settings?") + print _("This is recommend for first run.") + con = self.ask(_("Make basic setup?"), self.yes, bool=True) + + if con: + self.conf_basic() + + if ssl: + print "" + print _("Do you want to configure ssl?") + ssl = self.ask(_("Configure ssl?"), self.no, bool=True) + if ssl: + self.conf_ssl() + + print "" + print _("Do you want to configure webinterface?") + web = self.ask(_("Configure webinterface?"), self.yes, bool=True) + if web: + self.conf_web() + + print "" + print _("Setup finished successfully.") + print _("Hit enter to exit and restart pyLoad") + raw_input() + return True + + + def conf_basic(self): + print "" + print _("## Basic Setup ##") + + print "" + print _("The following logindata is valid for CLI, GUI and webinterface.") + + from pyload.database import DatabaseBackend + + db = DatabaseBackend(None) + db.setup() + username = self.ask(_("Username"), "User") + password = self.ask("", "", password=True) + db.addUser(username, password) + db.shutdown() + + print "" + langs = self.config.getMetaData("general", "language") + self.config["general"]["language"] = self.ask(_("Language"), "en", langs.type.split(";")) + + self.config["general"]["download_folder"] = self.ask(_("Download folder"), "Downloads") + self.config["download"]["max_downloads"] = self.ask(_("Max parallel downloads"), "3") + + reconnect = self.ask(_("Use Reconnect?"), self.no, bool=True) + self.config["reconnect"]["activated"] = reconnect + if reconnect: + self.config["reconnect"]["method"] = self.ask(_("Reconnect script location"), "./reconnect.sh") + + + def conf_web(self): + print "" + print _("## Webinterface Setup ##") + + print "" + self.config["webinterface"]["activated"] = self.ask(_("Activate webinterface?"), self.yes, bool=True) + print "" + print _("Listen address, if you use 127.0.0.1 or localhost, the webinterface will only accessible locally.") + self.config["webinterface"]["host"] = self.ask(_("Address"), "0.0.0.0") + self.config["webinterface"]["port"] = self.ask(_("Port"), "8000") + print "" + print _("pyLoad offers several server backends, now following a short explanation.") + print "threaded:", _("Default server, this server offers SSL and is a good alternative to builtin.") + print "fastcgi:", _( + "Can be used by apache, lighttpd, requires you to configure them, which is not too easy job.") + print "lightweight:", _("Very fast alternative written in C, requires libev and linux knowledge.") + print "\t", _("Get it from here: https://github.com/jonashaag/bjoern, compile it") + print "\t", _("and copy bjoern.so to pyload/lib") + + print + print _( + "Attention: In some rare cases the builtin server is not working, if you notice problems with the webinterface") + print _("come back here and change the builtin server to the threaded one here.") + + self.config["webinterface"]["server"] = self.ask(_("Server"), "threaded", + ["builtin", "threaded", "fastcgi", "lightweight"]) + + def conf_ssl(self): + print "" + print _("## SSL Setup ##") + print "" + print _("Execute these commands from pyLoad config folder to make ssl certificates:") + print "" + print "openssl genrsa -out ssl.key 1024" + print "openssl req -new -key ssl.key -out ssl.csr" + print "openssl req -days 36500 -x509 -key ssl.key -in ssl.csr > ssl.crt " + print "" + print _("If you're done and everything went fine, you can activate ssl now.") + self.config["ssl"]["activated"] = self.ask(_("Activate SSL?"), self.yes, bool=True) + + def set_user(self): + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), + languages=[self.config["general"]["language"], "en"], fallback=True) + translation.install(True) + + self.openDB() + + try: + while True: + print _("Select action") + print _("1 - Create/Edit user") + print _("2 - List users") + print _("3 - Remove user") + print _("4 - Quit") + action = raw_input("[1]/2/3/4: ") + if not action in ("1", "2", "3", "4"): + continue + elif action == "1": + print "" + username = self.ask(_("Username"), "User") + password = self.ask("", "", password=True) + self.db.addUser(username, password) + elif action == "2": + print "" + print _("Users") + print "-----" + users = self.db.getAllUserData() + for user in users.itervalues(): + print user.name + print "-----" + print "" + elif action == "3": + print "" + username = self.ask(_("Username"), "") + if username: + self.db.removeUserByName(username) + elif action == "4": + self.db.syncSave() + break + finally: + self.closeDB() + + def addUser(self, username, password): + self.openDB() + try: + self.db.addUser(username, password) + finally: + self.closeDB() + + def openDB(self): + from pyload.database import DatabaseBackend + + if self.db is None: + self.db = DatabaseBackend(None) + self.db.setup() + + def closeDB(self): + if self.db is not None: + self.db.syncSave() + self.db.shutdown() + + def save(self): + self.config.save() + self.closeDB() + + def conf_path(self, trans=False): + if trans: + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), + languages=[self.config["general"]["language"], "en"], fallback=True) + translation.install(True) + + print _("Setting new configpath, current configuration will not be transferred!") + path = self.ask(_("Config path"), abspath("")) + try: + path = join(pypath, path) + if not exists(path): + makedirs(path) + f = open(join(pypath, "pyload", "config", "configdir"), "wb") + f.write(path) + f.close() + print _("Config path changed, setup will now close, please restart to go on.") + print _("Press Enter to exit.") + raw_input() + exit() + except Exception, e: + print _("Setting config path failed: %s") % str(e) + + + def ask_lang(self): + langs = self.config.getMetaData("general", "language").type.split(";") + self.lang = self.ask(u"Choose your Language / Wähle deine Sprache", "en", langs) + gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) + translation = gettext.translation("setup", join(self.path, "locale"), languages=[self.lang, "en"], fallback=True) + translation.install(True) + + #l10n Input shorthand for yes + self.yes = _("y") + #l10n Input shorthand for no + self.no = _("n") + + def ask(self, qst, default, answers=[], bool=False, password=False): + """ Generate dialog on command line """ + + if answers: + info = "(" + for i, answer in enumerate(answers): + info += (", " if i != 0 else "") + str((answer == default and "[%s]" % answer) or answer) + + info += ")" + elif bool: + if default == self.yes: + info = "([%s]/%s)" % (self.yes, self.no) + else: + info = "(%s/[%s])" % (self.yes, self.no) + else: + info = "[%s]" % default + + if password: + p1 = True + p2 = False + while p1 != p2: + # getpass(_("Password: ")) will crash on systems with broken locales (Win, NAS) + sys.stdout.write(_("Password: ")) + p1 = getpass("") + + if len(p1) < 4: + print _("Password too short. Use at least 4 symbols.") + continue + + sys.stdout.write(_("Password (again): ")) + p2 = getpass("") + + if p1 == p2: + return p1 + else: + print _("Passwords did not match.") + + while True: + input = raw_input(qst + " %s: " % info) + input = input.decode(self.stdin_encoding) + + if input.strip() == "": + input = default + + if bool: + #l10n yes, true,t are inputs for booleans with value true + if input.lower().strip() in [self.yes, _("yes"), _("true"), _("t"), "yes"]: + return True + #l10n no, false,f are inputs for booleans with value false + elif input.lower().strip() in [self.no, _("no"), _("false"), _("f"), "no"]: + return False + else: + print _("Invalid Input") + continue + + if not answers: + return input + + else: + if input in answers: + return input + else: + print _("Invalid Input") + + +if __name__ == "__main__": + test = Setup(join(abspath(dirname(__file__)), ".."), None) + test.start() diff --git a/pyload/setup/__init__.py b/pyload/setup/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/pyload/setup/__init__.py diff --git a/pyload/setup/dependencies.py b/pyload/setup/dependencies.py new file mode 100644 index 000000000..f7a0e4ae7 --- /dev/null +++ b/pyload/setup/dependencies.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +import inspect + +# Provide gettext marker +_ = lambda x: x + + +def find_module(name): + from imp import find_module + + try: + f, pathname, desc = find_module(name) + if f is not None: + f.close() + return True + except: + return False + + +class Dependency(object): + name = None + optional = True + desc = None + + @classmethod + def check(cls): + """ Returns (availability, version) as tuple """ + inst = cls() + avail = inst.isStatisfied() + v = None + if avail: + v = inst.getVersion() + + return avail, v + + def isStatisfied(self): + raise NotImplementedError + + def getVersion(self): + return None + + +class Python(Dependency): + name = "Python" + optional = False + + def isStatisfied(self): + # obviously + return True + + def getVersion(self): + import sys + + return ".".join(str(v) for v in sys.version_info[:3]) + + +class JSON(Dependency): + name = "json" + optional = False + + def isStatisfied(self): + return find_module("json") or find_module("simplejson") + + +class PyCurl(Dependency): + name = "pycurl" + optional = False + + def isStatisfied(self): + return find_module("pycurl") + + +class Sqlite(Dependency): + name = "sqlite" + optional = False + + def isStatisfied(self): + return find_module("sqlite3") or find_module("pysqlite2") + +# TODO: ssl, crypto, image, tesseract, js + +deps = [Python, Sqlite, PyCurl, JSON]
\ No newline at end of file diff --git a/pyload/setup/system.py b/pyload/setup/system.py new file mode 100644 index 000000000..dab6d1d17 --- /dev/null +++ b/pyload/setup/system.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- + +import sys +import os + +from new_collections import OrderedDict + +# gettext decorator, translated only when needed +_ = lambda x: x + +# platform usually don't change at runtime +info = None + + +def get_system_info(): + """ Returns system information as dict """ + global info + + if info is None: + import platform + + info = OrderedDict([ + (_("Platform"), platform.platform()), + (_("Version"), sys.version), + (_("Path"), os.path.abspath("")), + (_("Encoding"), sys.getdefaultencoding()), + (_("FS-Encoding"), sys.getfilesystemencoding()) + ]) + + return info
\ No newline at end of file |