<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>StephenChan&#039;s Tech Space &#187; Unix/Linux</title>
	<atom:link href="http://blog.endlesscode.com/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.endlesscode.com</link>
	<description>Stay Hungry. Stay Foolish.</description>
	<lastBuildDate>Tue, 25 Oct 2011 01:15:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Shell的知识点整理</title>
		<link>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/</link>
		<comments>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 14:52:08 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1169</guid>
		<description><![CDATA[这几天抽了点时间看了一下《Advanced Bash-Scripting Guide》， 之前一直觉得shell这门脚本很有意思，虽然用得不多，但感觉shell这门脚本似乎有点粗糙，但看了abs-guide之后就觉得shell还是很强大的，很多高级特性之前都没曾接触过，平时也用得不算很多。浏览了一下abs-guide之后做了一些简单的笔记，方便以后查看，每个&#8221;echo ===&#8221;之间就是代码片段，在bash version 3.2.48下测试过，点解高亮区的&#8221;view source&#8221;可以直接复制所有代码。 #--------------- Begin #!/usr/bin/bash for arg in "Hello World What The Fuck" do echo $arg done echo "==================================" FILES="/usr/bin/accept /usr/sbin/pwck /usr/sbin/chroot /usr/badblocks /sbin/ypbind" for file in $FILES do if [ ! -e "$file" &#8230; <a href="http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>这几天抽了点时间看了一下《Advanced Bash-Scripting Guide》， 之前一直觉得shell这门脚本很有意思，虽然用得不多，但感觉shell这门脚本似乎有点粗糙，但看了abs-guide之后就觉得shell还是很强大的，很多高级特性之前都没曾接触过，平时也用得不算很多。浏览了一下abs-guide之后做了一些简单的笔记，方便以后查看，每个&#8221;echo ===&#8221;之间就是代码片段，在bash version 3.2.48下测试过，点解高亮区的&#8221;view source&#8221;可以直接复制所有代码。</p>
<p><span id="more-1169"></span></p>
<pre class="brush:bash">#--------------- Begin
#!/usr/bin/bash

for arg in "Hello World What The Fuck"
do
    echo $arg
done

echo "=================================="

FILES="/usr/bin/accept
/usr/sbin/pwck
/usr/sbin/chroot
/usr/badblocks
/sbin/ypbind"

for file in $FILES
do
    if [ ! -e "$file" ]
    then
        echo "$file does not exist."; echo
        continue
    fi
    ls -l $file | awk '{ print $8 "     file size:  " $5 }'
done

echo "=================================="

for file in *
do
    echo $file
done

echo "=================================="

NUMBERS="1 3 5 7 9 25.3"

for num in `echo $NUMBERS`
do
    echo -n "$num"
done

echo "=================================="

PASSWD_FILE=/etc/passwd
n=1
for name in $(awk 'BEGIN{FS=":"}{print $1}' &lt; "$PASSWD_FILE")
do
    echo "USER #$n = $name"
    let "n += 1"
done

echo "=================================="

echo `seq 10`

echo "=================================="

for ((a=1, b=2; a &lt;= 10; a++, b++))
do
    echo $((a-b))
    echo $[$a-$b]
done

echo "=================================="

ROOT_UID=0
E_NOTROOT=87
E_XCD=86 #can't change directory?

#root check
if [ "$UID" -ne "$ROOT_UID" ]
then
    echo "Must be root to run this script."
    exit $E_NOTROOT
fi
cd /var/log || {
    echo "Cannot change to necessary directory." &gt;&amp;2
    exit $E_XCD;
}

echo "=================================="

let "t2 = ((a = 9, 15 / 3))"

echo "=================================="

# ` -&gt; command substitution
# pdftk is a useful tool for pdf files
`pdftk f1.pdf,f2.pdf cat output combined.pdf`

echo "=================================="

# ${parameter-default}, ${parameter:-default}, return but not set
var1=1
var2=2
#var3 is unset
echo ${var1-$var2}  # 1
echo ${var3-$var2}  # 2
echo "\${var3}=${var3}"      # ${var3}=
# ${parameter=default}, ${parameter:=default}, return and set var default
echo ${var4=$var1}  # 1
echo $var4
echo "\${var4}=${var4}"     # ${var4}=1

echo "=================================="

args=$# # num of args
lastarg=${!args} # or lastarg=${!#}
echo "Last arg is ${lastarg}"
echo "Listing args with \"\$*\":"
for arg in "$*"
do
    echo "Arg #$index = $arg"       # all in one line
    let "index+=1"
done

echo "Listing args with \"\$@\":"
for arg in "$@"
do
    echo "Arg #$index = $arg"       # seperate every arg in new line
    let "index+=1"
done

echo "=================================="

# space should be quoted or escaped
echo {file1,file2}*\ :{\ A," B",' C'}
# file1* : A file1* : B file1* : C file2* : A file2* : B file2* : C

echo "=================================="

echo {a..z}
echo {0..3}

echo "=================================="

# both stdout &amp; stderr
`ls &amp;&gt; a.txt`
# stdout -&gt; stderr
`ls &gt;&amp;2`

echo "=================================="

dt=$(date +%m-%d-%Y)
echo $dt
a=$(ls -l)
echo $a # all in same line
echo "$(ls -l)" # Quoting , don't suppress in one line

echo "=================================="

shift  # shift 3, shift 3 positions
echo $1 # value of $2
echo $2 # nothings echoes, move not copy

echo "=================================="

exit $? # $? reads the exit status of the last command executed

echo "=================================="

if [ 0 ]
then
    echo "0 is true."
else
    echo "0 is false."
fi      # 0 is true.

if [ ]
then
    echo "NULL is true."
else
    echo "NULL is false."
fi      # NULL is false.

echo "=================================="

# page58, if test operators
# if, elif, else
if [ 0 ]
then
    # command
    echo "if statement"
elif [ 1 ]
then
    # command
    echo "elif statement"
else
    # default-command
    echo "else statement"
fi

echo "=================================="

type test
type '['
type '[['

echo "=================================="

# test/[ considers its arguments as comparison expressions or file tests
# and returns an exit status corresponding to the result of the comparison (0 for true, 1 for false)
[ 0 ]
echo $?     # 0/true
[ ]
echo $?     # 1/false

echo "=================================="

# The (( )) construct expands and evaluates an arithmetic expression.
# If the expression evaluates as zero, it returns an exit status of 1, or "false".
# A non-zero expression returns an exit status of 0, or "true".
# This is in marked contrast to using the test and [ ] constructs previously discussed.
((0))
echo $?     # 1/false
(( 5 &gt; 4))
echo $?     # 0/true

echo "=================================="

# A number preceded by a 0 is octal (base 8).
# A number preceded by 0x is hexadecimal (base 16).
# A number with an embedded # evaluates as BASE#NUMBER
a=021 # 8*2+1
b=0x21 # 16*2+1
c=4#21  # 4*2+1

echo "=================================="

# Double-parentheses ((..))  construct is also a mechanism for
# allowing C-style manipulation of variables in Bash, for example, (( var++ )).
(( a = 23 ))
(( a++ ))
(( t = a&lt;45?7:11 ))
let --a

echo "=================================="

ROOTUSER_NAME=root
username=`id -nu`
if [ "$username" = "$ROOTUSER_NAME" ]
then
    echo "Root!"
else
    echo "Not Root!"
fi

echo "=================================="

# $!, PID (process ID) of last job run in background
# Forces completion of an ill-behaved program.
# Useful, for example, in init scripts.
# possibly_hanging_job &amp; { eval 'kill -9 $!' &amp;&gt; /dev/null; }
`wget http://www.facebook.com &amp;`
{ eval 'kill -9 $!' &amp;&gt; /dev/null; echo "kill finished."; }

echo "=================================="

declare -i number=3
declare | grep HOME

echo "=================================="

echo $RANDOM
num=2
echo $((RANDOM % num))

echo "=================================="

# page 115
stringZ=abcABC123ABCabc
echo ${#stringZ}                # 15
echo `expr "$stringZ" : '.*'`

echo "=================================="

var1=unset
previous=$var1
# Four conditions on "while", but only the last one (exit status) controls loop.
while   echo "previous-variable = $previous"
        echo
        previous=$var1
        [ "$var1" != end ]
do
    echo "Input variable #1 (end to exit) "
    read var1
    echo "variable #1 = $var1"
done

echo "=================================="

t=0
condition() {
    ((t++))
    if [ $t -lt 5 ]
    then
        # like exit status
        return 0
    else
        return 1
    fi
}
# condition can be a function
while condition
do
    echo "Still going: t = $t"
done

echo "=================================="

END_CONDITION=end
# loop as long as the condition is false
until [ "$var1" = "$END_CONDITION" ]
do
    echo "Input variable #1 "
    echo "($END_CONDITION to exit)"
    read var1
    echo "variable #1 = $var1"
    echo
done

echo "=================================="

for outer in I II III IV V
do
    echo "$outer "
    for inner in 1 2 3 4 5
    do
        if [ $inner -eq 3 ]
        then
            # break can also optionally take a parameter
            continue 2
        fi
        echo  "$inner "
    done
done # Output : I 1 2 II 1 2 III 1 2 IV 1 2 V 1 2 

echo "=================================="

# case statement
while [ $# -gt 0 ]; do
    case "$1" in
        -d|--debug)
                DEBUG=1
                echo "Debug On."
                ;;
        -c|--conf)
                CONFILE="$2"
                shift
                if [ ! -f $CONFILE]; then
                    echo "Error: Supplied file doesn't exist!"
                    exit $ERROR_OF_FILE_NOT_FOUND
                fi
                ;;
    esac
    shift
done

echo "=================================="

# select statement, "select var [in list]"
# select uses the $PS3 prompt by default
# if [in list] omitted, use cmd line args or func args instead
PS3="Choose your favorite vegetable:"
echo
choice_of() {
    select vegetable
    # [in list] omitted, so 'select' uses arguments passed to function.
    do
        echo
        echo "Your fav veggie is $vegetable."
        echo "Yuck!"
        echo
        break
    done
}
choice_of beans rice carrots radishes tomatoes spinach

echo "=================================="

# cmd substitution, will invoke a subshell
file_listing=`ls -al`
echo $file_listing

file_listing2=$(ls -al)
echo $file_listing2

for arg in `echo a b`; do
    echo $arg
done        # a b in 2 lines

for arg in "`echo a b`"; do
    echo $arg
done        # ab in single line

echo "=================================="

declare -r PI=3.14159265358979
echo $PI
printf "PI is %1.12f\n" $PI
read var1 var2
echo $var1
echo $var2
read
echo "You just input : $REPLY"

echo "=================================="

echo "List of all users:"
OIFS=$IFS;
IFS=:
while read name passwd uid gid fullname ignore
do
    echo "$name ($fullname)"
done &lt; /etc/passwd

echo "=================================="

arr0=( 10 11 12 13 14 15)
arr1=( 20 21 22 23 24 25)
choose_array() {
    eval array_member=\${arr${array_number}[element_number]}
    echo "Element $element_number of arr$array_number is $array_member."
}
array_number=0
element_number=3
choose_array

echo "=================================="

a='$b'
b='$c'
c=d
# each invocation of eval forces a re-evaluation of its arguments
echo $a         # $b
eval echo $a    # $c
eval eval echo $a   # d

echo "=================================="

echo "Positional parameters before set \'uname -a\' :"
echo "Command-line argument #1 = $1"
echo "Command-line argument #2 = $2"
echo "Command-line argument #3 = $3"
# set `Command` can reset the positional parameters that a script
# sees as the result of a command
set `uname -a`
echo "Positional parameters after set \`uname -a\' : "
echo "Field #1 of 'uname -a' = $1"
echo "Field #2 of 'uname -a' = $2"
echo "Field #3 of 'uname -a' = $3"

echo "=================================="

# using set with -- option explicitly assigns the contents of a variable
# to the positional parameters. If no variable follows the --,
# it unsets the positional parameters.
var="one two three four five"
set -- $var
echo $1
echo $2
echo $3

echo "=================================="

usage() {
    echo "Usage:..."
    exit 0
}
flag=false
list=""
set -- $(getopt ahl: "$@")
while [ $# -gt 0 ]
do
    case "$1" in
        -h ) usage;;
        -a ) flag=true;;
        -l ) list="$2"; echo $list; shift;;
        -- ) shift; break;;
        -* ) echo "$0: unrecognized option $1" 1&gt;&amp;2; usage;;
        *  ) break;;
    esac
    shift
