2015小回顾

时间过得很快2015年最后一天。 还是继续给自己做个总结吧。 去年也有做总结,不过没有发布到Blog罢了。

2015年初在公司定了两个主要目标:

  • 对工具的打磨
  • 计算机图形学

第一个目标算是基本完成,现在在用的工具都很顺手,效率能提升很多,而且用起来也很爽!现在也还会再尝试一些其他的工具,或者提升现在使用的工具的便利性。有时间的话可以写篇文章介绍一下。第二个目标目前没有什么进展,可以考虑是不是要留到今年了XD,当然还有一些其他自己定的目标基本完成,大致写写自己的收获好了。

收获

(大致按照时间来写吧)

  • 读了一部分 Nginx 的源码,算是对Nginx有了比以前更深入的认识,但是现在回过头来再重新审视的话,发现对它的理解还远远不够,还需要继续深入。
  • 学习了 Haskell, Haskell我觉得是一门非常棒的语言,非常值得学习,通过对这门语言的学习,改变了我的一些思维方式。除了用它写过一些小程序以外,还没能在工程中大量使用,今后继续加油,尽量引入到工程中~
  • 学习了 Node.js, 同样的还缺乏工程中的实践
  • 学习了 Backbone.js,AngularJSReactJS. Backbone记忆中应该是5月份左右学习的,ReactJS要晚很多。写Backbone的时候想起来了之前用过的Riot, 轻量,随意,但是要写完整的应用相比AngularJS之类的要写很多代码。
  • 开源了qyweixin和一个HTTPmultipart的库,下载量各自也都已经几千了,上次在评论中也看到确实有人在使用~ 还是蛮开心的啦!
  • 学会了使用 Docker,也准备学习一些内部机制之类的东西。
  • 还在翻译中的Tornado 4.3文档也会尽快抽时间翻译完成的.
  • 此外还有学习了Lua和正在深入学习的Shell,还有一系列的框架和库, 正在用来写一些自己的小东西。
  • 1383 Contributions.
  • 运营了公众号 TheMoeLove

还有一些目前还无法放入收获这一项中的东西,在2016年尽量都再多积累一些。

另外,下面这部分也非常的重要!

  • 认识了很多好玩的小伙伴,从他们那里也学到了很多东西
  • 工作中同事们都很好,感谢给予的帮助~

总结

  • 学会拒绝。一些事情是可以容忍的,但是要遵守原则,也要考虑时间成本和效率问题。
  • 学习和思考。这一年之间其实学到的东西也蛮多的,只不过有些东西没能在工程实践中应用,效果不是很明显。多思考,做个靠谱的人,尽量不在相同的地方摔倒两次。
  • 多读书
  • 尝试新东西
  • 多深入一些。浅尝辄止不是应该有的状态。
  • 合理安排追番时间 2333

JSLint,JSHint,ESLint对比和Vim配置

最近在用React写项目,但是我的Vim配置之前并没有配置对JSXES6的支持,然后看着那堆报错各种不爽了,于是还是要继续折腾,顺便也增加了点知识,记录一下。

主流的JS Lint工具及介绍

JavaScript已经发展蛮长时间了,对应的Lint工具也是层出不穷,下面介绍一下比较主流的几个Lint工具(其实是我用过的几个XD)

JSLint

JSLint是由Douglas Crockford开发的,可能是最早的JavaScript Lint工具了吧,它的名字来源于著名的C语言工具Lint。老道把他认为的非Good Parts的部分都报了warning,而且在它的文档中也提到了你应该欣然接受所有的JSLint的建议。最近看了下,老道还在持续更新着这个项目,而且官网上也有着一个在线的体验工具,可以尝试一下。对了,如果想要使用这个工具,建议看看老道在YouTube上关于JavaScript编程风格的视频,讲的还是很幽默的。

JSHint

JSHint是由Anton Kovalyov基于JSLint的代码实现的开源项目,由于JSLint时期大多数人都在受JSLint压迫,JSHint相比较之下,更友好,也更容易配置,所以很快就发展了起来,也得到了众多IDE和编辑器的支持。但是,由于它是基于JSLint开发的,自然原有的一些问题它也继承下来了,比如不易扩展,不容易直接根据报错定位到具体的规则配置等,虽然之前好像是有过相关的讨论,但是现在仍然没有什么好的解决办法。好在它发展的不错,很多时候遇到的问题都可以在网上找到相关的解决方案,而且文档也是非常不错的。

