블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2009.10.02 19:11

[ShipIt] Software Release Tool - ShipIt with CPAN/Git/SVN Commit/Tag/Upload

   WWW::Shorten::Durl 을 업로드하면서 ShipIt 을 사용해봤습니다. ShipIt 은 LiveJournal 등을 만든 Brad Fitzpatrick 씨가 만든 소프트웨어 릴리즈 툴입니다. SVN/SVK/Git 에 자동으로 커밋, 푸시, 배포판을 만들어 태그도 생성해주고, CPAN 도 자동으로 업로드 해줍니다.
  꼭 Perl 에서만 쓸 수 있다는 제약은 없습니다. 하지만 제가 Perl 을 쓰니까 Perl 을 기준으로 설명드리겠습니다.

  우선 제가 WWW::Shorten::Durl 을 다 만들었다고 하고.. 이제 배포판을 만들어서 github 나 SVN 섭, 그리고 PAUSE 로 올리려고 합니다. ShipIt 을 쓰기 이전에는 대략 이런 플로우를 거칩니다.

  1. 배포판 버젼 지정/설정
  2. 신버젼 ChangeLog 기재
  3. 배포판 생성 테스트
  4. 커밋
  5. 태그
  6. 배포판 생성
  7. CPAN 업로드

  자... 그럼 대략 몇 번의 키보드 타이핑과 마우스를 몇번이나 클릭해야할까요? 아무튼 시간과 체력적인 면에서 많은 비용이 드는 것은 당연하겠죠.

  그럼 ShipIt 을 사용한다고 해봅니다. 그 전에 일단 ShipIt 을 실행할 준비를 해야겠죠.

  ShipIt 과 cpan-upload-http 를 설치합니다.

  ShipIt 은 평범하게 CPAN 을 통해서 설치할 수 있지만 cpan-upload-http 는 CPAN 인덱서에 걸리지 않는 듯 하니 직접 페이지에서 다운로드해서 설치합니다.
$ wget http://search.cpan.org/CPAN/authors/id/B/BR/BRADFITZ/cpan-upload-http-2.4.tar.gz
$ tar zxvf cpan-upload-http-2.4.tar.gz
$ cd cpan-upload-http-2.4
$ perl Makefile.PL
$ make & (sudo) make install   # use local::lib!!
  ShipIt 모듈 페이지에 자세한 설명이 나와있지만 여기서 다시 설명하면... 프로젝트의 루트 디렉토리에서

  1. 설정파일을 만듭니다. (프로젝트 루트 디렉토리에 .shipit 파일이 생성됩니다)
$ shipit --write-config
  2. 설정파일을 자신이 원하는 스텝/액션에 맞게 설정합니다.
# .shipit file
steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
git.push_to = origin
  3. shipit 커맨드를 실행합니다.
$ shipit
Running step ShipIt::Step::FindVersion=HASH(0x10099c228)
Current version is: 0.04
Next/release version? [0.04]                                                                                                                                                      
Running step ShipIt::Step::ChangeVersion=HASH(0x10099c1f8)
Running step ShipIt::Step::CheckChangeLog=HASH(0x10099c0d8)
No mention of version '0.04' in changelog file 'Changes'
Edit file? [Y/n] y                                                                                                                                                                
Running step ShipIt::Step::DistTest=HASH(0x10099c2e8)
include /Users/jeen/Work/dev/WWW-Shorten-Durl/inc/Module/Install.pm
include inc/Module/Install/Metadata.pm
include inc/Module/Install/Base.pm
include inc/Module/Install/AuthorTests.pm
include inc/Module/Install/TestBase.pm
include inc/Module/Install/Include.pm
include inc/Test/Base.pm
include inc/Test/Base/Filter.pm
include inc/Spiffy.pm
include inc/Test/More.pm
include inc/Test/Builder.pm
include inc/Test/Builder/Module.pm
include inc/Module/Install/WriteAll.pm
include inc/Module/Install/Makefile.pm
include inc/Module/Install/Win32.pm
include inc/Module/Install/Can.pm
include inc/Module/Install/Fetch.pm
Writing Makefile for WWW::Shorten::Durl
Writing META.yml
rm -rf WWW-Shorten-Durl-0.04
/opt/local/bin/perl "-Iinc" "-MExtUtils::Manifest=manicopy,maniread" \
        -e "manicopy(maniread(),'WWW-Shorten-Durl-0.04', 'best');"