done

echo "=================================="

usage() {
    echo "Usage:..."
    exit 0
}
flag=false
list=""
while getopts ":ahl:" Option
do
    case $Option in
        a )
            flag=true;
            echo "Option a : [OPTIND=${OPTIND}]";;
        h )
            echo "Option h : [OPTIND=${OPTIND}]";
            usage;;
        l )
            echo "Option l : [OPTIND=${OPTIND}]";
            list=$OPTARG; echo $list; break;;
        * ) echo "Unrecognized option. $Option";;
    esac
done

echo "$OPTIND"
shift $(($OPTIND -1))
# $1 now references the first non-option item supplied on the command-line
#+ if one exists.
echo $1

echo "=================================="

# same effect as the #include directive in a C program
# var_in_file1=wtf in file1.sh
source file1.sh
echo $var_in_file1

echo "=================================="

# Using the exec builtin, the shell does not fork,
# and the command exec'ed replaces the shell.
exec echo "Exiting \"$0\"."
echo "This echo will never echo."
exit 99

echo "=================================="

# caller is useful in debugging
function2() {
    caller 1
}
function1() {
    function2
    caller 0
}
function1
echo "wtf"
caller 0

echo "=================================="

# true returns a successful(0) exit status
# but does nothing else
# false does the same, but return (1)
true
echo $?     # 0
# endless loop, alias for ":"
while true
do
    echo "wtf"
    sleep 2
    #cmd1
    #cmd2
