MayCoder

Valarmorghulis

Hive Compile and Apply Patch

2012-09-20

回归来的第一篇,另外还有好几篇躺在 published:false 中,还没搞好 :-(

这个礼拜最大的收获是编译啥啥啥还是蛮简单的,又没叫你去改代码。有些东西动手尝试一下,往往会发现没有多难,不能停留在口上上说说而已。看到 一段相关但不是很切题的话 :

不可忽视的一点是:在技术性团体里,做永远比说要来的有效。在想法成熟之前就贸然游说,往往会招致相反的效果。大家都是工程师,不会贸然接纳陌生事物。如果自己都还没有想清楚就开始大肆游说,往往会被大家提出的实际的工程问题驳斥地体无完肤。当你哑口无言之时,大家也已经对你的方案产生了难以磨灭的 “不靠谱”的第一印象,这时要再想咸鱼翻身,可就没那么容易了。

相对的,首先自行查阅文档资料并进行试验,制作demo,通过试验发现和解决实际出现的问题。在想法基本成型时,和个别观念开放的同仁进行探讨,这时往往可以发现大量之前自己没有考虑到的问题,再转而细化方案。这个过程反复迭代几次之后,方案和demo逐渐成熟,同时也潜移默化地达到了传教的目的。等到方案完全成熟之后,再拿出实际可工作的demo开始游说,这时自然就成竹在胸了。

进入正题,这里主要是参考几篇文章,说说编译hive和打补丁, 或者说贴贴链接= =

hive 代码编译

install hive on linux
使用ant编译hive
hive打补丁编译hive

这里我在ubuntu上操作的, 编译hive需要依赖 JAVA, ANT (这里不依赖hadoop原因是ant会自动去下载hadoop)。
安装好后export JAVA_HOME , ANT_HOME 变量 (我直接加入.bashrc当中了)。
接下来去官网下载hive源码包。这里我使用的是 hive.0.9.0 。 解压之后进入src目录,需要修改一些配置:

build.properties
1
2
3
4
5
6
7
8
9
hadoop.version=1.0.1

主要是facebook被墙了,镜像地址可参考 http://www.apache.org/dyn/closer.cgi/hadoop/core/
hadoop.mirror1=http://mirror.bjtu.edu.cn/apache  
hadoop.mirror2=http://mirror.bjtu.edu.cn/apache

以下的修改主要是看到镜像中的hadoop版本已经没有默认的版本号了,估计是不支持了?故改成包含的版本号。
hadoop-0.20.version=0.20.2
hadoop-0.20S.version=1.0.1 (S的版本不知有没有啥区别)

接下来执行 ant package 即开始编译了, 结果默认会放在 build/dist 目录中,使用 -Dtarget.dir=xxx 可以更新目标位置。

如果BUILD FAIL的话,一般参考提示可以看出是哪里出了问题(遇到比较多还是被墙的问题= =)。

hive 单元测试

hive中的单元测试
hive中的test case
QtestUtil.java
hive unit test

hive 中的 单元测试 还是蛮有趣的,既有传统的单元测试代码,又可以批量执行查询脚本判断结果是否一致:

在hive中会有大量的.q的文件即执行测试的query文件,.q.out是测试的结果文件。 进行新测试后产生的结果和标准的q.out一致则表示测试成功。
具体来说,src/ql/src/test/queries下面是测试用例,clientpositive是运行成功的用例,clientnegative是运行失败,返回非0的用例。 src/ql/src/test/results 下面是测试用例对应的输出结果。 如src/ql/src/test/queries/case_sensitivity.q对应的输出结果是src/ql/src/test/results/case_sensitivity.q.out 。

使用 ant test 运行单元测试,不过此命令要跑好多测试, 光TestCliDriver一项就要跑好几个小时 , 我们可以

ant test
1
2
3
4
5
运行所有的正面的测试
ant test -Dtestcase=TestCliDriver
 
运行特定的测试,以groupby为例子
ant test -Dtestcase=TestCliDriver -Dqfile=groupby1.q

使用 -Doverwrite=true 可以覆盖结果文件,后面有新的更新想测试表现是否一致的时候就可以使用了, 通常在我们增加新的udf的时候可以这么来生成测试数据。

hive代码打补丁

下载了 hive 0.9.0 稳定版,不过发布之后还是有若干bug,这时搜索一下 hive jira 一般能看到相应ticket,比如 这个substr遇到UTF8的问题 。一般打的补丁会走一个 publish-review-apply过程 ,准确解决问题的补丁会被加入版本库中,而临时补丁一般不会采用。作为用户,有时难免得打一些这样的补丁。打补丁也很方便,下载社区提供的补丁之后,使用 patch 命令即可以应用到源码中, 后续在进行编译测试即可。

另外我们有时会有需求将 自己使用的 udf 编译到hive当中以方便使用 ,这其实也可以看成打补丁的行为。

打补丁多了,管理是后面会遇到的问题。 就个人而言,可以自己载个官方的git仓库,然后开分支来维护自己的变更。如果要多人协作的话,可以创建一个新的git仓库,然后添加两个远端, 其中一个是官方的git仓库,另外一个可以是大家从某个分支开始维护的版本。纯属yy,实际操作起来也未必省心。 这里看起来使用 github organization 是蛮适合的。

当然,可以预见的是,大部分时间我们都不会打补丁,可能只会在新增一些UDF= =, 于是似乎完全没有必要这么干, 大概 类似这样就可以了 , 看起来一般将用到的udf打包,然后要用的时候加一句声明即可。

不过我还是蛋疼去搞了一个 organization , fork一下官方代码。 我在本地git加入 apache/hive 作为另一个远端, 称为 mirror 。由于我们目前使用的是 0.9, 故我考虑的是在 origin/branch-0.9 下做开发,并将 mirror/branch-0.9 定期 merge 回 branch-0.9 。至于 trunk 则不动。

这样一来我就开始捣鼓了,首先还是改 build.properties , 我将这些也一并提交到分支里面了。 然后我开始将 udf 编译进去,这次遇到一个比较坑爹的问题就是 编译一直成功,但是执行单元测试一直找不到新的UDF 。 捣鼓了很久无果后找小美支援,小美在分析一阵之指出测试的时候没有引用到编译的 FunctionRegistry.class , 估计使用到别的旧的文件了。又过了一段时间之后我确实发现有个地方 ~/.ivy2/ 下面有一些cache, 简单google之后又发现 hive jira 上已经有一个 tck , 看了大概是由 HIVE-2646 引入的, 导致测试的时候会从ivy cache来加载hive相关的类而不是 build/dist/lib 。这个改动恰恰不在 0.9.0发布版但是 commit到 branch-0.9 中了, 所以我从 branch-0.9 的代码开始编译就中招了。这个patch有加入trunk中,故 cherry-pick 一下即可(本来我打算直接打patch的)。当然这里我不清楚为啥这个补丁不加入 0.9 分支,估计不算大问题? 没有运行bug?从版本库编译就是比较坑爹= =

Learning Algo Part I at coursera.org

用来记录我在 coursera.org 上学习 Algo Part I的记录,写完之后发布。

看起来要来不及了。。。要不然就看PPT恶补吧,dealline(9月30号)快到了。

2012.12.16
以上已经完全来不及= = 我的第一门coursera课就这样悲剧了。
另外后续我跟小美同学一起开始学 compiler 这门课,还是没有分出足够的时间来做相应的学习,不过小美同学就很有效率地完成了大部分作业。
近期我的 第三门课 已经开课两个星期了,我感觉必须搞定这种被时间追赶着的状态。
之前一直困扰我的是网络太差,看视频太麻烦,于是google 一个能下载视频的脚本,果然 很容易在github上找到了
代码写的还蛮简单漂亮的,后续下载视频只需要一句话:

coursera video download
1
/Users/code6/git/coursera/coursera-dl -n --path  "/Users/code6/Downloads/coursera/videos/algo2/"  -w /usr/local/bin/wget algo2-2012-001

如果一个东西很难获得,势必增加做某件事情的阻力,但如果太容易获得,也是如此,在下载视频这件事来看也是如此。

Back for Blogging More

2012-09-13

感到很失败,未能完成之前所说的一周发表一篇blog的计划。
但我还是有很多想说的,感觉如果在工作中不能记录下只言片语的话,那到头来就没有什么留下了了,所谓经验其实远不如总结沉淀来得安稳。
但我是不是没有干活呢,只能说是懒惰,不想多费些时间心力来记录生活,学习。
那今天是什么一个情况呢,组里面吃饭的时候在讨论一些问题,聊到了执行力,能力。想想我在blogging上的动作,实在羞愧。
其实有很多方面可以记录,无论是失败还是成功,我常常想所谓的不成熟其实是最大的阻碍,就像wiki一样,先有了,然后可以慢慢更新的,犯不着要一下子就掌握的非常好。
所以,仅以此blog作为契机,让我再次开始记录生活,记录工作。
blog是另外一种认识自己的方式,可以更深刻,更有味道。

6月第一周比赛小计

2012-06-04

6月第一个周末比赛好多啊,做了其中的4个,很爽:

比赛 开始时间
Astar 2012 R1a 2012.6.2 10:00
ipsc 2012 2012.6.2 18:0 0
TCO 2012 R2c 2012.6.3 00:00
Astar 2012 R1b 2012.6.3 10:00

结果不是很重要,关键是又稍微思考了下, 但这样没有规律的思考是无法提高的,倒是也得想办法弄一个周期性较强的训练时间, 挨个稍微说一下吧。

  • Astar 2012 R1a
题目ID 标题
A 度度熊就是要第一个出场
B 小小度刷礼品
C 集合的交与并
D 轮子上的度度熊

这场做了B和D吧, B就是很土的算1到N里面有多少个以x结尾的数, D的话我暴力了一下,大数据会超时,不过来不及想优化了, 感觉没有优化写起来就像很无聊的DP。 另外A其实是可做的,bfs一下应该就可以了, 跟印象中某ZOJ月赛一题有像,也跟今年的WF的镜面反射的题目有点相似(题型)。 感觉运气好可以晋级吧,毕竟只做了1题多一点点而已。

  • ipsc 2012
    与毛哥一起搞了今年的ipsc, 用的是我们当年组队的名字 ACOrz , 可惜daxia没来一起做。稍微迟到了半小时,毛哥已经把A过了,然后看了C, F, I了。C我尝试了两三次,无果,后面先放弃了。放弃C之后就很顺了,跟毛哥一起砍了一些大众题目。依次是
    • G
      算有向图最大长度的链。由于图挺特殊的,只有一个出度,故也挺好算。
    • I
      md5 decrypt 挺好用的,直接将大小数据都过了= =国内的网站就不行,还要收费- -
    • F
      毛哥暴力了小数据,然后我们在只有两个硬币的情况下做简单演算, 得到 p1*(1-p2)+p2*(1-p1)=1/2 这个式子,直接解出 p1 = 1/2 or p2 = 1/2 , 于是也很容易了。
    • C1
      C1 后面我又试了下记忆化搜索,于是就过了= =, 一开始dp比较随意了,改成记忆化暴力所有可能于是过了。猜测大数据也是类似搞法,不过状态可能稍微多了,未作深究。
    • B
      B毛哥猜得很欢乐, B1还好,B2我们真是非常惊险,猜到第30次才得到答案(最多猜测30次),毛哥还用啥迭代法来逼近来着。

      最终ipsc排名一百多名,算是本周最欢乐的比赛了,当然还有很多没有切出来, 回头可以再看看。
  • TCO 2012 R2c
    ipsc 做到了晚上11点结束,12点就是 TCO R2c了,能不能拿衣服就看这场了。悲剧的是比赛前20分钟家里断网了,折腾了好些,搞好的时候已经12点20分了,顾不上就奔去了。300分是一个有点代码量的枚举,写到了144分。。500打开只有半小时了,看了下,这不就是土土的树状数组吗!马上搞啊搞,在最后10分钟的时候样例一直过不了,还有一个即simple的样例,没来得及看明白 比赛结束了。后面再看了下,发现题目看错了= = 顺序有点小变化,当然做法还是树状数组。感觉构造还是挺巧妙的,多增加了啥,该扣除啥。另外本次的900pt貌似也可做,没来得及看,某些人直接搞900晋级了,真给力。
  • Astar 2012 R1b
    由于2号搞到比较晚,起床的时候已经是10:30了,外加还得洗碗= = 题目现在看不到了,仍然是4道题。最终做了B, C。B是二分加并查集,挺简单的。C 简单yy了一个贪心,感觉想简单了。A是算n个数中选若干数异或值的最大和次大,没想明白, 别人说是’搞基’ 。 D没有想法。 这场要晋级的话也比较悬,重在参与~

总之,整个周末还是挺紧凑以及有趣的(还出去骑了两次车),每次比赛后都留下一些未解之谜,现在不能像以往一一攻克并提高战斗力了,不过真想把不会的继续搞懂!

Deal With Special Characters in Hive Query Result

2012-06-02

知识,想法是需要整理的, 不然容易遗忘, 又过了好久没有更新, 怨念= -
这段时间搞了一点hive之类的东西,遇到一些问题,后续也许还会整理一点出来。
最近遇到的关于hive的问题是:

将hive查询结果从临时文件导入mysql的时候, 由于查询结果中有特殊字符(比如反斜杠, 制表符等), 导致数据导入mysql时解析出错。

这里得先说明一下mysql导入导出的默认行为。 mysql命令行输出默认会做转义 并且在 导入的时候默认会将反斜杠转义 , 我们一般不会感觉到这一步。当相同问题发生在hive的查询结果时,有些时候字段末尾或行末尾的 \ 会将间隔符 \t 或换行符 \n 转义, 导致导入出错。 如果关闭mysql导入时默认转义的话, 那么字段中包含的间隔符 \t 会导致列数变多,同样出现问题。

十分讨厌hive查询结果中的特殊字符, 究其原因主要是 hive查询结果目前无法对特殊字符进行转义 , 另外比较头疼的是 hive cli 或者 hiveserver 的查询结果中, 默认的字段分隔符都是 \t 且不方便变更。 在解析日志的过程中, 字段中难免包括 \t, \ 这类特殊字符。此问题还得仔细对待, 在网上搜了下,大概有几种方法, 未找着较优雅的方案。

绕过转义问题

一种做法是我们绕过此问题。如果我们不对查询结果进行转义,那么我们就只能让mysql不对导入数据进行转义了( no_backslash_escapes ), 这里需要我们对查询结果给定一个特殊的分隔符,比如 0x01

  • CTAS
    具体内容即

When you are doing output to the console \T is your only option. The
best way to handle this is create another table with the delimiters
you wish and then select into that table. You can do this with CTAS.

比如

CTAS
1
2
3
4
create table xzy 
row format delimited
fields terminated by '\001'
as select age, dt  from ibtest limit 1;

这里可以指定任意的分隔符,但这边文件在 /user/hive/warehouse/xzy 中,我们还得将其合并输出到临时文件中。

  • INSERT OVERWRITE LOCAL DIRECTORY

local directory
1
2
INSERT OVERWRITE LOCAL DIRECTORY '/mydir'
SELECT XXX

直接写到外部文件夹, 此时分隔符为 0x01

  • concat_ws
    这个算是一个比较取巧的方法吧,xyc介绍的:
    将查询结果先转成string, 然后 concat 起来,并指定分隔符。这样由于最终只有一列,所以不会 加上系统默认的分隔符了。

concat_ws
1
select concat_ws('\001', cast(userid as string), cast(cityid as string), regdate) from hiveuser limit 10;

勉强进行转义

另外一种做法是勉强在hql中进行转义, 比如将 \ 替换成 \\ , 将制表符替换成 \t :

regexp_replace
1
regexp_replace(regexp_replace(column, '\\\\', '\\\\\\\\'), '\t', '\\\\t')

这里得在可能出现特殊字符的地方做上述修改, 为防止写得繁琐,可以考虑封成 udf

总结

总而言之,目前并没想到较好的处理方法。反过来想,类似制表符的特殊字符在日志中是否有意义,如果没有的话,可否去掉? 这样一来就愉快多了,但是 破坏原始日志 ,感觉也不是很好。

How to Build a Dynamic SQL in an Elegant Way

2012-04-04

换上octopress, 写blog还是不勤快, 目前装在虚拟机当中,怎么勤快:(。

不岔开话题,这次讨论的是如何 动态地生成一条查询SQL 。起因是一个统计报表要新增加一些筛选条件, 而这些筛选条件并非简单加一个where条件,有时还要涉及到联表(join)以及聚合条件的改变。原先我的做法是 设几个变量,诸如where, groupby, joins等,然后再将这几个变量合起来,这之中得考虑逗号,是否需要插入’and’等, 简单来说还行,但如果多个地方都需要用到,那么稍微麻烦了,而且代码重复较多, 所以我想找找有没有动态生成查询SQL的更方便的方法。

看到 一篇blog , 大概讲的就是平常的一些小技巧吧, 比如使用implode来拼where条件。

后来在stackoverflow看到 一个帖子 , 这个问题跟我面对的问题基本一致,帖子的第一个解答即是我最终采取的方案。即是写一些函数来记录主要的内容(select内容,join表与条件, where条件, groupby条件等), 然后按确定的方式来拼出最终的查询语句。

后面看到一个 squlbuilder ,看上去有点重,有很多功能目前都还不需要用到。

最后看到github上的一个 SQLBuilder ,感觉实现得还不错,当然也有很多我不太需求的功能,故在其基础上删减了一下,快速实现了,放到 github 上了。

一个简单的demo:

demo 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$sqlbuilder = new QueryBuilder();
 $sqlbuilder->table('fact.`order`', 'f')
          ->select(array(
                'city',
               'quantity' => 'sum(quantity)',
               'averageprice' => 'ifnull(sum(revenue) / sum(quantity), 0)'))
          ->join('dim.date', 'd', '', 'f.date = d.date')
          ->where('d.date between ? and ?', 'ss', array($begin_date, $end_date))
          ->groupby('d.month_num_overall')
          ->orderby('d.month_num_overall desc')
          ->limit(3)
          ->offset(3);

echo $sqlbuilder->build();

输出结果格式化如下:

demo 1 output
1
2
3
4
5
6
7
8
9
SELECT city,
       sum(quantity) AS quantity,
       ifnull(sum(revenue) / sum(quantity), 0) AS averageprice
FROM fact.`order` f
JOIN dim.date d ON f.date = d.date
WHERE d.date BETWEEN ? AND ?
GROUP BY d.month_num_overall
ORDER BY d.month_num_overall DESC,d.month_num_overall ASC 
LIMIT 3, 3

其中 getBindParams 函数返回一个数组, 包含绑定的变量的类型以及具体的变量, 比如 array('ii', 1, 2) , 而 getReturnParams 函数则返回查询结果列名数组。

目前还简单增加了 子查询 的支持。

一个查询 gini系数 的demo如下:

gini demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$sub1 = new QueryBuilder();
$sub1->table('fact.`order`', 'f')
  ->where('d.date between ? and ?', 'ss', array($begin_date, $end_date))
  ->where ('coupontype != 4')
  ->orderby('focus', 'f.revenue');

$sub0 = new QueryBuilder();
$sub0->table(" (select @cs := 0) ", 'cs_idx')
  ->join(" (select @focus:='') ", "s_idx")
  ->join($sub1, 'raw')
  ->select(array('accumulate_revenue' => '@cs := CASE WHEN @focus != raw.focus THEN raw.revenue ELSE @cs + raw.revenue END',
                'focus' => '@focus := raw.focus'));

$gini  = new QueryBuilder();
$gini->table($sub0, 'base')
  ->select(array(
        'focus',
       'g' => 'truncate(1 - 1.0 / count(*) * (2 * sum(base.accumulate_revenue) / max(base.accumulate_revenue) -1), 2)'))
  ->groupby('base.focus');

echo $gini->build();

输出如下:

gini demo output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SELECT focus,
       truncate(1 - 1.0 / count(*) * (2 * sum(base.accumulate_revenue) / max(base.accumulate_revenue) -1), 2) AS g
FROM
  (SELECT @cs := CASE
                     WHEN @focus != raw.focus THEN raw.revenue
                     ELSE @cs + raw.revenue
                 END AS accumulate_revenue, @focus := raw. focus AS focus
   FROM
     (SELECT @cs := 0) cs_idx
   JOIN
     (SELECT @focus:='') s_idx
   JOIN
     ( SELECT f.FOCUS AS focus,
          f.revenue
      FROM fact.`order` f
      WHERE d.date be tween ?
        AND ?
        AND coupontype != 4
      ORDER BY focus,
               f.revenue) raw) base
GROUP BY base.focus

代码测试方面, 后面发现参考代码是使用 phpunit 来进行单元测试的,简单地使用一下,还是挺好用的:)

目前还算能满足需求,当然对于预处理语句的变量处理还可以改进,收集需求再改进吧。

Octopress Setup

2012-03-09

最早是在lzyy的blog看到 使用github作为博客引擎, 后面在github上看到了 他的博客的源代码 , 顿时感觉很不错, 这样写blog大概有几个优点:

  • markdown
    可以使用惯用的markdown来写文章(比如我觉得 textileconfluence 的编辑语法很像)
  • git && githhub
    使用git进行版本控制, 放在github上保存, 使用 github pages 发布, 空间再不是写blog的障碍了:)