mkdir WWW-Shorten-Durl-0.04
mkdir WWW-Shorten-Durl-0.04/inc
mkdir WWW-Shorten-Durl-0.04/inc/Test
mkdir WWW-Shorten-Durl-0.04/inc/Test/Base
mkdir WWW-Shorten-Durl-0.04/inc/Module
mkdir WWW-Shorten-Durl-0.04/inc/Module/Install
mkdir WWW-Shorten-Durl-0.04/xt
mkdir WWW-Shorten-Durl-0.04/inc/Test/Builder
mkdir WWW-Shorten-Durl-0.04/lib
mkdir WWW-Shorten-Durl-0.04/lib/WWW
mkdir WWW-Shorten-Durl-0.04/lib/WWW/Shorten
mkdir WWW-Shorten-Durl-0.04/t
cd WWW-Shorten-Durl-0.04 && /opt/local/bin/perl "-Iinc" Makefile.PL
Checking if your kit is complete...
Looks good
Writing Makefile for WWW::Shorten::Durl
cd WWW-Shorten-Durl-0.04 && make LIBPERL_A="libperl.a" LINKTYPE="dynamic" PREFIX="/Users/jeen/local" INSTALL_BASE="/Users/jeen/local"
cp lib/WWW/Shorten/Durl.pm blib/lib/WWW/Shorten/Durl.pm
Manifying blib/man3/WWW::Shorten::Durl.3pm
cd WWW-Shorten-Durl-0.04 && make test LIBPERL_A="libperl.a" LINKTYPE="dynamic" PREFIX="/Users/jeen/local" INSTALL_BASE="/Users/jeen/local"
PERL_DL_NONLAZY=1 /opt/local/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'inc', 'blib/lib', 'blib/arch')" t/*.t
t/durl.t .. ok  
All tests successful.
Files=1, Tests=4,  1 wallclock secs ( 0.03 usr  0.01 sys +  0.16 cusr  0.03 csys =  0.23 CPU)
Result: PASS
rm -f \
      *.a core \
      core.[0-9] blib/arch/auto/WWW/Shorten/Durl/extralibs.all \
      core.[0-9][0-9] Durl.bso \
      pm_to_blib.ts core.[0-9][0-9][0-9][0-9] \
      Durl.x  \
      perl tmon.out \
      *.o pm_to_blib \
      blib/arch/auto/WWW/Shorten/Durl/extralibs.ld blibdirs.ts \
      core.[0-9][0-9][0-9][0-9][0-9] *perl.core \
      core.*perl.*.? Makefile.aperl \
      perl Durl.def \
      core.[0-9][0-9][0-9] mon.out \
      libDurl.def perlmain.c \
      perl.exe so_locations \
      Durl.exp
rm -rf \
      blib
mv Makefile Makefile.old > /dev/null 2>&1
rm -f \
      Makefile.old Makefile
rm -rf \
      MYMETA.yml WWW-Shorten-Durl-0.04
rm -f WWW-Shorten-Durl-0.04.tar.gz
rm -f MANIFEST.bak _build
/opt/local/bin/perl "-Iinc" "-Ilib" "-MModule::Install::Admin" -e "remove_meta()"
rm -rf inc
/opt/local/bin/perl "-Iinc" "-MExtUtils::Manifest=fullcheck" -e fullcheck
Running step ShipIt::Step::Commit=HASH(0x10099d628)
[master 8a222dc] Checking in changes prior to tagging of version 0.04.  Changelog diff is:
 2 files changed, 6 insertions(+), 2 deletions(-)
