2014年2月27日星期四

Debian package 打包時遇到需要使用 Pre-Depends 來解決問題

最近在使用 Python 的 XlsxWriter 來產生 Excel 檔案。

可是在 Ubuntu 上面只有在 Trusty 裡面才有 python-xlsxwriter/python3-xlsxwriter 可以使用。

但是我自己在使用的是 Ubuntu 13.10 (Saucy) 於是我就先自己從 Trusty 上面抓 Debian source package 回來 backport 到 Saucy 上面使用。

本來想說等到程式寫好的差不多再來 backport 到 Ubuntu 12.04 (Precise) 上面給人家使用,結果卻發現事情並非如此單純,因為 xlsxwriter 這個套件還需要使用 dh-python 來編譯,但是在 Precise 上面根本就沒有這個套件,於是這件事就變成要先去 backport dh-python 到 Precise 上面使用。

想說不然就從跟 Precise 比較接近的 Wheezy 來抓 Debian source package 回來 backport 好了,於是就找到了 wheezy-backports 裡面的 dh-python,原本以為只要抓回來改一下 debian/changelog 再推到 PPA 上編譯完成就可以了,沒想到 dh-python 已經編譯好了,再去修改 xlsxwriter 裡面的 debian/control 加上 dh-python 的相依性來編譯就可以了,結果卻又遇到了下面這段錯誤訊息

running python rtupdate hooks for python3.2...
Usage: py3clean [-V VERSION] [-p PACKAGE | DIR_OR_FILE]

py3clean: error: only one action is allowed at the same time (cleaning directory or a package)
error running python rtupdate hook dh-python
dpkg: error processing python3 (--configure):
 subprocess installed post-installation script returned error exit status 4
dpkg: dependency problems prevent configuration of dh-python:
 dh-python depends on python3 (>= 3.2.3-0); however:
  Package python3 is not configured yet.
dpkg: error processing dh-python (--configure):
 dependency problems - leaving unconfigured
dpkg: dependency problems prevent configuration of python3-all:
 python3-all depends on python3 (= 3.2.3-0ubuntu1.2); however:
  Package python3 is not configured yet.
dpkg: error processing python3-all (--configure):
 dependency problems - leaving unconfigured
Processing triggers for libc-bin ...
No apport report written because the error message indicates its a followup error from a previous failure.
No apport report written because the error message indicates its a followup error from a previous failure.
ldconfig deferred processing now taking place
Errors were encountered while processing:
 python3
 dh-python
 python3-all
E: Sub-process /usr/bin/dpkg returned an error code (1)

後來追查了一下才發現,原來 dh-python 在 python3 還沒有安裝好的時候會去執行 py3clean 才導致這個問題的發生,於是查了一下 Debian Policy Manual,發現在 7.2 Binary Dependencies 這一章節提到 Pre-Depends 可以使用來解決我遇到的問題。

於是我就再修改一下 dh-python 將 ${python3:Depends} 移到 Pre-Depends 上面,等 dh-python 推上 PPA 編譯完成後,再來編譯 xlsxwriter 這個額外加上 dh-python 相依性的套件,才順利過關。

xlsxwriter backports 的 PPA 放在 ppa:fourdollars/xlsxwriter

2013年12月6日星期五

Bash 內建的 getopts 與外部的 getopt 的使用方式

通常在 GNU/Linux 系統底下使用 command 時都會有帶一些額外的參數,像是以下的例子:

$ echo `seq 0 9` | xargs -n1 | wc -l

利用 `seq 0 9` 產生出 0 到 9 的數字,然後 echo 輸出,再用 xargs -n1 利用空白分開每個數字插入換行符號,然後再導到 wc -l 去計算行數。(其實寫成 `seq 0 9 | wc -l` 也有同樣的效果,利用 hexdump -C 就可以看出其中的不同)

其中的 wc -l 也可以寫成 wc --lines 這樣更清楚、更容易理解。

如果說我們想要利用 Bash shell 寫一個同樣的功能,就可以寫成下面這樣:

#!/bin/bash

while getopts l name; do
    case "$name" in
        ('l')
            line=1
            ;;
    esac
    shift
done

if [ -n "$line" ]; then
    awk 'END { print NR }' "$@"
fi

跟原本的 wc -l 提功同樣功能只是換成使用 awk 這個指令來計算行數。

然而 Bash 內建的 getopts 無法直接提供 --lines 這樣的使用方式,於是就可以改用外部的 getopt 指令來達成。

#!/bin/bash

set -e
eval set -- $(getopt -o l -l "lines" -- "$@")
set +e

while :; do
    case "$1" in
        ('-l'|'--lines')
            line=1
            ;;
        ('--')
            shift
            break
            ;;
    esac
    shift
done

