ちょっととあるコマンドラインツール作ろうと思って、また gem で作ろうかと思ったんだけど Windows でも動かせるようにしたいし、使う人に Ruby 入れさせるのもアレなので、golang で作ってみようと思った。
土日ぐらいで A Tour of Go. を始めとしていろんな入門エントリ読んで、とりあえず手始めに github.com/pinzolo/casee とかいうライブラリ作ってみた。
とりあえずテストは通るし、動いている。
ちょっととあるコマンドラインツール作ろうと思って、また gem で作ろうかと思ったんだけど Windows でも動かせるようにしたいし、使う人に Ruby 入れさせるのもアレなので、golang で作ってみようと思った。
土日ぐらいで A Tour of Go. を始めとしていろんな入門エントリ読んで、とりあえず手始めに github.com/pinzolo/casee とかいうライブラリ作ってみた。
とりあえずテストは通るし、動いている。
sudo aptitude install -y tomcat7 tomcat7-admin
sudo vi /etc/tomcat7/server.xmlHTTPのConnector設定をコメントアウトし、AJPのConnector設定を有効にする。
wget https://github.com/gitbucket/gitbucket/releases/download/3.13/gitbucket.war sudo mv gitbucket.war /var/lib/tomcat7/webapps ls -al /var/lib/tomcat7/webappsdrwxrwxr-x 4 tomcat7 tomcat7 4096 Apr 7 14:37 . drwxr-xr-x 6 root root 4096 Apr 7 14:24 .. drwxr-xr-x 7 tomcat7 tomcat7 4096 Apr 7 14:37 gitbucket -rw-r--r-- 1 root root 39783199 Apr 7 14:37 gitbucket.war drwxr-xr-x 3 root root 4096 Apr 7 14:25 ROOT
sudo vi /etc/apache2/sites-available/gitbucket.conf<VirtualHost *:443> ServerName gitbucket.my-domain:443 <Location /> ProxyPass ajp://localhost:8009/ </Location> SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>sudo a2ensite gitbucket
sudo service tomcat7 restart sudo service apache2 restartしかし、アクセスしても 404 となる。
/var/log/tomcat7/localhost.2016-04-07.log を見ると、こんなエラーが出ている。
SEVERE: Error configuring application listener of class gitbucket.core.ssh.SshServerListener
java.lang.UnsupportedClassVersionError: gitbucket/core/ssh/SshServerListener : Unsupported major.minor version 52.0 (unable to load class gitbucket.core.ssh.SshServerListener)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2948)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1208)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1688)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1569)
at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:529)
at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:511)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:139)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4888)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1073)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
https://github.com/gitbucket/gitbucket/issues/1082 によると、Java8を必要としているがJava8ではない場合に出るエラーのようだ。TomcatがJava8で動いていないっぽい。
sudo vi /etc/default/tomcat7
JAVA_HOME=/usr/lib/jvm/java-8-oracleを追加して再起動。
SEVERE: Exception sending context initialized event to listener instance of class gitbucket.core.servlet.InitializeListener
java.sql.SQLException: Connections could not be acquired from the underlying database!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:692)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.createConnection(JdbcBackend.scala:47)
at scala.slick.jdbc.JdbcBackend$BaseSession.conn$lzycompute(JdbcBackend.scala:397)
at scala.slick.jdbc.JdbcBackend$BaseSession.conn(JdbcBackend.scala:397)
at scala.slick.jdbc.JdbcBackend$BaseSession.withTransaction(JdbcBackend.scala:420)
at scala.slick.backend.DatabaseComponent$DatabaseDef$$anonfun$withTransaction$1.apply(DatabaseComponent.scala:54)
at scala.slick.backend.DatabaseComponent$DatabaseDef$$anonfun$withTransaction$1.apply(DatabaseComponent.scala:54)
at scala.slick.backend.DatabaseComponent$DatabaseDef$class.withSession(DatabaseComponent.scala:34)
at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.withSession(JdbcBackend.scala:46)
at scala.slick.backend.DatabaseComponent$DatabaseDef$class.withTransaction(DatabaseComponent.scala:54)
at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.withTransaction(JdbcBackend.scala:46)
at gitbucket.core.servlet.InitializeListener.contextInitialized(InitializeListener.scala:30)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1073)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1469)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:644)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:554)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:758)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:685)
... 25 more
Caused by: org.h2.jdbc.JdbcSQLException: Error while creating file "/usr/share/tomcat7/.gitbucket" [90062-190]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.store.fs.FilePathDisk.createDirectory(FilePathDisk.java:274)
at org.h2.store.fs.FileUtils.createDirectory(FileUtils.java:42)
at org.h2.store.fs.FileUtils.createDirectories(FileUtils.java:309)
at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:73)
at org.h2.engine.Database.getPageStore(Database.java:2450)
at org.h2.engine.Database.open(Database.java:672)
at org.h2.engine.Database.openDatabase(Database.java:269)
at org.h2.engine.Database.(Database.java:263)
at org.h2.engine.Engine.openSession(Engine.java:65)
at org.h2.engine.Engine.openSession(Engine.java:175)
at org.h2.engine.Engine.createSessionAndValidate(Engine.java:153)
at org.h2.engine.Engine.createSession(Engine.java:136)
at org.h2.engine.Engine.createSession(Engine.java:28)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:349)
at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:107)
at org.h2.jdbc.JdbcConnection.(JdbcConnection.java:91)
at org.h2.Driver.connect(Driver.java:72)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:175)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:220)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:206)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:203)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1138)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1125)
at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:44)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1870)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
/usr/share/tomcat7/.gitbucket が作成できないらしい。パーミッションかls -al /usr/share/tomcat7rootになっとる。drwxr-xr-x 4 root root 4096 Apr 7 14:24 . drwxr-xr-x 155 root root 4096 Apr 7 14:25 .. drwxr-xr-x 2 root root 4096 Apr 7 14:24 bin -rw-r--r-- 1 root root 39 Feb 21 2014 defaults.md5sum -rw-r--r-- 1 root root 2030 Feb 21 2014 defaults.template drwxr-xr-x 2 root root 4096 Apr 7 14:24 lib -rw-r--r-- 1 root root 53 Feb 21 2014 logrotate.md5sum -rw-r--r-- 1 root root 118 Feb 21 2014 logrotate.template
sudo chown -R tomcat7:tomcat7 /usr/share/tomcat7再度再起動したら表示はされたが assets が効いていない。
/gitbucket が存在しないから /gitbucket/assets も当然見えないわけだ。/etc/apache2/sites-available/gitbucket.conf を書き換えた。
<VirtualHost *:443> ServerName gitbucket.my-domain:443 ProxyReverseHost On RewriteEngine On ProxyPass /gitbucket ajp://localhost:8009/gitbucket/ ProxyPassReverse /gitbucket ajp://localhost:8009/gitbucket/ ProxyPass /gitbucket/assets ! # 静的ファイルはAapacheに処理させる Redirect / /gitbucket # ルートにアクセスしても大丈夫なように RewriteRule ^/gitbucket/(.*) ajp://localhost:8009/gitbucket/$1 [P,L,QSA] SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>RewriteRule がないとトップは表示されても、サインインできなかった。
wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - sudo sh -c 'echo "deb http://pkg.jenkins-ci.org/debian binary/" > /etc/apt/sources.list.d/jenkins.list' sudo aptitude update sudo aptitude install -y jenkins
sudo vi /etc/default/jenkins
HTTP_PORTを-1に、AJP_PORTを8008に(Tomcat導入予定のため)
sudo vi /etc/apache2/sites-available/jenkins.conf<VirtualHost *:443> ServerName jenkins.my-domain:443 <Location /> ProxyPass ajp://localhost:8008/ </Location> SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>sudo a2ensite jenkins
sudo service jenkins restart sudo service apache2 restart
とっても簡単だった
% git --versionとくに問題なし、前回と同じ。git version 2.0.0% cd /opt/src % wget https://www.kernel.org/pub/software/scm/git/git-2.8.1.tar.gz % tar xf git-2.8.1.tar.gz % cd git-2.8.1 % ./configure --prefix=/opt/git/git-2.8.1 --with-openssl --with-curl % make % make install % /opt/git/git-2.8.1/bin/git --versiongit version 2.8.1% ln -sfn /opt/git/git-2.8.1/bin/* /usr/bin % git --versiongit version 2.8.1
業務アプリを作っているとテーブルのヘッダを固定して欲しいという話はよくある。よくありすぎる。
2つのテーブルを作って列の幅を固定して、body担当テーブルはdivで囲って overflow-y 程度でできればいいんだけど、IEはスクロールバーを出しっぱなしなのでずれる。
仕方なくheader担当にもスクロールバーをだしっぱなすとかまあ色々苦労する。
今回は、ページの上部にヘッダが来たらそこでheader担当を固定させてやればいいよね。ということでやってみた。
AngularJS の directive でやったけど、参考にした jQuery も備忘録的にメモっておいた
Bootstrapのpanelなんかの中にあった場合、固定した瞬間にはみ出て横幅がずれるので、body担当の横幅に合わせられるようにしている。
本当は thead に設定して1つのテーブルでやりたかったんだけどどうしても幅指定が出来なくて仕方なくテーブルを分けた。
横幅やスクロール距離、固定位置などパラメータは要件次第だけど結構手軽にできるもんだな
作業中に「お使いの起動ディスクは一杯です」というダイアログが表示された。
この3つのコマンド走らせるだけで、30Gほど空きスペースを確保できた。
ちょっと放置し過ぎか
PostgreSQL には ? という演算子があって、JSONB型に対して文字列の検索が行える。
-- true を返す SELECT '["a", "b", "c"]' ? 'a'; -- 管理者検索 SELECT * FROM users WHERE roles ? 'ADMIN';といった使い方ができる。
ところが、例えば DOMA のようなフレームワークやバックエンドでJDBCを使っているツールなどではエラーとなる。
これを避けるためには ? をエスケープしてやればよくて、
-- true を返す SELECT '["a", "b", "c"]' ?? 'a'; -- 管理者検索 SELECT * FROM users WHERE roles ?? 'ADMIN';としてやればよい。
tail -f pinzo.log: Deviseの有効期限設定をテストする で書いた有効期限検証のコードで不思議な事が起こった。Macでは正常にパスするのだが、Amazon Linux上ではパスしない。
ミニマムなコードで示すとこんな感じ
で、こんなデバッグコードを仕込んで実行してみた
Macで実行するとこんな感じ
[test-code][sent_at] to_s: 2016-02-01 23:51:31 +0900, to_i: 1454338291, usec: 197593, subsec: 197593/1000000 [test-code][added] to_s: 2016-02-11 23:51:31 +0900, to_i: 1456930291, usec: 197593, subsec: 197593/1000000 [devise][now] to_s: 2016-02-11 23:51:31 +0900, to_i: 1456930291, usec: 197593, subsec: 197593/1000000 [devise][sent_at] to_s: 2016-02-01 23:51:31 +0900, to_i: 1454338291, usec: 197593, subsec: 197593/1000000 [devise][added] to_s: 2016-02-11 23:51:31 +0900, to_i: 1456930291, usec: 197593, subsec: 197593/1000000 [devise] now > added: false [devise] now.subsec > added.subsec: false
Amazon Linuxで実行するとこんな感じ
[test-code][sent_at] to_s: 2016-02-01 23:53:20 +0900, to_i: 1454338400, usec: 369658, subsec: 369658841/1000000000 [test-code][added] to_s: 2016-02-11 23:53:20 +0900, to_i: 1456930400, usec: 369658, subsec: 369658841/1000000000 [devise][now] to_s: 2016-02-11 23:53:20 +0900, to_i: 1456930400, usec: 369658, subsec: 369658841/1000000000 [devise][sent_at] to_s: 2016-02-01 23:53:20 +0900, to_i: 1454338400, usec: 369658, subsec: 184829/500000 [devise][added] to_s: 2016-02-11 23:53:20 +0900, to_i: 1456930400, usec: 369658, subsec: 184829/500000 [devise] now > added: true [devise] now.subsec > added.subsec: true
usecまでは同じなのだが、subsec をみると Amazon Linux では、桁落ちが発生している。
ためしにそれぞれで Time.now.subsec としてみる。
# mac $ ruby -e 'puts Time.now.subsec' 276987/1000000 # Amazon Linux $ ruby -e 'puts Time.now.subsec' 704462593/1000000000
つまりこういうことが起こっている
Time#subsec が返す精度が異なるcreate で返すのは、コードで指定された値を格納したオブジェクトであり、DBに登録後取得したものではないので confirmation_sent_at はそのままの精度である。つまり、スタブで突っ込んでいるのは元の精度Time#subsecの精度がsqliteの精度と同じだったため桁落ちが発生せず正常に動作するこれを避けるためには、スタブに突っ込む値をDBから取得したものにすれば良さそうだ。たとえばこんな感じ
ちなみに Mac でも、桁落ちを引き起こすことは可能で、こんな感じで usec を超えた範囲を指定すれば桁落ちさせられる。
あー疲れた、腹減った
管理者とユーザーでのログイン機能が存在し、別モデルで管理したい場合、Devise を使うとscoped_viewsをtrueにすれば簡単に実装できる。(参考:Ruby - Railsでdeviseひとつで複数モデルを管理しよう - Qiita)
しかし、デフォルトの場合 Devise のログアウトは全てのスコープでログアウトしてしまう。つまり管理者とユーザーでログインしていた場合、管理者としてログアウトすると同時にユーザーとしてもログアウトしてしまう
これを防ぎたい場合、config/initializers/devise.rb にて config.sign_out_all_scopes = false としてやればよい。
初期状態ではこの設定はコメントアウトされているので、コメントアウトを外しfalseに設定するだけで、スコープごとのサインアウトが実装できる。
テストコード込みのサンプルコードはこんな感じ。