经过约一周的围观与尝试= =, 差不多搞到可用了,剩下了就是加page, 搞插件,熟悉语法了。捣鼓过程无比心酸, 鉴于一个windows用户, 又不愿在windows上搞, 碰巧vmplayer中仅有一台别人配的centos, 于是开始捣鼓了。octopress 需要ruby, python(其中用到 rubypython 似乎有依赖), git, ssl等一系列乱七八糟的东西, 按官方的说明去安装倒也无碍, 不过由于之前随意安装了一些低版本的东西, 往往会导致后面发现跑不起来, 于是也多了很多弯路, 总的来说, 顺风顺水的话, 安装还是很容易的

Octopress Setup

安装过程可以参考官方文档(参见附录), 这里结合我的环境(centos 5.7)复述一下, 后面再说说我遇到的囧问题。

  • git && github
    首先要有git, 为了在github上保存且发布, 要申请一个github账号并上传ssh key以支持push, 见 github帮助
  • 创建ruby环境
    octopress 需要 ruby 1.9.2, 用 rvm 可以方便安装, 先安装rvm

install rvm
1
bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

为了更方便使用rvm, 我们将其加入bash_profile中

add rvm to bash_profile
1
2
echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
source ~/.bash_profile

安装ruby 1.9.2 获取最新的 rubygems , 并安装 bundler