done

echo "=================================="

# page 204
jobs
disown
bg
fg
wait

echo "=================================="

# external cmd, page 210
`cat`
`tac`
`chattr`
# ...

echo "=================================="

# here documents, simlilar to
# interactive-program &lt; command-file,
# where command-file contains contents
# between "this_is_a_mark_string"
wall &lt;&lt;'this_is_a_mark_string'
Do u know who i am?
this_is_a_mark_string
# - option can supress leading tabs(but not spcaes)
# Quoting or escaping the "limit string" at the head of a here document
# disables parameter substitution within its body
var1=wth
cat &lt;&lt;-MARK_OF_STR
	what the fuck? $var1
MARK_OF_STR

echo "=================================="

# file descriptor
echo 1234567890 &gt; file_name     # write string to "file_name"
exec 3&lt;&gt; file_name              # open "file_name" and assign fd 3 to it
read -n 4 &lt; &amp;3                   # read only 4 chars
# builtin echo do not support -n
printf . &gt;&amp;3                    # write a decimal point there
exec 3&gt;&amp;-                       # close fd 3
cat file_name                   # 1234.67890
# n&lt; &amp;-          close input fd n
# 0&lt;&amp;-, &lt;&amp;-     close stdin
# n&gt;&amp;-          close output fd n
# 1&gt;&amp;-, &gt;&amp;-     close stdout
# child process inhreit open fd, close it if no need

echo "=================================="

# There is no method of 'declaring" the function like C
func1               # error, func1 not defined
declare -f func1    # not help
func1               # still error

echo "=================================="

file=/etc/passwd
pattern=hallo
return_value=""
file_excerpt() {
    echo "Pattern : $1"
    local i=0
    while read line
    do
        echo $line
        ((i++))
        if [ $i -eq 5 ];then
            # custom pre-defined return value
            return_value=(1 2 3)
            # max return value, positive int 255
            return 0
        fi
    done
} &lt; $file

file_excerpt $pattern
echo "Return value is : ${return_value[1]}"

echo "=================================="

# must set this option, else script will not expand aliases
shopt -s expand_aliases
alias llm='ls -al | more'
llm
echo
unalias llm
llm         # error, unalias already

echo "=================================="

