Browse Source

Restructuring

Logging
Basic config loading from plugins/providers
pull/1/merge
Ruud 14 years ago
parent
commit
722731c8bc
  1. 2
      .gitignore
  2. 17
      CouchPotato.py
  3. 58
      couchpotato/cli.py
  4. 9
      couchpotato/core/__init__.py
  5. 21
      couchpotato/core/logger.py
  6. 1
      couchpotato/core/plugins/__init__.py
  7. 4
      couchpotato/core/plugins/renamer/__init__.py
  8. 0
      couchpotato/core/providers/__init__.py
  9. 3
      couchpotato/core/providers/tmdb/__init__.py
  10. 74
      couchpotato/settings/__init__.py
  11. 0
      couchpotato/settings/db.py
  12. 47
      couchpotato/settings/loader.py
  13. 12
      couchpotato/settings/model.py
  14. 1
      logs/__init__.py

2
.gitignore

@ -0,0 +1,2 @@
/settings.conf
/logs/*.log

17
CouchPotato.py

@ -1,16 +1,21 @@
#!/usr/bin/env python #!/usr/bin/env python
"""Wrapper for the command line interface.""" """Wrapper for the command line interface."""
import os
from os.path import dirname, isfile from os.path import dirname, isfile
import os
import subprocess import subprocess
import sys import sys
import traceback import traceback
# Root path
base_path = dirname(os.path.abspath(__file__))
# Insert local directories into path
sys.path.insert(0, os.path.join(base_path, 'libs'))
try: try:
from couchpotato import cli from couchpotato import cli
except ImportError: except ImportError, e:
print "Checking local dependencies..." print "Checking local dependencies..."
if isfile(__file__): if isfile(__file__):
cwd = dirname(__file__) cwd = dirname(__file__)
@ -31,12 +36,6 @@ except ImportError:
print "=" * 78 print "=" * 78
print stderr print stderr
print "=" * 78 print "=" * 78
print "Registering libraries..."
# Insert local directories into path
lib_path = os.path.join(os.path.abspath(cwd), 'libs')
src_path = os.path.join(os.path.abspath(cwd), 'src')
sys.path.insert(0, lib_path)
sys.path.insert(0, src_path)
print "Passing execution to couchpotato..." print "Passing execution to couchpotato..."
try: try:
@ -53,4 +52,4 @@ except ImportError:
raise NotImplementedError("Don't know how to do that.") raise NotImplementedError("Don't know how to do that.")
if __name__ == "__main__": if __name__ == "__main__":
cli.cmd_couchpotato() cli.cmd_couchpotato(base_path)

58
couchpotato/cli.py

@ -1,8 +1,54 @@
from blinker import signal
from couchpotato import app from couchpotato import app
import argparse from couchpotato.settings import Settings
from logging import handlers
from optparse import OptionParser
import logging
import os.path
import sys
def cmd_couchpotato():
"""Commandline entry point.""" def cmd_couchpotato(base_path):
# Make sure views are imported and registered. '''Commandline entry point.'''
import couchpotato.views
app.run(debug=True) # Options
parser = OptionParser('usage: %prog [options]')
parser.add_option('-l', '--logdir', dest = 'logdir', default = 'logs', help = 'log DIRECTORY (default ./logs)')
parser.add_option('-t', '--test', '--debug', action = 'store_true', dest = 'debug', help = 'Debug mode')
parser.add_option('-q', '--quiet', action = 'store_true', dest = 'quiet', help = "Don't log to console")
parser.add_option('-d', '--daemon', action = 'store_true', dest = 'daemon', help = 'Daemonize the app')
(options, args) = parser.parse_args(sys.argv[1:])
# Register settings
settings = Settings('settings.conf')
register = signal('settings_register')
register.connect(settings.registerDefaults)
debug = options.debug or settings.get('environment') == 'development'
# Logger
logger = logging.getLogger()
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%H:%M:%S')
level = logging.DEBUG if debug else logging.INFO
logger.setLevel(level)
# Output logging information to screen
if not options.quiet:
hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
# Output logging information to file
hdlr2 = handlers.RotatingFileHandler(os.path.join(options.logdir, 'CouchPotato.log'), 'a', 5000000, 4)
hdlr2.setFormatter(formatter)
logger.addHandler(hdlr2)
# Load config
from couchpotato.settings.loader import SettingsLoader
SettingsLoader(root = base_path)
# Create app
app.run(host = settings.get('host'), port = int(settings.get('port')), debug = debug)

9
couchpotato/core/__init__.py

@ -0,0 +1,9 @@
config = ('global', {
'environment': 'production',
'host': '0.0.0.0',
'port': 5000,
'username': '',
'password': '',
'launch_browser': True,
'url_base': '',
})

21
couchpotato/core/logger.py

@ -0,0 +1,21 @@
from couchpotato import app
class CPLog():
context = ''
def __init__(self, context = ''):
self.context = context
self.logger = app.logger
def info(self, msg):
self.logger.info(self.addContext(msg))
def debug(self, msg):
self.logger.debug(self.addContext(msg))
def error(self, msg):
self.logger.error(self.addContext(msg))
def addContext(self, msg):
return '[%+25.25s] %s' % (self.context[-25:], msg)

1
couchpotato/core/plugins/__init__.py

@ -0,0 +1 @@

4
couchpotato/core/plugins/renamer/__init__.py

@ -0,0 +1,4 @@
config = ('Renamer', {
'enabled': False,
'cleanup': False
})

0
couchpotato/core/providers/__init__.py

3
couchpotato/core/providers/tmdb/__init__.py

@ -0,0 +1,3 @@
config = ('TheMovieDB', {
'key': '9b939aee0aaafc12a65bf448e4af9543'
})

74
couchpotato/settings/__init__.py

@ -0,0 +1,74 @@
from __future__ import with_statement
from blinker import signal, Signal
from couchpotato.core.logger import CPLog
import ConfigParser
import time
log = CPLog(__name__)
settings = signal('settings_register')
class Settings():
on_save = Signal()
on_register = Signal()
bool = {'true':True, 'false':False}
def __init__(self, file):
self.file = file
self.p = ConfigParser.RawConfigParser()
self.p.read(file)
def parser(self):
return self.p
def sections(self):
return self.s
def registerDefaults(self, section_name, options):
self.addSection(section_name)
for option, value in options.iteritems():
self.setDefault(section_name, option, value)
log.debug('Registered defaults %s: %s' % (section_name, options))
self.on_register.send(self)
self.save()
def set(self, section, option, value):
return self.p.set(section, option, value)
def get(self, option = '', section = 'global'):
value = self.p.get(section, option)
if(self.is_int(value)):
return int(value)
if str(value).lower() in self.bool:
return self.bool.get(str(value).lower())
return value if type(value) != str else value.strip()
def is_int(self, value):
try:
int(value)
return True
except ValueError:
return False
def save(self):
with open(self.file, 'wb') as configfile:
self.p.write(configfile)
log.debug('Saved settings')
self.on_save.send(self)
def addSection(self, section):
if not self.p.has_section(section):
self.p.add_section(section)
def setDefault(self, section, option, value):
if not self.p.has_option(section, option):
self.p.set(section, option, value)

0
couchpotato/db.py → couchpotato/settings/db.py

47
couchpotato/settings/loader.py

@ -0,0 +1,47 @@
from blinker import signal
from couchpotato.core.logger import CPLog
import glob
import os
import sys
log = CPLog(__name__)
class SettingsLoader:
def __init__(self, root = ''):
self.register = signal('settings_register')
self.paths = {
'plugins' : ('couchpotato.core.plugins', os.path.join(root, 'couchpotato', 'core', 'plugins')),
'providers' : ('couchpotato.core.providers', os.path.join(root, 'couchpotato', 'core', 'providers')),
}
for type, tuple in self.paths.iteritems():
self.loadFromDir(tuple[0], tuple[1])
def loadFromDir(self, module, dir):
for file in glob.glob(os.path.join(dir, '*')):
plugin_name = os.path.basename(file)
plugin_dir = os.path.join(dir, plugin_name)
if os.path.isdir(plugin_dir):
self.loadConfig(module, plugin_name)
def loadConfig(self, module, name):
module_name = '%s.%s' % (module, name)
try:
m = getattr(self.loadModule(module_name), name)
(section, options) = m.config
self.register.send(section, options = options)
except:
log.error("Failed loading config for %s" % name)
def loadModule(self, name):
try:
m = __import__(name)
splitted = name.split('.')
for sub in splitted[1:-1]:
m = getattr(m, sub)
return m
except:
raise

12
couchpotato/model.py → couchpotato/settings/model.py

@ -1,7 +1,7 @@
from sqlalchemy.orm import scoped_session, sessionmaker from elixir import *
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.schema import ThreadLocalMetaData from sqlalchemy.schema import ThreadLocalMetaData
from elixir import *
# We would like to be able to create this schema in a specific database at # We would like to be able to create this schema in a specific database at
# will, so we can test it easily. # will, so we can test it easily.
@ -30,19 +30,19 @@ class Release(Entity):
class File(Entity): class File(Entity):
"""File that belongs to a release.""" """File that belongs to a release."""
history = OneToMany('RenameHistory') history = OneToMany('RenameHistory')
path = Field(UnicodeString(255), nullable=False, unique=True) path = Field(UnicodeString(255), nullable = False, unique = True)
# Subtitles can have multiple parts, too # Subtitles can have multiple parts, too
part = Field(Integer) part = Field(Integer)
release = ManyToOne('Release') release = ManyToOne('Release')
# Let's remember the size so we know about offline media. # Let's remember the size so we know about offline media.
size = Field(Integer, nullable=False) size = Field(Integer, nullable = False)
type = ManyToOne('FileType') type = ManyToOne('FileType')
class FileType(Entity): class FileType(Entity):
"""Types could be trailer, subtitle, movie, partial movie etc.""" """Types could be trailer, subtitle, movie, partial movie etc."""
identifier = Field(String(20), unique=True) identifier = Field(String(20), unique = True)
name = Field(UnicodeString(255), nullable=False) name = Field(UnicodeString(255), nullable = False)
files = OneToMany('File') files = OneToMany('File')

1
logs/__init__.py

@ -0,0 +1 @@
Loading…
Cancel
Save