uWSGI的几个使用技巧

November 24, 2011

uWSGI基本上是python做web服务的不二选择了,但似乎项目的开发者比较热衷于其新功能开发,对其使用文档还是相当缺乏的。

安装:

Ubuntu

添加ppa,安装。 目前只有Lucid, Maverick, Natty几个版本还需要添加,以后版本都在官方原,直接apt-get install即可。

1
2
3
add-apt-repository ppa:uwsgi/release
apt-get update
apt-get install uwsgi-python

Debian

目前Debian sid已经收录了uwsgi,一般服务器安装的testing/stable,只能自己修改apt的配置,从sid里面port过来。

注意:以下操作可能毁掉您的整个debian包系统。以下命令仅在Debian wheezy,即目前的testing运行测试安装过,如果你的是squeeze,自己修改01all那里 Pin: release a=squeeze 一行,但不保证能够正常运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo "deb http://ftp.tw.debian.org/debian sid main non-free contrib" >> /etc/apt/sources.list
cat > /etc/apt/preferences.d/01all << EOF
Package: *
Pin: release a=testing
Pin-Priority: 1000
EOF
 
cat > /etc/apt/preferences.d/02uwsgi << EOF
Package: uwsgi
Pin: release a=sid
Pin-Priority: 1010
EOF
 
apt-get update
apt-get install uwsgi uwsgi-core uwsgi-plugin-python

Centos, RHEL, Fedora, ...

You're on your own, linux user.

配置

常见配置文件:

1
2
3
4
5
6
7
8
9
10
11
cat > /etc/uwsgi/apps-enabled/test.ini << EOF
[uwsgi]
chmod-socket = 666
limit-as = 256
processes = 6
max-request = 2000
memory-report = true
enable-threads = true
virtualenv = /somewhere/to/your/virtualenv
wsgi-file = /home/somewhere/app.py
EOF

用ini方式的配置是比xml的容易写多了。具体配置说明请看Doc

默认的sock文件在/var/run/uwsgi/test/socket

配合nginx使用的配置文件:

1
2
3
4
5
6
7
8
9
10
cat > /etc/nginx/sites-enabled/test << EOF
server {
        listen   80;
        server_name host.domain.com;
        location / {
                include uwsgi_params;
                uwsgi_pass unix:///var/run/uwsgi/test/socket;
        }
}
EOF

切换Python版本

系统中可能安装有多个版本的Python,又或者同个系统里面有的app跑python3, 有的跑python2.6 stackless, 有的跑python2.7...

uwsgi 是通过plugin的方式加载不同的python解析器的,debian的uwsgi-plugin-python包里面提供了python26_plugin.so, python27_plugin.so, 不过uwsgi如果在app配置里面没有plugins参数指定使用哪个时候,会尝试加载/usr/lib/uwsgi/plugins/python_plugin.so,这个文件在debian下是个链接文件,可以运行update-alternatives --config uwsgi-plugin-python命令来修改这个默认版本。

源里面没有提供stackless python的plugin,只能自己编译了,还好非常简单:

/path/to/your/stackless/python uwsgiconfig.py --plugin plugins/stackless

然后把生成的python_stackless.so放到/usr/lib/uwsgi/plugins 就能被uwsgi加载了。

其他plugin的编译基本都这样,看源代码里面的plugins目录。

代码

使用uwsgi运行代码的时候,可以import uwsgi模块,和uwsgi进行一定的交互。

uwsgi 的源代码包当中有个uwsgidecorators.py,提供了多数的uwsgi接口,描述文档在此。以下是几个典型应用。

自动重载

好一些web框架都有检测修改了源文件就自动重新加载的功能,但是在uwsgi里面这个方法是不好用了。

Django

加入以下代码:

1
2
3
4
5
6
7
8
import uwsgi
from uwsgidecorators import timer
from django.utils import autoreload
 
@timer(3)
def change_code_gracefull_reload(sig):
    if autoreload.code_changed():
        uwsgi.reload()

Bottle

Bottle 的reload是它内置基础web服务器的功能,在uwsgi里面只能自己写代码监控。

想要简单很难做到完美:

1
2
3
4
5
6
7
from uwsgidecorators import filemon
 
