命令启动odoo
./odoo-bin --addons-path=addons,./myproject -d dev12 -u library_app
./myproject
自己定义的模块目录
odoo.cli.main()
程序入口
根据程序入口找到odoo/cli/command.py
里面的def main()
函数
def main():
args = sys.argv[1:]
# 根据输入的启动命令 args:['--addons-path=addons,./myproject', '-d', 'dev12', '-u', 'library_app']
# The only shared option is '--addons-path=' needed to discover additional
# commands from modules
if len(args) > 1 and args[0].startswith('--addons-path=') and not args[1].startswith("-"):
# 只分析加载项路径,不设置记录器…
odoo.tools.config._parse_config([args[0]])
args = args[1:]
# args[0]:--addons-path=addons,./myproject, args[1]开头为- 所以条件不成立
# 默认的 command
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) # 禁用等级为CRITICAL的日志
# get_modules()为返回模块名称列表
for module in get_modules():
#isdir 判断是否为目录
if isdir(joinpath(get_module_path(module), 'cli')):
__import__('odoo.addons.' + module)
# 这里的条件是不成立的
logging.disable(logging.NOTSET)
command = args[0]
args = args[1:]
# 这里commands为{'help': <class 'odoo.cli.command.Help'>, 'scaffold': <class 'odoo.cli.scaffold.Scaffold'>,
# 'deploy': <class 'odoo.cli.deploy.Deploy'>, 'shell': <class 'odoo.cli.shell.Shell'>, 'server': <class 'odoo.cli.server.Server'>, 'start': <class 'odoo.cli.start.Start'>}
if command in commands: # server在其中条件成立
o = commands[command]() # 运行得知o为<odoo.cli.server.Server object at 0x7fb3513f1ef0>
o.run(args) # 调用cli下的Server.py 文件中的Server方法下的run函数
else:
sys.exit('Unknow command %r' % (command,))
接下来继续运行run()
函数
class Server(Command):
"""Start the odoo server (default command)"""
def run(self, args):
main(args)
从run()
函数了解到接下来要运行main()
函数
def main(args):
check_root_user() # 判断是否为POSIX系统中的root用户
# 如果是的话 则判断当前用户是否为root,因为使用系统用户root作为odoo的user是一个不安全的做法
odoo.tools.config.parse_config(args) # 解析配置文件和命令行参数,这里是将所有的命令添加到Python包里
check_postgres_user() # 检测到用户是‘postgres’会拒绝登陆,并且弹出错误信息
report_configuration() # 日志输出 odoo的版本,配置文件路径,插件路径,数据库信息(user,host,port);该方法假定配置已被初始化:
config = odoo.tools.config
# the default limit for CSV fields in the module is 128KiB, which is not
# quite sufficient to import images to store in attachment. 500MiB is a
# bit overkill, but better safe than sorry I guess
csv.field_size_limit(500 * 1024 * 1024) # 设置csv文件的大小
preload = []
if config['db_name']: # config['db_name']:dev12
preload = config['db_name'].split(',') # preload:dev12
for db_name in preload:
try:
#创建一个名为dev12的数据库
odoo.service.db._create_empty_database(db_name)
config['init']['base'] = True
except ProgrammingError as err:
if err.pgcode == errorcodes.INSUFFICIENT_PRIVILEGE:
# We use an INFO loglevel on purpose in order to avoid
# reporting unnecessary warnings on build environment
# using restricted database access.
_logger.info("Could not determine if database %s exists, "
"skipping auto-creation: %s", db_name, err)
else:
raise err
except odoo.service.db.DatabaseExists:
pass
if config["translate_out"]: # 为空 False
export_translation()
sys.exit(0)
if config["translate_in"]: # 为空 False
import_translation()
sys.exit(0)
# This needs to be done now to ensure the use of the multiprocessing
# signaling mecanism for registries loaded with -d
if config['workers']: # 0
odoo.multi_process = True
stop = config["stop_after_init"] # stop = False
setup_pid_file() # 使用写入的进程ID创建文件
# 接着开始调用odoo/service/server.py 文件
rc = odoo.service.server.start(preload=preload, stop=stop)
sys.exit(rc)
接着开始start()
函数的运行
def start(preload=None, stop=False):
""" 启动odoo HTTP服务器和cron处理器.
"""
global server # 设置全局变量server
load_server_wide_modules() # 加载openerp模块 如:base,web
# 将它们转换为str,以便在python 2和python 3之间具有一致的行为
odoo.service.wsgi_server._patch_xmlrpc_marshaller()
if odoo.evented: # odoo下的evented为False不成立
server = GeventServer(odoo.service.wsgi_server.application)
elif config['workers']: # Fales不成立
if config['test_enable'] or config['test_file']:
_logger.warning("Unit testing in workers mode could fail; use --workers 0.")
server = PreforkServer(odoo.service.wsgi_server.application)
# Workaround for Python issue24291, fixed in 3.6 (see Python issue26721)
if sys.version_info[:2] == (3,5):
# turn on buffering also for wfile, to avoid partial writes (Default buffer = 8k)
werkzeug.serving.WSGIRequestHandler.wbufsize = -1
else:
# 进入到这里,创建一个线程
server = ThreadedServer(odoo.service.wsgi_server.application)
watcher = None
if 'reload' in config['dev_mode'] and not odoo.evented # config['dev_mode']为空条件不成立
if inotify:
watcher = FSWatcherInotify()
watcher.start()
elif watchdog:
watcher = FSWatcherWatchdog()
watcher.start()
else:
if os.name == 'posix' and platform.system() != 'Darwin':
module = 'inotify'
else:
module = 'watchdog'
_logger.warning("'%s' module not installed. Code autoreload feature is disabled", module)
if 'werkzeug' in config['dev_mode']:
server.app = DebuggedApplication(server.app, evalex=True)
rc = server.run(preload, stop) # 运行线程服务
if watcher:
watcher.stop()
# like the legend of the phoenix, all ends with beginnings
if getattr(odoo, 'phoenix', False):
_reexec()
return rc if rc else 0
可以看出从程序入口文件一直到程序成功运行,需要整理好并传输程序运行所需的的配置,根据配置创建好所需要的数据库,加载好模块,运行客户端,然后通过ThreadedServer创建的线程来运行服务