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
"""Wrapper for the command line interface."""
import os
from os.path import dirname, isfile
import os
import subprocess
import sys
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:
from couchpotato import cli
except ImportError:
except ImportError, e:
print "Checking local dependencies..."
if isfile(__file__):
cwd = dirname(__file__)
@ -31,12 +36,6 @@ except ImportError:
print "=" * 78
print stderr
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..."
try:
@ -53,4 +52,4 @@ except ImportError:
raise NotImplementedError("Don't know how to do that.")
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
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."""
# Make sure views are imported and registered.
import couchpotato.views
app.run(debug=True)
def cmd_couchpotato(base_path):
'''Commandline entry point.'''
# 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.orm import scoped_session, sessionmaker
from sqlalchemy.schema import ThreadLocalMetaData
from elixir import *
# We would like to be able to create this schema in a specific database at
# will, so we can test it easily.
@ -30,19 +30,19 @@ class Release(Entity):
class File(Entity):
"""File that belongs to a release."""
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
part = Field(Integer)
release = ManyToOne('Release')
# Let's remember the size so we know about offline media.
size = Field(Integer, nullable=False)
size = Field(Integer, nullable = False)
type = ManyToOne('FileType')
class FileType(Entity):
"""Types could be trailer, subtitle, movie, partial movie etc."""
identifier = Field(String(20), unique=True)
name = Field(UnicodeString(255), nullable=False)
identifier = Field(String(20), unique = True)
name = Field(UnicodeString(255), nullable = False)
files = OneToMany('File')

1
logs/__init__.py

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