filemon('/tmp/foo')(uwsgi.reload)
filemon('/tmp/foo2')(uwsgi.reload)
filemon('/tmp/foo3')(uwsgi.reload)
filemon('/tmp/foo4')(uwsgi.reload)
filemon('/tmp/foo5')(uwsgi.reload)

于是这些文件出现修改的时候,就自动reload。其实你可以自己加入调用uwsgi.reload()的响应。

pylons, web.py, cherrypy ..

程序员自己研究去。

threading

原来使用内置线程做的异步程序会发现在uwsgi,里面的线程好像都没启动了、数据库没有连接了……原因是uwsgi加载了代码后,fork出多个子进程,子进程里面的线程如果没有被再度激活,是不工作的。

有两个方法,一是在这个app的配置里面加上:

lazy = true

这样代码会在子进程fork了之后才开始加载。

二是使用uwsgi模块的api,uwsgidecorators 里面有相应的装饰器,这样uwsgi会在fork之后自动调用你要重新启动的线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
from uwsgidecorators import postfork
 
@postfork
def reconnect_to_db():
    myfoodb.connect()
 
@postfork
def restart_threads():
    global thread1, thread2
    thread1 = MyThread1()
    thread1.start()
    thread2 = MyThread2()
    thread2.start()

监控

虽然uwsgi 默认带了SNMP功能,可以给外部监控其运行情况,但uwsgi的源码包里面带了个uwsgistatus.py文件,里面简单的提供了读取uwsgi模块的属性形成的报告。 可以把里面的代码copy到app项目里面,作为一个简单的监控数据。

2011-11-24_19-04-14.png

Reference

以上部分代码取自uWSGI Wiki页面

Python多重继承的异构构造器

November 23, 2011

What

在Python里面,如果你使用上Qt,SQLAlchemy,Twisted之类各种大型类库时候,有时候多重继承Multiple Inheritance是个简单的解决方法,但是多重继承的复杂性总容易造成误解和疑惑。

一般“常识”说,使用super访问父类的属性/方法,这种说法在多重继承里面是不成立的,多重继承的类并没有父类的概念(There is no superclass in a MI world)。类似的博客在过去几年被人写了无数遍了,因为过去版本里面python官方文档对super的解释非常有限而且有误导解释,直到2.6以后的文档,才详细说明了super在单继承和多继承的两种不同工作方式。当时苦逼的程序员甚至不得不去翻看Python源码才搞清楚是什么回事。以致几年来很多人对python的多重继承保持怀疑态度。

Python多重继承使用Method Resolution Order的动态算法来解决一个方法名的调用顺序,mro其实说来简单,就是一个深度优先的继承列表,很易理解,但随之来的是遇到互不相同的构造器__init__参数的问题。

Codepad运行结果:http://codepad.org/qQNiMzBl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A(object):
    def __init__(self, arg1):
        print "init func in A, with arg1 '%s'" % arg1
        super(A, self).__init__()
 
class B(object):
    def __init__(self, arg1, arg2):
        print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        super(B, self).__init__(arg1)
 
class C(B, A):
    def __init__(self, arg1, arg2):
        print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        super(C, self).__init__(arg1, arg2)
        print C.__mro__
 
c = C("C's arg1", "C's arg2")

执行结果:

init func in C, with arg1'C's arg1', arg2 'C's arg2'
init func in B, with arg1'C's arg1', arg2 'C's arg2'
init func in A, with arg1 'C's arg1'
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

可见几个类的构造器的执行顺序正是mro列表的顺序。重点是多重继承的各个类的构造器__init__之所以能够执行,是因为每个构造器里面都有一句super(),这个super完成mro列表中下一个类的构造器的调用

这个事实听起来似乎很自然,但看代码,B的构造器还得必须知道A的构造器的参数?B需要知道自己将会被C同时继承A,并且调用A的构造?!!很荒谬,但不幸的这是mro的特点。代码是可以这么写,但不应该,为另一个不知道什么时候会被一起继承的类特地地写代码,跟面对对象设计的解耦原则相违背。

How

在mro方式的基础上,这个问题是不可能有效解决的,只能避免。概括起来大概有这么 两种方式。

1.使用传统类的方式,显式调用被继承类的构造器,避开super的mro自动化工作。

Codepad 看运行效果: http://codepad.org/XCVdKCPm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A(object):
    def __init__(self, arg1):
        print "init func in A, with arg1 '%s'" % arg1
 