Running step ShipIt::Step::Tag=HASH(0x10099f520)
pushing to origin at /Users/jeen/local/lib/perl5/ShipIt/VC/Git.pm line 92.
Counting objects: 14, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (8/8), 953 bytes, done.
Total 8 (delta 3), reused 0 (delta 0)
To git@github.com:JEEN/WWW-Shorten-Durl.git
 * [new tag]         0.04 -> 0.04
Running step ShipIt::Step::MakeDist=HASH(0x10099f628)
include /Users/jeen/Work/dev/WWW-Shorten-Durl/inc/Module/Install.pm
include inc/Module/Install/Metadata.pm
include inc/Module/Install/Base.pm
include inc/Module/Install/AuthorTests.pm
include inc/Module/Install/TestBase.pm
include inc/Module/Install/Include.pm
include inc/Test/Base.pm
include inc/Test/Base/Filter.pm
include inc/Spiffy.pm
include inc/Test/More.pm
include inc/Test/Builder.pm
include inc/Test/Builder/Module.pm
include inc/Module/Install/WriteAll.pm
include inc/Module/Install/Makefile.pm
include inc/Module/Install/Win32.pm
include inc/Module/Install/Can.pm
include inc/Module/Install/Fetch.pm
Checking if your kit is complete...
Warning: the following files are missing in your kit:
    META.yml
Please inform the author.
Writing Makefile for WWW::Shorten::Durl
Writing META.yml
rm -rf WWW-Shorten-Durl-0.04
/opt/local/bin/perl "-Iinc" "-MExtUtils::Manifest=manicopy,maniread" \
        -e "manicopy(maniread(),'WWW-Shorten-Durl-0.04', 'best');"
mkdir WWW-Shorten-Durl-0.04
mkdir WWW-Shorten-Durl-0.04/inc
mkdir WWW-Shorten-Durl-0.04/inc/Test
mkdir WWW-Shorten-Durl-0.04/inc/Test/Base
mkdir WWW-Shorten-Durl-0.04/inc/Module
mkdir WWW-Shorten-Durl-0.04/inc/Module/Install
mkdir WWW-Shorten-Durl-0.04/xt
mkdir WWW-Shorten-Durl-0.04/inc/Test/Builder
mkdir WWW-Shorten-Durl-0.04/lib
mkdir WWW-Shorten-Durl-0.04/lib/WWW
mkdir WWW-Shorten-Durl-0.04/lib/WWW/Shorten
mkdir WWW-Shorten-Durl-0.04/t
/opt/local/bin/perl "-Iinc" -I. "-MModule::Install::Admin" -e "dist_preop(q(WWW-Shorten-Durl-0.04))"
COPY_EXTENDED_ATTRIBUTES_DISABLE=1 COPYFILE_DISABLE=1 tar cvf WWW-Shorten-Durl-0.04.tar WWW-Shorten-Durl-0.04
a WWW-Shorten-Durl-0.04
a WWW-Shorten-Durl-0.04/.gitignore
a WWW-Shorten-Durl-0.04/Changes
a WWW-Shorten-Durl-0.04/inc
a WWW-Shorten-Durl-0.04/lib
a WWW-Shorten-Durl-0.04/Makefile.PL
a WWW-Shorten-Durl-0.04/MANIFEST
a WWW-Shorten-Durl-0.04/META.yml
a WWW-Shorten-Durl-0.04/README
a WWW-Shorten-Durl-0.04/t
a WWW-Shorten-Durl-0.04/xt
a WWW-Shorten-Durl-0.04/xt/01_podspell.t
a WWW-Shorten-Durl-0.04/xt/02_perlcritic.t
a WWW-Shorten-Durl-0.04/xt/03_pod.t
a WWW-Shorten-Durl-0.04/xt/perlcriticrc
a WWW-Shorten-Durl-0.04/t/durl.t
a WWW-Shorten-Durl-0.04/lib/WWW
a WWW-Shorten-Durl-0.04/lib/WWW/Shorten
a WWW-Shorten-Durl-0.04/lib/WWW/Shorten/Durl.pm
a WWW-Shorten-Durl-0.04/inc/Module
a WWW-Shorten-Durl-0.04/inc/Spiffy.pm
a WWW-Shorten-Durl-0.04/inc/Test
a WWW-Shorten-Durl-0.04/inc/Test/Base
a WWW-Shorten-Durl-0.04/inc/Test/Base.pm
a WWW-Shorten-Durl-0.04/inc/Test/Builder
a WWW-Shorten-Durl-0.04/inc/Test/Builder.pm
a WWW-Shorten-Durl-0.04/inc/Test/More.pm
a WWW-Shorten-Durl-0.04/inc/Test/Builder/Module.pm
a WWW-Shorten-Durl-0.04/inc/Test/Base/Filter.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install
a WWW-Shorten-Durl-0.04/inc/Module/Install.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/AuthorTests.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Base.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Can.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Fetch.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Include.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Makefile.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Metadata.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/TestBase.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/Win32.pm
a WWW-Shorten-Durl-0.04/inc/Module/Install/WriteAll.pm
rm -rf WWW-Shorten-Durl-0.04
gzip --best WWW-Shorten-Durl-0.04.tar
Distfile now at /Users/jeen/shipit-dist/WWW-Shorten-Durl-0.04.tar.gz
Running step ShipIt::Step::UploadCPAN=HASH(0x10099f580)
Upload to CPAN? [Y/n] Y                                                                                                                                                           
$
 이걸로 끝입니다.

 아, 여기에서의 Step 중에 마지막에 UploadCPAN 이 있는데, 이 경우에는 홈 디렉토리에 .pause 파일을 필요로 합니다.
 물론 PAUSE 계정이 있어야 되겠죠.