if [ -n "$line" ]; then
    awk 'END { print NR }' "$@"
fi

如果說要利用 Bash 內建的 getopts 寫一個 xargs -n1 這樣的功能,則可以寫成以下這樣:

#!/bin/bash

while getopts n: name; do
    case "$name" in
        ('n')
            max="$OPTARG"
            ;;
    esac
    [ "$OPTIND" = 2 ] && shift
    [ "$OPTIND" = 3 ] && shift 2
done

if [ -n "$max" ]; then
    awk "{for (i = 1 ; i <= NF ; i++) { if (i % $max == 0) printf \"%s\\n\", i; else printf \"%s \", i } }" "$@"
fi

如果要支援 xargs --max-lines=1 這樣的使用方式,則可以利用外部的 getopt 改寫成以下這樣:

#!/bin/bash
# filename: xargs.sh

set -e
eval set -- $(getopt -o "n:" -l "max-lines:" -- "$@")
set +e

while :; do
    case "$1" in
        ('-n'|'--max-lines')
            max="$2"
            shift 2
            ;;
        ('--')
            shift
            break
            ;;
    esac
done

if [ -n "$max" ]; then
    awk "{for (i = 1 ; i <= NF ; i++) { if (i % $max == 0) printf \"%s\\n\", i; else printf \"%s \", i } }" "$@"
fi

這樣就可以使用 `xargs.sh --max-lines=1` 了。

2013年12月4日星期三

Debian/Ubuntu 無人值守的系統更新

Debian/Ubuntu 上面有一個套件叫做 unattended-upgrades - automatic installation of security upgrades 可以用來設定系統的自動更新,這對於一些特別講究系統安全的伺服器特別有用。

以 Ubuntu 12.04 為例,安裝完成及在下面 APT::Periodic::Unattended-Upgrade 打開之後,預設上只會做安全更新,但是我想要它做一般性的系統更新,於是就修改 /etc/apt/apt.conf.d/50unattended-upgrades

// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}-security";
        "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Automatically reboot *WITHOUT CONFIRMATION* if a
// the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "true";

簡單說就是包含使用 precise-updates 上面的更新,更新之後再用 apt-get autoremove 把多餘的套件移除掉,如果有些更新需要重開機才會生效的話,就重開機吧。

然後再修改一下 /etc/apt/apt.conf.d/10periodic

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";

意思是每日檢查更新,如果有更新的話先下載,每週自動清除不需要的套件快取,使用無人值守自動更新。

關於 linux kernel 的更新,有一個腳本程式 /etc/kernel/postinst.d/apt-auto-removal 產生 /etc/apt/apt.conf.d/01autoremove-kernels,用來保留當下正在使用、或是最新安裝、或是上一份使用的 linux kernel。

至於詳細的運作細節則可以參考 /etc/cron.daily/apt 裡面的內容。

2013年12月2日星期一

VirtualBox Guest 裡面共用資料夾的自動掛載

VirtualBox 有提供一個方便的功能,能將 Host 的某個資料夾自動掛載到 Guest 裡面使用,只是自動掛載的權限不是預設的使用者。

sylee@vbox:~$ mount
/dev/sda1 on / type ext4 (rw,errors=remount-ro)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
none on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
vbox on /media/sf_vbox type vboxsf (gid=999,rw)
sylee@vbox:~$ id
uid=1000(sylee) gid=1000(sylee) groups=1000(sylee),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),111(lpadmin),112(sambashare)

這時候只要參考以前寫過的『如何解決在 Ubuntu 上面安裝 VirtualBox 後缺少 vboxusers 群組權限的問題』,將預設的使用者加入到 vboxsf 這個群組裡面,再重新登入後,就可以自由地使用 /media/sf_vbox 底下的檔案了。

sylee@vbox:~$ sudo usermod -a -G vboxsf sylee

隨意拿了 linux-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-signed-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-signed-image-generic-lts-quantal_3.5.0.44.50_amd64.deb linux-image-3.5.0-44-generic_3.5.0-44.67~precise1_amd64.deb linux-signed-image-3.5.0-44-generic_3.5.0-44.67~precise1_amd64.deb 來測試。

使用 vboxsf 來複製檔案。

real    0m0.661s
user    0m0.004s
sys     0m0.284s

使用 sshfs 來複製檔案。

real    0m2.276s
user    0m0.000s
sys     0m0.103s

sshfs 掰~

2013年9月25日星期三

Debian/Ubuntu 上好用的 Spotify 網路音樂串流軟體

有高興看到有原生支援 Debian/Ubuntu 的網路音樂軟體。

在 Ubuntu 上面使用的方法如下:

$ echo "deb http://repository.spotify.com stable non-free" | sudo tee /etc/apt/sources.list.d/spotify.list
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 94558F59
$ sudo apt-get update
$ sudo apt-get install spotify-client

