聚會時間公告: 因應COSCUP 2011, Kalug 8月份休會一次

十月 21, 2011
» 在Python用Data Object傳遞資料 II

前言

之前我從在在Python 用Data Object傳遞資料裡介紹了 Data Object的寫法, 在這篇介紹另一種實做方式 – Metaclass

源碼如下:

?View Code PYTHON
class DataObjectType(type):                                                                                                                                            
    def __init__(mbs, name, bases, dct):
 
        super(DataObjectType, mbs).__init__(name, bases, dct)
        # 將建好的class的__init__ function 設為 clsinit
        mbs.__init__ = clsinit
        # 將建好的class的__repr__ function 設為 clsrepr
        mbs.__repr__ = clsrepr
 
def clsinit(self, **kwargs):
    # 更新self, 也就是建構好的instance的attributes
    self.__dict__.update(kwargs)
 
def clsrepr(self):
    # 顯示 DataObject(a=1,b=2)這樣的字串
    return "{}({})".format(self.__class__.__name__,
            ','.join([ "{}={}".format(k,v) for k,v in self.__dict__.items()]))
 
# 將Value class 的 type 改成 DataObjectType, 原本應該是object的type (也就是type)
# 你可以在python interpreter裡打 type(object) 看一下結果 :p
class Value(object):
    __metaclass__ = DataObjectType
 
# here we go!
v = Value(x=1,y=2,z=3)
print v.x
# 1

而如果你想要跟collections.namedtuple 一樣可以動態產生class的話, 像這樣

?View Code PYTHON
Value = dataobject('Value', 'x,y,z')
print Value.x
# None

其實做方式如下

?View Code PYTHON
def dataobject(name, attrsstr):
    for attrname in attrsstr.split(','):
        dct[attrname] = None
    return DataObjectType(name, (), dct)

ok, 我們來檢查一下class的行為是不是符合我們的預期.

1. 建立名為Value的class,含有x,y屬性

?View Code PYTHON
>>> dataobject('Value', 'x,y')
<class 'metaclass.Value'>

2. Value class 含有y 屬性, 正確

?View Code PYTHON
>> dataobject('Value', 'x,y').y == None
True

3. Value class 沒有包含z屬性(因為沒有定義), 正確

?View Code PYTHON
>>> dataobject('Value', 'x,y').z == None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Value' has no attribute 'z'

讓DataObject的屬性為唯讀

到目前為止我們已經可以動態產生data object class, 也可以動態設定data object 的值.
但卻沒辦法像namedtuple一樣, 強迫設值的動作只能在建立instance時進行. 範例如下

?View Code PYTHON
>>> from collections import namedtuple
>>> cls = namedtuple('TestClass', 'x,y')
# 建立instance
>>> obj = cls(x=1,y=2)
# 讀取instance的x 屬性
>>> obj.x
1
# 設定instance 的 x 屬性 (喔喔, 不能設定)
>>> obj.x = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

要達成相似的行為非常簡單, 只要對DataObjectType 的 __setattr__ method 動點手腳 :p
先寫一個會檢查instance有沒有readonly的變數, 若有檢查其值, 為真時, 則不允許設值

?View Code PYTHON
def clssetattr(self, k, v):
    try:
        # check readonly attributes
        readonly = self.readonly
    except AttributeError:
        readonly = False
    if readonly:
        raise AttributeError("can't set attribute")
    object.__setattr__(self, k, v)

再把DataObjectType產生的class的__setattr__換掉

?View Code PYTHON
class DataObjectType(type):                                                                                                    
    def __init__(mbs, name, bases, dct):
        super(DataObjectType, mbs).__init__(name, bases, dct)
        mbs.__init__ = clsinit
        mbs.__repr__ = clsrepr
        mbs.__setattr__ = clssetattr
.....

完成! 來看看結果吧

?View Code PYTHON
#首先, 沒有設定readonly的狀態下
>>> obj = Value(x=3)
#成功設定x為4
>>> obj.x=4
#再來把Value設為readonly
>>> Value.readonly = True
>>> obj = Value(x=3)
# 沒辦法把x設成4, 成功!
>>> obj.x=4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "metaclass.py", line 41, in clssetattr
    raise AttributeError("can't set attribute")
