LinuxのシェルコマンドでFuelPHP開発環境を構築

こんにちは。金髪エンジニアのみきあらいです。今日でGeNERACEに入って2ヶ月めになります。
今回はLinuxのシェルコマンドを使ってFuelPHPの開発環境を構築する方法について書きます。

個人で開発環境を設定するのなら一人でコマンドを叩けばいいのですが、複数人で同じことをする場合、
各人がそれぞれコマンドを叩くのはあまり効率的とは言えません。
そこで、「これさえあれば一瞬で開発環境が作れる!」というシェルスクリプトを書きました。

☆下準備

  • GitのリポジトリにFuel PHPをフォークする。
  • DNSにサブドメインを設定する。
  • Apacheが入っているLinuxサーバーを準備する。
  • PHP5.3がApacheで起動していることを確認する。
  • サーバー用のssh鍵を作成する。(Git使用時に必要)
  • configファイル、xxx_setupを書いてサーバー上に置く。(注意:本物のconfigファイルではなく、あくまで別のconfigファイルを作成するためのものなので、拡張子を.confにしないこと!)

xxx_setupの中身

<VirtualHost *:80>
        ServerName 任意の名前(例:xxx)
        DocumentRoot 任意のドキュメントパス(例:/home/xxx/www/public)
        DirectoryIndex 任意のファイル(今回はindex.phpとindex.htmlを設置)
</VirtualHost>

ServerNameに記載した名前でブラウザから参照することができます。

☆今回やりたいこと

  • 作成したconfigファイル、xxx_setupの中身をコピー。
  • コピーしたファイルをもとに”各ユーザー名.conf”を作る。
  • コピー元ファイルでユーザーごとにあわせて置換したい部分を置換。(上記の例だとサーバー名やルートパス内の”xxx”を各ユーザー名に置換)
  • Gitに置いたFuelPHPをサーバーにgit cloneする。
  • Apacheを再起動する。

シェルスクリプトを書きます。
今回は”shelltest.sh”というシェルスクリプトを作成します。

vi shelltest.sh

“shelltest.sh”の編集を行います。
まず、シェルスクリプトを/bin/shで実行させます。

#!/bin/sh

echoの後ろに変数や文字列を指定します。今回はコメントを文字列として表示します。
すでに”ユーザー名.conf”がある場合も考慮し、スーパーユーザー権限で事前に削除します。-rfをつけてエラーなしで削除します。

echo "setting for httpd"
sudo rm -rf /etc/httpd/conf.d/${USER}.conf

事前に作成したxxx_setupを、”ユーザー名.conf”としてコピーします。

sudo cp -rf /etc/httpd/conf.d/xxx_setup /etc/httpd/conf.d/${USER}.conf

コピー元のxxx_setupの中には”xxx”という文字列があり、それを各ユーザー名に変えたいので、置換するためのコマンドを書きます。

sudo sed -i "s/xxx_setup/"${USER}"/g" /etc/httpd/conf.d/${USER}.conf

変数として${USER}と書くと、そのまま${USER}という文字列として置換されてしまうので、${USER}以外をダブルクオーテーションで囲みます。

次に、confで作成したDocumentRootにFuelPHPを配置します。今回は/home/ユーザー名/www以下にFuelPHPを置きます。
/home/ユーザー名/wwwが既にあることを想定して一度エラーなしで削除し、新たにディレクトリを作り直します。

echo "delete old folder"
rm -rf /home/${USER}/www
echo "settings"
mkdir /home/${USER}/www

/home/${USER}/wwwに移動し、Gitに置いたFuelPHPをサーバーにクローンします。
git@github.com:の後ろにはGithubの各人のユーザー名を書くので、変数として$1を引き渡します。

echo "clone git@github.com:"$1"/fuel.git "
cd /home/${USER}/www/
git clone git@github.com:$1/fuel.git

今回はクローンするだけとしましたが、中央リポジトリのリモートリポジトリを作成したい場合は以下のコマンドを書きます。
(例:fuel.gitのクローン元があるGithubのユーザー名=”UserXXX”、リモートリポジトリ名=”upstream”)

git remote add upstream git@github.com:UserXXX/fuel.git

例として”dev”というブランチを作成し、devブランチに切り替えてpullとpushを行います。

git checkout dev
git pull upstream dev
git push origin dev

最後に作成したconfファイルを反映させるためにApacheを再起動させます。
restartだとエラーが起きたときにApache自体が落ちてしまうので、それを避けるためにgracefulコマンドを使います。

echo "graceful httpd"
sudo /etc/rc.d/init.d/httpd graceful