ESLint

ESLint是由Nicholas C. Zakas在2013年开始开发的,它的初衷就是为了能让开发者能自定义自己的linting rules,而且它提供了一套相当完善的插件机制,可以自由的扩展,动态加载配置规则,同时可以方便的根据报错定位到具体的规则配置。而且我比较喜欢它的一点是文档非常详细,可能这也是灵活所必须的吧。在这里还要提一点,ESLint最初并不是为了造一个重复的轮子,而是作者在实际使用中的需求没有能得到JSHint团队的回应,所以他就结合当时的JSHint和另一个代码风格的检查工具JSCS写出来了现在具备代码风格检查自定义插件扩展功能的ESLint了。

JSLint,JSHint和ESLint的对比

这三个工具各有特色,我只是做一下对比,选择的话,看个人需求就好了。

JSLint

优点

  • 配置是老道已经定好的,开箱即用。

不足

  • 有限的配置选项,很多规则不能禁用
  • 规范严格,凡是不符合老道所认为的好的风格的,都会有警告(这一项就看你是否完全认同老道了)
  • 扩展性差
  • 无法根据错误定位到对应的规则

JSHint

优点

  • 有了很多参数可以配置
  • 支持配置文件,方便使用
  • 支持了一些常用类库
  • 支持了基本的ES6

不足

  • 不支持自定义规则
  • 无法根据错误定位到对应的规则

ESLint

优点

  • 默认规则里面包含了JSLintJSHint的规则,易于迁移(这肯定是故意的XD)
  • 可配置为警告错误两个等级,或者直接禁用掉
  • 支持插件扩展
  • 可以自定义规则
  • 可以根据错误定位到对应的规则
  • 支持ES6
  • 唯一一个支持JSX的工具

不足

  • 需要进行一些自定义配置(因为太灵活了嘛,不过文档是很详细的)
  • (它比其他两个都要慢)

Vim支持

我们都使用Syntastic来配置

JSLint的Vim配置

有一个jslint.vim当然版本太老了。。我们不用这种方式做。

  • 安装jslint
1
sudo npm install jslint -g
  • vimrc中添加如下配置
    1
    let g:syntastic_javascript_checkers = ['jslint']

JSHint的Vim配置

  • 安装jshint

    1
    sudo npm install jshint -g
  • vimrc中添加如下配置

    1
    let g:syntastic_javascript_checkers = ['jshint']
  • 也可以使用独立插件jshint.vim

ESLint的Vim配置

1
sudo npm install eslint -g
  • vimrc中添加如下配置
    1
    let g:syntastic_javascript_checkers = ['eslint']

这里有个很重要的问题,记得要在添加一份配置文件,在官网或者在我vim配置的仓库可以找到

用正确的姿势开源Python项目

做个备忘,也希望可以帮到别人。

目录结构(初始化)

一般我们都会选择在项目的顶层包含较基础的文件,比如setup.pyrequirementsREADME等文件。
一般情况下,一个预发布的Python项目中应该包含以下几类文件:

  • projects (项目的主体文件)
  • setup.py
  • requirements
  • Readme (项目说明)
  • docs (项目文档)
  • test

其中,projects文件夹要以项目命名,存放实际的Python Package.
这里放一个我的项目的目录作为例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
➜  httpmultipart git:(master) tree -L 2
.
├── build
│   ├── bdist.linux-x86_64
│   └── lib.linux-x86_64-2.7
├── dist
│   ├── httpmultipart-0.1.0-py2.py3-none-any.whl
│   └── httpmultipart-0.1.0.tar.gz
├── docs
│   ├── _build
│   ├── conf.py
│   ├── index.rst
│   ├── Makefile
│   ├── userguide
│   └── userguide.rst
├── env
│   ├── bin
│   ├── include
│   ├── lib
│   └── local
├── httpmultipart
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── main.py
│   └── main.pyc
├── httpmultipart.egg-info
│   ├── dependency_links.txt
│   ├── not-zip-safe
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   └── top_level.txt
├── LICENSE
├── MANIFEST.in
├── README.rst
├── setup.cfg
├── setup.py
└── test_httpmultipart.py

14 directories, 21 files