AttributeError: can't set attribute

結論

在Refactory一書中, 建議使用data object來減少需要傳遞的參數, 而Python又可以使用property使得getter function 使用方式與讀取attribute 一模一樣, 使得data object在python裡面更powerful.

推薦大家使用 :)

十月 4, 2011
» What’s new in Python UCLTIP-0.6?

Summary

After 0.5 released, I did so much exercise in my holidays, like hiking,
swimming, those less my hacking time, so ucltip development became very slowly recently,

which means 0.6 does not have too much changes!

New Feature: Pipeline

In subprocess, the way for doing pipeline is

?View Code PYTHON
>>> p1 = Popen(["dmesg"], stdout=PIPE)
>>> = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
>>>output = p2.communicate()[0]

which is not convenience when you want to pipe many commands.

Pipe class provide similar interface as C library `libpipeline` (http://libpipeline.nongnu.org/)
that manipulating pipelines of subprocesses in a flexible and convenient way in C.

firstly, you need to create a Pipe instance

?View Code PYTHON
>>>pipe = ucltip.Pipe()

and then add some command arguments as you want

?View Code PYTHON
>>>pipe.add('expr', 1, '+' 3)
>>>pipe.add('sed', 's/4/5/', '--posix')

finally run the process, wait it terminate and get its output

?View Code PYTHON
>>>pipe.wait()
>>>pipe.stdout.read()
5

the first argument of Pipe.add function can be Cmd or SubCmd,
please remaind the usage of add function is changed in this case

Receive first arguments is instance of Cmd

?View Code PYTHON
>>>pipe = ucltip.Pipe()
>>>pipe.add(Cmd('expr'), 1, '+', 3)
>>>pipe.add(Cmd('sed'), 's/4/5', posix=True)
>>>pipe.wait()
>>>pipe.stdout.read()
5

Receive first arguments is instance of SubCmd

?View Code PYTHON
>>>apt_cache = ucltip.CmdDispatcher('apt-cache')
>>>pipe = ucltip.Pipe()
>>>pipe.add(apt_cache.search, 'vim-common')
>>>pipe.add(Cmd('grep'), 'vim')
>>>pipe.wait()
>>>pipe.stdout.read()

New Feature: Global Config

executing mode setting:

There are 3 type ofexecuting behavior of Cmd or CmdDispatcher, each are

  1. ‘process’: produce command string and execute (default)
  2. ‘list’, : only produce command arguments list
  3. ‘string’ : only produce command string

Example of list mode:

?View Code PYTHON
# produce command arguments only, same as dry_run
>>>ucltip.global_config(execmod='list')
>>>ucltip.Cmd('ls')(a=True)
['ls', '-a']

Example of string mode:

?View Code PYTHON
# produce command string only
>>>ucltip.global_config(execmod='string')
>>>ucltip.Cmd('ls')(a=True)
'ls -a'

debug mode setting:

?View Code PYTHON
>>>import ucltip
>>>ucltip.global_config(debug=True)
>>>ucltip.Cmd('ls')()

the debug message will be storaged in /var/log/syslog as the following

1896 Oct  4 21:36:53 host python: UCLTIP: Created a Cmd object bound 'ls'
1897 Oct  4 21:36:53 host python: UCLTIP: Trasform Kwargs:input:{}, result:[]
1898 Oct  4 21:36:53 host python: UCLTIP: Builded command string:['ls']

it includes

  1. command be bound
  2. the keyword arguments to command options transform input and output
  3. produced command line string

New Feature: Logging

The error message will also be logged in /var/log/syslog by default as the following

1899 Oct  4 21:42:53 host python: UCLTIP: Executed "ls --nonop" failed, Err Msg:ls: unrecognized option '--nonop'#012Try `ls -     -help' for more information.

API Changes

Rename ‘interact’ parameter to ‘as_process’ of Cmd and CmdDispatcher.execute method for better understanding

?View Code PYTHON
>>>import ucltip
>>>ls=ucltip.Cmd('ls')
#old:
>>>proc=ls(interact=True)
#new:
>>>proc=ls(as_process=True)

How to install

Source Code released in http://pypi.python.org/pypi/ucltip, and
Debian unstable user can ‘python-ucltip’ package very soon.

六月 25, 2011
» Pyctw2011 UCLTIP簡報

2011/6/25 在 PycTW 2011 講了"UCLTIP",本次跟OSDC時說得差別只在一些用法稍稍變動, 還有多了可以為command設定default的options

下面則是當天Demo用的 Example Code:

?View Code PYTHON
#!/usr/bin/env python
#適用0.5rc1以下
from ucltip import *
 
# Result is string When execute Succeses
def ex_get():
    expr = Cmd('expr')
    result = expr(7, '+', 3)
    print result
    print int(result.replace("\n", ""))
 
# Raise Exception when the executed return code is not 0.
def ex_err():
    expr = Cmd('expr')
    try:
        result = expr('A', '+', 3)
    except CommandExecutedFalur as e:
        print "Return code:%d"%e.status
        print "Error message is %s"%e.errmsg
 
def ex_zenity1():
    zenity = CmdDispatcher('zenity')
    zenity.subcmd_prefix = '--'
    zenity.conf.opt_style = 1
    zenity.conf.dry_run=True
    print zenity.info(text='hello')
 
def ex_zenity2():
    zenity = CmdDispatcher('zenity')
    zenity.subcmd_prefix = '--'
    zenity.conf.opt_style = 1
    res = zenity.entry()
    print res
 
#Use Helper to create Cmd
def ex_helper1():
    regcmds('uname')
    print uname(a=True)
 
#Use Helper to create CmdDispatcher
def ex_helper2():
    regcmds('apt-get', 'apt-cache', cls=CmdDispatcher)
    apt_get.conf.dry_run=True
    apt_cache.conf.dry_run=True
    print apt_cache.search('vim')
    print apt_get.install('vim')
 
#Create custom class
def ext_cls():
    import datetime
    class Zenity(CmdDispatcher):
        def __init__(self):
            super(Zenity, self).__init__('zenity')
            self.conf.opt_style=1
            self.subcmd_prefix='--'
 
        def print_calendar(self,*args, **kwargs):
            try:
                ret = map(int, self.calendar(*args, **kwargs).replace('\n', '').split('/'))
                return datetime.datetime(ret[2],ret[0],ret[1])
            except CommandExecutedFalur as e:
                return False
 
    z=Zenity()
    date = z.print_calendar(text='Helllo!!!!!!', year=2015)
    print date
    print type(date)
 
if __name__ == '__main__':
    import sys
    import os
    try:
        func = sys.argv[1]
    except IndexError:
        print "USAGE: {} funcname".format(os.path.basename(__file__))
    else:
        try:
            eval(func)()
        except NameError:
            print 'can not find example function'


六月 16, 2011
» 在Python 用Data Object傳遞資料

當資料耦合度很高時候, 我習慣做一個data object class把他放進去, 因為python是dynamic programming language, 所以你可以在create object時, 直接設定object attribute value

以下是很偷懶的版本

?View Code PYTHON
class Data(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
 
# the result is hychen
print Data(name='hychen').name

這個版本則保護了built-in attributes, 避免被污染

?View Code PYTHON
class Data(object):
    _excludes = ['__class__',
                 '__delattr__',
                 '__dict__',
                 '__doc__',
                 '__format__',
                 '__getattribute__',
                 '__hash__',
                 '__init__',
                 '__module__',
                 '__new__',
                 '__reduce__',
                 '__reduce_ex__',
                 '__repr__',
                 '__setattr__',
                 '__sizeof__',
                 '__str__',
                 '__subclasshook__',
                 '__weakref__']
    def __init__(self, **kwargs):
        for k,v in kwargs.items():
            if k in self._excludes:
                raise TypeError("{0} is not a valide keyword argument".format(k))
            self.__dict__[k] = v 
# the result is hychen
print Data(name='hychen').name

當attribute value需要被動態產生時,像是需要被計算, 或是需要執行系統命令去獲得,則可以對getter動手腳, 例如下面這個範例, access dist_info.uname 會得到在shell執行’uname -a’一樣的結果

?View Code PYTHON
class Data(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
 
    @property
    def uname(self):
        import commands                                                                                                        
        return commands.getoutput('uname -a')
 
dist_info = Data(id=1)
#the result is Linux xluna 2.6.38-8-generic-pae #42-Ubuntu SMP Mon Apr 11 05:17:09 UTC 2011 i686 i686 i386 GNU/Linux
print dist_info.uname

setter, getter也是可以被修改的, 進階運用請在shell 執行 `pydoc property` 了解

» How to find scan code or key code when you press key

Terms

  1. scan code: indicate real position in keyboard for BIOS,  include press code and break code
  2. keycode: kernel will convert scan code to keycode for X
  3. keysym: X convert keycode to keysym for application

How to find keyboard controller id, the controller is usually i8042 today

root# cat /proc/interrupts
           CPU0       CPU1
  0:    7750828    8113456   IO-APIC-edge      timer
  1:         23         43   IO-APIC-edge      i8042
  8:          0          1   IO-APIC-edge      rtc0
  9:      13091        302   IO-APIC-fasteoi   acpi
 12:         80         77   IO-APIC-edge      i8042
 16:          0          0   IO-APIC-fasteoi   uhci_hcd:usb6
 17:          3          7   IO-APIC-fasteoi   uhci_hcd:usb7
 18:          0          0   IO-APIC-fasteoi   ata_generic, uhci_hcd:usb8
 19:          0          0   IO-APIC-fasteoi   ehci_hcd:usb2
 20:          0          0   IO-APIC-fasteoi   uhci_hcd:usb3
 21:         60         58   IO-APIC-fasteoi   uhci_hcd:usb4
 22:          0          0   IO-APIC-fasteoi   uhci_hcd:usb5
 23:     115099     113301   IO-APIC-fasteoi   ehci_hcd:usb1

How to enable debug mode of i8042 to find scan code

please note that you can not use this method to find USB keyboard scan code.

echo 1 > /sys/module/i8042/parameters/debug
# clean kernel message
root@xluna:/sys/devices/platform/i8042# dmesg -c
# press any key in internal keyboard(not usb)
root@xluna:/sys/devices/platform/i8042# dmesg
[15984.225845] i8042: [3995774] 1e <- i8042 (interrupt, 0, 1)
[15984.297092] i8042: [3995792] 9e <- i8042 (interrupt, 0, 1)

How to get keycode

root@xluna:/sys/devices/platform/i8042# showkey
kb mode was RAW[ if you are trying this under X, it might not worksince the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
keycode  28 release
akeycode  30 press
keycode  30 release
keycode  29 press
^Ccaught signal 2, cleaning up...

Reference

  1. Scan Code – Wikipidia
  2. Scan Code Set 1
  3. Key Code
  4. Keysym Recongnised by Xmodmap

二月 13, 2011
» How to get metadata of Python Package

What is metadata of Python Package

PEP0345 describes a mechanism for adding metadata to Python distributions. It includes specifics of the field names, and their semantics and usage.

Where is the metadata in Python Package?

I don’t know is there a specific file to describe metadata in Python package or not,  but
most Python Packages use distutils to depoly so the authors wrote metadata in setup.py

here is a example

setup(
    name = 'ucltip',
    version = open('VERSION.txt').read().strip(),
    description = 'A library to help making command line tool Python binding faster',
    long_description="""
This library makes you to use command line tool in Python by OO way.
The concept is to transform 1) command as a instance, 2) options
of command as arguments and keyword arguments of function or
instance method when method be used as a sub command of a command.
""",
    author = 'Hsin-Yi Chen (hychen)',
    author_email = 'ossug.hychen@gmail.com',
    url='http://github.com/hychen/ucltip',
    license = 'BSD-2-clause License',
    packages=['ucltip'],
    classifiers = [
      "Development Status :: 3 - Alpha",
      "Intended Audience :: Developers",
      "License :: OSI Approved :: BSD License",
      "Operating System :: OS Independent",
      "Programming Language :: Python",
      "Programming Language :: Python :: 2.5",
      "Programming Language :: Python :: 2.6",
      "Topic :: Software Development :: Libraries :: Python Modules",
    ]
)

How to get it?

parse it?

that is not good… you may have a risk that you can not get whole metadata, in this case, the author wrote version in VERSION.txt file and did not write in setup function immediately.

Thus, what I thought is can we get the argument of setup function? here we go

The Implementation

    def find_meta():
        #@FIXME: very dirty hack
        import re
        # open setup.py file
        with open('setup.py', 'r') as f:
            class _Catcher():
                self.data = {}
                def __call__(self, **kargs):
                    # __call__ makes our instance is callable
                    # kargs is function argument, which is what we want
                    self.data = kargs
            setup = _Catcher()
            try:
                # read the content and get the string in "setup(...)"
                r= re.findall('setup(.*)', f.read(), re.DOTALL)
                # evaluate string, this action will let python to call setup function,
                # but the setup function is override before!
                eval(r[0])
                # so the function argument is cached in setup.data
                ret = setup.data
                del(setup)
                return ret
            except:
                return None
    #}}}

Conculution

Even this solutions is functional and acceptable, but I still want to find a better way to do the same things, because it uses `eval`.

» 利用 cowbuilder 建立不同的debian package 編譯環境

前言

在編譯Debian Package 時, 開發者常使用 pbuilder 建立乾淨的root filesystem, 並且在其中編譯,如此才不會有相依性不完整, 或是少檔案等在原始開發環境難以發現的錯誤 (因為開發環境會安裝所需的套件)

而 cowbuilder 與 pbuilder 的不同為 cowbuilder 並不會將建立好的 root filesystem 壓縮, 因此在編譯套件時可以省下解壓縮 root filesystem的時間。

安裝相關套件

user@host# sudo apt-get install cowbuilder debootstrap devscripts

將下面內容寫入 .pbuilderrc

export CCACHE_DIR="/var/cache/ccache"
export PATH="/usr/lib/ccache:${PATH}"

EXTRAPACKAGES="${EXTRAPACKAGES} ccache pbuilder cowdancer cowbuilder devscripts gnupg patchutils vim-tiny"
BINDMOUNTS="${BINDMOUNTS} ${CCACHE_DIR}"
COMPONENTS="main restricted universe multiverse"
PDEBUILD_PBUILDER=cowbuilder

UNSTABLE_CODENAME="sid"
TESTING_CODENAME="wheezy"
STABLE_CODENAME="squeeze"
STABLE_BACKPORTS_SUITE="$STABLE_CODENAME-backports"

# List of Debian suites.
DEBIAN_SUITES=($UNSTABLE_CODENAME $TESTING_CODENAME $STABLE_CODENAME
"unstable" "testing" "stable")

# List of Ubuntu suites. Update these when needed.
UBUNTU_SUITES=("natty" "maverick" "lucid" "karmic" "jaunty" "hardy")

# Mirrors to use. Update these to your preferred mirror.
DEBIAN_MIRROR="ftp.tw.debian.org"
UBUNTU_MIRROR="mirrors.kernel.org"

# Optionally use the changelog of a package to determine the suite to use if
# none set.
if [ -z "${DIST}" ] && [ -r "debian/changelog" ]; then
DIST=$(dpkg-parsechangelog | awk ‘/^Distribution: / {print $2}’)
# Use the unstable suite for certain suite values.
if $(echo "experimental UNRELEASED" | grep -q $DIST); then
DIST="$UNSTABLE_CODENAME"
fi
fi

# Optionally set a default distribution if none is used. Note that you can set
# your own default (i.e. ${DIST:="unstable"}).
: ${DIST:="$(lsb_release –short –codename)"}

# Optionally change Debian release states in $DIST to their names.
case "$DIST" in
unstable)
DIST="$UNSTABLE_CODENAME"
;;
testing)
DIST="$TESTING_CODENAME"
;;
stable)
DIST="$STABLE_CODENAME"
;;
esac

# Optionally set the architecture to the host architecture if none set. Note
# that you can set your own default (i.e. ${ARCH:="i386″}).
: ${ARCH:="$(dpkg –print-architecture)"}

NAME="$DIST"
if [ -n "${ARCH}" ]; then
NAME="$NAME-$ARCH"
DEBOOTSTRAPOPTS=("–arch" "$ARCH" "${DEBOOTSTRAPOPTS[@]}")
fi
#BASETGZ="/var/cache/pbuilder/$NAME-base.tgz"
# Optionally, set BASEPATH (and not BASETGZ) if using cowbuilder
BASEPATH="/var/cache/pbuilder/$NAME-base.cow/"
DISTRIBUTION="$DIST"
BUILDRESULT="/var/cache/pbuilder/$NAME/result/"
APTCACHE="/var/cache/pbuilder/$NAME/aptcache/"
BUILDPLACE="/var/cache/pbuilder/build/"

if $(echo ${DEBIAN_SUITES[@]} | grep -q $DIST); then
# Debian configuration
MIRRORSITE="http://$DEBIAN_MIRROR/debian/"
COMPONENTS="main contrib non-free"
DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "–keyring=/usr/share/keyrings/debian-archive-keyring.gpg")
# This is for enabling backports for the Debian stable suite.
if $(echo "$STABLE_CODENAME stable" | grep -q $DIST); then
EXTRAPACKAGES="$EXTRAPACKAGES debian-backports-keyring"
OTHERMIRROR="$OTHERMIRROR | deb http://www.backports.org/debian $STABLE_BACKPORTS_SUITE $COMPONENTS"
fi
elif $(echo ${UBUNTU_SUITES[@]} | grep -q $DIST); then
# Ubuntu configuration
MIRRORSITE="http://$UBUNTU_MIRROR/ubuntu/"
COMPONENTS="main restricted universe multiverse"
DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "–keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg")
else
echo "Unknown distribution: $DIST"
exit 1
fi

