#193 使用 git-daemon

2017-03-15

有时需要临时分享一个仓库给朋友,我们可以用 SSH 协议:

git clone ssh://markjour@192.168.64.234/home/markjour/Projects/Mine/lego

其实 git-daemon 是一个更好的方法。

#192 logging 时间格式

2017-03-12
import logging
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(asctime)s %(levelname)s %(message)s'
logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT)
logging.info('hello world')

默认时间格式是 yyyy-mm-dd hh:mm:ss,xxx,如果我们要改这个格式可以用 datefmt 参数,遵循 time.strftime 的格式化参数格式。

问题有一个,毫秒从哪里来?

方法一:使用 msecs 占位符

最简单的办法:在格式字符串中使用 msecs 占位符,比如:

import logging
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(asctime)s.%(msecs)03d %(levelname)s %(message)s'
LOG_DATEFMT = '%H:%M:%S'
logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT, datefmt=LOG_DATEFMT)
logging.info('hello world')

方法二:改用 datetime 对象

import logging
from datetime import datetime

class MyFormatter(logging.Formatter):
    converter = datetime.fromtimestamp

    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            # s = time.strftime(datefmt, ct)
            s = ct.strftime(datefmt)
        else:
            # t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s,%03d" % (t, record.msecs)
        return s

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
console = logging.StreamHandler()
logger.addHandler(console)
formatter = MyFormatter(fmt='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S.%f')
console.setFormatter(formatter)
logging.info('hello world')

#191 dc 计算器

2017-02-26

dc, desk caclulator,使用的是逆波兰式表达方法,而不是熟悉的代数标记法。

只是一些简单的用法,复杂的指令就不研究了:

# 1 + 2 + 3 + 4 + 5
dc -e "1 2 + 3 + 4 + 5 + p"

# 4 ** 3
dc -e "4 3 ^ p"

就是数在前面,操作符在后面,最后 p 输出。

# 加 减 乘 除 取余
+ - * / %
# 乘方 开方
^ v
# 用后面的数除以前面的数
~
# 清除结果
c
# 设置精度为 3
3k

如果进入 bc 交互模式,按 q 退出。

dc -e "3k 1 2 / p 2 / p"
.500
.250

#190 MySQL 增加或修改注释

2017-02-19

表注释

SELECT TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = '5mzb' AND TABLE_NAME = 'user';
ALTER TABLE `user` COMMENT = '用户';

字段注释

SELECT COLUMN_NAME, COLUMN_COMMENT FROM `information_schema`.`COLUMNS`
WHERE TABLE_SCHEMA = 'sendcloud' AND TABLE_NAME = 'user_info' ORDER BY ORDINAL_POSITION;
ALTER TABLE `user`
CHANGE COLUMN `create_time`
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' AFTER `expire_time`;
ALTER TABLE `user`
MODIFY COLUMN
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' AFTER `expire_time`;

好傻 X 啊,只改个备注,却必须要把字段声明带上,增加出错的可能。

#189 JS: split 方法

2017-02-12
"ni wo ta".split(" ");
// [ 'ni', 'wo', 'ta' ]

"ni wo ta".split(" ", 1);
// [ 'ni' ]
"ni wo ta".split(" ", 2);
// [ 'ni', 'wo' ]
"ni wo ta".split(" ", 3);
// [ 'ni', 'wo', 'ta' ]
"ni wo ta".split(" ", 4);
// [ 'ni', 'wo', 'ta' ]

"ni wo ta".split(":");
// [ 'ni wo ta' ]
"ni wo ta".split(":", 1);
// [ 'ni wo ta' ]
"ni wo ta".split(":", 2);
// [ 'ni wo ta' ]

如果要一刀将字符串切两半:

var line = "a : b : c";
var part1 = line.split(":", 1)[0];
if (a !== line) {
  var a = part1.trim();
  var b = line.substr(part1.length + 1).trim();
  console.log([a, b]);
}
var line = "a : b : c";
var index = line.indexOf(":");
if (index != -1) {
  var a = line.substr(0, index).trim();
  var b = line.substr(index + 1).trim();
  console.log([a, b]);
}

