logback.groovyで設定記述しようとしたらアレな事になった件について

Gradleを使っているせいでGroovyづいているのでログの出力設定もGroovyで書いてみたら、
どうもlogbackがバグってるぞなもし。って話。

具体的には何かっつうと、logback自体の動作ログを出すために、
OnConsoleStatusListenerってのを使うのだけど、それを普通に使っても特に何も出力されないのです。
何が足りないのかというと動作する為に呼出しが必要なContextが設定されず、
又、ライフサイクルメソッドであるstartが呼び出されないのです。


という訳で、logback-classic-1.0.1logback.groovyを使う際には以下の様なワークアラウンドが必要になります。

import static ch.qos.logback.classic.Level.*
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.status.OnConsoleStatusListener

statusListener(OnConsoleStatusListener)
statusManager.getCopyOfStatusListenerList().each {
	// TODO workaround
	it.context = context
	it.start()
}

appender("CONSOLE", ConsoleAppender) {
	encoder(PatternLayoutEncoder) { pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" }
}

logger 'com.example', INFO, ['CONSOLE']
root WARN, ['CONSOLE']

イラっときたので、GitHubのリポジトリから、
Forkしてビルドしようとしたらテストがコケるし、eclipse:eclipseまでERRORでコケよるので面倒になりました。
それで気になってpull request見ると随分とマージされずに残っている。


僕の目下の目的とは随分ズレているのでちゃんとビルド出来る訳でもないものにコントリビュートする程の熱意がある筈もなく、
とりあえずワークアラウンドだけメモ書きしておこう、と相成りましたとさ。


そもそも、logbackをGroovyで設定するってのは余り使われてないんですかね?

Gradle-WrapperにHTTPとHTTPSのプロキシを設定して動かす。

環境変数GRADLE_OPTSを設定しておく。

set GRADLE_OPTS=-Dhttp.proxyHost=example.jp -Dhttp.proxyPort=8080 -Dhttps.proxyHost=example.jp -Dhttps.proxyPort=8080

これはつまりJVMに対して設定を行うのでHTTPとHTTPSはエントリとして別立てにしないといけません。

片方しか設定していない場合、Gradleを使っていると依存ライブラリを自動的にダウンロードする時にHTTPSだったりHTTPだったりするので、途中まで動いているにも関わらず急に

Exception in thread "main" java.net.ConnectException: Connection refused 

とか言われて??となったりするます。


参考:

GitHubにGradleでリリース作業する。

タグをpushしてダウンロードAPI叩くだけなんですけども。

パスフレーズ付のSSH鍵を使っていると良い感じにハマるのでメモしておきます。

  • 今回のスクリプトを実行する為の依存関係とかそういうの
import org.eclipse.egit.github.core.*
import org.eclipse.egit.github.core.client.*
import org.eclipse.egit.github.core.service.*

import org.eclipse.jgit.api.*
import org.eclipse.jgit.lib.*
import org.eclipse.jgit.transport.*
import org.eclipse.jgit.errors.*

apply plugin: 'java'
apply plugin: 'war'

buildscript {
	repositories {
		mavenCentral()
		mavenRepo(url: 'http://download.eclipse.org/jgit/maven')
		flatDir { dirs 'lib' }
	}
	dependencies {
		classpath 'org.eclipse.jgit:org.eclipse.jgit:1.+'
		classpath 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:1.+'
	}
}

タグを打ってpushするコード。

class PassphraseProvider extends CredentialsProvider {
	def passphrase = ""
	PassphraseProvider() {
		def pass = System.console().readPassword("\nenter ssh passphrase: ")
		this.passphrase = "$pass"
	}
	def boolean isInteractive() {
		false
	}
	def boolean supports(CredentialItem... items) {
		true
	}
	def boolean get(URIish uri, CredentialItem... items) {
		items.each {
			if(it instanceof CredentialItem.StringType) {
				it.value = passphrase
				return true
			} else {
				throw new UnsupportedCredentialItem(uri, it.promptText);
			}
		}
	}
}

task tag << {
	def g = Git.open file('.git')
	def tag = null
	try {
		def n = "$version-$war.classifier"
		tag = g.tag() setName n setMessage "release $n" call()
		g.push().setPushTags().setCredentialsProvider new PassphraseProvider() setProgressMonitor new TextProgressMonitor() call()
	} catch(e) {
		g.tagDelete().setTags(tag?.tagName).call()
		throw e
	} finally {
		g.repository.close()
	}
}

pushでコケたら使ったタグを消さないと、パスフレーズのエントリに失敗するたんびに謎のタグがガシガシ出来てしまうからでつ。

PassphraseProviderなんてクラスを実装しとりますが、これはJGitの実装を誤魔化す為にやっとります。

  • org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(CredentialsProvider, FS, String, String, String, int, Host)
private Session createSession(CredentialsProvider credentialsProvider,
		FS fs, String user, final String pass, String host, int port,
		final OpenSshConfig.Host hc) throws JSchException {
	final Session session = createSession(hc, user, host, port, fs);
	if (pass != null)
		session.setPassword(pass);
	final String strictHostKeyCheckingPolicy = hc
			.getStrictHostKeyChecking();
	if (strictHostKeyCheckingPolicy != null)
		session.setConfig("StrictHostKeyChecking",
				strictHostKeyCheckingPolicy);
	final String pauth = hc.getPreferredAuthentications();
	if (pauth != null)
		session.setConfig("PreferredAuthentications", pauth);
	if (credentialsProvider != null
			&& (!hc.isBatchMode() || !credentialsProvider.isInteractive())) {
		session.setUserInfo(new CredentialsProviderUserInfo(session,
				credentialsProvider));
	}
	configure(hc, session);
	return session;
}

バッチモードだとしても、インタラクティブ性があって良い様な気がしないでもないけど、良く分からない。
自動的な作業はパスフレーズの無いSSH鍵を使えってのは、何か良く聞く気がしないでもない。


次に、GitHubAPIのJava実装を使って、各リポジトリにあるダウンロードタブからアーカイブをダウンロード出来る様にしるます。

task uploadArchives(overwrite: true, dependsOn: war) << {
	def client = new GitHubClient()
	client.setCredentials(github_username, github_password)
	def repoid = RepositoryId.create('username', 'reponame')
	def dls = new DownloadService(client)
	def d = new Download()
	d.name = war.archiveName
	dls.createDownload(repoid, d, war.archivePath)
}

このコードではwarタスクで作ったアーカイブをアップロードしているます。
repoidの辺りにはテキトーにユーザ名とリポジトリ名を埋めてクダサシ。
アクセスに必要なユーザIDとパスワードは、gradle.propertiesの中に書いてリポジトリには共有しない様にしてあるます。

github_username=oreore
github_password=KaA30re0re

最後にリリース用のタスクを定義しる。

task release(dependsOn:[build, tag, uploadArchives]) << { println "release fishined !!" }

最近、そろそろgradleのGitプラグインがあっても良いんじゃないかと思い始めているのだけど、
僕が見つけられてないだけで存在しているのかな?

同一のGroupIdかつ同一バージョンで複数のArtifactIdを依存ライブラリとして指定する。

  • Gradle 1.0-milestone-7

で動かしてるます。

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    [
        'jersey-core',
        'jersey-server',
        'jersey-servlet'
    ].each { compile "com.sun.jersey:$it:1.+" }
}