當 ubuntu 或 debian 有新的release時需要修改的變數

UNSTABLE_CODENAME="sid"
TESTING_CODENAME="wheezy"
STABLE_CODENAME="squeeze"
# List of Ubuntu suites. Update these when needed.
UBUNTU_SUITES=("natty" "maverick" "lucid" "karmic" "jaunty" "hardy")

設定 sudo

由於sudo後環境變數並不會延用, 因此我們要設定DIST, ARCH sudo後仍然維持原值, 修改 /etc/sudoers

8 #Defaults->>>>>>env_reset
9 Defaults env_reset,env_keep="DIST ARCH"

使用方式

環境變數 DIST 代表要使用哪個serias, 例如我要建立debian unstable 的chroot

# 若要建立的chroot是debian, 需要安裝keyring
user@host# sudo apt-get install debian-archive-keyring
user@host# sudo DIST=unstable cowbuilder –create
# 產生好的chroot 為 /var/cache/pbuilder/sid-i386-base.cow

編譯 package

# 使用 pdebuild
user@host# sudo DIST=unstable pdebuild
#也可使用 git-buildpackage 編譯 package (個人推薦使用git-buildpackage管理debian package)
user@host$ sudo DIST=unstable git-buildpackage –git-upstream-tag=$ver –git-debian-branch=debian –git-
builder=pdebuilder
# 編好的套件在 /var/cache/pbuilder/sid-i386/result/