参考资料与拓展阅读

#188 为旧版本 CentOS 设置更新源

2017-02-08

总有些时候需要操作一些老旧的 CentOS 版本,如果需要更新就比较麻烦了,因为绝大部分更新源都不对老版本提供服务了。
这时我们只好使用 CentOS Vault,从官方接受这最后的支持,慢慢的下载更新。

#187 Nginx 连接处理方法

2017-02-07

Syntax: use method;
Default: —
Context: events

Specifies the connection processing method to use. There is normally no need to specify it explicitly, because nginx will by default use the most efficient method.

Nginx 默认会自动选择当前平台最高效的方法。

  • epoll Linux 平台上的最佳选择
  • kqueue BSD 家族(包括 MacOS)的最佳选择
  • poll 第一备选
  • select 第二备选
  • eventport Solaris 提供的机制,但是 Nginx 文档上建议使用 /dev/poll
  • /dev/poll

我们接触多的是 Linux 服务器,所以知道是 epoll 就行了。
除非你非常知道自己在做什么,不要调整 use 参数。

以下参数可以控制相关模块的引入:

--with-poll_module
--without-poll_module
--with-select_module
--without-select_module

#186 勇敢者的游戏

2017-02-04
  1. 勇敢者的游戏 Jumanji
  2. 勇敢者的游戏 2:太空飞行棋
  3. 勇敢者游戏:决战丛林
  4. 勇敢者游戏 2:再战巅峰

Jumanji

莎拉 展翅飞得高,白天看不到,晚上来追杀,赶紧把命逃
     # 吸血蝙蝠
艾伦 身陷丛林难回家,色子要等五或八
朱迪 它个子最小,咬一下起个包,能让你昏迷发高烧
     # 大蚊子
皮特 这段任务很艰难,红毛长尾阻你向前
     # 猴子
皮特 头大体胖牙齿尖,用你来个大会餐,腿短胆小命难保
     # 狮子

莎拉 长得又快又急促,小心别让它抓住
     # 食人花
艾伦 野蛮猎人一出现,鲁莽射击不留人
     # 范培特
朱迪 打雷没什么,不要被迷惑,按兵不动,必成大祸
     # 动物大迁徙
皮特 游戏规则被破坏,往后倒退一大块
     # 皮特作弊变猴子

莎拉 每月一逢台风到,大雨滂沱起浪潮
     # 暴雨
艾伦 陷阱就在你脚下,地板瞬间变流沙
     # 流沙
朱迪 有个教训宜记取,后退一步有转机
     # 流沙消失,地板凝固
皮特 除了具有山核桃,我们还有八只手
     # 蜘蛛

莎拉 紧要关头目标近,地牛翻身陷困境
     # 地震
艾伦 Jumanji (赢了,游戏结束)

#185 Supervisor 进程守护

2017-01-31

子命令

  • help
  • help <action>
  • add <name> […]
  • remove <name> […]
  • update
  • update all
  • update <gname> […]
  • clear <name>
  • clear <name> <name>
  • clear all
  • fg <process>
  • pid
  • pid <name>
  • pid all
  • reload
  • reread
  • restart <name> 不会重新加载配置文件
  • 如果配置有更新,应该 reread 一下
  • 如果有 section 增删,还应该 update 一下
  • restart <gname>:*
  • restart <name> <name>
  • restart all
  • signal
  • start <name>
  • start <gname>:*
  • start <name> <name>
  • start all
  • status
  • status <name>
  • status <name> <name>
  • stop <name>
  • stop <gname>:*
  • stop <name> <name>
  • stop all
  • tail [-f] <name> [stdout|stderr] (default stdout)

#184 Werkzeug WSGI 框架

2017-01-30

示例

from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule

class Application:
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='hello')
        ])

    def hello(self, request):
        text = 'Hello, World!'
        response = Response(text, content_type='text/plain')
        return response

    @Request.application
    def __call__(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        endpoint, values = adapter.match()

        handler = getattr(self, endpoint)
        return handler(request, **values)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = Application()
    run_simple('localhost', 5000, app)

Werkzeug 与协程(async/await

Werkzeug 1.x 开始已经提供了对协程的支持。
PS:WSGI 规范是基于同步的设计,没有较好的适配异步编程,所以后面一些更年轻的框架选择了 ASGI(Async Server Gateway Interface)。
PS:2014/03/01, WSGI
PS:2021/11/06, 体验 ASGI

import asyncio
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule

class Application:
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='hello')
        ])

    async def hello(self, request):
        text = 'Hello, World!'
        response = Response(text, content_type='text/plain')
        return response

    @Request.application
    async def __call__(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        endpoint, values = adapter.match()

        handler = getattr(self, endpoint)
        response = await handler(request, **values)
        return response

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = Application()
    run_simple('localhost', 5000, app)

附:版本历史

版本 时间
2.3.4 May 9, 2023
2.3.3 May 1, 2023
2.3.2 Apr 29, 2023
2.3.1 Apr 27, 2023
2.3.0 Apr 26, 2023
2.2.3 Feb 15, 2023
2.2.2 Aug 9, 2022
2.2.1 Jul 28, 2022
2.2.0 Jul 24, 2022
2.1.2 Apr 29, 2022
2.1.1 Apr 2, 2022
2.1.0 Mar 29, 2022
2.0.3 Feb 8, 2022
2.0.2 Oct 6, 2021
2.0.1 May 18, 2021
2.0.0 May 12, 2021
1.0.1 Apr 1, 2020
1.0.0 Feb 7, 2020
0.16.1 Jan 27, 2020
0.16.0 Sep 19, 2019
0.15.6 Sep 5, 2019
0.15.5 Jul 17, 2019
0.15.4 May 15, 2019
0.15.3 May 15, 2019
0.15.2 Apr 3, 2019
0.15.1 Mar 22, 2019
0.15.0 Mar 20, 2019
0.14.1 Jan 1, 2018
0.14 Dec 31, 2017
0.13 Dec 8, 2017
0.12.2 May 16, 2017
0.12.1 Mar 16, 2017
0.12 Mar 10, 2017
0.11.15 Dec 31, 2016
0.11.14 Dec 31, 2016
0.11.13 Dec 27, 2016
0.11.12 Dec 26, 2016
0.11.11 Aug 31, 2016
0.11.10 May 24, 2016
0.11.9 Apr 25, 2016
0.11.8 Apr 15, 2016
0.11.7 Apr 15, 2016
0.11.6 Apr 14, 2016
0.11.5 Mar 23, 2016
0.11.4 Feb 15, 2016
0.11.3 Dec 20, 2015
0.11.2 Nov 12, 2015
0.11.1 Nov 10, 2015
0.11 Nov 8, 2015
0.10.4 Mar 26, 2015
0.10.3 Mar 26, 2015
0.10.2 Mar 26, 2015
0.10.1 Feb 4, 2015
0.10 Jan 30, 2015
0.9.6 Jun 7, 2014
0.9.5 Jun 7, 2014
0.9.4 Aug 26, 2013
0.9.3 Jul 25, 2013
0.9.2 Jul 18, 2013
0.9.1 Jun 14, 2013
0.9 Jun 13, 2013
0.8.3 Feb 5, 2012
0.8.2 Dec 16, 2011
0.8.1 Sep 30, 2011
0.8 Sep 30, 2011
0.7.2 Sep 30, 2011
0.7.1 Jul 26, 2011
0.7 Jul 24, 2011
0.6.2 Apr 24, 2010
0.6.1 Apr 13, 2010
0.6 Feb 19, 2010
0.5.1 Jul 10, 2009
0.5 Apr 25, 2009
0.4.1 Jan 11, 2009
0.4 Nov 23, 2008
0.3.1 Jun 24, 2008
0.3 Jun 15, 2008
0.2 Feb 14, 2008
0.1 Dec 10, 2007