class B(object):
    def __init__(self, arg1, arg2):
        print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)
 
class C(A, B):
    def __init__(self, arg1, arg2):
        print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)
        #super(C, self).__init__(arg1) #这两行
        A.__init__(self, arg1)       #等价
        B.__init__(self, arg1, arg2)
        print C.__mro__
 
c = C("C's arg1", "C's arg2")

注意 C继承A,B的顺序已经改变。

要排除一个容易产生的误解。Python文档里面的super有个很显著的Note:super() only works for new-style classes. super只适用于新类。但新类并不必须使用super

直接调用被继承类__init__作为unbound方法调用,需要指定一个实例,如self作为参数,依次调用各个被继承类。缺点是若果这几个被继承类也在构造方法里面使用这样调用了同一个上级被继承类,会出现“爷爷类”的构造方法被调用多次的情况。

如果一定使用super,要注意继承列表的顺序。super(TYPE, self).method调用的是mro列表中第一个,也即继承列表第一个类的方法。

PyQt里面的类内部一般(未细究)都使用__init__的方式来初始化代码,因而很多PyQt的例子代码都是使用QtGui.QMainWindow.__init__(self)这样的代码来初始化。当然在单继承时候和super的写法是等价的,但最好使用统一的原则:

一个简单好记的原则:

  • 如果"被继承类"都使用__init__,"继承类"就使用__init__来初始化;
  • 如果"被继承类"都使用super,"继承类"就使用super来初始化;

2.使用Composition / Association Pattern的设计模式(即'Is-A'转换成'Has-A')来实现相同功能,避免多重继承。

这个方法听起来未免有点让人不快(破坏了原有设计思维),但实际上很可能这是更好的方式,更清晰的代码,尤其是要继承的类里面混合了使用super__init__两种初始化方式的时候。

Reference

HG的秘密武器 -- Mercurial Queue

November 2, 2011

Why

惯用版本管理的coder会发现,经常整理代码时候,要提交出一个完美的版本库还真不容易,有时候不仔细连语法错误的版本都commit进去了仓库,如果以洁癖的眼光看,这是不可容忍的:

  • 仓库每个版本均可无错编译
  • 每次提交的目的简单明了,不应多个不相关修改合在同一次commit
  • 提交说明可以简单明了和修改了的代码联系起来

Mercurial 默认配置情况下不易做到这个,相比起git,hg没有git的index概念,一次commit可以经过多次记录才确认成一个版本。但是hg自带了个插件Mercurial Queue,功能上可比git更胜一筹。

考虑这么一个情况,在做新功能探索的代码,尝试到有一步成果了,但后面出现几种方案需要测试,暂时还不知道用那个。如果把目前的版本提交,又不成熟,不足以作为一个版本。有mq的话,直接qrefresh记录当前的修改,再随便折腾代码,不爽直接revert,这个记录还没有成为commit,直到最后觉得满意了,qfinish my_perfect_patch,才最后提交成一个版本。

另外一个情况,在开发新功能时候,代码改了一堆了,突然rp爆发,一眼就发现了以前版本留下的一个很隐藏的bug。

没有mq的话,你有3种方式处理:

  • 记住!好大的BUG!完成这次功能,提交后再Fix掉! (然后忘了)
  • 把这行代码的位置写到paster贴显示器上;
  • 马上修正bug,继续写代码,最后提交版本的时候写: added xxxxxxx; fixed xxxxxx;

都不怎么靠谱吧,使用mq的话,这可不是什么问题:

  1. 暂停coding,记录下目前的进展,qrefreshqpop出当前已有修改。
  2. 创建一个新的patch,qnew fix_xxx
  3. fix bug,qrefreshqfinish fix_xxx。这时仓库里面已经有一个修好bug的版本了。
  4. qpush回到刚才的状态,继续coding新功能。

“提交 commit”是版本管理里面一系列不可修改的历史,一旦提交后就不能修改他们的状态和顺序。mq里面的queue虽然也是历史的部分,但还没有永久成型,可以任意改变,直到成熟,可有效提高仓库中的版本质量。

不过使用mq后这个情况也有点改变,配置好mq后会有了一个邪恶的strip命令,可以从提交历史当中直接删除一个commit。虽然这显然是不尊重历史的,不过作为灵活特性,git也有这样的功能,毕竟特殊时候可以避免信息泄漏等事情。