另外也可使用環境變數 ARCH 來指定要用amd64 or arm等其他架構,預設值為你電腦的架構

延伸閱讀

十二月 16, 2010
» UCLTIP – Use command line tool in Python

Description

This library makes you use command line tool in Python more easier.
The original idea and most of basic codes are from GitPython project
`http://pypi.python.org/pypi/GitPython/`

  1. PyPi web: http://pypi.python.org/pypi/ucltip/
  2. Source repo: http://github.com/hychen/ucltip.git

Installation

  1. download tarbar
  2. user@host# ./setup install

Basic Usage

?View Code PYTHON
# without options
uname = SingleCmd('uname')
# result is Linux
print uname()
 
# with args
expr  = SingleCmd('expr')
# result is 10
print expr(7, '+', 3)
 
# with options, the style is '-a - l'
# example: ls -a -l
ls = SingleCmd('ls')
# enable debug mode to see what command string will be executed.
# show the debug message like this: DBG: execute cmd 'ls -a -l'
ls.__DEBUG__ = True
print ls(l=True, a=True)
 
# with boolean options, the style is 'ls --all --almost-all'
# variable has '-' should replaced by '_', otherwise syntax error happens
print ls(all=True, almost_all=True)
 
# with key-value optons, has 2 different style,
# `--key value` or `--key=value`, you can use opt_style variable to control them
wget = SingleCmd('wget')
 