“shelltest.sh”の編集モードを終了します。これで”shelltest.sh”の完成です。

☆”shelltest.sh”の実行!
早速作成した”shelltest.sh”を実行しましょう。引数$1としてLinuxに渡すGitHubの各人のユーザー名を実行時に入力します。

cd shelltest.shが格納されている場所
sh shelltest.sh GitHubの各人のユーザー名

これでシェルスクリプトを叩くだけで、FuelPHPの開発環境ができるようになります!
シェルスクリプト全体はこちらのgistを参照してください。

今回はここまでです。ご覧いただきましてありがとうございます。

参考記事一覧

Andengineを使ってみる その1

GeNERACE laboを御覧の皆様、はじめまして。

ピンキリエンジニアのひろゆきです。

先日からAndengineを使っていますが、日本語の紹介があんまりないので書いてみます。

少しでもお役に立てば幸いです。

本家はここ→ http://www.andengine.org/

用意したものはAndroid開発環境があるMac、Eclipse、DLしたAndengine。

プロジェクト作成などはこちらを参考にしてください。

では、簡単ではありますが、サンプルを記載します。

※SampleScene.javaを作成して動かしています

文字を出力する。

// フォントを指定
Texture texture = new BitmapTextureAtlas(activity.getTextureManager(), 480, 800, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
Font font = new Font(activity.getFontManager(), texture, Typeface.DEFAULT_BOLD, 30, true, Color.WHITE);
activity.getTextureManager().loadTexture(texture);
activity.getFontManager().loadFont(font);

// 出力する文字を設定
String str = "hello andengine!!";
Text text = new Text(0, 0, font, str, str.length(), new TextOptions(HorizontalAlign.LEFT), activity.getVertexBufferObjectManager());
attachChild(text);

まずはTextureの生成から使用したいFontを指定します。
それをActivityに設定して、Textにて文字を生成します。

画像を表示する

// 使用する画像名
String fileName = "button.png";

// 使用する画像の設定
BitmapTextureAtlas bta = new BitmapTextureAtlas(activity.getTextureManager(), 100, 100, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
activity.getEngine().getTextureManager().loadTexture(bta);
ITextureRegion btr = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, fileName, 0, 0);
Sprite sprite = new Sprite(0, 0, btr, activity.getVertexBufferObjectManager());
sprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(sprite);

ボタン画像を表示する

// 使用する画像名
String btnName = "button.png";
String btnPressName = "button_press.png";

// 使用する画像の設定
BuildableBitmapTextureAtlas bta = new BuildableBitmapTextureAtlas(activity.getTextureManager(), 100, 200);
ITextureRegion trBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnName);
ITextureRegion trPresseBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnPressName);
try {
    bta.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 0, 0));
    bta.load();
} catch (TextureAtlasBuilderException e) {</em>
    Debug.e(e);
}

// 通常時と押された時の画像を指定する
ButtonSprite buttonSprite = new ButtonSprite(0, 0, trBtn, trPresseBtn, activity.getVertexBufferObjectManager());
buttonSprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(buttonSprite);

ボタン画像を押した時に処理を行う

public class SampleScene extends Scene implements ButtonSprite.OnClickListener {

ButtonSprite.OnClickListenerを定義します。

// 識別タグ
buttonSprite.setTag(1);
// リスナー
buttonSprite.setOnClickListener(this);
// 認識するエリア登録
registerTouchArea(buttonSprite);

上記で表示したボタン画像に対して、この処理を加えます。

@Override
public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {
    if (pButtonSprite.getTag() == 1) {
        // ボタン画像を大きくする
        buttonSprite.setScale(1.2f);
    }
}

どのボタン画像が押されたかはTagで識別します。

画像を動かす

// Handloerを定義する
public TimerHandler timeHandler = new TimerHandler(1f / 60f, true, new ITimerCallback() {
    @Override
    public void onTimePassed(TimerHandler pTimerHandler) {
        // Y軸に移動させる
        sprite.setPosition(sprite.getX() ,sprite.getY() + 1);
        // 拡大させる
        sprite.setScale(sprite.getScaleX() * 1.01f, sprite.getScaleY() * 1.01f);
        // 透明にする
        sprite.setAlpha(sprite.getAlpha() * 0.99f);
    }
});

これだけでは画像は動きません。
Handlerは登録する必要があります。

registerUpdateHandler(timeHandler);

動きを止めたいときは

unregisterUpdateHandler(timeHandler);

とします。
慣れてないときは、これを忘れて動かない!ということが多々ありました。

Sceneを遷移させる

NextScene scene = new NextScene(activity);
activity.getEngine().setScene(scene);

SceneからActivityを遷移させる

activity.startActivity(new Intent(activity, NextActivity.class));
activity.finish();

現在のActivityを終了して、次のActivityを呼び出します。

他にAndengineの機能は多々ありますが、調べきれていない部分などもありますので、次回に続きたいと思います。

ご覧頂きありがとうございました。

AndEngineでAndroidネイティブのView操作をSceneから行う

こんにちは
Zynga Japanを12月に退職し、GeNERACEという作りたての会社でCTOやってます、村松です。
GeNERACEではAndroidのネイティブゲーム開発にAndEngine(gituhub)を使ってます。

AndEngineはとっても便利ですが、ネイティブのViewと連携させるとより便利です。
今開発中のゲームもネイティブのViewをいくつかのSceneで使っています。
その際にScene1ではいらないけど、Scene2では使いたいとかいう場合ありますよね。
これ、単純にActivityのインスタンスを取得し、対象のViewにsetVisibilityで制御出来るようで実は出来ない。

何故か。

Viewはシングルスレッドモデルです。
AndEngineのSceneはActivityとは別スレッド。
SceneでネイティブのView操作を行うとアプリが強制終了します。

その為、こんな感じに実装してみました。