然後就可以執行 Spotify 來使用了。

目前的 Spotify 似乎無法自動偵測到正體中文的環境,所以要手動去偏好設定裡面調整。

最後一點小小的想法,看到許多好用的軟體都會在推出的時候,都會同時支援跨平台的 Windows/Mac/Linux 桌面系統,還有 Android 與 iOS 的移動平台,也許 Linux 桌面的使用族群相對稀少,也許支援 Linux 並沒有什麼高獲利可言,但是卻會讓人感受到該軟體對於使用者的誠意在哪裡,套一句從 Even Wu 那邊看到的:「正確 > 進度,是我的理念。因為正確會有未來的尾速!」。

2013年9月18日星期三

使用 Ubuntu Juju 中的 Local Provider (Linux Container) 心得

Ubuntu Juju 是一套 Canonical 設計給使用 Ubuntu 做為雲端平台的一套工具。

基本概念是輕鬆地使用一堆專家們精心寫好的 Juju Charms,無痛地將網路服務部署到使用 Ubuntu 的雲端平台上面。

Ubuntu Juju 目前支援的雲端平台有 Amazon Web Services (AWS), Microsoft Azure, HP Cloud, OpenStack, MAAS, Local,而 Ubuntu Juju 的工具本身可以在 Ubuntu, Mac OS X, Windows 上面安裝使用。

而 Ubuntu Juju 的 Local Provider 就是利用 Linux Container (LXC) 來在自己的主機上面架設使用 Ubuntu Juju,以下就是介紹 Local Provider 的設定方法。(窮人省錢的雲端解決方案)

首先當然要有一個 Ubuntu 12.04 以上的系統,然後先要加入 ppa:juju/stable 這個 PPA 然後更新索引:

$ sudo apt-add-repository ppa:juju/stable
$ sudo apt-get update

接下來安裝所需要的軟體套件。

如果是 Ubuntu 12.04 的話執行:

$ sudo apt-get install juju-local linux-image-generic-lts-raring linux-headers-generic-lts-raring

然後重新啟動系統來使用 linux-lts-raring 的 kernel

如果是其它比 Ubuntu 12.04 新的版本的話執行:

$ sudo apt-get install juju-local

然後檢查一下 MongoDB 有沒有支援 SSL (這點很重要,一定要支援 SSL 否則就無法使用):

$ mongod -h | grep ssl
  --sslOnNormalPorts      use ssl on configured ports
  --sslPEMKeyFile arg     PEM file for ssl
  --sslPEMKeyPassword arg PEM file password

還有要檢查一下 LXC 的 DHCP server 有沒有被執行起來 (這點也很重要,不然 LXC 的網路就無法正常運作):

$ ps aux | grep lxc-dnsmasq
dnsmasq       1640  0.0  0.0  26080   900 ?        S    10:13   0:00 dnsmasq -u lxc-dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/lxc/dnsmasq.pid --conf-file= --listen-address 10.0.3.1 --dhcp-range 10.0.3.2,10.0.3.254 --dhcp-lease-max=253 --dhcp-no-override --except-interface=lo --interface=lxcbr0 --dhcp-leasefile=/var/lib/misc/dnsmasq.lxcbr0.leases --dhcp-authoritative
user    12013  0.0  0.0  13660   952 pts/2    S+   15:47   0:00 grep --color=auto lxc-dnsmasq

接下來就可以產生 Juju 的設定檔了:

$ juju init 
A boilerplate environment configuration file has been written to /home/user/.juju/environments.yaml.
Edit the file to configure your juju environment and run bootstrap.

然後修改一下 ~/.juju/environments.yaml 將 "default: amazon" 改成 "default: local",接下來就可以執行 `sudo juju bootstrap` 來產生 Local Provider 所需要的環境。

`sudo juju bootstrap` 所做的動作就是產生 ~/.juju/local-cert.pem 及 ~/.juju/local-private-key.pem 還有 /etc/init/juju-*.conf 的檔案來執行一個 MongoDB Server 給 Juju 使用。

接下來執行 Ubuntu Juju 的資料就會全部儲存在 ~/.juju/local/ 目錄底下了。