# replacement of wget -o log http://url
wget('http://url', o='log')
 
# replacement of wget -o log=http://url
wget = SingleCmd('wget', opt_style=1)
wget('http://url', o='log')
 
# you can also overwrite the bound command
ls.cmdname = 'echo'
# the result is
# DBG: execute cmd 'echo hi'
#'hi\n'
print ls("hi")

The command be executed by subprocess.call, it bypass the shell.

?View Code PYTHON
# the result is $HOME, and it will not show output directly
print SingleCmd('echo')("$HOME")

if you want execute command via shell and use shell enviroment variable, please do as follow, if args of function includes `via_shell=True`, the command be executed by os.system

?View Code PYTHON
# the result is "/home/somebody", and show output directly
SingleCmd('echo')("$HOME", via_shell=True)

And here is the replacement if you want to do pipe for mutiple commands

?View Code PYTHON
ls = SingleCmd('ls')
grep = SingleCmd('grep')
# the result is setup.py
print grep('setup.py', stdin=ls(a=True, interact=True).stdout))
 
#p.s ls(a=True, interact=True) return a Popen instance, so you can have more control
#    of that process

Handling Error of command execution

if the command you want to use is not exists, the exception ucltip.CommandNotFound raises

?View Code PYTHON
a=ucltip.SingleCmd('oo')
Traceback (most recent call last):
    File "", line 1, in
    File "ucltip/__init__.py", line 103, in __init__
    raise CommandNotFound()