# .pause in your home directory
user JEEN
password ********
mailto [YOUR EMAIL]
 .pause 파일을 생성했으면 chmod 600 으로 설정해서 다른 사람이 읽지 못하도록 합니다 (이것도 ShipIt 에서 체크되며, 다른 사람이 읽을 수 있다면 자동으로 처리를 중단시켜버립니다).

 .shipit 에서 자신이 원하는 스텝을 추가해주기만 하면 됩니다. 이것도 확장성을 고려해서 설계되어 있기 때문에... ShipIt::Step::* 의 네임스페이스를 통해서 자신만의 스텝을 만들어 나갈 수 있습니다.
  현재 다른 CPAN 모듈 제작자들이 Twitter  에 릴리즈 정보를 트윗한다든가 하는 스텝 모듈이 있기는 합니다. 그걸 참고하면 쉽게 만들 수 있을 겁니다. (저도 뭐 생각나면 만들어 볼까 생각하고 있습니다)

  그외 자세한 내용은 ShipIt 모듈 페이지를 참고하면 도움이 될 겁니다.

   http://search.cpan.org/perldoc?ShipIt

  혹시 모르시는 것이 있다면 저도 같이 노력해서 궁리해보고자 합니다. :-)
  ShipIt 으로 이제 마구마구 만들고 배포를 해보도록 합시다!
신고
IT/Perl 2008.12.04 17:05

[ Perl, PHP ] Job Queue 를 통해 친해지길 바래?


  현재 진행중인 프로젝트의 구성에서... Web 은 PHP 로 다른 사람에 의해 만들어 지고 있고, 백그라운드에서 작동하는 녀석은 제가 Perl 로 쓰고 있습니다.