GradleはGroovyなのでこういう事も出来ますよ。という話。
ここではGString使えているけどなぁ…どんな違いがあるのだろう…。

Gradleで文字エンコーディングを指定する方法

Gradleで文字エンコーディングを指定する方法 - 豆無日記

が余りにカッコワルイのでひねりだしてみた。

  • Gradle 1.0-milestone-7

で動かしてるます。

apply plugin: 'java'
apply plugin: 'groovy'

repositories {
	mavenCentral()
	mavenRepo(url: 'http://download.eclipse.org/jgit/maven')
	flatDir { dirs 'lib' }
}

sourceCompatibility = 1.6
targetCompatibility = 1.6

def encoding = { it.encoding = "UTF-8" }
tasks.withType(AbstractCompile) each { encoding it.options }
tasks.withType(GroovyCompile) each { encoding it.groovyOptions }

第一回 太一にモダンJSを教える会

と言う会が品川某所で、2011/10/05にヒッソリと開催されました。
お客様は主催者たる僕のみで、それ以外の参加者は基本的に講師という大変贅沢な会です。
それなりに話はあっちこっちしていたし、
話題に上がった重要そうな部分で、僕が覚えている事を補足しながらメモ書き。


妥当でない部分があったので、変更。

続きを読む

一歩先行くJavaプログラマが読むべきオープンソースソフトウェア10選

10万行コード読んだらJava分かるよってTwitterに書いたらすげぇ勢いでRTされたので、調子に乗って捕捉エントリ書くよ。

続きを読む