How

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
#几乎所有资料都叫你先运行hg qinit,不过这是过时的命令,所有mq的命令都会默认创建好patch环境
 
# 往常地,在版本目录里面改代码,coding ...
 
# 好了差不多了,我要记录下我刚才这一次优秀的改进,可能还不够完美,但绝对是空前绝后的。
 
hg qnew -m "fabulous improvement" wonderful-2011 # 创建了名为`wonderful-2011` 的一个patch,包括了刚才的所有改动;
 
# 现在hg diff是没有改变输出的;hg qdiff倒有。
 
# 继续浏览了一次刚才的美妙代码,哎呀有好几处暇疵什么的,啊有几个只有半边括号的,好吧已经改善了,已经运行过,跑的很好
 
hg qrefresh  # 现在改善后的代码也记录完成了。
 
# 哎呀发现了个大bug,这个bug应该在之前的代码上就完成修改的
 
hg qpop #把刚才的修改暂时去掉
 
hg qnew -m "fix bug" fix-bug # 新建一个patch
 
# fix bug fix bug fix bug
 
hg qrefresh #记录fix bug的修改
 
hg qfinish fix-bug #把fix-bug提交进去
 
hg qpush # 回到刚才的,wonderful-2011
 
# 继续coding
 
hg qfinish -a # 完美了,把所有patch都commit到仓库。收工。

Advanced

Mercurial Queue 名字虽然叫queue,但里面主要都是一个个patch栈的形式,对每一次patch进行pop/push那样的操作,每个栈称为一个queue,使用qqueue命令可以创建多个queue,并在它们之间自由切换,各个queue内的patch相互独立,自由度非常高(比git还灵活)。

每个队列里面的一系列patch是按先后顺序排列的,要应用的话必须按顺序。但是qguard命令可以让你选择性地应用相应的guard下某些补丁来测试 (orz) 。

其实mq的工作是基于项目目录下.hg/patches里面的内容,里面记录着你所有的patch。细细一想,其实每次qrefresh就是覆盖掉之前的修改,如果不小心改错了怎么办啊!!! 不怕,还有管理版本管理目录的版本管理 (误!),给patches目录建个仓库就是了嘛,mq已经为你设计好了,执行hg init --mq,即可,之后每次qrefresh,都可以qcommit一下让patches里面的仓库记录你的修改。

不过这样的特性太高级了,让我处理那么复杂的补丁机制估计会疯掉的,真有兴趣的同学情参考下列文档。

Reference

初级资料

高级资料

重点推荐A Git User’s Guide to Mercurial Queues,文章比较图文并茂解释mq里面的概念,而且和git特性做了优缺点对比。

以Python+Bottle框架作为jQuery.Uploadify控件的后端

September 5, 2011

jQuery.Uploadify是个功能强大的文件上传控件,基于Flash(3.0兼容HTML5),作为前端使用是个不错的选择。

目前的前端技术中,能够实现跨域POST的成熟方案一般只有借助flash,这也是Uploadify的特点吧。

Uploadify的官方提供的是一个php的后端,后端需要做的事情相当简单,就是把POST的临时数据存放到指定路径。 有不少中文资料是把uploadify作为.net程序的上传控件,原理其实一样,所以用Python实现也是很简单的。

其实那些实现的后端(包括官方实现的php)都有安全性问题,比如限制文件类型、指定上传路径都可以在远端控制,上传个木马之类会导致服务器被入侵。当然这是因为他们提供的例子是半成品,实际使用起码应该加上session id的验证之类,因为上传时候数据是由Flash发出的,和浏览器的Session无关。

下面的Python例子中,则就如还在beta阶段的uploadify 3的开发日志讨论的,暂时忽略掉folder参数。

完整的例子代码可在我的仓库下载

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
import bottle
bottle.debug(True)
from bottle import run, route, request, get, view, static_file, abort
import shutil
import os
 
UPLOAD_BASE = "/tmp/upload"
ALLOWED_TYPE = ("wmv","rmvb","mpeg","3gp","avi","mov","mp4","flv","mpg","vob","png","jpg")
 
