from __future__ import print_function
import logging
import sys
import os
from os.path import join as joinpath, isdir
import odoo
from odoo.modules import get_modules, get_module_path
commands = {}
"""
元类CommandType.
可以看到Command类里定义了一个空run方法就没了。但由于它的元类是CommandType(注意所有自定义的元类都要继承自type),
在解释器执行到Command类时,先收集代码中定义的Command类的属性,继承列表等,然后由于这里定义了元类,就不是直接调用type来创建一个了类了。
而是会调用元类的new方法,来创建一个类,然后调用元类的init方法。
这里由于CommandType类没有定义new方法,会直接调用其父类也就是type的new方法创建一个类,
然后传给init方法执行初始化。在初始化的时候传入了Command类的属性,装进了commands这个字典里。
稍后到了Help类,由于其继承自Command,也继承了它的元类属性,所以也会执行刚刚Command类创建时的一些操作,
从而也将Help类的一些属性装进了commands里,server.py, shell.py中的继承自Command的类也是如此。
然后后面main方法在遍历commands字典,根据参数取出相应的类来执行其方法。这就实现了一种模式,
任何想要拓展commands的行为,只需要继承Command类,然后定义run方法就行了。感觉很不错的思路。
"""
class CommandType(type):
def __init__(cls, name, bases, attrs):
super(CommandType, cls).__init__(name, bases, attrs)
name = getattr(cls, name, cls.__name__.lower())
cls.name = name
if name != 'command':
commands[name] = cls
Command = CommandType('Command', (object,), {'run': lambda self, args: None})
class Help(Command):
"""Display the list of available commands"""
def run(self, args):
print("Available commands:\n")
names = list(commands)
padding = max([len(k) for k in names]) + 2
for k in sorted(names):
name = k.ljust(padding, ' ')
doc = (commands[k].__doc__ or '').strip()
print(" %s%s" % (name, doc))
print("\nUse '%s <command> --help' for individual command help." % sys.argv[0].split(os.path.sep)[-1])
"""
Main 主要过程:
1.获取系统启动参数
2.获取模块信息并导入
3.根据命令,实例化服务并启动
"""
def main():
args = sys.argv[1:]
# 此处是获取启动参数
# The only shared option is '--addons-path=' needed to discover additional
# commands from modules
"""
一般启动odoo server的时候有多种方式,所需的一些参数我们可以直接在启动命令上带上,
也可以写到配置文件里,然后启动的时候用”-c”指定配置文件就行了.
用得比较多的是启动的时候只指定配置文件,所以以下开发直到 args = args[1:]不会被执行.
"""
if len(args) > 1 and args[0].startswith('--addons-path=') and not args[1].startswith("-"):
# parse only the addons-path, do not setup the logger...
odoo.tools.config._parse_config([args[0]])
args = args[1:]
# Default legacy command # 默认启动命令的方式 为‘server’
command = "server"
# TODO: find a way to properly discover addons subcommands without importing the world
# Subcommand discovery
if len(args) and not args[0].startswith("-"):
logging.disable(logging.CRITICAL)
for module in get_modules(): # 获取模块
if isdir(joinpath(get_module_path(module), 'cli')):
__import__('odoo.addons.' + module) # 导入模块
logging.disable(logging.NOTSET)
command = args[0]
args = args[1:]
if command in commands:
"""
程序执行到这里会发现,command默认值为’server’是会在commands里的.
"""
o = commands[command]() # 获取命令并执行, 实际是实例了一个 Server对象
o.run(args) # 调用Server的run()方法, 程序会执行到odoo.cli.server.main()方法
else:
sys.exit('Unknow command %r' % (command,))