# bash permits array operations on variables
# even if the variables are not explicitly declared as arrays.
string=abcd1234
arr_str=("what" "the" "fuck")
echo ${string[*]}           # abcd1234
echo ${arr_str[*]}          # what the fuck
echo ${string[@]}           # abcd1234
echo ${arr_str[@]}          # what the fuck
echo ${#string[@]}          # 1, length
echo ${#arr_str[@]}         # 3

echo "=================================="

# page 416
# many of the standard string operations work on arrays
arrayZ=( one two three four five)
echo ${arrayZ[@]:0}
echo ${arrayZ[@]:1}
echo ${arrayZ[@]:1:3}
echo ${arrayZ[@]/ive/XYZ}
# ...

echo "=================================="

# combine 2 array
arr1=(one two three)
arr2=(four five six)
combined=(${arr1[@]} ${arr2[*]})
echo ${combined[*]}

echo "=================================="

arr1=(
    VAR1=value1
    VAR2=value2
    VAR3=value3
)
arr2=(
    v1="test"
    v2="VAR1=value1 VAR2=value2 VAR3=value3"
    v3=${arr1[*]}
)

test_for_2d_array() {
    t="arr2[*]"
    local ${!t}
    echo "${!t}"        # v1=test v2=VAR1=value1 VAR2=value2 VAR3=value3 v3=VAR1=value1 VAR2=value2 VAR3=value3
    echo "${v1}"        # test
    echo "${v2}"        # VAR1=value1
    echo "${VAR2}"      # value2
    echo "${VAR3}"      # value3
    echo "${v3}"        # VAR1=value1
}

test_for_2d_array

echo "=================================="

# indirect reference
a=b
b=hallo
eval res=\$$a
echo "$res"     # hallo

echo "=================================="

# trap specifies an action on receipt of a signal,
# useful for debugging
trap 'echo "omg"'  EXIT
while true
do
    sleep 2
    echo "hallo"
done

echo "=================================="

# The DEBUG argument to trap causes a specified action to execute
# "after" every command in a script, useful for tracing variables
trap 'echo "TRACE&gt; \$variable = \"$variable\""' DEBUG
variable=29
echo "Just init \$variable to $variable."

echo "=================================="

# trap '' SIGNAL disables SIGNAL for the remainder of the script
# This is useful to protect a critical portion of some uninterruptable actions
trap '' 2       # Signal 2 is Control-C, now disabled
sleep 2
cd
ls
sleep 2
# command...
trap 2          # Reenables Control-C

echo "=================================="

#--------------- End</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Debian搭建SVN</title>
		<link>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/</link>
		<comments>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 13:14:49 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1143</guid>
		<description><![CDATA[今天在Linode买的vps上搭了个svn，简单记录一下过程和遇到的问题。 先说遇到的问题吧，基本上就是 1. &#8220;Could not open the requested SVN filesystem&#8221;; 2. &#8220;Server sent unexpected return value (403 Forbidden) in response to OPTIONS &#8220;. 第一个问题是因为开始没有搞清楚创建一个和多个svn repository的区别，而第二个是因为权限设置的问题。 svn服务器比较重要的涉及安全的问题就是用户认证、访问授权以及传输加密。根据官方的介绍，搭建svn有几种方式，各有优劣，我用的是Apache + mod_dav_svn＋Basic Auth。 具体流程如下，以多个为例，单个的只是参数的差别： 1. 安装所需软件 apt-get install subversion subversion-tools apache2 libapache2-svn 2. 创建存放的路径 &#8230; <a href="http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今天在Linode买的vps上搭了个svn，简单记录一下过程和遇到的问题。</p>
<p>先说遇到的问题吧，基本上就是<br />
1. &#8220;Could not open the requested SVN filesystem&#8221;;<br />
2. &#8220;Server sent unexpected return value (403 Forbidden) in response to OPTIONS &#8220;.</p>
<p>第一个问题是因为开始没有搞清楚创建一个和多个svn repository的区别，而第二个是因为权限设置的问题。</p>
<p>svn服务器比较重要的涉及安全的问题就是用户认证、访问授权以及传输加密。根据官方的介绍，搭建svn有几种方式，各有优劣，我用的是Apache + mod_dav_svn＋Basic Auth。 具体流程如下，以多个为例，单个的只是参数的差别：</p>
<h3>1. 安装所需软件</h3>
<pre class="brush:shell">apt-get install subversion subversion-tools apache2 libapache2-svn</pre>
<h3>2. 创建存放的路径</h3>
<pre class="brush:shell">#路径任意
#注意的是这是多个svn repositories的根目录
mkdir -p /home/svn/repos
#设置apache访问的权限, www-data是apache默认的user和group
chown -R www-data.www-data /home/svn/repos</pre>
<p><span id="more-1143"></span></p>
<h3>3. Apache访问权限设置</h3>
<p>可以写在&#8221;/etc/apache2/sites-available/default&#8221;里面，不过我是独立写在另一个文件，然后在&#8221;/etc/apache2/sites-enabled/&#8221;里面加个软链接。</p>
<pre class="brush:plain">NameVirtualHost *:8080
Listen 8080
&lt;VirtualHost *:8080&gt;
    ErrorLog /home/svn/logs/error.log
    CustomLog /home/svn/logs/access.log combined
    &lt;Location /&gt;
        DAV svn
        #SVNParentPath是指定是的多个svn repository的根目录，如果只设定一个，可以用SVNPath来指定；
        #如果想设置多个的但用了SVNPath就会出现第一个问题了
        SVNParentPath /home/svn/repos
        AuthType Basic
        AuthName "Subversion Repository"
        #dav_svn.passwd是设定认证的user和password，等下介绍
        AuthUserFile /etc/apache2/dav_svn.passwd
        Require valid-user
    &lt;/Location&gt;
&lt;/VirtualHost&gt;</pre>
<p>&lt;Location/&gt;节点的内容可以参考&#8221;/etc/apache2/mods-available/dav_svn.conf&#8221;，这里设置了8080端口来访问svn，并且指定了error和access这2个log的位置，设定的时候注意给apache有权限访问就可以了，也可以用chown来设定logs目录的拥有者为www-data.www-data。</p>
<h3>4. 在dav_svn.passwd设定认证的user和password</h3>
<pre class="brush:shell">#首次创建文件的时候用-c，后面添加则用-d，不然-c会把之前的覆盖掉；按提示输入密码即可
htpasswd -c /etc/apache2/dav_svn.passwd endlesscode</pre>
<h3>5. 设置访问目录的权限</h3>
<p>目录的权限配置是在&#8221;/etc/apache2/dav_svn.authz&#8221;这个文件里面，</p>
<pre class="brush:plain">[groups]
admin=stephenchan, otheradmin
user=endlesscode, otheruser

[repository:/]
*=
@admin=rw

[repository:/test]
endlesscode=rw

[repository:/demo]
endlesscode=rw</pre>
<p>因为设置的是多个repositories的，所以在设定访问的目录的时候也是分开设置的。这里我在&#8221;/home/svn/repos&#8221;目录下创建了demo和test这2个svn repository，分别设置了rw权限。&#8221;*=&#8221;这个是将所有的用户权限清空，&#8221;*&#8221;代表所有用户。</p>
<p>要注意的是，如果只设定单个的repository，应该直接使用&#8221;[/path/to/dir]&#8220;而不是用&#8221;[repository:/project/path/to/dir]&#8220;这种方式，否则会无效，并可能出现开始说的第二个问题。</p>
<h3>6. 创建svn repository</h3>
<p>写个脚本来创建就比较方便了</p>
<pre class="brush:shell">#!/bin/bash
# create_svn.sh
echo "create svn repos : "$1
mkdir $1
svnadmin create $1
chown -R www-data:www-data $1</pre>
<h3>7. 测试</h3>
<p>初次创建的revision是0的，可以&#8221;svn co http://hostname:8080/demo&#8221;来checkout下来，然后修改一下，再commit上去就变成1了。</p>
<p>虽然基本搭起来，但是传输加密这个还没有弄，还有post-commit，email这些都没有设置，找个时间再弄吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VirtualBox拷贝vdi丢失eth0</title>
		<link>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/</link>
		<comments>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/#comments</comments>
		<pubDate>Thu, 18 Nov 2010 17:21:52 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1111</guid>
		<description><![CDATA[今天用VirtualBox的工具去拷贝虚拟机vdi文件的时候，在拷贝出来的vdi文件中找不到eth0。 # debian lenny VBoxManage clonevdi old.vdi new.vdi 拷贝成功，但当打开new.vdi的时候就出现eth0找不到了。原来是使用VBoxManage的时候不但会为新的vdi文件产出新的UUID，还会为其分配一个新的mac地址，以避免冲突，这样在debian中就会把新的mac地址设置为eth1，结果就杯具了。 解决方法有2个，其实差不多： 在new.vdi中，修改/etc/udev/rules.d/70-persistent-net.rules，一般会有eth0和eth1两行，把eth0那行去掉，然后将eth1改成eth0。 把/etc/udev/rules.d/70-persistent-net.rules中的内容直接删除，然后重启，让系统自动去检测网卡，然后重新生成该文件。其实在copy之前就可以删掉了，这样所有copy出来的都不用修改了，让系统自己去检测。 /etc/udev/rules.d/70-persistent-net.rules这个文件是在网卡有变动的时候才会变化的，里面记录着网卡的信息，虽然VBoxManage会为new.vdi创建新的网卡，但是debian的行为是把这个网卡作为新增的网卡记录在/etc/udev/rules.d/70-persistent-net.rules中，而没有进行调整，所以使用的还是有冲突的eth0。]]></description>
			<content:encoded><![CDATA[<p>今天用VirtualBox的工具去拷贝虚拟机vdi文件的时候，在拷贝出来的vdi文件中找不到eth0。</p>
<pre class="brush:bash"># debian lenny
VBoxManage clonevdi old.vdi new.vdi</pre>
<p>拷贝成功，但当打开new.vdi的时候就出现eth0找不到了。原来是使用VBoxManage的时候不但会为新的vdi文件产出新的UUID，还会为其分配一个新的mac地址，以避免冲突，这样在debian中就会把新的mac地址设置为eth1，结果就杯具了。</p>
<p>解决方法有2个，其实差不多：</p>
<ul>
<li>在new.vdi中，修改<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>，一般会有eth0和eth1两行，把eth0那行去掉，然后将eth1改成eth0。</li>
<li>把<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>中的内容直接删除，然后重启，让系统自动去检测网卡，然后重新生成该文件。其实在copy之前就可以删掉了，这样所有copy出来的都不用修改了，让系统自己去检测。</li>
</ul>
<p><strong>/etc/udev/rules.d/70-persistent-net.rules</strong>这个文件是在网卡有变动的时候才会变化的，里面记录着网卡的信息，虽然VBoxManage会为new.vdi创建新的网卡，但是debian的行为是把这个网卡作为新增的网卡记录在<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>中，而没有进行调整，所以使用的还是有冲突的eth0。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Crontab</title>
		<link>http://blog.endlesscode.com/2010/01/28/crontab/</link>
		<comments>http://blog.endlesscode.com/2010/01/28/crontab/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 17:37:44 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=201</guid>
		<description><![CDATA[Intro: crontab  is  the  program used to install, deinstall or list the tables used to drive the cron(8) daemon in Vixie Cron.  Each user can have their own crontab, and though these are files in /var/spool/cron/crontabs, they are not intended &#8230; <a href="http://blog.endlesscode.com/2010/01/28/crontab/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h3>Intro:</h3>
<p>crontab  is  the  program used to install, deinstall or list the tables used to drive the cron(8) daemon in Vixie Cron.  Each user can have their own crontab, and though these are files in /var/spool/cron/crontabs, they are not intended to be edited directly.</p>
<p>If the /etc/cron.allow file exists, then you must be listed therein in order to be allowed to use this command.  If the /etc/cron.allow file does not exist  but  the  /etc/cron.deny  file does exist, then you must not be listed in the /etc/cron.deny file in order to use this command.  If neither of these files exists, then depending on site-dependent configuration parameters, only the super user will be allowed to use this command, or all  users will be able to use this command. For standard Debian systems, all users may use this command.</p>
<h3>Usage:</h3>
<p>crontab [ -u user ] file<br />
crontab [ -u user ] { -l | -r [ -i ] | -e }</p>
<p>The -l option causes the current crontab to be displayed on standard output. See the note under DEBIAN SPECIFIC below.</p>
<p>The -r option causes the current crontab to be removed.</p>
<p>The  -e option is used to edit the current crontab using the editor specified by the VISUAL or EDITOR environment variables.  After you exit from the  editor, the modified crontab will be installed automatically.  If  neither  of  the  environment  variables  is  defined,  then  the  default  editor /usr/bin/editor is used.</p>
<p>The -i option modifies the -r option to prompt the user for a &#8216;y/Y&#8217; response before actually removing the crontab.</p>
<p><span id="more-201"></span></p>
<p>crontab的命令格式如下：</p>
<p><strong>minute hour day-of-month month-of-year day-of-week commands</strong></p>
<p>即：“<strong>分 时 日 月 周 命令</strong> ”，共计6段，前5段都是时间，最后一段才是定期执行的命令，每个时间之间使用空格或者制表符分隔。<br />
前5段即日期和时间的取值范围 ：<strong><br />
分钟[00-59]    小时[00-23]    日[01-31]    月份[01-12]    周[0-6](0表示周日)</strong></p>
<p>示例：</p>
<pre class="brush:bash">#每天8点30分输出一个"Hello World!"
30 08 * * * (echo "Hello World!" &gt; /tmp/hw.txt)</pre>
<p>对时间段的控制除了&#8221;*&#8221;符号外，还有&#8221;-&#8221;、&#8221;/&#8221;、&#8221;,&#8221;。</p>
<ul>
<li>&#8220;-&#8221;表示时间范围，如[1-30]表示从1到30；</li>
<li>&#8220;/&#8221;表示时间间隔，如 /5 表示每5个时间单位；</li>
<li>&#8220;,&#8221;表示离散的时间点，如 1,3,5,7 等；</li>
</ul>
<p>示例：</p>
<pre class="brush:bash">#表示每晚11点开始，每5分钟尝试一次关机
[0-59]/5 23 * * * (/sbin/shutdown -h now)

#要在每个星期一、星期三和星期五的  6:30 a.m. 运行 imacmd 命令
30 6 * * 1,3,5 /usr/bin/imacmd

#在 12 月内, 每天的早上 6 点到 12 点中，每隔3个小时执行一次 /usr/bin/backup :
0 6-12/3 * 12 * /usr/bin/backup

#晚上11点到早上8点之间每两个小时，以及早上8点运行imacmd2命令
0 23-7/2,8 * * * imacmd2</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/28/crontab/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Debian Package系统学习小结</title>
		<link>http://blog.endlesscode.com/2010/01/25/debian-package/</link>
		<comments>http://blog.endlesscode.com/2010/01/25/debian-package/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 15:07:48 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=172</guid>
		<description><![CDATA[这里先介绍一下创建repository的步骤和apt-get命令的相关数据流程，以后有时间再将其他的细节补充。 一、创建repository locate root direcotry, create pool move binary and source packages to pool generate Packages, Sources file(dpkg-scanpackages, dpkg-scansources) create Release file and signature Release.gpg(apt-ftparchive, gpg) publish repository : http, ftp, file 下面这个是创建repository的简单脚本： #!/bin/bash release="jaunty" version="9.04" categories="main" architectures="i386" origin="EndlessCode" label="EndlessCode" &#8230; <a href="http://blog.endlesscode.com/2010/01/25/debian-package/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>这里先介绍一下创建repository的步骤和apt-get命令的相关数据流程，以后有时间再将其他的细节补充。</p>
<h4>一、创建repository</h4>
<ul>
<li>locate root direcotry, create pool</li>
<li>move binary and source packages to pool</li>
<li>generate Packages, Sources file(dpkg-scanpackages, dpkg-scansources)</li>
<li>create Release file and signature Release.gpg(apt-ftparchive, gpg)</li>
<li>publish repository : http, ftp, file</li>
</ul>
<p>下面这个是创建repository的简单脚本：</p>
<p><span id="more-172"></span></p>
<pre class="brush:bash">#!/bin/bash

release="jaunty"
version="9.04"
categories="main"
architectures="i386"

origin="EndlessCode"
label="EndlessCode"
description="Ubuntu jaunty 9.04"

#scan all binary and source package
#generate Packages, Sources
for category in $categories; do
    for architecture in architectures; do
        mkdir -p  dists/$release/$category/binary-$architecture
        dpkg-scanpackages pool/$category /dev/null \
            2 &gt; /dev/null &gt; dists/$release/$category/binary-$architecture/Packages
        gzip -c dists/$release/$category/binary-$architecture/Packages &gt; \
            dists/$release/$category/binary-$architecture/Packages.gz

        mkdir -p dists/$release/$category/source
        dpkg-scansources pool/$category /dev/null \
            2 &gt; /dev/null &gt; dists/$release/$category/source/Sources
        gzip -c dists/$release/$category/source/Sources &gt;  \
            dists/$release/$category/source/Sources.gz

    done
done

#create Release file
cd dists/$release
rm Release Release.gpg
apt-ftparchive release .\
    -o APT::FTPArchive::Release::Origin="$origin" \
    -o APT::FTPArchive::Release::Codename="$release" \
    -o APT::FTPArchive::Release::Label="$label" \
    -o APT::FTPArchive::Release::Architectures="$architectures" \
    -o APT::FTPArchive::Release::Version="$version" \
    -o APT::FTPArchive::Release::Suite="$release" \
    -o APT::FTPArchive::Release::Components="$categories" \
    -o APT::FTPArchive::Release::Description="$description" \
    &gt; Release
#create detached sig of Release
gpg -abs -o Release.gpg Release</pre>
<h4>二、apt-get数据流图</h4>
<p style="text-align: center; "><img class="alignnone size-large wp-image-177" title="apt-get" src="http://blog.endlesscode.com/wp-content/uploads/2010/01/apt-get1-1024x724.jpg" alt="apt-get" width="1024" height="724" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/25/debian-package/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python项目生成Debian包小记</title>
		<link>http://blog.endlesscode.com/2010/01/24/generate-deb-from-python-project/</link>
		<comments>http://blog.endlesscode.com/2010/01/24/generate-deb-from-python-project/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 06:04:35 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=163</guid>
		<description><![CDATA[一、安装打包需要的工具 apt-get install dh-make debhelper devscripts cdbs build-essential fakeroot python2.5-dev 在对Python源代码进行打包的时候，需要用于打包的专用命令，例如创建文件模板、加入man文件、生成Debian包使用的md5sum文件、将所有的文件整合成“*.deb”文件等，debhelper库的安装提供了一系列小工具来完成这些任务。 dh-make是一个方便对源代码进行Debian化的工具，主要体现在根据当前的Debian系统为我们自动生成一系列格式化的build files，省去我们手动创建的功夫。 Debian包本身的所有者是root，同时也需要root权限来安装的，为了使非root权限的开发者也能够创建Debian包，fakeroot命令使在创建文件的时候让非root用户获取到root的权限，仅仅在创建文件的时候。 传统的makefile文件是需要自己写一系列的命令来完成打包的过程，包括检查权限、调用打包命令等等，为了减轻打包的工作，使用cdbs(Common Debian Build System)为开发人员处理打包的细节和检查相关的配置。 python2.5-dev的加入是为了能够编译Python源代码中的extensions，可以根据当前系统的python版本(如X.Y)来下载相应的pythonX.Y-dev包。 安装devscripts可以获得许多的辅助性工具，有利于提高制作Debian包的效率。比如使用dch命令来编辑changelog文件、使用debclean清除包创建过程中生成的各种临时文件等等。 创建Debian软件包的环境主要在Debian操作系统上。 二、创建相关文件 通过dpkg &#8211;info &#60;package&#62;可以查看到关于这个&#60;package&#62;的相关信息，比如版本号、依赖包、支持的Python版本、描述信息等等，这些信息并非在包的制作过程中由命令自动识别并生成的(还没有这么智能)，除了这些信息外，还有更新日志，Makefile等文件，这些文件的信息都需要人为的输入。 在创建这些文件之前，先理清一下目录结构。先把python的项目处理成可安装的目录（假如我要打包的项目是myproject-0.1.14），打目录打包成tar.gz格式，并重命名为myproject_0.1.14.orig.tar.gz(制作包的工具会自动地用Debian化后的文件与orig.tar.gz文件进行对比，将对比的结果用于生成diff.gz文件)。 ----mydir ----myproject-0.1.14/ ----change.log ----docs/ ----sample_proj/ ----setup.py ----src/ ----myproject_0.1.14.orig.tar.gz 在创建相关文件之前，文件目录大概如上。然后进入myproject-0.1.14/目录，这里我们使用dh_make命令生成一个打包用到的文件模板，我们直接在这些模板文件的基础上进行修改。在调用之前，先设置两个dh_make需要用到的环境变量： export DEBFULLNAME="Your Name" export DEBEMAIL="Your.Email@address.com" &#8230; <a href="http://blog.endlesscode.com/2010/01/24/generate-deb-from-python-project/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>一、<strong>安装打包需要的工具</strong></p>
<pre class="brush:plain">apt-get install dh-make debhelper devscripts cdbs build-essential fakeroot python2.5-dev</pre>
<p>在对Python源代码进行打包的时候，需要用于打包的专用命令，例如创建文件模板、加入man文件、生成Debian包使用的md5sum文件、将所有的文件整合成“*.deb”文件等，<strong>debhelper</strong>库的安装提供了一系列小工具来完成这些任务。</p>
<p><strong>dh-make</strong>是一个方便对源代码进行Debian化的工具，主要体现在根据当前的Debian系统为我们自动生成一系列格式化的build files，省去我们手动创建的功夫。</p>
<p>Debian包本身的所有者是root，同时也需要root权限来安装的，为了使非root权限的开发者也能够创建Debian包，<strong>fakeroot</strong>命令使在创建文件的时候让非root用户获取到root的权限，仅仅在创建文件的时候。</p>
<p>传统的makefile文件是需要自己写一系列的命令来完成打包的过程，包括检查权限、调用打包命令等等，为了减轻打包的工作，使用<strong><a href="http://cdbs-doc.duckcorp.org/">cdbs</a></strong>(Common Debian Build System)为开发人员处理打包的细节和检查相关的配置。</p>
<p><strong>python2.5-dev</strong>的加入是为了能够编译Python源代码中的extensions，可以根据当前系统的python版本(如X.Y)来下载相应的pythonX.Y-dev包。</p>
<p>安装<strong>devscripts</strong>可以获得许多的辅助性工具，有利于提高制作Debian包的效率。比如使用dch命令来编辑changelog文件、使用debclean清除包创建过程中生成的各种临时文件等等。</p>
<p>创建Debian软件包的环境主要在Debian操作系统上。<br />
<span id="more-163"></span><br />
二、<strong>创建相关文件</strong></p>
<p>通过dpkg &#8211;info &lt;package&gt;可以查看到关于这个&lt;package&gt;的相关信息，比如版本号、依赖包、支持的Python版本、描述信息等等，这些信息并非在包的制作过程中由命令自动识别并生成的(还没有这么智能)，除了这些信息外，还有更新日志，Makefile等文件，这些文件的信息都需要人为的输入。</p>
<p>在创建这些文件之前，先理清一下目录结构。先把python的项目处理成可安装的目录（假如我要打包的项目是myproject-0.1.14），打目录打包成tar.gz格式，并重命名为myproject_0.1.14.orig.tar.gz(制作包的工具会自动地用Debian化后的文件与orig.tar.gz文件进行对比，将对比的结果用于生成diff.gz文件)。</p>
<pre class="brush:plain">----mydir
      ----myproject-0.1.14/
            ----change.log
            ----docs/
            ----sample_proj/
            ----setup.py
            ----src/
      ----myproject_0.1.14.orig.tar.gz</pre>
<p>在创建相关文件之前，文件目录大概如上。然后进入myproject-0.1.14/目录，这里我们使用dh_make命令生成一个打包用到的文件模板，我们直接在这些模板文件的基础上进行修改。在调用之前，先设置两个dh_make需要用到的环境变量：</p>
<pre class="brush:plain">export DEBFULLNAME="Your Name"
export DEBEMAIL="Your.Email@address.com"</pre>
<p>设置好之后，使用dh_make命令来生成文件模板：</p>
<pre class="brush:plain">dh_make -c gpl -s -b</pre>
<p>其中，要先说明的是我们要制作的Deian软件包是基于GPL license(<strong>-c gpl</strong>，copyright文件会体现)，并且我们只需要从当前的源代码中生成一个二进制包(<strong>-s</strong>)，同时，为了使制作Debian化的过程更简单，我们使用cdbs(<strong>-b</strong>, Common Debian Build System)。</p>
<p>调用dh_make命令要<strong>注意</strong>的一点是，是必须在myproject-0.1.14/目录下执行，即必须包括源代码的目录下执行，并且源代码的目录命名必须为&lt;packagename&gt;-&lt;version&gt;。</p>
<p>成功调用了dh_make命令后，在myproject-0.1.14/目录下会多了一个debian的目录，在debian/目录下，我们目前只需要要保留changelog, compat, control, copyright, rules这5个文件，其他的可以删除掉，关于这些文件的可参考<a href="http://www.debian.org/doc/debian-policy/index.html#contents">这里</a>。</p>
<p><strong>debian/changelog</strong></p>
<pre class="brush:plain">myproject (0.1.14-1) unstable; urgency=low

* Initial release (Closes: #nnnn)  &lt;nnnn is the bug number of your ITP&gt;

-- myname &lt;myemail@address.com&gt;  Thu, 16 Jul 2009 01:20:48 +0800</pre>
<p>这个文件是一个关于更新日志的记录，描述了在新版本中Debian化和源代码上与旧版本的不同之处，生成Debian软件包之后主要体现在&#8221;*.changes&#8221;文件中。可以使用debchange编辑或者直接手动编辑，如果是手动编辑，要注意缩进是否正确（在*之前要注意有两个空格，在签名和日期之前还有一个空格）。</p>
<p>可以将第一行中的&#8221;unstable&#8221;改写成当前制作的包可用的Debian系统（如lenny, etch, stable&#8230;)。如果是官方的Debian包的话，在&#8221;Initial release&#8221;后面要写上这个版本所fix的一些bug的number。详见的细节，可参考<a href="http://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog">这里</a>。</p>
<p><strong>debian/compat</strong></p>
<p>compat文件必须只包括一行，这一行指出这个包使用debhelper的兼容级别，一般是当前系统安装的debhelper的版本，使用dpkg -p debhelper | grep Version可以看到版本号。通过dh_make命令生成的compat文件已经是有内容的。关于debhelper，可以参考<a href="http://www.ambienteto.arti.beniculturali.it/cgi-bin/man2html?debhelper+1#index">这里</a>。</p>
<p><strong>debian/control</strong></p>
<p>control文件包含这个包的相当多的重要信息，包括Section, Maintainer, Homepage, Stardards-Version, Architecture, Description等等。这些信息可以通过dpkg &#8211;info &lt;packagename&gt;来获取，同时在成功安装后会被存储在/var/lib/dpkg/status文件中。具体的control信息可参考<a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html">这里</a>和<a href="http://debathena.mit.edu/packaging/#control">这里</a>。</p>
<p>对相应的属性进行修改如下：</p>
<pre class="brush:plain">Source: myproject
Section: python
Priority: optional
Maintainer: Stephen Chan&lt;stephenchan@endlesscode.com&gt;
Build-Depends: cdbs (&gt;= 0.4.49), debhelper (&gt;= 7), python-support (&gt;= 0.6)
XS-Python-Version: &gt;=2.5, &lt;&lt;3.0
Standards-Version: 3.8.0
Homepage: http://www.endlesscode.com/myproject/

Package: myproject
Architecture: i386
XB-Python-Version: 2.5, 2.6
Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python-jinja2, python-simplejson, python-mysqldb, python-m2crypto
Replaces: myproject-0.1.13, myproject-0.1.12
Description: help you build web application in an easy and lazy way(this is a short description, must not exceed a single line)
Here you should put a long description about your package. This line *MUST*
begin with a single space.
Look for more information about this:

http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description</pre>
<p>其中关于<strong>XS-Python-Version</strong>和<strong>XB-Python-Version</strong>是专门用于Python源代码的打包信息。XS-Python-Version说明当前的Debian源代码包所支持的Python版本，用于在系统的Python版本变化时跟踪软件包，以及用于某些软件包的脚本中自动生成合适的Depends和Provides。XS-Python-Version属性中的值可以是下面格式中的一种：</p>
<pre class="brush:plain">XS-Python-Version: all
XS-Python-Version: current
XS-Python-Version: current, &gt;= X.Y
XS-Python-Version: &gt;= X.Y
XS-Python-Version: &gt;= A.B, &lt;&lt; X.Y
XS-Python-Version: A.B, X.Y</pre>
<p>其中&#8221;all&#8221;表示当前的Debian软件包支持所有的Python可用版本，&#8221;current&#8221;表示支持当前Debian系统默认的Python版本。显示指定版本或者是指定支持版本的范围也是被允许的。</p>
<p>对于XB-Python-Version(生成的二进制软件包支持的Python版本)，当要生成Debian软件包的Python源代码中没有extensions时，此项可直接表示为XB-Python-Version: ${python:Versions}，python:Versions会自动被赋予和XS-Python-Version一样的值。当源代码中有extensions时(myproject中有)，但必须显示列出支持的Python版本。</p>
<p><strong>debian/copyright</strong></p>
<p>copyright的信息与普通的copyright信息一样，在这里添加上作者和Email就可以了，相关信息可参考<a href="http://www.debian.org/doc/debian-policy/ch-docs.html#s-copyrightfile">这里</a>。由于信息太多，这里只截取&#8221;License&#8221;节前的内容。</p>
<pre class="brush:plain">This package was debianized by:

Stephen Chan &lt;stephenchan@endlesscode.com&gt; on Wed, 17 Jun 2009 16:30:35 +0800

It was downloaded from:

&lt;http://www.endlesscode.com/myproject/&gt;

Upstream Author(s):

Stephen Chan&lt;stephenchan@endlesscode.com&gt;

Copyright:

&lt;Copyright (C) 2008-2009 EndlessCode&gt;</pre>
<p><strong>debian/rules</strong></p>
<p>rules文件就是用于生成Debian软件包的Makefile文件，这个文件必须是能够执行的，如果是手动创建这个文件，要注意将文件设置为可执行文件。</p>
<p>将文件修改成：</p>
<pre class="brush:plain">#!/usr/bin/make -f

DEB_PYTHON_SYSTEM=pysupport

include /usr/share/cdbs/1/rules/debhelper.mk

include /usr/share/cdbs/1/class/python-distutils.mk</pre>
<p>在这个Makefile文件中，使用了CDBS来创建的模板会自动调用python-distutils.mk需要的debhelper相关工具函数(dh_*)来生成Debian软件包。在DEB_PYTHON_SYSTEM的值中除了pysupport，还可以赋值pycentral，这是两个用于打包python源代码的不同工具系统。我们可以在rules文件中改变一样默认的安装参数，比如改变默认的生成脚本名字(默认是&#8221;setup.py&#8221;)、改变Python默认的安装目录等等，详见可参考<a href="http://cdbs-doc.duckcorp.org/en/cdbs-doc.xhtml#id490854">这里</a>。</p>
<p>三、<strong>生成</strong><strong>Debian</strong><strong>包</strong></p>
<p>当完成了所有的Debian化的信息更改之后，就可以生成Debian软件包了。在与debian/同个目录下(此为myproject-0.1.14/)调用下面命令：</p>
<pre class="brush:plain">dpkg-buildpackage -us -uc -rfakeroot</pre>
<p>在调用dpkg-buildpackage来创建Debian软件包时，我们需要指出当前的软件包不需要将签名内嵌到Debian软件包中(-us)，也不需要对生成的changes文件进行签名(-uc)，同时也要说明当需要获取root的权限来创建文件时要调用的获取root权限的工具(-rfakeroot)。</p>
<p>在成功调用了dpkg-buildpackage命令后，会生成有4个文件：*.diff.gz, *.dsc, *.changes, *.deb。目录结构如下：</p>
<pre class="brush:plain">----mydir
      ----myproject-0.1.14/
            ----change.log
            ----docs/
            ----sample_proj/
            ----setup.py
            ----src/
      ----myproject_0.1.14.orig.tar.gz
      ----myproject_0.1.14-1.diff.gz
      ----myproject_0.1.14-1_i386.deb
      ----myproject_0.1.14-1.dsc
      ----myproject_0.1.14-1_i386.changes</pre>
<p>myproject_0.1.14-1.diff.gz的内容主要是Debian化的改变的内容，也就是上面所添加的debian/目录下面的5个文件的内容。<br />
myproject_0.1.14-1.dsc就是Debian软件包的相关信息，与control文件的内容一致。<br />
myproject_0.1.14-1_i386.changes主要就是在debian/changelog中所添加的一些版本改变的信息。<br />
myproject_0.1.14-1_i386.deb就是我们所生成的Debian软件包了。</p>
<p>四、<strong>参考</strong></p>
<p>a)         Debian Python Policy<br />
<a href="http://www.debian.org/doc/packaging-manuals/python-policy/index.html#contents">http://www.debian.org/doc/packaging-manuals/python-policy/index.html#contents</a><br />
b)        Debian Policy Manual<br />
<a href="http://www.debian.org/doc/debian-policy/index.html#contents">http://www.debian.org/doc/debian-policy/index.html#contents</a><br />
c)         Debian New Maintainer&#8217;s Guide<br />
<a href="http://www.debian.org/doc/manuals/maint-guide/">http://www.debian.org/doc/manuals/maint-guide/</a><br />
d)        Debian packaging with CDBS<br />
<a href="http://debathena.mit.edu/packaging/">http://debathena.mit.edu/packaging/</a><br />
e)         CDBS Documentation<br />
<a href="http://cdbs-doc.duckcorp.org/en/cdbs-doc.xhtml">http://cdbs-doc.duckcorp.org/en/cdbs-doc.xhtml</a><br />
f)         Creating a .deb package from a python setup.py<br />
<a href="http://ghantoos.org/2008/10/19/creating-a-deb-package-from-a-python-setuppy/">http://ghantoos.org/2008/10/19/creating-a-deb-package-from-a-python-setuppy/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/24/generate-deb-from-python-project/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