这个目录中包含了我的virtual enviroment 和打包构建时候生成的文件夹。
这些东西在下面会提到。

文档

文档的话,并没有严格要求必须使用什么样的工具进行构建,也没有很严格的格式要求。不过我推荐使用SPHINX,它是用Python写的工具,使用了一种叫做reStructuredText的语法编辑,可以对多个文本文件重编,可以输出成HTML或者PDF等格式。

这里稍微介绍下使用:

  • 安装

    1
    $ pip install sphinx
  • 初始化

    1
    2
    3
    $ cd docs
    $ sphinx-quickstart
    ...#(这里有一系列的提问,进行初始化)
  • 编译

    1
    $ make html #(如果按照默认配置生成的Makefile的话,这样就可以编译出html了)

Sphinx的使用还有很多值得说的地方,推荐两个资料:

官方文档写的非常详细,那本书偏向于实战,是很不错的书。
还有很关键的一点是Sphinx有autodocautomodule的扩展,
可以从代码中提取出文档,与代码直接进行关联。提供一个例子可以方便的在文档和源码中进行跳转。

Read the Docs 持续文档集成

说完写文档就不得不提到Read the Dosc了,这是一个第三方的文档托管平台,使用Django开发,它可以很轻松的和Github上的项目进行集成,在每次代码提交的时候会自动进行文档构建,我们可以看看生成文档的效果。现在有很多开源项目的文档都是托管在这里的,具体的配置可以参考官方文档

TravisCI 持续集成

Travisci可以与Github非常好的结合,可以手动导入repo,并设置Webhooks & services,在每次提交的时候都会测试运行来发现是否存在异常。在使用之前,我们需要先做一些初始化的操作:

  • 创建.travis.yml文件

    我们需要告诉它一些基本的信息:

    • 我们项目使用的语言
    • 项目使用的语言版本
    • 环境的依赖
    • 是否需要sudo权限运行
    • 使用什么命令来安装
    • 使用什么命令运行测试

      下面提供一个例子:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      language: python
      python:
      - 2.7

      env:
      - DEPS=true
      - DEPS=false

      sudo: false

      install:
      - travis_retry python setup.py install
      - travis_retry pip install coveralls
      - coverage run test_httpmultipart.py
      - coverage report

      script:
      - python test_httpmultipart.py

      after_success:
      coveralls

PS: 在install这一项配置中要注意,如果项目存在依赖,一定要进行安装,还有Travisci提供了多项配置,包括出错重试等,具体配置可以参考官方文档,要特别注意travis_retry等命令的使用,非常容易出现坑。

测试

Python有内置的unittest测试库,支持断言;当然还有其他的一些测试框架,看个人喜好和项目需求。在项目中应该包含测试文件或者测试目录,测试文件一般以test_projects_name.py命名。我选择使用coverage作为测试覆盖率的检查,下面是一个运行示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜  httpmultipart git:(master) coverage run test_httpmultipart.py 
....
----------------------------------------------------------------------
Ran 4 tests in 36.125s

OK


➜ httpmultipart git:(master) coverage report
Name Stmts Miss Branch BrPart Cover
-------------------------------------------------------------
httpmultipart/__init__.py 10 0 0 0 100%
httpmultipart/main.py 37 0 4 0 100%
-------------------------------------------------------------
TOTAL 47 0 4 0 100%

Coveralls 测试覆盖率检查

Coveralls可以很友好的支持Github和Bitbucket仓库的导入,同时也可以很好的和Travisci集成,在上面我们的.travis.yml文件中,在最后一项after_success中,我们就配置了对Coveralls的支持。

发布包到PyPI

PyPI - the Python Package Index
是Python的包仓库,它允许我们将自己写的包上传上去,这样就可以使用pipeasy_install进行安装了。这里说一个很重要的事情:
请在发布自己项目之前做好测试,确认自己上传的是一个可用,无害的包
当你已经完成上面的步骤之后,那么你只需要以下几步就可以完成了。以我的项目为例子:

  • 配置setup.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python

import os
import re
import sys
from codecs import open

try:
from setuptools import setup
except ImportError:
from distutils.core import setup

if sys.argv[-1] == 'publish':
os.system('python setup.py sdist upload')
sys.exit()

packages = [
'httpmultipart',
]

requires = []