install ruby
1
2
3
4
rvm install 1.9.2 && rvm use 1.9.2
rvm rubygems latest
ruby --version  # Should report Ruby 1.9.2
gem install bundler

  • 下载并安装octopress

install octopress
1
2
3
4
git clone git://github.com/imathis/octopress.git octopress
cd octopress    # If you use RVM, You'll be asked if you trust the .rvmrc file (say yes).
bundle install  #install dependencies
rake install    # Install the default Octopress theme.

上文中用到一个 rake , 可以认为就是一种预先编好的 任务脚本 , 观察文件夹中有一个 Rakefile 打开看看就大概猜了下。

到这一步基本在本机上已经安装好octopress了, 我们可以把它发布到Github上(当然你还可以部署到 其他地方 )。首先你得建一个以用户名命名的类似 username.github.com 的Repository。比如我的就是 code6.github.com, 然后设定Github Pages:

rake setup_github_pages

之后会要求 read/write url for repository
git@github.com:yourname/yourname.github.com.git 替换成自己的即可。

  • 建立和发布

deploy
1
2
rake generate
rake deploy

很简单吧, 两条命令就搞定了~, 接下来就可以浏览 http://username.github.com
这里我们是将生成的站点的静态文件发布到了 username.github.com这个仓库的master分支上, 但这并不包含我们的源文件。 这里我们可以将原始文件提交到source分支上