ucltip.CommandNotFound

if the command be executed falied, the exception ucltip.CommandExecutedFalur raises

here is a example to hanlde error:

?View Code PYTHON
try:
    print ucltip.SingleCmd('ls')
except ucltip.CommandExecutedFalur as e:
    print e

Command Dispatcher

Some command tools has sub command, like `git`, `zenity`, `pbuilder`, `apt-get`, etc.and some commands like `zenity`, they have prefix string in their sub command.

?View Code PYTHON
# the sub command name is the method name
git = CmdDispatcher('git')
git.log()
# and you can also give args and options like what SingleCmd can use
git.log(raw=True, since='2010')
 
# you can get Popen instance also
proc = git.log(interact=True)
 
# zenity has '--' prefix in its sub command, so you need to specify prefix string
# and option style
zenity = CmdDispatcher('zneity', opt_style=1, subcmd_prefix='--')
 
# zneity --info --text=hi
zneity.info(text="hi")

十二月 14, 2009
» Can not use xmodem to upload file in minicom in Ubuntu

If you need upload file to target device from host PC, you can use minicom and select xmodem. here are the command.

Ctrl-a and press s

then choice which file you want to upload.

If you met the problemt that upload file by xmodem protocol in minicom in Ubuntu, you should install lrzsz first. basically, I don' know why minicom doest show any error message....