version = ''
with open('httpmultipart/__init__.py', 'r') as fd:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
fd.read(), re.MULTILINE).group(1)

if not version:
raise RuntimeError('Cannot find version information')

with open('README.rst', 'r', 'utf-8') as f:
readme = f.read()

setup(
name='httpmultipart',
version=version,
description='A httpmultipart post handler',
long_description=readme + '\n\n',
author='TaoBeier',
author_email='zhangjintao9020@gmail.com',
url='https://github.com/tao12345666333/httpmultipart',
packages=packages,
package_data={'': ['LICENSE']},
package_dir={'httpmultipart': 'httpmultipart'},
include_package_data=True,
install_requires=requires,
license='MIT',
zip_safe=False,
platforms='any',
classifiers=(
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
),
)

当然大部分时候也不需要这么麻烦,简化的配置可以参考官方的文档。注意最下面那部分classifiers是按照PyPI官方的列表填写的。还有,如果有些文件想要额外打包进去,那么需要在根目录添加MANIFEST.in文件。

  • 打包代码
1
2
$ python setup.py sdist # 生成pip支持的安装包
$ python setup.py bdist_wheel # 生成支持easy_install的安装包
  • 发布到PyPI上

    首先在PyPI注册一个帐号,然后进行下面两步:

    • 注册package
      1
      2
      3
      4
      5
      6
      $ python setup.py register
      $ # 在这一步会有一些提示,按照提示选择,输入自己帐号密码相关的信息即可
      $ # 在提示你要不要保存帐号信息的时候,
      $ # 你选择了‘y’,
      $ # 则会在你的用户目录下生成一个 .pypirc 的文件,
      $ # 其中明文保存着你的帐号和密码。

这里稍微再提一点,如果在提示是否保存账户信息的时候,选择了‘n’,想反悔了也没关系,我们可以手动创建一个~/.pypirc文件。格式如下:

1
2
3
4
5
6
7
[distutils]
index-servers=pypi

[pypi]
repository = https://pypi.python.org/pypi
username = your username
password = your password

  • 上传package
    1
    $ python setup.py sdist bdist_wheel upload

在上传完成提示200响应的时候,你就上传成功了,去PyPI上看看有没有上传成功的包,并且试着用pip进行安装吧!

这里我省略了一步,就是发布前的测试,你可以使用PyPI的测试服务器进行测试发布,发布到这里的包并不会对你正式发布有任何影响。

项目托管在Github上

开源到Github上后,就是继续维护和开发,这点就不多说了。

开发相关

建议使用virtualenv之类的工具构建纯净的环境,重复的动作交给Make之类的工具。

这篇算是一个小小的总结加备忘吧,经验尚缺,还望指正。

对监控系统的思考

近期在做运维监控方面的事情,也研究了一下其他人是如何做的。把自己的想法做个总结记录一下吧。

监控期望的目标

  • 及时发现

需要的是即时监控并报警

  • 及时定位

定位问题要分开讲

  • 运维层面

    是机器硬件问题还是上面运行的基础服务的问题,或者是新上线代码的问题,需要回滚。

  • 代码层面

    在发生问题的时候,优先解决问题。定位代码问题提交hotfix 可以在解决问题之后做。

  • 及时处理
  • 提前预测(尽量减少问题的发生)