initial commit
1
2
3
git add .
git commit -m 'initial source commit'
git push origin source

  • 目录结构

到这里我们基本搞差不多了, 可以开展日常工作了,这里可以先熟悉相应的代码结构。
这里主要的目录有 source , public , _deploy , 还有个全局配置文件 _config.yml
其中
source 为源文件目录, 我们写的文章就在 source/_posts 中, 当然还包括布局, 页面等好多东西
public 为渲染后的静态blog目录
_deploy 是用来需要部署的文件目录, 大概觉得是 public 的一份拷贝
_config.yml 是全局的配置文件, 语法参考 这里

这里插一个题外话, octopress是基于 Jekyll 的, 最开始尝试时下载了jekyll, 由于前端方面的薄弱技能, handler不住, 于是才使用octopress的。最初还看了一个 jekyll-bootstrap , 用起来也不麻烦,但猜测没有octopress强大这边的 _config.yml , source 都跟jekyll中的有关, 于是后面如果要捣鼓的话, 可以在那边多看看。 source 目录可以参考jekyll的相关 wiki

  • 日常任务

建立新文章
文章必须发表在 source/_posts 下,命名成 YYYY-MM-DD-post-title.markdown 的格式, 我们可以使用octopress的rake 任务来快速创建一篇新文章:

rake new post
1
2
rake new_post["Zombie Ninjas Attack: A survivor's retrospective"]
# Creates source/_posts/2011-07-03-zombie-ninjas-attack-a-survivors-retrospective.markdown

默认的后缀是 markdown , 可以在 Rakefile中修改。通过此任务创建的文章会补上开头的 元信息
接下来我们就可以用自己喜爱的编辑器来编辑了。

建立页面

生成与预览
当我们完成一篇文章的创作时,我们可以在本机预览我们的文章。

generate and preview
1
2
rake generate   # Generates posts and pages into the public directory
rake preview    # Watches source/ and sass/ for changes and regenerates, and mounts a webserver at http://localhost:4000

其中 rake generate 是将文章和页面生成到 public 目录中,后面我们才能发布我们的改动。
rake preview 会在本地4000端口起一个网站服务器, 我们访问 http://localhost:4000 则可以看到自己的博客。还有一点是它会监听 sourcesass 的改动,并重新生成文件,也就是说我们无需重启服务器就可以预览最新的文章。

发布
同上文。

更新octopress

upgrade octopress
1
2
3
4
git pull octopress master     # Get the latest Octopress
bundle install                # Keep gems updated
rake update_source            # update the template's source
rake update_style             # update the template's style

更多请参考 官方文档

