글쓴이 보관물: litcoder

Repo와 OpenGrok update를 위한 cron용 script

OpenGrok은 여러면에서 좋은 점이 많은 도구이지만 source code가 변경될 때마다 오랜시간이 걸리는 indexing을 해야 한다는 점은 불편 한 점 중 하나이다. 여기서는 cron으로 돌릴 수 있는 간단한 shell script를 사용해서 한가한 시간에 source가 최신으로 유지될 수 있도록 하는 방법을 설명한다.

Cron runnable update script

Cron으로 동작시키는 script를 작성할 때 가장 많이 실수하는 것은 환경변수들을 사용할 수 없다는 것을 종종 잊는다는 점이다. 이 script 역시 cron에서 동작시킬 것을 감안해서 절대 경로를 사용하도록 작성되어야 한다.

이 script는 REPO_DIR_ROOT로 선언한 directory에 있는 directory들을 돌아다니면서 repo sync를 수행한 다음 OpenGrok index를 돌리는 일을 한다. 다음 세개의 변수를 자신에 맞게 변경해 주자.

  • REPO_DIR_ROOT: Source repository들의 최상위 directory
  • OPENGROK_DIR: OpenGrok binary의 위치
  • REPO: Repo script의 위치
#!/bin/bash
#
# Cron runnable OpenGrok updating script.
# This script syncs all source repositories under 
#  the REPO_DIR_ROOT then runs OpenGrok indexing. 
#
#                                      -litcoder

####
# Configuration variables. - Use absolute path.
#
# * REPO_DIR_ROOT : Top of the source repositories
# * OPENGROK_DIR : Path to OpenGrok executable
# * REPO : Path to repo script
REPO_DIR_ROOT="/var/opengrok/src"
OPENGROK_DIR="/var/opengrok/bin/OpenGrok"
REPO="/home/<<YOUR_HOME_DIR>>/bin/repo"
####

sync_cmd="$REPO sync"
repodirs=`ls ${REPO_DIR_ROOT}`

#################
function clear_all_modifications
{
  #Make a master branch
#  MASTER_BRANCH="master"
#  echo "$REPO start $MASTER_BRANCH --all"

  #Clear all
  echo "$REPO forall -c 'git checkout -f&&git clean -f -d ./'"
}

function print_msg
{
  msg=$1
  echo "$msg"
}

function print_msg_with_time
{
  msg=$1
  echo "$msg - [`date`]"
}

function run_repo_sync
{
  repo_prj=$1
  dirs_skip=$2
  print_msg_with_time "Syncing [$repo_prj]"
  cd ${REPO_DIR_ROOT}/$repodir/

  print_msg "Clear modifications"
  clear_all_modifications

  $sync_cmd 2>&1
}

function run_opengrok_index
{
  $OPENGROK_DIR index
}

#################

#RepoSync 
print_msg "start syncing"

for repodir in $repodirs
do
  run_repo_sync $repodir
done
echo "syncing has done at `date`"

#OpenGrok
print_msg_with_time "Start OpenGrok indexing (`date`)"
run_opengrok_index

echo "done at `date`"

Cron Job 등록

Cron을 설정하는 방법에 대해 잘 설명된 문서들이 많으니 이것을 참고해서 crontab을 실행하고 시간을 설정한다.

$> crontab -e

다음은 금요일 오후 7시 부터 script를 실행하고 home directory에 ‘opengrok_sync_log.txt’  file에 수행 log를 남기도록 설정하는 예이다. /home/<your_home_dir>/bin 아래에 update_opengrok.sh라는 이름으로 script를 저장한다고 가정했다.

# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command
00 19 * * 5 /home/<YOUR_HOME_DIR>/bin/update_opengrok.sh > /home/<YOUR_HOME_DIR>/opengrok_sync_log.txt

주의할 점

Crontab 실행주기를 결정할 때 script의 수행에 소요되는 시간을 고려해야 한다. 너무 잦은 주기로 설정해 놓으면 이전의 job들이 끝나지 않은 상태에서 다음 job이 실행되는 경우가 생기게 되고 이것들이 쌓여서 system 자원을 잡아먹고 느려지다가 결국은 system 관리자의 전화를 받게 될 수도 있다. 😉

Virtual Box에 ext4 partition을 직접 mount

Windows용 Virtual Box에서 vdi file이 아닌 HDD의 특정한 영역을 ext4로 직접 mount하는 방법에 대한 설명이다. 오래전에 해본거라 실제로 속도 향상이 있었는지는 기억이 나지 않는다..

HDD를 format하지 않으면 windows의 탐색기에서는 표시되지 않지만 Disk Manager에서는 연결된 모든 HDD가 보인다. Virtual Box를 설치한 directory에 보면 vboxmanage.exe라는 실행 파일이 있는데 이것을 이용하면, vdmk file을 생성하고 물리적인 HDD를 virtual box에 mapping할 수 있다.