$ sudo tree .juju                                                                                                                                                                              
.juju
├── charmcache
│   ├── cs_3a_precise_2f_mysql-27.charm
│   └── cs_3a_precise_2f_wordpress-16.charm
├── environments.yaml
├── local
│   ├── agents
│   │   └── machine-0
│   │       └── agent.conf
│   ├── db
│   │   ├── admin.0
│   │   ├── admin.ns
│   │   ├── journal
│   │   │   ├── j._0
│   │   │   ├── lsn
│   │   │   ├── prealloc.1
│   │   │   └── prealloc.2
│   │   ├── juju.0
│   │   ├── juju.ns
│   │   ├── mongod.lock
│   │   ├── presence.0
│   │   ├── presence.ns
│   │   └── _tmp
│   ├── log
│   │   └── machine-0.log
│   ├── server.pem
│   ├── shared-storage
│   ├── storage
│   │   ├── bootstrap-verify
│   │   ├── provider-state
│   │   └── tools
│   │       ├── juju-1.14.0.1-precise-amd64.tgz
│   │       └── juju-1.14.0.1-raring-amd64.tgz
│   └── tools
│       └── 1.14.0.1-raring-amd64
│           ├── downloaded-url.txt
│           ├── FORCE-VERSION
│           └── jujud
├── local-cert.pem
└── local-private-key.pem

13 directories, 26 files

像是如果要架設一台 WordPress Blog Server 就只需要執行以下四行指令:

$ juju deploy wordpress
$ juju deploy mysql
$ juju add-relation wordpress mysql
$ juju expose wordpress

因為建構這些服務需要一些時間去網路上抓取資料回來安裝設定,所以馬上執行 `juju status` 會看到以下輸出,表示動作還沒有完成:

$ juju status
environment: local
machines:
  "0":
    agent-state: started
    agent-version: 1.14.0.1
    dns-name: 10.0.3.1
    instance-id: localhost
    series: raring
  "1":
    instance-id: pending
    series: precise
  "2":
    instance-id: pending
    series: precise
services:
  mysql:
    charm: cs:precise/mysql-27
    exposed: false
    relations:
      cluster:
      - mysql
      db:
      - wordpress
    units:
      mysql/0:
        agent-state: pending
        machine: "2"
  wordpress:
    charm: cs:precise/wordpress-16
    exposed: true
    relations:
      db:
      - mysql
      loadbalancer:
      - wordpress
    units:
      wordpress/0:
        agent-state: pending
        machine: "1"

過一會後再執行 `juju status` 就可以看到全部完成的結果了。

$ juju status                                                                                                                                                                     
environment: local
machines:
  "0":
    agent-state: started
    agent-version: 1.14.0.1
    dns-name: 10.0.3.1
    instance-id: localhost
    series: raring
  "1":
    agent-state: started
    agent-version: 1.14.0.1
    instance-id: user-local-machine-1
    instance-state: missing
    series: precise
  "2":
    agent-state: started
    agent-version: 1.14.0.1
    instance-id: user-local-machine-2
    instance-state: missing
    series: precise
services:
  mysql:
    charm: cs:precise/mysql-27
    exposed: false
    relations:
      cluster:
      - mysql
      db:
      - wordpress
    units:
      mysql/0:
        agent-state: started
        agent-version: 1.14.0.1
        machine: "2"
        public-address: 10.0.3.158
  wordpress:
    charm: cs:precise/wordpress-16
    exposed: true
    relations:
      db:
      - mysql
      loadbalancer:
      - wordpress
    units:
      wordpress/0:
        agent-state: started
        agent-version: 1.14.0.1
        machine: "1"
        open-ports:
        - 80/tcp
        public-address: 10.0.3.69

然後就可以連到 10.0.3.69 這個 IP 就可以開始使用 WordPress 了。 :-)

如果想要清掉這些服務,只要執行下面一行指令:

$ sudo juju destroy-environment
WARNING: this command will destroy the "local" environment (type: local)
This includes all machines, services, data and other resources.

Continue [y/N]? y

這樣就會將之前用 `sudo juju bootstrap` 產生的環境整個清除乾淨。

$ tree .juju
.juju
├── charmcache
│   ├── cs_3a_precise_2f_mysql-27.charm
│   └── cs_3a_precise_2f_wordpress-16.charm
├── environments.yaml
├── local-cert.pem
└── local-private-key.pem

1 directory, 5 files

x11-touchscreen-calibrator 自動校正觸控螢幕的小程式

現在的筆記型電腦很多都搭配著觸控螢幕的功能,在 X Window System 上面使用時會遇到一些問題,像是接上外接螢幕後、或是變更螢幕解析度後,使用觸控螢幕時游標不再跟著手指頭觸控到的地方了。

可是我找來找去都沒有可以自動校正的應用程式,於是就開始了這個小小的專案。

專案首頁在 http://fourdollars.github.io/x11-touchscreen-calibrator/

目前這個程式已經放到 Debian 官方套件庫裡面了,也準備了一個 Ubuntu PPA 來使用。

在 Debian/Ubuntu 上面使用方式很簡單,就是安裝它後重新啟動 X Window System 就會自動在背景執行校正動作。

如果有使用上的問題請回報到 https://github.com/fourdollars/x11-touchscreen-calibrator/issues