2014年3月30日日曜日

[mac][haskell] Marvericksにアップグレードするとsys/cdefs.hが見つからなくなる問題の対処

Mac OS Xを10.8(Mountain Lion)から10.9(Marverhicks)にアップグレードしたところ、cabal installでパッケージをインストールしようとすると、以下のようなエラーが出る状態になってしまいました。

     fatal error: sys/cdefs.h: No such file or directory
     #include <sys cdefs.h>
                           ^
compilation terminated.


これはアップグレードにより、xcodeのコマンドラインツールによってインストールされていた/user/include以下のファイルが削除されていたために、sys/cdefs.hが見つからず、エラーになっていたようです。
ここの情報を参考にして、以下のコマンドでxcode5のコマンドラインツールをインストールすることで、sys/cdefs.hが配置されエラーは発生しなくなりました。

% xcode-select --install


なお、Haskell Platformのインストール手順に記載されているghc-clang-wrapperなるものも必要なのでお忘れなく。

2014年3月13日木曜日

[heroku][yesod] Heroku上でSQLiteを使ってはいけない

HerokuでSQLiteを使ってはいけない理由

なぜHerokuでSQLiteを使ってはいけないか。理由は以下の2つです。
  • HerokuのCedar Stackはephemeral filesystemを持っており、一見ファイルの読み書きができるように見えるが、一日に一度すべてクリアされる。このためSQLiteで保存したデータも毎日失われてしまう。
  • もしHerokuのファイルシステムが永続的にデータを保持したとしても別の問題がある。SQLiteはサービス機能を持っていないため各dynoの間でデータを共有することができず、それぞれ固有のDBを保持しているように振る舞ってしまう。
HerokuサイトのLearning - Application Architectureで公開されているSQLite on Herokuに詳細が説明されています。SQLiteの代わりにアドオンで提供されているPostgreSQL、MySQL、MongoDBなどを使うことになります。
今回YesodチュートリアルのYosogアプリで利用するデータベースをSQLiteからPostgreSQLに移行しました。その手順を紹介しておきます。

ローカル(mac)環境でのPostgres対応

まずローカル環境で動作しないことにはサーバ上で動作するはずがない、ということで、mac上のDevelopment環境でPostgreSQLを利用する手順を記載しておきます。
Yesodチュートリアルのサンプル(Yosogアプリ)をローカル環境でPostgreSQL上で動作させるには以下の修正が必要でした。yesod initコマンド実行時に利用DBとしてsqliteでなくpostgresqlを選択すれば、ここで述べるのSQLiteからPostgreSQLへの変更手順は不要になります。
  1. SQLite環境をPostgreSQL環境に変更
    1. Application.hsのdbconfをSQLiteからPostgreSQLに
    2. 
      -     dbconf <- withYamlEnvironment "config/sqlite.yml" (appEnv conf)
      +     dbconf <- withYamlEnvironment "config/postgresql.yml" (appEnv conf)
      
      
    3. Settings.hsのPersistentConfをSQLiteからPostgreSQLに
    4. (その1)
      
      -import Database.Persist.Sqlite (SqliteConf)
      +import Database.Persist.Postgresql (PostgresConf)
      
      
      (その2)
      
      -type PersistConf = SqliteConf
      +type PersistConf = PostgresConf
      
      
    5. Yosog.cabalのbuild-dependsをpersistent-sqliteからpersistent-postgresに
    6. (その1)
      
      -                 , persistent-sqlite             >= 1.3        && < 1.4
      +                 , persistent-postgresql         >= 1.3        && < 1.4
      
      
      (その2)
      
      -                 , persistent-sqlite
      +                 , persistent-postgresql
      
      
    7. config/postgresql.ymlの準備
    8. 
      Default: &defaults
        user: Yosog
        password: Yosog
        host: localhost
        port: 5432
        database: Yosog
        poolsize: 10
      
      Development:
        <<: *defaults
      
      Testing:
        database: Yosog_test
        <<: *defaults
      
      Staging:
        database: Yosog_staging
        poolsize: 100
        <<: *defaults
      
      Production:
        database: Yosog_production
        poolsize: 100
        <<: *defaults
      
      
  2. MacPortsでpostgresql93をインストールする
    1. postgresql93パッケージをインストール
    2. 
      % sudo port install postgresql93
      % sudo port install postgresql93-server
      % sudo port select postgresql postgresql93
      
      
    3. DBインスタンスの生成(serverのinstall時の指示に従う)
    4. 
      % sudo mkdir -p /opt/local/var/db/postgresql93/defaultdb
      % sudo chown postgres:postgres /opt/local/var/db/postgresql93/defaultdb
      % sudo su postgres -c '/opt/local/lib/postgresql93/bin/initdb -D /opt/local/var/db/postgresql93/defaultdb' 
      
      
    5. サーバーの起動
    6. 
      % sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql93-server.plist
      % sudo launchctl start org.macports.postgresql93-server
      
      

  3. Yosogアプリが利用するDBを生成する
    1. ユーザーとデータベースの生成
    2. 自動生成されるconfig/postgres.ymlを確認するとYosogユーザーでYosogデータベースにアクセスする設定になっています。このため以下のコマンドでユーザーとデータベースを作成しておきます。
      
      % createuser -U postgres -P Yosog
      % createdb -U postgres Yosog
      
      
      ユーザーとデータベースが作成されていないと、Yosogアプリ起動時に以下のエラーになります。
      
      Yosog: SqlError {sqlState = "", sqlExecStatus = FatalError, sqlErrorMsg = "FATAL:  role \"Yosog\" does not exist\n", sqlErrorDetail = "", sqlErrorHint = ""}
      
      
    3. PostgreSQL対応したYosogアプリの起動
    4. 
      % cabal run -- Development
      
      