提前预测可以做的事情有很多,数据挖掘/分析之类的。当然有个更简单的方法,就是先小范围上线,进行监控。如果发现出问题了,就停止上线,进行回滚。(我们现在就是这样做的,虽然原因并不是这个 2333

监控遇到的主要问题

  • 监控指标多

服务器CPU,内存,网络等的指标,基础服务Redis, MongoDB等的运行指标,对外服务的API是否正常工作,还有数据是否正确等。

  • 监控报警多

监控指标多的时候,自然报警也会相应增加,但是报警的分组与轻重缓急也是一个很麻烦的问题。还有就是部署着不同服务的机器,触发报警时候的指标也不好确定。

  • 报警多而且有关联,如何查找原因

可能同时会有多个指标触发了报警,但是要定位问题的时候,如何可以快速的定位问题。

多维度数据监控

这个话题太大(要感谢Baidu的颜大大的指点)

  • 数据监控符合二八原则,重要数据需要多角度进行观察,需要有meta管理,需要动态简单配置。选择 好的,合理的数据模型可以有效的进行处理。

  • 数据采集部分,在单机器做聚合;命名上使用正则格式化;完善的配置功能,支持数据流自定义维度。

  • 对开源系统的使用,需要按照自己的实际情况进行适配。保证高可用性

先写这些吧,之后有时间再写,还有QCon上对运维监控上的一些分享也非常值得思考

Open-Falcon监控系统部署

本文并不分析Open-Falcon的架构或者选用它的原因,官方的文档在这里,虽然还不够完善。不过这也是我写这篇的原因,官方文档并没能把整个部署过程连在一起,而且个别地方有点问题。我在这篇文章中就不介绍各个组件的作用和功能了,只是单纯的介绍如何从零部署。

安装

下载

1
wget https://github.com/XiaoMi/open-falcon/releases/download/0.0.5/open-falcon-0.0.5.tar.gz -O open-falcon.tar.gz

解压

1
2
mkdir tmp
tar -zxvf open-falcon.tar.gz -C ./tmp

基础环境

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo apt-get install redis-server
sudo apt-get install mysql-server
pip install virtualenv

# 数据库初始化的代码来源于官方文档
git clone https://github.com/open-falcon/scripts.git
cd scripts
mysql -h localhost -u root -p < db_schema/graph-db-schema.sql
mysql -h localhost -u root -p < db_schema/dashboard-db-schema.sql

mysql -h localhost -u root -p < db_schema/portal-db-schema.sql
mysql -h localhost -u root -p < db_schema/links-db-schema.sql
mysql -h localhost -u root -p < db_schema/uic-db-schema.sql

配置

数据库连接的配置格式是: username:password@tcp(path:port)/xxxx

agent

mv cfg.example.json cfg.json && ./control start && ./control tail
开始监听1988端口,查看log.
默认端口是1988, 可以打开 http://127.0.0.1:1988 查看一个比较简单的web dashboard. 没什么特殊需要的话, 可以使用默认配置.

hbs

mv cfg.example.json cfg.json && ./control start && ./control tail
心跳服务默认http端口是6030, rpc 端口 6031

transfer

mv cfg.example.json cfg.json && ./control start && ./control tail
默认http端口是6060, rpc端口8433

judge

mv cfg.example.json cfg.json && ./control start && ./control tail
http端口6081, rpc端口 6080
配置项中注意alarm的 redis链接 和hbs的server地址,如果修改过请记得对应.

graph

mv cfg.example.json cfg.json && ./control start && ./control tail
rpc端口 6070, http端口 6071
数据库文件存储在/home/work/data/6070 启动报错的话, 换sudo 或者 root 用户启动.
注意修改数据库连接.

上面的服务配置完成数据就开始采集了.

dashboard

1
2
3
4
5
6
7
virtualenv env
source env/bin/activate
./env/bin/pip install -r pip_requirements.txt
# 使用
./env/bin/python wsgi.py
# 或者用
deactivate && ./control start && ./control tail

可以更改为自定义端口.这里可以查看Endpoints 的相关数据并绘图.

query

mv cfg.example.json cfg.json && ./control start && ./control tail
只要修改cfg.json 文件即可, 注意还有 graph_backends.txt 文件

fe

mv cfg.example.json cfg.json && ./control start && ./control tail
注意配置项目中的数据库连接, 以及下面的shortcut 中需要配置外网可以访问的地址,如果不是在服务器部署的话,这里默认也没有关系.

portal

这里要注意一个坑. 如果使用./control start 启动服务, 并且更改了默认端口的, 请配置 gunicorn.conf 中的bind项. 如果是使用python wsgi.py启动的话, 修改wsgi.py中的端口即可.
同时在配置 frame/config.py 的时候, 要注意所谓UIC_ADDRESS 选项的配置, 其实就是填写上面fe 模块的地址.

1
2
3
4
UIC_ADDRESS = {
'internal': 'http://127.0.0.1:port', #你的内网地址
'external': 'http://your_fe_name', #外网访问的地址, 如果是本地部署,这里可以和内网地址一样
}

alarm

mv cfg.example.json cfg.json && ./control start && ./control tail
需要配置的就是自定义的端口监控地址, 和下面的api, 其他部分保持默认即可.
它的文档中写着下面这样的说明

1
2
3
4
5
6
7
{...
"api": {
"portal": "http://falcon.example.com", # 内网可访问的portal的地址
"uic": "http://uic.example.com", # 内网可访问的uic(或fe)的地址
"links": "http://link.example.com" # 外网可访问的links的地址
}
}

但是如果按照这样配的话,所有东西就只能在内网访问了.这明显是不符合我们的期望的. 所以这里要全部配置成外网可以访问的地址,防止踩坑.

sender

这个组件用于调用自己提供的短信和邮件接口, 编辑 cfg.json 添加

1
2
3
4
5
6
{...
'api': {
'sms': 'http://your_send_sms_api',
'mail': 'http://your_send_mail_api'
}
}

在调用的时候, 会把消息先写入redis队列中, 之后再调用接口,进行消息发送.
worker 参数是对队列的配置.

mv cfg.example.json cfg.json && ./control start && ./control tail
告警合并组件, python应用, 记得修改默认端口即可.

其他

task

监控自检程序

gateway

没有跨机房问题可以忽略.(hhah

redis-monitor.py

scripts 文件夹中一个很简单的脚本, 把redis info 中的数据读出,写入数据库, 供监控使用.

最后附图一张,前几天我启动这个服务时候的终端。
screen_shot

源码编译MongoDB

上周放假正好有时间,编译安装了MongoDB,虽然MongoDB用了挺长时间的,但还是第一次用源码编译。在此做个备忘。因为已经完整编译安装过了,所以写起来的时候,就按照先知视角来写了~ 2333

下载MongoDB源码

MongoDB的官网上是有已经编译好的二进制包的,这里选择clone MongoDB在github上的仓库

1
git clone https://github.com/mongodb/mongo && cd mongo

docs/building.md中是编译所需的依赖。

  • A modern C++ compiler. One of the following is required.
    • GCC 4.8.2 or newer
    • Clang 3.4 (or Apple XCode 5.1.1 Clang) or newer
    • Visual Studio 2013 Update 2 or newer
  • Python 2.7
  • SCons 2.3

我这台服务器是CentOS 6.5, 上面的gcc版本比较低,这里就先更新gcc咯.

1
2
3
4
5
6
gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
Copyright © 2010 Free Software Foundation, Inc.
本程序是自由软件;请参看源代码的版权声明。
本软件没有任何担保;
包括没有适销性和某一专用目的下的适用性担保。

编译升级gcc

在gcc的官网找到下载页面。使用svn或者通过ftp镜像站下载源码.
我使用了一个ftp镜像站下载的源码压缩包。 然后进行解压和安装依赖。

1
2
3
tar -xjf gcc-5.2.0.tar.bz2 && cd gcc-5.2.0

./contrib/download_prerequisites(等待依赖完成)

之后编译

1
2
3
4
5
cd .. && mkdir gcc-build-5.2.0 && cd gcc-build-5.2.0

# 编译

../gcc-5.2.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking target system type... x86_64-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking whether ln works... yes
checking whether ln -s works... yes
checking for a sed that does not truncate output... /bin/sed
checking for gawk... gawk
checking for libatomic support... yes
checking for libcilkrts support... yes
checking for libitm support... yes
checking for libsanitizer support... yes
checking for libvtv support... yes
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for g++... g++
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking whether g++ accepts -static-libstdc++ -static-libgcc... no
checking for gnatbind... no
checking for gnatmake... no
checking whether compiler driver understands Ada... no
checking how to compare bootstrapped objects... cmp --ignore-initial=16 $$f1 $$f2
checking for objdir... .libs
configure: WARNING: using in-tree ISL, disabling version check

一般情况下, 就这样gcc就可以编译完成了。 但是因为我这台机器是单核1G没有swap区, 所以我遇到了下面的问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 排版有点错乱惹...

build/vec.o
build/min-insn-modes.o
build/gensupport.o
build/print-rtl.o
build/read-md.o
build/errors.o ../build-x86_64-unknown-linux-gnu/libiberty/libiberty.a
build/genattrtab ../../gcc-5.2.0/gcc/common.md ../../gcc-5.2.0/gcc/config/i
386/i386.md insn-conditions.md \
-Atmp-attrtab.c -Dtmp-dfatab.c -Ltmp-latencytab.c
make[3]: *** [s-attrtab] 已杀死
make[3]: Leaving directory `/home/tao/gcc-build-5.0.2/gcc'
make[2]: *** [all-stage1-gcc] 错误 2
make[2]: Leaving directory `/home/tao/gcc-build-5.0.2'
make[1]: *** [stage1-bubble] 错误 2
make[1]: Leaving directory `/home/tao/gcc-build-5.0.2'
make: *** [all] 错误 2

大致查了下,是因为没有swap区的原因,根据这篇 得到的解决办法是:

1
2
3
4
SWAP=/tmp/swap
dd if=/dev/zero of=$SWAP bs=1M count=500
mkswap $SWAP
sudo swapon $SWAP

之后就是gcc 的编译时间了, 这个时间可以去写写代码补个番啥的。这台机器只是平时拿来玩的,配置炒鸡低。编译gcc从17:20开始,一直到20:09停止。(期间我去补番啦 2333)

1
2
3
4
5
6
7
8
9
10
11
# 只会执行下面的命令
make
make install
# 切换gcc到新版本
update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/gcc-5.0.2 66
# 我重新ssh登录后才看到更新生效的
gcc --version
gcc (GCC) 5.2.0
Copyright © 2015 Free Software Foundation, Inc.
本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保;
包括没有适销性和某一专用目的下的适用性担保。

升级Python

CentOS上默认的Python对于之后要安装的scons来说,还是版本太低。再次上Python 官网 (官网真是个好地方2333)下载Python2.7的源码
编译过很多次了, 就只写主要的东西了

1
2
3
4
5
6
7
8
9
10
xz -d python-2.7.10.tar.xz
tar -xvf python-2.7.10.tar && cd python-2.7.10
# 对于这次编译MongoDB来说,一定需要安装的是bzip2依赖
yum install -y bzip2-devel
# 编译
./configure --prefix=/usr/local/python2.7
make
make install
# 更新
update-alternatives --install /usr/bin/python python /usr/local/bin/python 69

安装scons

官网上找到源码包直接安装

1
2
3
4
5
# 依赖解决
yum install pcre-devel python-devel
# 解压安装
tar -zxvf scons-2.3.6.tar.gz && cd scons-2.3.6
python setup.py install

编译安装MongoDB

最后的安装过程就不是这篇里面的重点了, 遇到的一个坑是:

1
Initializer* _theGlobalInitializer = &getGlobalInitializer();

有这样的报错信息。 查了一下,根据这篇只要在构建的时候,加上--disable-warnings-as-errors就可以解决了

1
2
scons all --disable-warnings-as-errors
# 其他的设置可以查看scons的相关文档

本篇的重点是编译的过程,后续MongoDB配置部分抽空再写。全文完。

重置Ghost博客的密码

在搭建Ghost博客的时候,尚未配置mail服务器时,重置密码的方法做个记录

打开数据库查看用户信息

如果全部默认设置,使用生产环境的话,应该是
sqlite3 content/data/ghost.db

如果是开发环境应该是
sqlite3 content/date/ghost-dev.db

查看用户信息
sqlite>SELECT * FROM users;

更新用户密码

  • Ghost对用户密码用的是BCrypt加密,可以使用BCrypt Hash Generator之类的工具生成一个想要修改的密码,例如”mypasswd”生成的密码是
    $2a$10$QecJeBdw2lONRTnHJ0RoVO6DczdJWf4h4QgaUcgKsYFZlzTe1yeEK

  • 假设之前查看到的用户信息,邮箱是admin@domain.com 那么,使用这样更新密码

    1
    UPDATE users SET password="$2a$10$QecJeBdw2lONRTnHJ0RoVO6DczdJWf4h4QgaUcgKsYFZlzTe1yeEK" WHERE email="admin@domain.com"
  • 退出sqlite3
    .exit

近况

博客好长时间没有更新了,今天抽空大致来说一下近况吧

工作

用这个标题的话,其实感觉想写的确实好多,但是还是挑一些比较重要的来说吧。现在的公司说实话还确实没有让我失望,工位上配的是一个 22寸的 AOC 显示器和一个24寸的 Dell 显示器, 主机内存 12G (我每天跑个Linux是有点浪费)办公区每天有物业定时打扫神马的,下午的时候有茶歇(茶水间还有一堆零食)。同事们相处感觉都很不错,每天中午一起出去吃饭,各种聊天调侃神马的,只是一开始不太了解项目中的配置神马的,让老大费心了…

这段时间还有很多有趣的事情 比如: 去金海湾度假村团建之类的。 再说一下最近的感受吧。

因为国庆前需要上线,所以放假前就每天都是在忙着开发神马的。不过那两周也是近期感觉最爽的时候 写代码高潮不断 而且也确实感觉工作是蛮有挑战性的,确实是我想要的工作 :-) 。 不过我还记得那周一,一打开邮箱看到中有7份未读的需求邮件, 确实是略惊吓。
在开发的项目,因为改变了设计思路,所以这些天主要都是在写前端。只不过一开始的时候感觉略虐心啊, 写Python时间长了已经是不习惯其他语言那种书写规范了 一堆括号写的好烦躁 但是从这两天的感觉来看,得感谢老大的这种设计思路,这段时间学到的确实很多。 从框架到一些库,一些插件, 还有程序上一些比较巧妙的用法 正在努力消化中

生活

有点后悔加上标题了 其实主要要说的应该都放在这里吧。
从搬家后基本上每天生活都很规律,目前差不多适应了。(找工作和面试神马的我写到碎碎念里面了,具体的等半年或者一年后当回忆录来写 233)值得吐槽的就是电信的客服,用的是电信的网,前几天换了路由器忘记了密码,打客服重置密码,但是一直连接不成功(691错误,明显就是帐号密码的问题嘛)结果本来想到了周末放假的时候再好好处理,结果到了周末打电话却一直没有客服啊用联通号打电信的客服我也是醉了 最后到了周一才让客服又重置才成功。

其实那也是导致我这么久没有更新博客的原因orz 。

  • 一个原因是因为电脑重装了系统,环境啥的一直没有配置
  • 另一个就是因为网络坑爹,实在有心无力

再者就是帝都的天气让人确实有点无奈,有天早上刚下楼,我还以为我要迈步进入寂静岭了 TAT ,感觉能幸存下来确实是很不容易啊。

最后说一下最近在网络弄好之后,挖了一个坑。打算独立开发一个网站的说, 重复造轮子的原因和大多数人是一样的 ,现有的东西没有我想要的 正好把最近学到的东西都拿来练练手

Try My Best !

正则匹配中文及字符编码问题

匹配中文的正则表达式

窝写了一小段代码(虽然写的不太好,但是基本可以表达意思)

1
2
3
4
5
6
7
8
import re

nickname = raw_input('Please input your nickname > ')

if not re.search(u'^[\u4e00-\u9fa5a-zA-Z0-9]+$', unicode(nickname,'utf8')):
print 'Your nickname format is error, please try again !'
else:
print 'Hello %s'% nickname

如你所见,上面第5行的代码,就是匹配中文和字母,数字的正则表达式了。里面的\u4e00-\u9fa5 就是中文汉字的unicode编码所在位置。

运行截图


Python字符串的编码问题

还是以上面那段代码来说。注意看第5行的代码

1
if not re.search(u'^[\u4e00-\u9fa5a-zA-Z0-9]+$', unicode(nickname,'utf8')):

其实这样的代码并不严谨。因为在Python 中默认是用unicode编码来处理字符串的,因此做编码转换的时候,一般要以unicode作为中间编码,也就是说:
其他编码格式的字符串—>解码(decode)—>unicode—>编码(encode)—>所需要的编码格式。

因此,处理字符串编码的问题的时候,先要明白需要转换的字符串的编码格式是什么。

代码中字符串的默认编码格式与代码文件本身的编码格式是一样的

比如: s = ‘涛’ 在utf8的文件中,那么s就是utf8编码的,但是如果文件是gb2312编码,那么s就是gb2312编码的。此时,如果想要处理s这个字符串就要先decode成unicode编码了。

不过如果是酱紫 s = u’涛’,那么s就是unicode编码了,这个时候s的编码方式不会被文件的编码所影响。

如果一个字符串已经是unicode编码了,再解码就会出错

因此严谨的方式就是先对字符串进行编码格式的判别,最简单的办法就是使用Python 默认提供的isinstance() 方法.

代码可以这样写
isinstance(s, unicode) 如果不是unicode编码就会报错。

窝今天在处理用户昵称的地方,忘记字符串会直接使用文件的编码了,所以对它进行了重新编码orz果断就报错了。。。以后还是要好好注意细节的说。