root@hrdhy:/media# apt-get install lrzsz

Reference:
  1. IPAQ小心得
  2. 用MINICOM的XMODEM来传输文件

十二月 12, 2009
» Using ubi as 0xdroid root filesystem on Devkit8000

Main idea

0xdroid has a lazy installer on BeagleBoard, I want a one on Devkit8k, so this is a roughly prototype and is not good enough as which oxlab has.

  1. Copy Android root filesystem directory into Angstrom root filesystem directory in SD card.
  2. Mount MTD devices  in Angstrom on Devkit80000
  3. Copy Android root filesystem into mounted MTD device.
  4. Changed  to using ubit device as rootfs in bootargs in uboot.

Prepare Installer

the installer has 2 part, one is uboot settings, and one is SD card data.

a. Created Angsrom Root Filesystem

a. 1 Formated SD card and create two partitions, first is FAT, second is EXT3, and types below.

user@host$ cd  ~/$(DEVKIT8k_BSPSRC)/linux/demo/angstrom
user@host$ cp uImage /media/FAT
user@host$ tar xjpvf Angstrom-Beagleboard-demo-image-glibc-ipk-2009.X-test-20090111-beagleboard.rootfs.tar.bz2 -C /media/EXT3
user@host$ mkdir /media/EXT3/home/root/rfs