HerokuにPostgreSQL対応版Haskell/Yesodアプリをdeployする

PostgreSQLを利用する手順はRuby on Rails上であればHerokuのドキュメントで紹介されています。ここではHaskellのYesodフレームワーク上でPostgreSQLを利用するサーバーをHerokuにデプロイするための手順を示しておきます。
  1. postgresqlアドオンの登録&接続情報の確認
    1. postgresqlアドオン登録
    2. 
      %  heroku addons:add heroku-postgresql:dev
      
      
    3. DB情報の確認
    4. 
      % heroku pg:info
      === HEROKU_POSTGRESQL_IVORY_URL
      Plan:        Dev
      Status:      available
      Connections: 0
      PG Version:  9.3.3
      Created:     2014-03-12 15:42 UTC
      Data Size:   6.4 MB
      Tables:      0
      Rows:        0/10000 (In compliance)
      Fork/Follow: Unsupported
      Rollback:    Unsupported
      
      
    5. 接続情報の確認
    6. 
      % heroku pg:credentials HEROKU_POSTGRESQL_IVORY_URL
      Connection info string:
         "dbname=ddddd host=aaa-11-222-33-44.compute-1.amazonaws.com port=5432 user=uuuuu password=XXXXX sslmode=require"
      Connection URL:
          postgres://uuuuu:XXXXX@aaa-11-222-33-44.compute-1.amazonaws.com:5432/ddddd
      
      
  2. 接続情報の反映と接続確認
    1. config/postgresql.ymlの編集
    2. 接続情報で確認した、dbname, host, user, passwordをpostgresql.ymlのProduction:の設定に反映します。
      
      --- a/config/postgresql.yml
      +++ b/config/postgresql.yml
      @@ -19,6 +19,10 @@ Staging:
         <<: *defaults
       
       Production:
      -  database: Yosog_production
      +  user: uuuuu
      +  password: XXXXX
      +  host: aaa-11-222-33-44.compute-1.amazonaws.com
      +  port: 5432
      +  database: ddddd
         poolsize: 100
         << *defaults
      
      
    3. postgresql対応版サーバーのdeploy
    4. 
      % git commit -m "- use postgersql instead of sqlite." .
      % git push heroku master
      % heroku open
      
      
    5. psqlを用いた接続確認(おまけ)
    6. 以下のコマンドでPCからadonしたPostgreSQLのDBに接続することができます。postgresql.ymlのDevelopment:欄に同様の設定をすればアプリ本体はPC上、DBはサーバー上の組み合わせで動作確認することもできます。
      
      % psql -h aaa-11-222-33-44.compute-1.amazonaws.com -p 5432 -U uuuuu DDDDD
      ddddd> \d
                        List of relations
       Schema |      Name      |   Type   |     Owner      
      --------+----------------+----------+----------------
       public | article        | table    | uuuuu
       public | article_id_seq | sequence | uuuuu
       public | email          | table    | uuuuu
       public | email_id_seq   | sequence | uuuuu
       public | user           | table    | uuuuu
       public | user_id_seq    | sequence | uuuuu
      (6 rows)
      
      