@route('/upload', method='POST')
def do_upload():
    try:
        filename = request.POST.get('Filename')
        root, ext = os.path.splitext(filename)
        assert ext[1:].lower() in ALLOWED_TYPE, "Invalid file type: " + ext
        if not os.path.isdir(UPLOAD_BASE):
            os.makedirs(UPLOAD_BASE)
        filedata = request.POST.get('Filedata')
        assert filedata is not None, "Invalid Upload data."
        with open(os.path.join(UPLOAD_BASE, filename), 'wb') as f:
            shutil.copyfileobj(filedata.file, f, 8192)
    except AssertionError, e:
        abort(403, str(e))
    else:
        return filename
 
@route('/crossdomain.xml')
def crossdomain():
    return """<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
"""
 
@route('/static/:path#.+#')
def server_static(path):
    return static_file(path, root='static')
 
@route('/')
@view('upload')
def index():
    return dict()
 
run(host='0.0.0.0', port=8080)

Trac 运营环境最简易配置(uwsgi+nginx)

August 13, 2011

@felixonmars 点名要一份trac的最简易配置步骤,不过其实trac这样一个geek东西,即使按本文配置好跑起来后也依然是一套半成品,还有很多东西需要去看文档去配置,就像awesome, vim等,在一段陡峭的学习曲线之前,都不怎么好用。 所以其实本文也不会降低多少门槛,大概比直接看官方的guide安装的时候少点压力,但不一定是好事。

此前有在公司技术部内推广使用trac做项目管理的想法,做过了解,不过因为各种原因还是用不下来。赖勇浩的博客有一系列文章介绍trac,也包括了在公司环境使用的经验。

Trac作为一套web应用,其实部署步骤和此前介绍的MoinMoin, Mercurial很类似的。

以下步骤介绍安装包含多国语言的基本trac环境。

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
61
62
63
64
65
66
67
68
69
70
 
#安装基本组建
sudo -s
add-apt-repository ppa:nginx/stable
add-apt-repository ppa:uwsgi/release
apt-get update
apt-get install nginx uwsgi-python python-virtualenv subversion
 
#本次安装所需的路径,可按需修改
TRAC_ENV_PYHOME="/srv/trac/python-env"
TRAC_PROJECTS_DIR="/srv/trac/projects"
PROJECT_PATH="$TRAC_PROJECTS_DIR/myproject1"
 
#组件配置
cat >/etc/uwsgi-python/apps-enabled/uwsgi.xml << EOF
<uwsgi>
  <limit-as>256</limit-as>
  <processes>6</processes>
  <memory-report/>
  <vhost/>
  <no-site/>
</uwsgi>
EOF
 
#安装Trac, dev版本。
#虽然其实可以easy_install Trac,但是就不会编译多国语言了。
 
cd /tmp
virtualenv $TRAC_ENV_PYHOME
source $TRAC_ENV_PYHOME/bin/activate
easy_install Genshi
easy_install Babel
 
svn co http://svn.edgewall.org/repos/trac/trunk trac
cd trac
python setup.py install
 
#建立项目
mkdir $TRAC_PROJECTS_DIR
trac-admin $PROJECT_PATH initenv
 
#如果你的终端为中文(zh_CN.UTF-8,比如date命令是中文的年月日),现在应该是中文提示,否则以上安装可能问题。
 
#输入项目名称、数据库连接(默认)后,项目建立完成
 
trac-admin $PROJECT_PATH deploy $PROJECT_PATH/deploy
 
cd $PROJECT_PATH/deploy/cgi-bin
cp trac.wsgi trac_wsgi.py
 
chown www-data:www-data -R $PROJECT_PATH
 
cat >/etc/nginx/sites-enabled/trac-project1 << EOF
server {
    listen   80;
    server_name project1.trac.domain.com;
    location / {
                include uwsgi_params;
                uwsgi_pass unix:///var/run/uwsgi-python/uwsgi/socket;
                uwsgi_param UWSGI_PYHOME $TRAC_ENV_PYHOME;
                uwsgi_param UWSGI_CHDIR $PROJECT_PATH/deploy/cgi-bin;
                uwsgi_param UWSGI_SCRIPT trac_wsgi;
                uwsgi_param UWSGI_SCHEME \$scheme;
                uwsgi_param REMOTE_USER \$remote_user;
        }
}
EOF
 
service uwsgi-python restart
service nginx reload