2008/11/18 - [IT] - [ Selenium ] 웹서비스 테스트 자동화와는 별 상관없는 작업을 위해...
2008/11/18 - [IT] - [ Selenium ] Selenium RC 를 사용해보자. I
2008/11/19 - [IT] - [ Selenium ] Selenium RC 를 사용해보자. II

  이전 Selenium 을 소개했을 때, Test용이 아닌 용도로 사용한다고 했던 게 이것을 위해서 인데요. 웹에서 어떤 파라메터를 날리면 Selenium 쪽에서 그 파라메터를 받아서 백그라운드에서 열심히 달리는 구조입니다.
  그럼 웹에서 어떻게 Selenium 쪽으로 파라메터를 넘겨줄까요?
  제일 간단하게 생각할 수 있는 것이...
  Web 에서 직접 Selenium 을 기동하는 것, 하지만 한번 움직이면 Selenium 으로 5초 이상의 딜레이가 생기는 것은 어쩔 수 없겠죠. Web 에서 이 5초이상 이란 시간은 참 기다려주기 애매할 수 있습니다. 심하면 30초까지 생각할 수 있으니까요.
  다른 방법이 있습니다. 좀 하드코어한 방식으로는 PHP에서 system 으로 ...

  system('perl selenium-work-1.pl doSomething saillinux see fate_stay_night &');

  이렇게 날리는 방법...

  하지만 이런 식이라면 제대로된 파라메터를 날리기 힘듭니다. 예를들어, 다단계 배열이나 해쉬(연상배열) 같은 것을 어떻게 넘기느냐 하면 좀 애매하죠. 뭐 더 하드코어하게 간다면... 매번 파라메터를 JSON 으로 변환해서 이걸 파일로 덤프합니다. 그리고 파일이름을 지정해줄 수도 있겠죠?
 ...
 ...
 설마 이렇게 할 것이라고 생각하는 것은 아니시겠죠?

 제 해법은 Job Queue 입니다. memcached와 Live Journal 의 개발자로 유명하며, 현재 Perl 용 Google App Engine 을 만들고 있는 Brad Fitzpatrick의 Gearman 이 제 눈에 끌렸습니다. TheSchwartz 같은 경우도 생각해 볼 만하지만, TheSchwartz 의 경우라면 전용 DB 를 필요로합니다. 거기에 3-5초 정도의 작업 딜레이도 발생하게 됩니다(3-5초 정도에 한번씩 매번 DB 에 Job 이 등록되었는 지를 확인하기 때문이죠).
  Gearman 은 Client 에서 Job 을 날림과 동시에 Worker 가 움직이게 됩니다.

  Gearman 은 어떻게 입수하느냐. 당연히 CPAN 입니다.
  sudo cpan -i Gearman::Server
  sudo cpan -i Gearman::Client
  sudo cpan -i JSON

  이렇게 cpan 모듈을 인스톨합니다. 중간 중간에 나오는 의존모듈도 같이 인스톨해주시면 됩니다.  Gearman::Server 를 설치하면 gearmand 라는 gearman 데몬용 파일을 실행할 수 있습니다.

  sudo gearmand --daemon --pidfile=/tmp/gearmand.pid --debug=1

  프로세스 리스트를 확인하시면 gearmand 는 데몬으로 작동하는 것을 확인할 수 있습니다.
  그리고 Job 을 날릴 PHP 쪽도 Gearman 라이브러리를 설치해야 합니다. PHP 의 pear 로 간단하게 인스톨 할 수 있습니다.
 
   sudo pear upgrade http://bugs.joestump.net/code/Net_Gearman/Net_Gearman-0.0.4.tgz

  Net_Gearman 의 설치가 끝났다면 php 쪽의 소스는 이와 같습니다.
  client.php
  1. <?php
  2.  require_once 'Net/Gearman/Client.php';
  3.  $data = array( 'who' => 'saillinux', 'what' => 'fate_stay_night', how => 'haak' );
  4.  $pid = getmypid();
  5.  $set = new Net_Gearman_Set();
  6.  $task = new Net_Gearman_Task( 'job', $data, $pid, Net_Gearman_Task::JOB_BACKGROUND);
  7.  $client = new Net_Gearman_Client(array('localhost'));
  8.  $client->runSet($set);
  9. ?>

  짧게 코드를 설명하자면... $data 에 위와 같은 연상배열을 넣고, 6번째에 Task 를 추가합니다.   
  Net_Gearman_Task 에서 첫번째 인수는 function 이름입니다. 어떤 놈에게 일을 시킬까 하는 것인데, 물론 이 function 은 Worker 쪽에 정의되어 있어야 합니다.
  두번째 인수는 Worker 에 넘길 인수입니다. 이 인수는 JSON 으로 파싱해서 넘어가게 됩니다.
  7번째 줄에서 Net_Gearman_Client에서 배열에 localhost 를 넣었습니다. Worker 는 복수의 서버를 지정할 수 있습니다.
  그외에 대해선 문서를 참고하세요.

  위와 같은 Job 이 client 쪽에서 날아온다면, 이것을 받을 Worker 가 기동중이어야 합니다. 그리고 Worker는 아래와 같은 코드로 이루어져 있습니다.
  worker.pl
  1. use strict;
  2. use warnings;
  3. use Gearman::Worker;
  4. use JSON;
  5.  
  6. my $worker = Gearman::Worker->new;
  7. $worker->job_servers(qw/localhost/);
  8. $worker->register_function(
  9.   job => sub {
  10.     my $job = shift;
  11.     my $args = from_json( $job->arg );
  12.     print $args->{who}." ".$args->{how}." ".$args->{what}."¥n";
  13.   });
  14. $worker->work while 1;

  위의 client 에서 job 이라는 function 으로 job 을 날린 것을 $worker->register_function 으로 등록된 job 이라는 function 에서 처리합니다. JSON 으로 넘어온다고 했으니 넘어온 JSON($job->arg)을 해석합니다. 그리고 받은 인수를 찍어냅니다.

  일단 하나의 터미널에서 worker.pl 을 실행시키고, 다른 터미널에서 client 를 실행시킵니다. 그러면 client 에서 job 이 worker 로 넘어가서, worker 는 그 job 에 맞게 정의된 행동을 수행하겠죠.

  그럼 예외의 경우를 살펴보도록 하자면...
  client 에서 job 은 계속 날리는 데, worker 는 죽어있는 상태입니다(이런 상황이 걱정된다면 worker 를 여러개 띄워놓는 것도 한 방법이 될 수도 있습니다). 이렇게 되면 일하는 놈이 없으니까 당연히 일은 못하게 됩니다. job 은 계속 queue 에 쌓여 있겠죠. 그리고 worker 가 살아난다면, 쌓여있는 job 을 하나씩 처리해나가게 됩니다. gearmand 가 어느 정도 큐에 담아둘 수 있는 지는 잘 모르겠습니다. 메모리 여유분 만큼이려나요?
  그럼 gearmand 데몬 자체가 job 을 잔뜩 쌓아놓고 있는데 죽어버렸다면 어떻게 될까요? 이경우는 queue 에 쌓인 job 은 소실됩니다. 그래서 불안하시다면, TheSchwartz 나 Q4M 을 써서, DB 에 job 을 넣는 형식을 쓰는 것도 선택중의 하나가 되겠죠.
  (피드백 주신 a3r0/Luz_Luna님++)

  뭐, 제가 하려는 건 Selenium Agent 를 가동하기 위해 적당한 인수를 받아서 넘겨주는 것 밖에 없으니까요.
  아무튼 이런 식으로 Perl 과 PHP 간의 유대관계를... 쿨럭.. 아니, 그것보다 이런 식으로 Web 상에서 처리하기에는 좀 지지부진한 처리를 Job Queue 를 통해서 해결해보시는 것은 어떠실런지요?
  뭐 관리의 문제를 제외한다면(제외하기 힘들겠지만)... 여러명이 각자의 특색에 맞는 언어를 선택하는 것은 나쁘지 않다고 생각합니다. 저마다의 개성이겠죠. (물론 사람에 따라서 나쁘다고 생각하실 분도 있으시겠죠...;;)

  http://ido.nu/kuma/2008/01/20/implemented-reblogging-server-with-gearman/
 
  위의 링크를 참고로 했습니다.
신고
TOTAL 483,363 TODAY 14

티스토리 툴바