ここまでの修正はGitHubにコミット済みです。
https://github.com/kurokawh/Yosog/tree/Yosog_PostgreSQL
メモ:ローカルリポジトリの変更をリモートのmaster以外の別ブランチにプッシュするには、以下のコマンドを実行する。

% git push origin master:Yosog_PostgreSQL
Counting objects: 24, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 2.02 KiB | 0 bytes/s, done.
Total 18 (delta 12), reused 0 (delta 0)
To https://kurokawh@github.com/kurokawh/Yosog.git
   be68e29..8a25b29  master -> Yosog_PostgreSQL
% git branch -r
  origin/Yosog_PostgreSQL
  origin/master


参考にした情報:

2014年3月11日火曜日

[cygwin][linux] tcshのデフォルト補完設定のイマイチな部分を修正しよう

cygwinや最近のlinuxディストリビューション上でtcshを起動すると、デフォルトでたくさんの補完設定がされていて便利なのですが、局所的に自分の使い方とマッチしない設定があるのでそれを修正します。
cygwinでは/etc/profile.d/complete.tcshに、ubuntuでは/etc/complete.tcshにあるデフォルト設定ファイルを編集することになります。

イケてない設定1:cpやmvの第二引数の補完対象がディレクトリに限定されている

一番イケてないのがcp/mvのデスティネーション(第二引数)がディレクトリに限定されている点。上書き先に直接ファイルを指定したい、または複数ファイルをまとめてコピーしたい、といったケースで補完が効きません・・・。

    complete mv  c/--/"(backup force interactive update verbose suffix \
   version-control help version)"/ \
   c/-/"(b f i S u V v -)"/ \
   n/{-S,--suffix}/x:''/ \
   n/{-V,--version-control}/"(t numbered nil existing \
   never simple)"/ n/-/f/ N/-/d/ p/1/f/ p/2/d/ n/*/f/

    complete cp  c/--/"(archive backup no-dereference force \
       interactive link preserve parents sparse recursive \
   symbolic-link suffix update verbose version-control \
   one-file-system help version)"/ \
   c/-/"(a b d f i l P p R r S s u V v x -)"/ \
   n/-*r/d/ n/{-S,--suffix}/x:''/ \
   n/{-V,--version-control}/"(t numbered nil existing \
   never simple)"/ n/-/f/ N/-/d/ p/1/f/ p/2/d/ n/*/f/

取り消し線で潰してある"p/2/d"を削除すれば所望の動作になります。ちなみに"p"は引数位置を指定するパターンコマンドで"2"が第二引数、"d"が(ファイルを除く)ディレクトリを意味しています。


イケてない設定2:lnの第二・三引数で補完が効かない

lnコマンド実行時"-s"オプションを指定の上、任意のディレクトリ・ファイルを第一引数に指定しますが、これが第二引数と解釈され、以下のような結果になります。
% ln -s [CTRL-D]
<link_name>
取り消し線の"p/2/x:'<link_name>'"を"p/2/f/'"に置き換えれば第二・三引数で補完が効くようになります。
% ln -s [CTRL-D]
    complete ln  c/--/"(backup directory force no-dereference \
       interactive symbolic suffix verbose version-control \
   help version)"/ \
   c/-/"(b d F f i n S s V v -)"/ \
   n/{-S,--suffix}/x:''/ \
   n/{-V,--version-control}/"(t numbered nil existing \
   never simple)"/ n/-/f/ N/-/x:'<link_name>'/ \
   p/1/f/ p/2/x:'<link_name>'/ p/2/f/ 



イケてない設定3:gitコマンドが補完できない

svnは対応されており、以下のようなコマンドが補完されるのですが、gitは登録されておらずコマンドを補完してくれません。

% svn [CTRL-D]
add      cleanup  export   list     merge    propedit resolved unlock
blame    commit   help     lock     mkdir    propget  revert   update
cat      copy     import   log      move     proplist status   
checkout delete   info     ls       propdel  propset  switch   


svnの設定をコピって以下の補完を追加。"@"は"/"と同じ意味です。

    complete git  'n@help@(add bisect branch checkoutclone \
            commit diff fetch grep init log merge mv \
   pull push rebase reset rm show status tag)@' \
   'p@1@(add bisect branch checkoutclone \
            commit diff fetch grep init log merge mv \
   pull push rebase reset rm show status tag)@'
 