现在打开浏览器,根据你的地址,应该能打开自己的Trac了。

一个Trac实例只管理一个项目,如果需要多个trac就需要重复上述“添加项目”后的步骤。

Tips:

上述trac-admin /xxx deploy命令后,生成的目录里面有个htdocs目录,包含了项目内的静态文件。如果在nginx配置里面加上这样一段:

        location /htdocs/ {
                root $PROJECT_PATH/deploy;
        }

(注意里面的$PROJECT_PATH变量要对应你实际项目的路径),

然后修改$PROJECT_PATH/conf/trac.inihtdocs_location =的值为/htdocs/

可以降低静态文件请求对服务器的压力。

最后,多看官方文档。

Nginx + PHP (via php-fpm) on Ubuntu 环境最佳实践

July 21, 2011

Nginx团队维护的PPA源带有PHP 5.3.x的子源,更新迅速,现在在Ubuntu部署Nginx+PHP环境真是太容易了(虽然LAMP更容易,一句apt-get install lamp-server^搞定,别漏了最后的上尖号)。像以前那样跑cgi-fcgi简直弱爆了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apt-get install python-software-properties
add-apt-repository ppa:nginx/stable
add-apt-repository ppa:nginx/php5
 
#Ubuntu 10.10 以后可不需添加以上源
 
apt-get update
apt-get install nginx
apt-get install php5-cgi php5-mysql php5-fpm php5-curl php5-mcrypt
 
#或者你需要更齐全的php包:
#aptitude install php5-cgi php5-mysql php5-fpm php5-curl php5-gd php5-idn php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl
 
service nginx start
service php5-fpm start

FPM Tunning

php5-fpm默认参数启动的服务器还是比较耗资源的,如果环境不充裕(如512内存以下的VPS),可以做下配置。

这个包的fpm的默认配置文件是/etc/php5/fpm/main.conf,但对子进程的配置是在其包含的/etc/php5/fpm/pool.d/目录内,里面有个www.conf,可以对以下的参数做以下修改:

pm = dynamic              ;动态管理php-fpm的子进程
pm.max_children = 5       ;最多的时候开不超过5个
pm.start_servers = 2      ;启动服务时候开2个
pm.min_spare_servers = 2  ;空闲时候最少留2个
pm.max_spare_servers = 5  ;最多留5个
pm.max_requests = 300     ;每个子进程最多处理300个请求就退出换新的子进程。

按需调整这些参数可以达到最佳动态分配资源的效果。

Vimrepress Having Big Changes (Updated Beta Version)

May 13, 2011

Update
Vimpress 已经升级到2.x版本,使用、配置都有改进,请关注在vim.org的插件页面:

Vimpress had been updated to 2.x, usage and configurations are now different, read the officle page in vim.org:

http://www.vim.org/scripts/script.php?script_id=3510


Hi guys, glad to know that many of you are having vimpress forked to improved it's power, while i'm also doing the same thing.

I'm working on a version that had been refactored a lot, changes include:

  • Commands simplified. No more BlogPageNew/BlogPageSave commands anymore, managing pages are available via the argument to the original BlogNew/BlogList commands, Meta fields shows you what kind of post you're editing.

  • Much better Markdown integrated. No more MarkdownXXX commands. You can decide what you edit (Markdown or HTML) in the meta field, when execute BlogSave or BlogPreview, program parse the meta field to got things done.

  • More easier editing wordpress in Markdown. Markdown rawtext will automaticly uploads as an attachment file. Updating a post before is complicated, now after you write a post in markdown in vimpress, and then want to do some update, just open the post in Vimpress, it downloads the attachment and show you your original markdown text, when you BlogSave again, the attachment also got updated for further editing.

This version of vimpress is not yet released, for i'm still debuging, i just finished all this features past few days. If any of you got interested, go to my svn:

svn checkout http://ptcoding.googlecode.com/svn/trunk/vimpress-dev

I separated python code from blog.vim to avoid my coding editor got confused about python syntax, i'll combine them together when final release, if you want to try now, got to change the last line about the python file in "blog.vim".

Now this version is now available as beta, you may try it for now:

https://bitbucket.org/pentie/vimrepress/downloads/vimpress_2.1.0beta_r34_179c33a255c7.zip

I would like to hear any advices from you.

By the way, the document attached is not yet updated, the commands list below are "legle" in the new version, you would find them easy to use:

The document attached is now updated, you may refer to it about the new usage, which are all simplified and powerfied, command examples:

  • :BlogList - List 30 recent posts.
  • :BlogList page - List 30 recent pages.
  • :BlogList post 100 - List 100 recent posts.

  • :BlogNew post - Write an new post.

  • :BlogNew page - Write an new page.

  • :BlogSave - Save (defautely published.)

  • :BlogSave draft - Save as draft.

  • :BlogPreview local - Preview page/post locally in your browser.

  • :BlogPreview publish - Same as `:BlogSave publish' with brower opened.

  • :BlogOpen 679

  • :BlogOpen http://your-first-blog.com/archives/679
  • :BlogOpen http://your-second-blog.com/?p=679
  • :BlogOpen http://your-third-blog.com/with-your-custom-permalink

Vimpress内置markdown支持、多博客支持

March 28, 2011

此前介绍用来编辑Wordpress的vim插件vimpress 现在加入了markdown支持,可以直接在vim中以markdown语法编写,使用新增的vimpress命令即可发布成格式清新的博客了。

还加入多博客支持。只需把需要管理的博客资料写到vimrc文件内,可以随时用BlogSwitch命令切换需要发布的博客。

还有加入编辑Wordpress的Page,不仅是Post,见BlogPageXXXX等几个命令。

另外是改进了插件在windows等平台的支持,自动转换gbk等为utf-8编码来编辑博客。

这次版本改进得到了Lenin Lee的代码贡献和测试,在此表示感谢!

Markdown 介绍

Markdown 是一个很轻量的文本标记语言,其语法直接可翻译成HTML,便于用户编写和阅读,可以很方便地生成多级标题、链接、缩进、加粗、列表等等格式,实际上和通用的WikiText、reStructed等标记语言的语法都有一定的相通之处。

推荐:Markdown 语法

Vimpress的Markdown 命令

在Vim中用markdown书写好文章后,可以先使用:MarkdownPreview命令在浏览器里面看看编译效果。虽然这样的页面没有CSS修饰,但是文章的结构应该是清晰的,可重复修改。

然后使用:MarkdownNewPost命令,如果原文件中前10行有包含#符号开头的一行(即markdown语法中的header),会被复制成title,并跳转到vimpress的NewPost界面,就可以用:BlogSave publish发布了。

这个流程相当简单直接。

Vimpress的多帐号支持

该版本的博客信息要写入vimrc文件当中。通常, Linux下,该文件位于~/.vimrc; Windows下,C:\Program Files\Vim\_vimrc

在该文件加入这样一行:(vimrc中的前置\是换行号)

let VIMPRESS=[{'username':'user',
              \'password':'pass',
              \'blog_url':'http://your-first-blog.com/'
              \},
              \{'username':'user',
              \'password':'pass',
              \'blog_url':'http://your-second-blog.com/'
              \}]

启动vim后vimpress默认使用了第一组的配置信息,使用:BlogSwitch命令可以在它们之间轮环切换。

下载

http://www.vim.org/scripts/script.php?script_id=3510

改进记录

 2011 Mar. 24 [by Lenin Lee]
               Fix: use setl instead of set to set option value;
               Add: Detect current buffer content before switch to vimpress
                views, open a split buffer to avoid conflic.
               Add: Commands to manage wordpress pages.
 
[by Preston]
               Add: Auto charset convert for non-utf8 environment.(Win)
               Add: Use python markdown module. Both markdown and markdown2
               are supported.
 
2011 Mar. 15 [by Preston]
               Fix: MarkdownNewPost may override original mkd source file.
               Add: MarkdownNewPost command detects title begins with
                   "#" in first 10 lines of markdown source, copy the line
                   striped "#" to the new post view.
 
2011 Mar. 7  [by Preston]
               Add: MarkdownPreview command to preiview markdown in browser.
               Add: MarkdownNewPost command to convert a markdown
               written post into html and set to the new post view.
 
2011 Mar. 4  [by Preston]
               Add: Move blog config info to personal .vimrc
               Add: Multiple blog config is now supported with :BlogSwitch
               command.
               Add: Show which blog your editing at :BlogList view.
               Fix: bug running :BlogList in the List view got error.

Page optimized by WP Minify WordPress Plugin

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org