textile语法参考
考虑使用textile来写blog, 可以从很多github上的repo中来学习。参考 github上挂的Jekyll的站点 , 或者参考 相关手册 。 注意文件后缀名不要 拼错 , 否则无法渲染。 使用过程中感觉textile对于 空格要求比较严格 , 该 留空格 的地方还得留一下, 另外段落之间也最好 留一个空行 。 另外发现textile的一些标签不是非常好用, 还得自己做尝试才能得到预期效果。 当然你也可以考虑直接使用 markdown

安装补充

这边主要想说一下我所遇到的问题,当然不是所有人都会遇到,仅限于比较悲剧的人来说。

GemFile
把源改成http://ruby.taobao.org, 据说会比较快, 具体我这边就是讲 gemGemFile 稍微改了下。

ruby blows up with gem dependency
参考 这里 , 重装一下ruby并升级一下:

reinstall ruby
1
2
3
rvm uninstall 1.9.2
gem update --system;
gem pristine --all

rubypython 调用到libpython2.×.so失败

由于我先前是用pythonbrew来安装python的,装了python2.7, 本机自带了一个python2.4。 我将pythonbrew关掉, 就ok了,未深究。

ruby环境安装不全
通过 rvm requirements 查看一下需要预先安装什么,然后装好再重装ruby= =