a.2 Created a script which located in /media/EXT3/home/root/my_flash.sh, its content is below.

#!/bin/sh

flash_eraseall /dev/mtd4
ubiattach /dev/ubi_ctrl -m 4
ubimkvol /dev/ubi0 -N rootfs -s 100MiB
mount -t ubifs ubi0_0 /mnt
cp -a ~/rfs/* /mnt
umount /mnt

b. Copy Android root filesystem into SD card

The root file system is build before, if you want know how to get 0xdroid and how to build, please check http://gitorious.org/0xdroid/pages/Beagle-cupcake-0x1

user@host$ cd ~/$(OxDroidSRC)/out/target/product/beagleboard
user@host$ cp -a root/* /media/EXT3/home/root/rfs
user@host$ cp -a root/system/* /media/EXT3/home/root/rfs/system/

c. Copy Android uImage into SD card

user@host$ cp $(Oxkenerl)/arch/arm/boot/uImage /media/FAT/uImage_android

d. Booting Angstrom from SD card

Inserted SD card, and boot into uboot, then set boot args for running installer.
remember, in this step we will install mtd-utils, so you have to make sure that your network is available.

OMAP3 DevKit8000 # set installer 'set bootargs mem=128M console=ttyS2,115200n8 root=/dev/mmcblk0p2 rw noinitrd rootdelay=1;mmcinit;fatload mmc 0 80000000 uImage;bootm 80000000';save
OMAP3 DevKit8000 # run installer

e. Login as root

After booting successful, you can see Anstrom ask the login name, please use root to login.

f. Checks MTD devices exists

if the nand device nam is the same as kernel's , you can see the MTD devices informations by /proc/mtd

root@devkit8000$ cat /proc/mtd

g. Install mtd-utils

root@devkit8000$ opkg update
root@devkit8000$ opkg install mtd-utils

Using Installer

booted Installer(Angsrom) and login as root, then types

root@devkit8000$ cd ./my_flash.sh

Boot Oxdroid from nand

a. Flash uImage (the size of uImage should less than 2M bytes)

OMAP3 DevKit8000 # mmcinit
OMAP3 DevKit8000# fatload mmc 0:1 80000000 uImage_android
reading uImage 1991900 bytes read
OMAP3 DevKit8000 # nand unlock
device 0 whole chip nand_unlock: start: 00000000, length: 268435456!
NAND flash successfully unlocked
OMAP3 DevKit8000 # nand ecc sw
OMAP3 DevKit8000 # nand erase 280000 210000
NAND erase: device 0 offset 0x280000, size 0x200000
Erasing at 0x460000 -- 100% complete. OK
OMAP3 DevKit8000 # nand write.i 80000000 280000 $(filesize)
NAND write: device 0 offset 0x280000, size 0x200000
Writing data at 0x47f800 -- 100% complete.
2097152 bytes written: OK

b. Set nand bootargs and boot

OMAP3 DevKit8000 # set nandubi 'setenv bootargs console=ttyS2,115200n8 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs init=/init;run nandboot'
OMAP3 DevKit8000 # setenv bootcmd 'nand read.i 80300000 280000 210000;bootm 80300000'
OMAP3 DevKit8000 # save
OMAP3 DevKit8000 # boot

Reference

  1. UBI文件系统简介

support:

biggo.com.tw

A Django site.