イケてない設定4:Haskell関連コマンドの補完が未登録

ghc、ghci、cabalの補完設定も追加して幸せになりましょう。

    complete ghc  c/-v/"(0 1 2 3 4 5)"/ \
            c/-i/d/ \
            c/--/"(interactive make mk-dll help show-iface \
         supported-extensions supported-languages \
         info version numeric-version print-libdir)"/ \
   c/-W/"(all error warn)"/ \
   c/-{fwarn-,fno-warn-}/"(unrecognised-pragmas \
          warnings-deprecations deprecated-flags \
          unsupported-calling-conventions \
          dodgy-foreign-imports dodgy-exports \
          dodgy-imports lazy-unlifted-bindings \
          duplicate-exports hi-shadowing \
          identities implicit-prelude \
          incomplete-patterns incomplete-uni-patterns \
          missing-fields missing-import-lists \
          missing-methods missing-signatures \
          missing-local-sigs name-shadowing \
          orphans auto-orphans overlapping-patterns \
          tabs type-defaults monomorphism-restriction \
          unused-binds unused-imports unused-matches \
          unused-do-bind wrong-do-bind )"/ \
   c/-f/"(defer-type-errors helpful-errors \
          force-recomp warn- no-warn-)"/ \
    c/-/"(E C S c fglasgow-exts O prof H14m M e V w\
         ferror-spans ghc-timing fforce-recomp ?)"/ \
   n/-{odir,hidir,stubdir,dumpdir,outputdir,tmpdir}/d/ \
   'n/--make/f:*.hs/' \
    'n/*/f:*.hs/'

    complete ghci c/-i/d/ \
            c/-/"(fglasgow-exts H32m cpp i)"/

    complete cabal c/--{config-file,sndbox-config-file}=/f/ \
   c/--/"(help version numeric-version config-file= \
                  sandbox-config-file=)"/ \
   p/1/"(install update list info fetch get check \
        sdist upload report run init configure build \
        repl sandbox copy haddock clean hscolour \
        register test bench help)"/


参考にしたサイト:

2014年3月3日月曜日

[heroku][yesod] YesodアプリをHeroku上にデプロイする手順

YesodアプリをHeroku上にデプロイできました!以前にローカル環境で確認したYesodチュートリアルのwebアプリケーションをHeroku上で動作させることができたので、その手順をまとめておきます。

前提環境:

  • Yesodチュートリアルのアプリケーション(Yesog)が動作している
  • gitがインストールされている
  • heroku toolbeltがインストールされている
  • 動作確認した環境の詳細
    • % ghc --version
      • The Glorious Glasgow Haskell Compilation System, version 7.6.3
    • % cabal --version
      • cabal-install version 1.18.0.2
      • using version 1.18.1.2 of the Cabal library 
    • % yesod version
      • yesod-bin version: 1.2.6
    • % heroku version
      • heroku-toolbelt/3.4.1 (x86_64-darwin10.8.0) ruby/1.9.3

デプロイ手順:

以下の手順を実行することでYosogアプリケーションをHeroku上にデプロイし、クライアントからアクセスできるようになります。
  1. Yosog.cabalをエディタで開き、以下の取り消し線部分の記述を削除する
  2. 
    
    executable         Yosog
    
        if flag(library-only)
            Buildable: False
    
        main-is:           main.hs
        hs-source-dirs:    app
        build-depends:     base
                         , Yosog
                         , yesod
    
    
    この記述があると、cabal runで以下のようなエラーが発生してしまいます。原因不明…。
    
    cabal: Cannot build the executable 'Yosog' because the component is marked as
    
    disabled in the .cabal file.
    
    
  3. YosogルートディレクトリにProfileを用意する
  4. 
    % echo "web: cabal run -- production -p $PORT" > Profile
    
    
    このファイルはHerokuがサーバーを起動する手順になります。ローカル環境でも同様のコマンドでサーバーが起動することを確認しておきましょう。
  5. gitリポジトリにファイルを登録
  6. 
    % git init .
    % git add *
    % git commit -m "Initial commit." .
    
    
  7. heroku上にアプリケーションを登録
  8. 
    % heroku create --stack=cedar --buildpack https://github.com/begriffs/heroku-buildpack-ghc.git
    
    
  9. heroku上にアプリケーションをデプロイ
  10. 
    % git push heroku master
    
    
    10分くらい時間がかかります。状況によっては15分のビルド時間制限をオーバーしてしまうこともあるようです。そのようなときには、以下の手順で別サーバーでビルドを実行することができる模様。
    
    % heroku plugins:install https://github.com/ddollar/heroku-anvil
    % heroku build -r -b https://github.com/begriffs/heroku-buildpack-ghc.git
    