rdiscount fail to generate
据说 rdiscount 会快一些, 这里重装一下就好了。。

reinstall rdiscount
1
2
gem uninstall rdiscount
gem install rdiscount

deploy时拷贝swp/swo文件失败
简单在deploy时忽略swp,swo文件, 在Rakefile中修改:

modify rakefile
1
  FileList["#{args.source}/**/.*"].exclude("**/.", "**/..", "**/.DS_Store", "**/._*", '**/.*.swp', '**/.*.swo').each do |file|

异地重新clone一份blog的时候deploy失败
参考 这个issue ,看起来重新clone的时候还需要再次执行一边 rake setup_github_pages 才行。

rake preview 报"sorry i cannot find /"
看起来是public目录没有生成完整,可以尝试一下 rake generate 一下再 rake preview


附录

Octopress Setup
Octopress: a blogging framework for hackers
Ruby开源项目介绍(1):octopress—像黑客一样写博客
Blog = GitHub + Octopress
如何高效地使用GitHub
Blogging Like a Hacker

A Little Test

hello
h2. hello
h3. hello

  • affsffe
  • fsfewfewffe
    • wwwwwwwww

Textile Exmpale

(test.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
sample javascript from xui
*/

var undefined,
    xui,
    window     = this,
    string     = new String('string'),
    document   = window.document,
    simpleExpr = /^#?([\w-]+)$/,
    idExpr     = /^#/,
    tagExpr    = /<([\w:]+)/,
    slice      = function (e) { return [].slice.call(e, 0); };
    try { var a = slice(document.documentElement.childNodes)[0].nodeType; }
    catch(e){ slice = function (e) { var ret=[]; for (var i=0; e[i]; i++)
        ret.push(e[i]); return ret; }; }

window.x$ = window.xui = xui = function(q, context) {
    return new xui.fn.find(q, context);
};

Here’s an example .rvmrc file.
1
rvm ruby-1.8.6 # ZOMG, seriously? We still use this version?

install rvm
1
bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

    bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
  

echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
source ~/.bash_profile
# If using Zsh do this instead
echo '[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm' >> ~/.zshrc
source ~/.zshrc

ssh desktop -D 8080 desktop

ssh desktop -D 8080 desktop


ssh desktop -D 8080 desktop

hello rsync

from="10.1.1.1",command="/home/remoteuser/command" ssh-dss AAAA...

1
2
3
_Tweets_ = 1

module.exports = Tweets

  • Separate paragraphs with two newlines.
  • Use one newline only if you need a
    tag, otherwise, no newlines inside the paragraph.
  • When creating a new page, don’t forget the YAML premable at the top (Jekyll needs the page title and layout).
  • The layout uses H1 to render the page title; only use H2 through H4 for the page content.
  • Use H2 headers for the major page sections. Give each H2 header a unique ID so the table of contents can link to it.
  • Separating sentences with two spaces, just a convenience when editing in a text editor using monospaced fonts.
  • If in doubt, ask.

Hello

This is the first level of quoting.

This is nested blockquote.

Back to the first level.

(test.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
sample javascript from xui
*/

var undefined,
    xui,
    window     = this,
    string     = new String('string'),
    document   = window.document,
    simpleExpr = /^#?([\w-]+)$/,
    idExpr     = /^#/,
    tagExpr    = /<([\w:]+)/,
    slice      = function (e) { return [].slice.call(e, 0); };
    try { var a = slice(document.documentElement.childNodes)[0].nodeType; }
    catch(e){ slice = function (e) { var ret=[]; for (var i=0; e[i]; i++)
        ret.push(e[i]); return ret; }; }

window.x$ = window.xui = xui = function(q, context) {
    return new xui.fn.find(q, context);
};
    rake generate
rake deploy