  • StageScene.java(ゲーム画面のクラス)
  • public class StageScene extends GeneraceAndEngineBaseScene implements ButtonSprite.OnClickListener, IOnSceneTouchListener, IOnAreaTouchListener{
    	private void showResult() {
    		// ネイティブのViewを表示状態にしたいYO!
    		getBaseActivity().visibleNativeViewFromId(R.id.edit_text_result);
    	}
    }
    
  • GeneraceAndEngineBaseScene.java(ゲーム画面の親クラス)
  • public abstract class GeneraceAndEngineBaseScene extends Scene implements ButtonSprite.OnClickListener{
    	private GeneraceAndEngineBaseActivity baseActivity;
    	public GeneraceAndEngineBaseActivity getBaseActivity() {
    		return this.baseActivity;
    	}
    }
    
  • GeneraceAndEngineBaseActivity.java(アクティビティ制御クラス)
  • public abstract class GeneraceAndEngineBaseActivity extends SimpleLayoutGameActivity {
    	Handler goneNativeViewHandler = new Handler();
    	Handler visibleNativeViewHandler = new Handler();
    	Handler invisibleNativeViewHandler = new Handler();
    	public void goneNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				goneNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.GONE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void invisibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				invisibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.INVISIBLE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void visibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				visibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.VISIBLE);
    					}
    				});
    			}
    		}).start();
    	}
    }
    
  • activity_main.xml
  • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    	xmlns:tools="http://schemas.android.com/tools"
    	android:layout_width="match_parent"
    	android:layout_height="match_parent" >
    
    	<org.andengine.opengl.view.RenderSurfaceView
    		android:id="@+id/renderview"
    		android:layout_width="fill_parent"
    		android:layout_height="fill_parent" />
    	<EditText
    		android:id="@+id/edit_text_result"
    		android:gravity="left|top"
    		android:inputType="textMultiLine"
    		android:layout_marginLeft="10dip"
    		android:layout_marginRight="10dip"
    		android:layout_marginTop="300dip"
    		android:visibility="gone"
    		android:layout_width="match_parent"
    		android:layout_height="100dip"/>
    </RelativeLayout>
    

    非同期処理とかで使う実装に似た感じ。
    なんかイマイチ綺麗じゃないなー、俺Handlerあんま好きじゃないんだよなーとか思うけど、もう今日は眠いのでこれで限界。(3:30 AMなう)
    より良い実装が浮かんだら書き換えよう。そうしよう。

    そういえば、AndEngineってZyngaのNicolas Gramlich(facebook)さんが作ってるですよね。
    Zynga Japan辞めてもなんやかんやでZyngaにお世話になることはまだまだありそうです。

    GitとGitHubを使いこなすためのメモ

    こんにちは。2月から入った新人のあらいみきです。今日から「爆速」で開発できるエンジニアになるために頻繁にメモを書き残します。
    第一弾のテーマはGitです!

    macでGitを使いこなすための簡単なメモ。

    1. 下準備

    ☆用意するもの

    • Xcodeがインストールされていて、Command Line Toolsが入っているmacbook

    ☆インストールするもの

    • Tower

    ☆GitHubの設定をする。

    • GitHub https://github.com/

    ☆Git coreをmac portでダウンロード

    $ sudo port install git-core
    

    ☆Gitのバージョンを確認

    $ git version
    

    2. Gitを使う

    ☆登場人物

    • 中央リポジトリ…メインユーザーが持つプロジェクトのリポジトリ。
    • リモートリポジトリ…各人が中央リポジトリからforkしたリポジトリ。メインユーザーではなく各人のリポジトリとなる。
    • ローカルリポジトリ…リモートリポジトリからローカルへクローンして作るリポジトリ。

    ☆Gitのおさらい

    • fork…自分のGitのリポジトリに任意のGitのリポジトリをコピーする。
    • pull…任意のリモートリポジトリの変更を自分のところに反映させる。
    • push…自分のリモートリポジトリに、自分のローカルでの変更を反映させる。commitとセットで行うとわかりやすい。
    • commit…自分がローカルで行った変更を確定させる。commitしただけだと変更が自分のリモートリポジトリ反映されないことに注意!(svnとは違う)
    • pull request…自分のリモートリポジトリの変更を中央リポジトリに反映させたい場合は、中央リポジトリに対してpull requestを送る。
    • master…リポジトリの大本命。ここを簡単に変えられないように枝分かれのリポジトリ(=branch)を作る。
    • 中央リポジトリの設定について…Git Flowに似た運用をしているので、中央リポジトリの更新用にリモートリポジトリを追加します。

      中央リポジトリの設定について詳細は後述

    ☆ローカルにgitのリポジトリを置くディレクトリを作る。

    $ mkdir Git用ディレクトリ名
    

    ☆GitHubでコピーしたいリポジトリをforkする。

    ☆forkしたリポジトリのクローンをローカルに作る。

    $ cd Git用ディレクトリ名
    $ git clone git@xxx/yyy.git
    $ git checkout -b ブランチ名
    

    ※今回はSSHの鍵認証を使ってるので、HTTPではなくSSHを選択しました。

    ☆中央リポジトリの設定を行う。
    今回は中央リポジトリのリモートブランチとして、”upstream”という名前のリモートブランチを作成しました。

    $ git remote add upstream git@フォークしたリポジトリの元のURL
    

    ☆ローカルで、クローンしたリポジトリ内のどこかに変更を加える。

    ☆自分の変更をまずはコミットさせる。

    • Towerの左側のBRANCHESは常にチェックすること。ターゲットになってるブランチだったら、ブランチ名の横に(HEAD)と書いてある。
    • コミットさせたい変更したファイルを選ぶ方法→Statusタブを開いて、任意のファイルのStagedをチェックする。チェックしたら、上部にあるチェック印の”Commit”ボタンをクリック。

    これで「コミットは完了」!、、だけどローカルの変更は自分のリモートリポジトリに反映されていない。pushをして、ローカルでの変更を自分のリモートリポジトリに反映させる。

    ☆変更をpushする。
    Towerの上部のpushボタンをクリックし、ブランチの場所を要確認してokボタンをクリックする。
    これで自分のリモートリポジトリにも変更した内容が反映させる。
    今回はTowerでpushしましたが、ターミナルを使う場合は以下のコマンドを打ちます。

    $ git push origin ブランチ名/プロジェクト名
    

    ※引数なしのpushをすると、カレントブランチに関わらずローカルブランチと同名のブランチがリモート上にある場合はそれらを一気にpushします。

    ☆中央リポジトリの最新版を取り込む。

    $ git pull upstream ブランチ名
    

    ☆pull requestを送る。
    GitHub上で自分がフォークしたリポジトリのページに遷移し、Commitsというタブを選択し、自分のpush内容が反映されていることを確認し、pull requestボタンをクリックする。

    • pull(変更を)する側…master
    • pullするもの…pull requestを送る側が変更した箇所

    これで中央リポジトリの管理者にpull requestが送信される。

    ※pull requestを押した後、Tower上で空pushをする。これで自分が行った変更+中央リポジトリの変更を自分のリモートリポジトリに反映することができる。

    ☆mergeしたいときは?

    自分がpull requestを送ったと同時にほかの誰かもpull requestを送ったとき、エラーや競合が起きない範囲で変更を反映させたいところです。

    そこでGitHub上でmerge pull requestボタンを押すと、簡単にmergeを行うことができます。さらにmergeされた箇所に対してコメントを書くこともできます。これでソースレビューとマージが同時にできます!

    ※自分が行った変更と他の人が行った変更がコンフリクトした場合。
    例えば他の人と同じファイルを変更していて、pullした際にeclipse上などでファイルを確認したときにエラーが起こっている場合は、自分でeclipe上で変更分を手動でマージする必要があります。その後改めて変更分をpushし、pull requestを送る必要があります。

    今回はここまでです。ご覧いただきましてありがとうございます。

    参考記事一覧