以上です。
heroku open
上記のコマンドでパブリックなサーバーとして起動しているYosogアプリケーションにアクセスすることができます。GitHubでこの環境をを公開しておきます。

  • https://github.com/kurokawh/Yosog.git
  • 参考情報:

    以下、参考にした情報についてまとめておきます。複数サイトの情報を参照しつつ作業したのですが、自分の環境ではうまくいかなかった手順もありました。最終的に最も成功に近かった手順は以下のサイトの情報になります。
    以下のサイトの情報も試しましたが、いずれもクライアントからアクセスできる状態にたどりつけませんでした。
    • Haskell Buildpack Demo
      • サンプルのデプロイ、動作確認は成功。だが、自環境のYosogアプリについては、deployまで成功したが、heroku openを実行してもサーバーとは繋がらず…。
    • MacでHerokuにYesodを(Herokuに公開編)
      • この手順はバイナリをgitコミットして、コンパイルなしてサーバー上で起動する手順だと思われます。mac上でビルドしたバイナリはdeployまではできるものの、heroku openで繋がりませんでした。

    その他、新たに学習した情報のメモ

    いろいろはまったことで、自分にとっての新しい知識が少しだけ増えました。Herokuへのデプロイと直接は関係しませんが、それらもまとめておきます。
    • yesodアプリをリリースビルドする手順
      • scafoldsiteではyesod develでビルド&テストサーバーが起動されますが、リリース用のバイナリを生成するには
        • cabal install
      • を実行することになります。このコマンドを実行すると
        • dist/dist-sandbox-5ba8a016/build/Yosog/Yosog
      • が生成されます。production -p XXXという引数とともにこのバイナリを起動すると、プロダクション版のサーバーを起動できます。
        • dist/dist-sandbox-5ba8a016/build/Yosog/Yosog production -p 3000
    おわり。

    2014年3月1日土曜日

    [mac][haskell] Haskell Platformのアンインストール手順

    yesod-platformの更新を試みたところパッケージ間の依存関係に問題が発生してにっちもさっちもいかない状態になってしまいました。そこで不本意ではありますがHaskell Platform自体をゼロからクリーンインストールすることに。
    ところがHaskell Platformのインストール手順は本家のウェブサイトに記載されているのですが、アンインストールの手順が見あたりません。ネット上で見つかった「Haskell Platformをアンインストールして綺麗な環境を取り戻す」を参考に自分のmac環境からもクリーンアップできた(はず)なので、その手順を残しておきます。
    1. Haskell Platformのインストーラでコピーされたファイルを削除する
      • /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstallerを実行する
        • (2015.10.24追記)Uninstallerファイルに実行権限がないのが原因でした。以下の通り実行できました。
        • % sudo chmod +x /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstaller
          % sudo /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstaller
          Removing /Library/Frameworks/GHC.framework/Versions/7.6.3-x86_64
          Removing /Library/Frameworks/GHC.framework
          Removing package receipt
          Done.
          
      • 自分の環境では、このスクリプトを実行するとcommand not foundというエラーになってしまったため、手動で/Library/Frameworks/GHC.framework/を削除しました。
      • 
        sudo rm -rf /Library/Frameworks/GHC.framework/
        sudo rm -rf /Library/Haskell/
        
        
    2. ユーザー環境にインストールされたパッケージ群を削除する
      • ~/Library/Haskell/以下を全て削除
      • 
        rm -rf ~/Library/Haskell/
        
        
    3. ホームディレクトリ直下の.ghc, .cabalを削除する
      • 
        rm -rf ~/.ghc ~/.cabal
        
        
    1.の手順をスキップするとHaskell Platformを再インストールした直後のクリーンな状態と同じ状態にできます。追加インストールしたパッケージ群だけを全てクリアしたい、という目的に対しては、2.と3.だけを実行するのがおすすめです。