Записи с меткой ‘bumble

13
Апр
09

Git с нуля

Обилие ссылок на github.com репозитории в повествовании о JRuby on Rails в AppEngine натолкнуло меня на мысль о том, что неплохо бы рассказать как пользоваться этим самым git. Я не буду вас мучить примерами с пустыми репозиториями. Давайте попробуем решить сугубо практическую задачу – внести небольшое изменение в библиотеку Bumble. Она и будет нашим учебным репозиторием. Скопировать удаленный репозиторий git можно с помощью команды clone:

~$ git clone git://github.com/olabini/bumble.git
Initialized empty Git repository in /home/engineer/bumble/.git/
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (5/5), done.

Git обладает очень простым и понятным интерфейсом работы с ветками. Плодить ветки в git репозитории под любые свои нужды – практика совершенно нормальная. Основная ветка репозитория называется master, получить список всех доступных вам веток можно командой branch:

~/bumble$ git branch
* master

Пока вам доступна одна ветка, master. Обратите внимание на “*” справа – так обозначена текущая ветка. Давайте сделаем свою ветку, перейдем в нее и приступим к изменениям кода:

~/bumble$ git branch filters
~/bumble$ git branch
filters
* master
~/bumble$ git checkout filters
Switched to branch "filters"

Добавим в Bumble::DS::Query обертку для методов add_filter в DataStore. В исходной версии Bumble есть возможно выбирать данные только с одним фильтром – EQUAL. Кроме него, есть еще четыре фильтра, работу с которыми мы добавим в Bumble, на примере метода all:

class Query
[:equal, :greater_than, :greater_than_or_equal, :less_than, :less_than_or_equal].each do |filter|
filter = filter.to_s
class_eval <<-END_EVAL
def add_filter_#{filter.sub('_than', '')}(name, value)
add_filter(name, DS::Query::FilterOperator::#{filter.upcase}, value)
end
END_EVAL
end
end

Теперь немного поправим метод all. Тут мы поменяем только разрабор параметра conditions, так что полный код метода я приводить не буду:

def all(conditions = {}, options = {})
q = DS::Query.new(self.name)
conditions.each do |k, v|
property_name = k.to_s
if v.is_a? Hash
v.each do |filter_op, value|
q = q.send "add_filter_#{filter_op}", property_name, value
end
else
q = q.add_filter(property_name, DS::Query::FilterOperator::EQUAL, v)
end
end
# some code below

Результаты своего труда можно увидеть с помощью команды diff. Попробуйте сами, заодно посмотрите man. Теперь нам нужно каким-то образом изменения в своей ветке зафиксировать, перенести в основную и пользоваться в своих проектах. Конечно, в git есть commit, но сам процесс несколько отличается от обычных систем контроля версий (я имею ввиду CVS, Subversion).

Сперва, вы должны добавить нужные файлы для commit командой add. Узнать имена этих файлов можно не только из diff, но командой status:

~/bumble$ git status
# On branch filters
# Changed but not updated:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: bumble/bumble.rb
#
no changes added to commit (use "git add" and/or "git commit -a")
~/bumble$ git add bumble/bumble.rb
~/bumble$ git commit -m 'new filters and all() refactored'
[filters]: created 300e887: "new filters and all() refactored"
1 files changed, 39 insertions(+), 21 deletions(-)

Номер ревизии, как впрочем и количество измененных строк у вас могут быть совсем другими. Теперь перенесем наши изменения в основную ветку:

~bumble/$ git checkout master
Switched to branch "master"
~bumble/$ git merge filters
Updating 96bdfc0..300e887
Fast forward
bumble/bumble.rb | 60 +++++++++++++++++++++++++++++++++++------------------
1 files changed, 39 insertions(+), 21 deletions(-)
~bumble/$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

Ну вот, надеюсь вы догадались, что переходить между ветками можно командой checkout, а перенести изменения – merge. В status вы видете, что ваш локальный репозиторий “опережает” основную ветку на удаленном сервере на один commit.

Конечно, рассмотренные выше примеры работы с git довольно примитивны. К сложным вопросам мы еще вернемся, а ответы к несложным я надеюсь читатель найдет в документации. Мне лишь хотелось вас заинтересовать.

11
Апр
09

Запуск JRuby on Rails в Google AppEngine Java

Я не устоял перед соблазном и решил попробовать запустить JRuby on Rails в AppEngine. На этот шаг меня вдохновил целый ряд постов в разных блогах и мое повествование будет неполным без них:

По правде, до этого пользоваться JRuby мне приходилось только один раз, да и то, ради любопытства. Думаю многим JRuby знаком так же “хорошо”, поэтому начнем с самого начала. А для начала нам понадобиться свежий JRuby. Вытягиваем его из репозитория и собираем:

svn co http://svn.codehaus.org/jruby/trunk/jruby
cd jruby
ant && ant jar-complete

Использовать rake build тоже можно, но результатом его работы будет только собраный JRuby. А нам с вами нужен еще jruby-complete.jar, чуть позже мы вернемся к нему. Пока же для удобства пропишите себе путь к jruby/bin и продолжим – установим Rails и сделаем скелет приложения:

jruby -S gem install rails
jruby -S rails depot

Замораживаем все gems и удаляем в них тесты. Как я уже писал, GAE/J имеет ряд ограничений, в том числе и на число файлов. Их количество не должно привышать 1000 штук. Надеюсь, это временно ограничение. ActiveRecord нам тоже больше не нужен, на GAE/J применения ему нет, за компанию выбросим и ActionMailer с ActiveResource:

jruby -S rake rails:freeze:gems
rm -rf vendor/rails/actionpack/test/
rm -rf vendor/rails/activerecord/
rm -rf vendor/rails/actionmailer/
rm -rf vendor/rails/activeresource/

Поскольку от ActiveRecord, ActionMailer и ActiveResource мы избавились, будет разумным сразу поправить config/environment.rb:

environment.rb
config.frameworks -= [ :active_record, :active_resource, :action_mailer ]

Пока оставим Rails и займемся SDK для Google AppEngine Java. Для начала, вам следует скачать его с code.google.com, после разверните его в удобное для вас место и пропишите пути к скриптам в appengine-java-sdk/bin.

Из поставки GAE/J SDK нам понадобиться библиотека appengine-java-sdk/lib/impl/appengine-api.jar. Скопируйте ее в RAILS_ROOT/lib. Туда же нужно будет положить jruby-complete.jar из jruby/lib и jruby-jrack.jar. Последний можно найти в репозитории jruby-rack:

git clone git://github.com/nicksieger/jruby-rack.git
cd jruby-rack
jruby -S rake SKIP_SPECS=true

Поскольку jruby-complete.rb слишком большой для GAE/J, воспользуемся скриптом Ola Bini, позволяющим разбить его на две части – jruby-core.jar и ruby-stdlib.jar:

fix_libs.sh
#!/bin/sh
rm -rf jruby-core.jar
rm -rf ruby-stdlib.jar
rm -rf tmp_unpack
mkdir tmp_unpack
cd tmp_unpack
jar xf ../jruby-complete.jar
cd ..
mkdir jruby-core
mv tmp_unpack/org jruby-core/
mv tmp_unpack/com jruby-core/
mv tmp_unpack/jline jruby-core/
mv tmp_unpack/jay jruby-core/
mv tmp_unpack/jruby jruby-core/
cd jruby-core
jar cf ../jruby-core.jar .
cd ../tmp_unpack
jar cf ../ruby-stdlib.jar .
cd ..
rm -rf jruby-core
rm -rf tmp_unpack
rm -rf jruby-complete.jar

Этот скрипт можно найти в репозитории Ola Bini YARBL. Для замены ActiveRecord нужно будет установить Bumble из репозитория. Добавьте загрузку Bumble в environment.rb. В enviroments/session_store.rb отключите сессии. Готового решения для Rails 2.3.2 пока нет (узнать подробней об этом можно здесь). Пользоваться cookie для хранения сессий пока нельзя, нет обвязок для java.security и javax.crypto.

Библиотеки все собраны и для запуска нам осталось совсем немного. Установите warbler и сконфигурируйте его. Делать это надо в RAILS_ROOT и обратите внимание на коварство разработчиков – gem называется warbler, а скрипт warble:

jruby -S gem install warbler
jruby -S warble pluginize
jruby -S warble config

Конфигурация находиться в config/warble.rb:

warble.rb
config.includes = FileList["appengine-web.xml", "datastore-indexes.xml"]
config.webxml.jruby.min.runtimes = 1
config.webxml.jruby.max.runtimes = 2

Файлы appengine-web.xml и datastore-index.xml стандартные для приложений GAE/J. В первом доступна конфигурация приложения, во втором – индексы для DataStore. В нашем случае мы воспользуемся самым простыми вариантами этих двух файлов:

appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>depot</application>
<version>2</version>
<static-files />
<resource-files />
<sessions-enabled>true</sessions-enabled>
<system-properties>
<property name="jruby.management.enabled" value="false" />
<property name="os.arch" value="" />
<property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
<property name="jruby.compile.fastest" value="true"/>
<property name="jruby.compile.frameless" value="true"/>
<property name="jruby.compile.positionless" value="true"/>
<property name="jruby.compile.threadless" value="false"/>
<property name="jruby.compile.fastops" value="false"/>
<property name="jruby.compile.fastcase" value="false"/>
<property name="jruby.compile.chainsize" value="500"/>
<property name="jruby.compile.lazyHandles" value="false"/>
<property name="jruby.compile.peephole" value="true"/>
</system-properties>
</appengine-web-app>

datastore-indexes.xml
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
</datastore-indexes>

Теперь можно попробовать запустить тестовый сервер GAE/J:

jruby -S warble
dev_appserver.sh tmp/war

Если все в порядке, то по адресу http://localhost:8080 вам будет доступен тестовый сервер GAE/J с вашим приложением.




Follow

Get every new post delivered to your Inbox.