vboxmanage.exe은 VirtualBox 4.2.10 현재 admin 권한이 있는 CLI로만 동작하기 때문에, Admin 권한으로 명령창을 열고 Virtual Box의 설치 경로로 가서 vboxmanage.exe를 실행시킨다.

c:\Program Files\Oracle\VirtualBox> vboxmanage internalcommands createrawvmdk -filename "C:\Users\<USER>\VirtualBox VMs\vmdks\extdata1.vmdk" -rawdisk \\.\PhysicalDrive1

-rawdisk의 parameter인 ‘PhysicalDrive’뒤의 숫자는 windows Disk Manager에 나오는 Disk 0, Disk 1 …에 나오는 숫자와 일치한다.

이제 Virtual Box에서 설정을 열고 storage에 지금 생성한 vmdk file을 추가한다.

Add the vmdk from Settings -> Storage -> SATA

Booting을 하고 linux에서 fdisk -l 명령어로 확인해 보면 새로운 HDD가 인식된 것이 보인다. fdisk로 새로운 partition을 만들고 ext4 fs를 만든다음 fstab을 수정해서 linux에서 새로운 partition이 인식되도록 해주면 된다.

App engine – 지정한 달의 google calendar event 가져오기

Google calendar API 설명문서에는 event list를 가져오는 방법이 설명과 함께 예제 code가 제시되어 있다.

page_token = None
while True:
  events = service.events().list(calendarId='primary', pageToken=page_token).execute()
  for event in events['items']:
    print event['summary']
  page_token = events.get('nextPageToken')
  if not page_token:
    break

이 코드를 수행하면 달력이 가지고 있는 모든 event들을 가져오는데, 이것을 조금 수정해서 지정된 달에 해당하는 event 목록을 가져오는 것으로 변경해 보자.

timeMax / timeMin

가져올 event의 범위는 lower bound를 나타내는 timeMin과 upper bound를 나타내는 timeMax값으로 제한할 수 있는데 이때 사용되는 날짜의 형식은 RFC3339을 따라야 한다.

calendar.monthrange() 

이 method는 년도와 월을 받아서 시작일의 주와 마지막 날짜를 tuple로 반환해 준다. 다음과 같이 특정 달의 마지막 날짜를 구할 수 있다.

>>> import calendar
>>> calendar.monthrange(2002, 06)
(5, 30)
>>> calendar.monthrange(2002, 06)[1]
30

Python에서 RFC3339 표시하기

이 형식은 간단히 말해 날짜를 나타내는 YYYY-MM-DD 형식과 시간을 나타내는 hh:mm:ss가 대문자 ‘T’로 연결되며 그 뒤에는 UTC로 부터의 time zone offset값이 붙는다.

2002-06-30T20:00:00+09:00

datetime.isoformat()을 이용하면 비슷한 형식을 얻을 수는 있으나, 뒤에 붙는 time zone offset이 표시되지 않는다.

>>> datetime(2002, 06, 30, 20, 0, 0).isoformat()
'2002-06-30T20:00:00'

Python에서 time zone을 나타내는 tzinfo class의 설명문에 따르면 tzinfo는 abstract class여서 직접 사용할 수 없고, 이를 상속받는 class를 구현해서 사용해야 한다. 다음은 이 문서에 있는 예제를 조금 수정하여 time zone offset 값을 반환하는 tzinfo의 concrete class를 구현한 것이다.

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)

class TimeZoneOffset(tzinfo):
    def __init__(self, hours, name):
        self.__offset = timedelta(hours = hours)
        self.__name = name

    def utcoffset(self, dt):
        return self.__offset

    def tzname(self, dt):
        return self.__name

    def dst(self, dt):
        return ZERO

Code

TimeZoneOffset class를 선언한 후에는 datetime()을 호출할때 tzinfo에 TimeZoneOffset의 instance를 넘겨서 time zone offset 정보를 포함하는 RFC3339 날짜 형식을 얻을 수 있다.

# What's the last date of the Jun, 2002?
lastDate = calendar.monthrange(2002, 6)[1]

# Lower bound RFC3339 format '2002-06-01T00:00:00+09:00'
lbound = datetime(2002, 6, 1, tzinfo=TimeZoneOffset(9, "KST")).isoformat()

# Lower bound RFC3339 format '2002-06-01T23:59:59+09:00'
ubound = datetime(2002, 6, lastDate, 23, 59, 59, tzinfo=TimeZoneOffset(9, "KST")).isoformat()

page_token = None
while True:
  # Fetch events within given lower/upper bounds.
  events = service.events().list(calendarId='primary', minTime=lbound, maxTime=ubound, pageToken=page_token).execute()
  for event in events['items']:
    print event['summary']
  page_token = events.get('nextPageToken')
  if not page_token:
    break