2013年12月20日金曜日

EPUBファイルの中身を確認する

EPUBファイルの実体は、EPUBの仕様に沿って配置されたファイル・フォルダをzipで圧縮したものなので、解凍することによりその中身を確認することができる。

Pandocを使ってMarkdownからEPUBを作成する』で作成したEPUBファイルの拡張子をzipに変更してzipで解凍すると、以下のようなファイル・フォルダで構成されていることがわかる。
ch001.xhtml
ch002.xhtml
content.opf
mimetype
nav.xhtml
stylesheet.css
title_page.xhtml
toc.ncx
META-INF
├─com.apple.ibooks.display-options.xml
└─container.xml
なお、解凍されたファイル・フォルダを単純に圧縮しなおしてもEPUBファイルとは認識されない点に注意。これは、EPUB内に含まれているファイルであるmimetypeが、zipの先頭エントリに無圧縮で追加されている必要があるため。Windowsの標準機能でこの要件を満たすには、mimetypeのみを右クリックしてzip圧縮し、できたzipファイルに他のファイル・フォルダを追加すればよいらしい。詳細は、下記リンクを参照。

関連リンク

Pandocを使ってMarkdownからEPUBを作成する

前提


手順

Pandocを使ってMarkdownからEPUBを作成する手順は、以下の通り。

任意のディレクトリに、以下のmybook.md(Markdown形式のファイル)を作成する。
% タイトル\
% 作者

---
language: ja-JP
---

# 見出し1

見出し1です。試しに書いてみます。

# 見出し2

見出し2も書いてみます。

1-2行目はtitle blockと呼ばれるPansocの拡張Markdown記法。1行目がタイトル、2行目が著者名として認識される。タイトルブロックは必ずファイルの先頭に記述する必要がある。

4-6行目もPandocの拡張Markdown記法でYAML metadata blockと呼ばれるもの。EPUB生成時に必要となるメタデータを指定することができる。ここでは、EPUBで使用する言語として日本語(ja-JP)を指定している。なお、この指定がないと、Adobe Digital Editionsで日本語が正しく表示されない。

8行目以降は、通常のMarkdown記法で見出しと本文を記述している。

このmybook.mdからPandocを使ってEPUBを生成するには、mybook.mdが含まれているディレクトリで以下のコマンドを実行する。
pandoc mybook.md -o mybook.epub
mybook.mdが入力ファイル、oオプションで指定したmybook.epubが出力ファイルとなる。入出力のフォーマットは拡張子から自動的に判断される(コマンドラインオプションで明示的に指定することも可能)。

生成されたEPUBを、Adobe Digital Editionsで表示した結果は、以下の通り。mybook.mdの内容をもとに、表紙や目次が自動的に生成されていることがわかる。




2013年12月19日木曜日

Adobe Digital Editionsのインストール

WindowsまたはMac OSX上で動作するEPUBリーダーであるAdobe Digital Editionsをインストールする手順は、以下の通り。

Adobe Digital Editions のダウンロードページから、該当OSのインストーラーをダウンロードする。

ダウンロードしたインストーラーはウィザード形式になっている。基本的にデフォルトのままインストールすれば問題はない。

2013年12月18日水曜日

PandocをWindowsにインストールする

Pandocをwin7にインストールする手順は、以下の通り。

まず、Pandoc – Installingからリンクをたどってダウンロードページに移動し、Windows用のインストーラーをダウンロードする。

ダウンロードしたインストーラーはウィザード形式になっているが、インストールのオプションなどは特に用意されていない。ライセンスに同意しInstallボタンをクリックするとインストールが完了する。

なお、Pandocのインストール先ディレクトリは、C:\Users\UserName\AppData\Local\Pandoc(UserNameはインストールを実行したユーザのアカウント名)になる。

2013年11月28日木曜日

WindowsでJenkins 1.540が起動しない

最近PCをWin7にアップデートしたのに合わせ、Jenkinsをインストールしようとしたが、Jenkins起動時にJava VMが強制終了してしまう。どうも、Jenkins 1.540にはWindows上で起動しないという致命的な問題があるようで、JenkinsのJIRAにも既に報告が上がっている。


現時点の最新版である 1.541でもこの問題は解消していない。上記JIRAにある川口さんのコメントによると、1.542でこの問題が修正される予定とのこと。

修正版がリリースされるまでは、Windows上でJenkinsを動かす際には、1.539以前のバージョンを使用するか、あるいはLTS版(Long-Term Support Release)の使用を検討したほうがよいかも。

2013年11月27日水曜日

Windows7でコマンドプロンプトを管理者モードで実行する

Win7で、コマンドプロンプトを管理者モードで実行する手順は、以下の通り。

  • Winキーを押す
  • “cmd”を入力
    • 「プログラムとファイルの検索」に“cmd”と入力される
  • Shift + Ctrl + Enter を入力
    • 「ユーザー アカウント制御」のダイアログが表示される
  • Alt + y を入力
    • 「ユーザー アカウント制御」のダイアログで、「はい」を選択することに相当

やや手数は多いが、マウスを使わずにコマンドプロンプトを管理者モードで実行できる。

2013年7月9日火曜日

GradleからJSmoothを呼び出して実行可能jarをexe化する

GradleからJSmoothを呼び出して実行可能jarをexe化する手順は、以下の通り。

前提

  • JSmoothがインストールされている


手順

以下のbuild.gradleを用意する。

apply plugin: 'groovy'
apply plugin: 'eclipse'
archivesBaseName = 'myapp'
ext.jsmoothHome = 'C:/program Files/JSmooth 0.9.9-7'
configurations { jsmooth }
repositories{
flatDir dirs: "${jsmoothHome}/lib"
}
dependencies{
groovy localGroovy()
jsmooth 'net.charabia:jsmoothgen-ant:@jar'
}
jar {
copy {
from configurations.runtime
into "lib"
}
def manifestClasspath = configurations.compile.collect{ 'lib/' + it.getName() }.join(' ')
manifest {
attributes "Main-Class" : "com.example.Main"
attributes 'Class-Path': manifestClasspath
}
from (configurations.compile.resolve().collect { it.isDirectory() ? it : fileTree(it) }) {
exclude 'META-INF/MANIFEST.MF'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.RSA'
exclude '**/*.jar'
}
}
build << {
ant.copy(file: 'build/libs/myapp.jar', todir: '.')
}
task jsmooth << {
def basedir = '.'
ant.taskdef(name:'jsmoothgen'
,classpath:configurations.jsmooth.asPath
, classname:"net.charabia.jsmoothgen.ant.JSmoothGen"
)
ant.jsmoothgen(project:"myapp.jsmooth"
,skeletonroot:"${jsmoothHome}/skeletons"
)
}
jsmooth.dependsOn(build)
view raw build.gradle hosted with ❤ by GitHub

6行目に、JSmoothのインストールディレクトリを指定する。JSmoothのAntタスクを呼び出すために、jsmoothという名前のconfigurationを定義し(8行目)、そのconfigurationにJSmoothのantタスクのjarを指定(16行目)する。

jarタスク(19行目)で、依存関係のあるjarをlibフォルダにコピー(20-23行目)した上で、実行可能jarを作成している。実行可能jarの作成については、下記サイトの内容をもとにしている。


jsmoothタスク(42行目)で、JSmoothのAntタスクを呼び出し、実行可能jarをexe化している。Antタスク呼び出すjsmoothの設定ファイルは、あらかじめjsmoothを使って保存しておく必要がある。jsmoothの設定については、下記を参照。


なお、この例で使用したjsmoothの設定ファイルは以下の通り。

<?xml version="1.0" encoding="ISO-8859-1"?>
<jsmoothproject>
<JVMSearchPath>registry</JVMSearchPath>
<JVMSearchPath>javahome</JVMSearchPath>
<JVMSearchPath>jrepath</JVMSearchPath>
<JVMSearchPath>jdkpath</JVMSearchPath>
<JVMSearchPath>exepath</JVMSearchPath>
<JVMSearchPath>jview</JVMSearchPath>
<classPath>lib\groovy-all-1.8.6.jar</classPath>
<embeddedJar>true</embeddedJar>
<executableName>myapp.exe</executableName>
<initialMemoryHeap>-1</initialMemoryHeap>
<jarLocation>myapp.jar</jarLocation>
<mainClassName>com.example.Main</mainClassName>
<maximumMemoryHeap>-1</maximumMemoryHeap>
<maximumVersion></maximumVersion>
<minimumVersion></minimumVersion>
<skeletonName>Console Wrapper</skeletonName>
<skeletonProperties>
<key>Message</key>
<value>This program needs Java to run.
Please download it at http://www.java.com</value>
</skeletonProperties>
<skeletonProperties>
<key>PressKey</key>
<value>0</value>
</skeletonProperties>
<skeletonProperties>
<key>Debug</key>
<value>0</value>
</skeletonProperties>
</jsmoothproject>
view raw myapp.jsmooth hosted with ❤ by GitHub

jsmoothタスクを実行すると、実行可能jarがexe化される。なお、このexeはlibフォルダとともに配布する必要がある点に注意。


関連リンク

2013年7月3日水曜日

Gradleを使ってEclipseとEclipse Pluginをインストール

2014.02.04 追記:Eclipse 4.3対応のスクリプトは、『dev-xconnecting: Gradleを使ってEclipse 4.3+Groovy Eclipse+Gradle IDEをインストール』を参照。

Gradleを使ってEclipse本体とEclipseプラグイン(フィーチャー)をインストールするためのbuild.gradleは、以下の通り。なお、動作確認はWindows上で行っているが、適宜書き換えればUnix系のOSでも動くはず。

project.ext.tempDir = 'tmp'
project.ext.targetEclipseDir = 'd:/eclipse'
ant.condition(property: "os", value: "windows") { os(family: "windows") }
ant.condition(property: "os", value: "unix" ) { os(family: "unix") }
task clean << { delete 'tmp' }
task installEclipse << {
new File(tempDir).mkdirs()
ant.get(dest:tempDir, skipexisting:true){
url(url:"http://ftp.jaist.ac.jp/pub/eclipse/technology/epp/downloads/release/juno/SR2/eclipse-rcp-juno-SR2-win32.zip")
}
ant.unzip(dest:tempDir, overwrite:"false"){
fileset(dir: project.tempDir){ include (name:'*.zip')}
}
ant.move(toDir: project.targetEclipseDir){
fileset(dir: "${tempDir}/eclipse")
}
ant.copy(file:'files/eclipse.ini', toDir: targetEclipseDir)
}
def getCommandList(String command){
def commandList = [
"${targetEclipseDir}/eclipse",
"-application",
"org.eclipse.equinox.p2.director",
"-noSplash"
]+
command.replaceAll(/,[^\\]\n/, ',').replaceAll(/[^\\]\n/, ' ').split(/\s+/) +
[
"-vmargs",
"-Dlogback.configurationFile=logback.xml"
]
if(ant.properties.os == 'windows'){
commandList = ['cmd', '/c']+ commandList
}
commandList.flatten()
}
task installPlugins(type:Exec) {
ext.command = """\
-repository http://dist.springsource.org/release/GRECLIPSE/e4.2/,^
http://dist.springsource.com/release/TOOLS/gradle^
-installIUs org.codehaus.groovy.eclipse.feature.feature.group,^
org.springsource.ide.eclipse.gradle.feature.feature.group^
-d ${targetEclipseDir}"""
commandLine getCommandList(command)
}
installPlugins.mustRunAfter installEclipse
task wrapper(type: Wrapper) { gradleVersion = '1.6' }
view raw build.gradle hosted with ❤ by GitHub

2行目で、Eclipseのインストール先ディレクトリを指定している。

Eclipse本体のインストールは、installEcliseタスク(9行目)で行っている。単にEclipseのダウンロードサイトにあるアーカイブをダウンロード(11行目)して解凍しているだけ。必要なら、インストールしたいEclipseのバージョンや対象プラットフォームに合わせて適宜書き換える。eclipse.iniの置き換え(20行目)はお好みで。

Eclipseプラグインのインストールには、上記でダウンロードしたEclipse本体に含まれるp2 director (org.eclipse.equinox.p2.director) を利用する(27行目)。プラグインをインストールする際に、やたら細かいDebugログが出力されるのを抑止するために、logbackの設定ファイルを指定している(33行目)。

インストールするEclipseプラグインは、p2 directorのコマンドオプションとして指定する。p2 directorを使ったEclipseプラグインのインストールについては、下記リンクを参照。


installPluginsタスク(42行目)で、インストールに必要な更新サイトをp2 directorのrepositoryオプション(44, 45行目)に、インストール対象のプラグイン(フィーチャー)をinstallIUsオプション(46, 47行目)に指定している。

repositoryオプションおよびinstallIUsオプションでは、複数の更新サイト、プラグインをカンマ区切りで指定できるが、途中にスペースを入れると実行時エラーとなる点に注意。なお、インストールするプラグインがひとつの場合は、installIUsの代わりにinstallIUオプションを使用する。オプションの詳細については、下記を参照(ただし、installIUsについては記載がない)。


上記のbuild.gradleや関連するファイル(eclipse.iniやlogback.xml)を、任意のディレクトリに以下のように配置する。
build.gradle
logback.xml
│
└─files
     └─eclipse.ini
build.gradleが含まれるディレクトリで以下のコマンドを実行すれば、build.gradleで指定したEclipse本体とEclipseプラグイン(上記の例では、Groovy-EclipseとGradle IDE)がインストールされるはず。
gradle installEclipse installPlugins
なお、mustRunAfter(53行目)は、タスクを直列実行するためにGradle 1.6から追加された機能なので、Gradle 1.5以前で実行する場合は、depandsOnなどに書き換える。

上記ファイルをgradlewとともにgitリポジトリなどに公開しておけば、幸せになれそう。

関連リンク

2013年7月1日月曜日

Gradle Flyway PluginでGradleからGroovy Migration

FlywayのGroovy MigrationをGradleで試す』では、build.gradleからFlywayのクラスを直接呼び出しているが、Gradle Flyway Pluginを使うと、より簡単にGradleからFlywayを実行できる。

前提

手順

FlywayのGroovy MigrationをGradleで試す』のbuild.gradleを、以下のように書き換える。

apply plugin: 'groovy'
apply plugin: 'flyway'
repositories { mavenCentral() }
dependencies {
compile localGroovy()
compile 'com.googlecode.flyway:flyway-core:2.1.1'
}
buildscript {
repositories { mavenCentral() }
dependencies {
classpath 'com.h2database:h2:1.3.171'
classpath 'com.github.ben-manes:gradle-flyway-plugin:0.6'
}
}
flyway {
dependsOnTasks(compileGroovy)
databases {
main {
url = "jdbc:h2:file:sampledb"
driver = 'org.h2.Driver'
user = 'SA'
password = ''
locations = [
'classpath:db.migration',
"filesystem:${projectDir}/build/classes/main"
]
}
}
}
task wrapper(type: Wrapper) { gradleVersion = '1.6' }
view raw build.gradle hosted with ❤ by GitHub

flywayタスクの設定で、Groovy Migrationに使用するGroovyクラスのパッケージ名(29行目)、およびGroovyクラスのクラスパス(30行目)を指定するのがポイント。

このbuild.gradleにより、flywayMigrateなど、Gradle Flyway Pluginで提供されているタスクが実行できる。使用可能なタスクは、gradle tasksで確認できる。

2013年6月21日金曜日

Gradle Wrapperを試す

GradleプロジェクトをGradle Wrapperとともに公開すると、プロジェクトの利用者の端末にあらかじめGradleがインストールされていなくても、Gradleでのビルドが可能になる(ただし、Javaはインストールされている必要がある)。具体的な手順は、以下の通り。

下記のbiuld.gradleを含むGradleプロジェクトがあるとする。

task hello << {
println 'hello'
}
task wrapper(type: Wrapper) {
gradleVersion = '1.6'
}
view raw build.gradle hosted with ❤ by GitHub
プロジェクトの公開者は、Graldeがインストールされている端末で、上記のwrapperタスクを実行する。wrapperタスクを実行すると、Gradle Wrapperの実体として以下のファイルが生成される。
gradlew
gradlew.bat
└─gradle
    └─wrapper
            gradle-wrapper.jar
            gradle-wrapper.properties

プロジェクトの公開者は、GradleプロジェクトをGradle Wrapperとともに公開する(例えば、Gitリポジトリとして公開するなら、build.gradleとともに上記のファイルもcommitし、リポジトリに含める)。

プロジェクトの利用者は上記のGradleプロジェクトを取得し(例えば、Gitリポジトリからcloneする)、gradleコマンドの代わりに、Gradleプロジェクト内に含まれているgradlewコマンドを使ってGradleのタスクを実行する。

例えば、gradlew helloを実行すると、Gradle Wrapper作成時に指定したバージョンのGradleが、ユーザのホームディレクトリ直下の.gradle/wrapper/distsフォルダにダウンロードされ(すでにダウンロードされている場合は、それが使用される)、そこに含まれるgradleコマンドを使ってhelloタスクが実行される。

Gradle Wrapperは上記のような仕組みで動作するため、ビルドに使用するGradleのバージョンを固定できるという利点もある。

関連リンク

2013年6月13日木曜日

diffとpatchの使い方

diffコマンドでパッチを作成する方法と、作成したパッチをpatchコマンドで適用する方法は、下記を参照。


なお個人的には、ディレクトリへのパッチ適用は
  • パッチを当てる時は、その親ディレクトリで作業
  • 親ディレクトリにパッチファイルを配置
  • patch -p1 -d src < hoge.20080201.diff
    • srcはパッチを当てるディレクトリ
 のほうが、しっくりきそう。

関連リンク

cucumber-jvm-groovyをGradleで試す

2013.06.13 追記:タイトルを誤って投稿していたため、先日投稿したものと同じ内容のものを再度アップします。

前提

 

手順


まず、以下のfeature (hello.feature) をsrc/test/resourceに配置する。なお、Rubyでは、featureはfeaturesフォルダに配置される。

Feature: Hello World
Scenario: Say hello
Given I have a hello app with "Howdy"
When I ask it to say hi
Then it should answer with "Howdy World"
view raw hello.feature hosted with ❤ by GitHub

さらに、以下のbuld.gradleを作成する。

apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'eclipse'
//build stuff
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
cucumberRuntime {
extendsFrom testRuntime
}
}
dependencies {
// Groovy library for groovy building!
groovy 'org.codehaus.groovy:groovy-all:2.0.0-beta-2'
/*
In order to work around a really flagrant bug ( http://issues.gradle.org/browse/GRADLE-732 )
You have to create a configuration that includes the jar.archivePath (the jar.archivePath is created by the java plugin)
and give it the same name as the cucumberRuntime configuration, or name it something different and have the cucumberRuntime
configuration extend from it as well.
VERY ANNOYING BUG
*/
cucumberRuntime files("${jar.archivePath}")
testCompile 'junit:junit:4.10'
testCompile 'info.cukes:cucumber-junit:1.0.9'
testCompile 'info.cukes:cucumber-groovy:1.0.9'
}
repositories {
mavenCentral()
}
task cucumber() {
dependsOn assemble
doLast {
javaexec {
main = "cucumber.cli.Main"
classpath = configurations.cucumberRuntime
args = ['-f', 'pretty', '--glue', 'src/test/groovy', 'src/test/resources']
}
}
}
view raw build.gradle hosted with ❤ by GitHub

この時点で、gradle cucumberを実行した結果は、以下の通り。
$ gradle cucumber
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:cucumber
Feature: Hello World

  Scenario: Say hello                        # hello.feature:3
    Given I have a hello app with "Howdy"
    When I ask it to say hi
    Then it should answer with "Howdy World"


You can implement missing steps with the snippets below:

Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

When(~'^I ask it to say hi$') { ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}


BUILD SUCCESSFUL

Total time: 2.39 secs

上記出力の後半に出力されているテンプレートをもとに、以下のsetp definition (HelloSteps.groovy) を作成し、src/test/groogyに配置する。なお、Rubyでは、step definitionはfeatures/step_definitionsフォルダに配置される。

import cucumber.runtime.PendingException
this.metaClass.mixin(cucumber.runtime.groovy.Hooks)
this.metaClass.mixin(cucumber.runtime.groovy.EN)
Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}
When(~'^I ask it to say hi$') { ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}
Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}

3,4行目でCucmberから呼び出されるメソッドをmixinしている。これを忘れると、Cucumber実行時に必要なメソッドが見つからず、groovy.lang.MissingMethodExceptionが発生してしまうので注意。

再度gradle cucumberタスクを実行すると、cucumber.runtime.PendingExceptionが発生する。これは、step definitionからthrowされているPendingExpectionそのものであり、まだstep definitionが実装されていないことを表している。

ここから、通常はTDD的な手法でstep definitionとテスト対象の機能を実装していくのだが、今回そのあたりの手順は省略。最終的なstep definitionは以下の通り。

this.metaClass.mixin(cucumber.runtime.groovy.Hooks)
this.metaClass.mixin(cucumber.runtime.groovy.EN)
Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
hello = new Hello(arg1)
}
When(~'^I ask it to say hi$') { ->
hi = hello.sayHi();
}
Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
assert arg1 == hi
}

なお、step definition内では、コンテキストが共有される。例えば、上記では、Givenメソッドで定義したhelloインスタンス(5行目)をWhenメソッド内で参照(9行目)している。

テスト対象の機能を実装したHelloクラスは、以下の通り。このファイルは、src/main/groogyに配置する。

public class Hello {
String greeting;
public Hello(String greeting){
this.greeting = greeting
}
public String sayHi() {
return greeting + " World";
}
}
view raw Hello.groovy hosted with ❤ by GitHub

再度gradle cucumberタスクを実行する。
$ gradle cucumber
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:cucumber
Feature: Hello World

  Scenario: Say hello                        # hello.feature:3
    Given I have a hello app with "Howdy"    # HelloSteps.groovy:13
   Given I have a hello app with "Howdy"
   # HelloSteps.groovy:13
    When I ask it to say hi                  # HelloSteps.groovy:17
   When I ask it to say hi                  # HelloSteps.groovy:17
    Then it should answer with "Howdy World" # HelloSteps.groovy:21


BUILD SUCCESSFUL

Total time: 2.734 secs

Cucumberで定義したテストが、無事パスしたことが確認できる。

 

感想


Ruby版のCucumberと同様にcucumber-jvm-groovyが動作することが確認できた。ただ、実際に使用するとなると、featureをどう記述するかは、なかなか難しそう。このあたりは、Use Case Descriptionと同様の難しさがあるように思う。

 

関連リンク

2013年6月12日水曜日

cucumber-eclipse

cucumber-eclipseは、Cucumberのfeatureファイルを編集するためのEclipse Plugin。


featureファイルのシンタックスハイライト、ソース?整形および保存時の構文チェックが可能。シンプルだが、意外に便利。

2013年6月10日月曜日

Word2007形式のファイルをWord2000形式に変換する

Word2007形式のファイルをWord2000形式に変換するVB Scriptは下記を参照。


上記サイトのスクリプト中で、myDocument.SaveAs FolderName & “\” & FS.GetBaseName(FileName) & “.doc”,0の末尾のゼロはファイル形式を表している模様。詳細は下記を参照。


この数字を替えることで、ほかのファイル形式への変換も可能なはず。

2013年5月31日金曜日

Outlookのメールをタスクに変換する

Outlookで受信したメールをOutlookのタスク(仕事)に変換する手順は、下記リンクの通り。


上記の適用対象はOffice 2003となっているが、Outlook 2007でも同じ手順で操作できた。

2013年5月28日火曜日

FlywayのGroovy MigrationをGradleで試す

Flywayのホームページの記述(ページ下部の表を参照)ではGroovy Migrationをサポートしていないことになっているが、Java migrationはコンパイル後のJavaクラスを読み込んで動作しているため、原理的にはGroovyでも動作するはず。ということで、FlywayのGroovy MigrationをGradleで試してみる。

前提

 

手順


まずは、src/main/groovy内に、以下のGroovyクラスを作成する。

package db.migration;
import com.googlecode.flyway.core.api.migration.jdbc.JdbcMigration;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* Example of a Groovy-based migration.
*/
public class V1_0__Create_person_table implements JdbcMigration {
public void migrate(Connection connection) throws Exception {
def sql = """\
create table PERSON (
ID int not null,
NAME varchar(100) not null
);"""
PreparedStatement statement =
connection.prepareStatement(sql)
try {
statement.execute()
} finally {
statement.close()
}
}
}

Java Migrationと同様、FlywayのJdbcMigrationインターフェースを実装したクラスを作成する(9行目)。このクラスの命名規約は以下の通り。

  • パッケージ名
    • 必ずdb.migrationにする
  • クラス名
    •  V(バージョン)__(説明)
    • 先頭は必ず大文字のV
    • バージョンは数字、バージョンの区切り文字はアンダーバー
    • バージョンと説明はアンダーバー2文字で区切る
    • 説明は英数字で単語をアンダーバーで区切る

クラス名の命名規則の詳細は、下記を参照。

上記の移行スクリプトをビルド、実行するためのgradleスクリプトは、以下の通り。

apply plugin: 'groovy'
apply plugin: 'eclipse'
import java.util.Properties;
import com.googlecode.flyway.commandline.Main
import com.googlecode.flyway.core.Flyway
import com.googlecode.flyway.core.util.PropertiesUtils
repositories{ mavenCentral() }
dependencies{
groovy localGroovy()
compile 'com.googlecode.flyway:flyway-core:2.1.1'
}
buildscript {
repositories { mavenCentral() }
dependencies {
classpath fileTree(dir: 'build/libs', include: '*.jar')
classpath 'com.googlecode.flyway:flyway-core:2.1'
classpath 'com.googlecode.flyway:flyway-commandline:2.1.1'
classpath 'com.h2database:h2:1.3.171'
}
}
def flyway = new Flyway()
flyway.setDataSource("jdbc:h2:file:sampledb", 'SA', '')
Properties properties = new Properties();
int consoleWidth = PropertiesUtils.getIntProperty(properties, "flyway.consoleWidth", 80);
Main.initLogging(false)
task flywayInit << {
Main.executeOperation(flyway, "init", consoleWidth);
}
task flywayClean << {
Main.executeOperation(flyway, "clean", consoleWidth);
}
task flywayMigrate << {
Main.executeOperation(flyway, "migrate", consoleWidth);
}
task flywayRepair << {
Main.executeOperation(flyway, "repqir", consoleWidth);
}
task flywayInfo << {
Main.executeOperation(flyway, "info", consoleWidth);
}
view raw build.gradle hosted with ❤ by GitHub

gradleのbuildタスクを実行してGroovy migrationの移行スクリプトをビルドした後、flywayInfoタスクを実行する。
$ gradle flywayInfo
:flywayInfo

+----------------+----------------------------+---------------------+---------+
| Version        | Description                | Installed on        | State   |
+----------------+----------------------------+---------------------+---------+
| 1.0            | Create person table        |                     | Pending |
+----------------+----------------------------+---------------------+---------+

上記出力から、移行スクリプトは存在するが、まだ実行されていない(StateがPending)ことが確認できる。なお、DBが作成されていない場合は、このタイミングで自動的に作成され、上記の表などの情報を含むメタデータを格納するためのテーブル(テーブル名はschema_version)が作成される。

続いて、flywayMigrateタスクを実行し、移行スクリプトを適用する。
$ gradle flywayMigrate
:flywayMigrate
Creating Metadata table: "PUBLIC"."schema_version"
Current version of schema "PUBLIC": << Empty Schema >>
Migrating schema "PUBLIC" to version 1.0
Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.094s).

再度、flywayInfoタスクを実行する。
$ gradle flywayInfo
:flywayInfo

+----------------+----------------------------+---------------------+---------+
| Version        | Description                | Installed on        | State   |
+----------------+----------------------------+---------------------+---------+
| 1.0            | Create person table        | 2013-05-24 20:20:17 | Success |
+----------------+----------------------------+---------------------+---------+

移行スクリプトが適用されている(StateがSuccess)ことを確認できる。

 

感想


Groovy migrationは、Java migrationと比べて記述の簡略化が期待できる。特に、データの変換やファイルからの読み込みなど、SQL文では記述が難しい、あるいは不可能な処理を移行時に行いたい場合に威力を発揮しそう。

 

関連リンク

 

2013年5月27日月曜日

データベース移行ツールFlyway

Java系のデータベース移行(DB Migration)ツール、Flywayを調査中。


移行スクリプトは、通常のSQL文(SQL migration)のほかに、Java(Java migration)でも記述可能。XMLに記述する必要がないのがシンプルでよい。

Java migrationはJavaバイナリをロードして実行するため、Groovyでも記述できそう。詳細は、下記を参照(なお、回答者はFlywayの開発者の模様)。


具体的にどのようなツールなのかの概要をつかむには、コマンドラインツールを利用してみるのがよい。試してみる際は、h2dbなどのいわゆる組み込みDBを使うのが吉。


なお、現時点での最新版(2.1.1)では、Windows環境でコマンドラインツールを実行する際にNumberFormatExceptionが発生するが、環境変数CONSOLE_WIDTHを設定(例:set CONSOLE_WIDTH=80)することで回避できる。詳細は、下記参照。

2013年4月26日金曜日

バッチファイル自身のパスを取得する

Windowsでバッチファイル実行時に、バッチファイル自身のパスを取得するには、
バッチファイル内で下記のように記述する
@echo %~d0
@echo %~dp0
@echo %~dpn0
@echo %~dpnx0

上記のバッチファイルを実行した結果は、以下の通り。
D:
D:\bat\
D:\bat\test
D:\bat\test.bat

なお、上記はバッチファイル内のみで有効な記述であり、コマンドプロンプトで直接実行はできない。ちなみに、上記のような記述は、WindowsでRoRのrailsコマンドを起動するバッチファイルに使われてるらしい。

 

関連リンク

2013年4月25日木曜日

コマンドプロンプトでドライブとディレクトリを同時に移動する

コマンドプロンプトでドライブとディレクトリを同時に移動するには、cdコマンドのdオプションを使用する。
具体的には、以下の通り
cd /d d:\tmp

上記のコマンドを実行すると、現在のディレクトリがCドライブであったとしても、Dドライブに移動した上でtmpディレクトリに移動する。

 

関連リンク

2013年4月4日木曜日

Bashのショートカット

Bashで使用できる主要なキーボードショートカットは、下記リンクを参照。


なお、Bashのショートカットはemacsのショートカットがベースになっている模様。

2013年4月3日水曜日

GroovyからKyoto Cabinetを使用する

いわゆるKVS(キーバリューストア)の実装のひとつであるKyoto CabinetをGroovyから使用する手順は、以下の通り。

前提

  • lib/kyotocabinet.jar(Kyoto CabinetのJavaバインディング)をクラスパスに含める
  • Groovyスクリプト(下記参照)の実行ディレクトリにjkyotocabinet.dll(Kyoto CabinetのDLL)が存在する

手順

下記のGroovyスクリプトを用意する。なお、このスクリプトは、Kyoto CabinetのJavaDocにあるサンプルをGroovyスクリプトにしただけのもの。

import kyotocabinet.*;
// create the object
DB db = new DB();
// open the database
if (!db.open("casket.kch", DB.OWRITER | DB.OCREATE)){
System.err.println("open error: " + db.error());
}
// store records
if (!db.set("foo", "hop") ||
!db.set("bar", "step") ||
!db.set("baz", "jump")){
System.err.println("set error: " + db.error());
}
// retrieve records
String value = db.get("foo");
if (value != null){
System.out.println(value);
} else {
System.err.println("set error: " + db.error());
}
// traverse records
Cursor cur = db.cursor();
cur.jump();
String[] rec;
while ((rec = cur.get_str(true)) != null) {
System.out.println(rec[0] + ":" + rec[1]);
}
cur.disable();
if(!db.close()){
System.err.println("close error: " + db.error());
}
view raw KCSample.groovy hosted with ❤ by GitHub

Gradleから下記のGroovyスクリプトを実行するには、下記のbuild.gradleを使用する。
apply plugin: 'groovy'
apply plugin: 'eclipse'
repositories {
flatDir(dirs: file("lib"))
}
dependencies {
groovy localGroovy()
compile ":kyotocabinet:@jar"
}
task execJava (type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "KCSample"
}
view raw build.gradle hosted with ❤ by GitHub

execJavaタスクを実行すると、上記のGroovyスクリプトが実行される。


 

感想

別途アプリケーションをインストールすることなくKVSを手軽に利用できるのがよい。ただし、作成されるDBのファイルサイズは小さくない(上記サンプルで6MB程度)。

2013年3月28日木曜日

Mylyn WikitextがMarkdownに対応中

Mylyn WikitextがMarkdownへの対応に着手している模様。


ただし、現時点で最新のnightly buildでは未実装の機能もあり、実戦投入には時期尚早。

なお、最近Wikitextについてはウォッチしていなかったが、現在はMylynのサブプロジェクト?であるMylyn Docsに含まれている。Mylyn Docsには、ePubファイルを作成、操作、読み書きするためのAPIを提供するEPUB Frameworkなどのコンポーネントも含まれていて興味深い。

2013年3月22日金曜日

Gradleでポップアップ通知

Gradleでポップアップウインドウによる通知を行うには、announce pluginを使用する。 Snarl(Windows), Growl(Mac OS X), notify-send(Ubuntu)への通知のほか、Twitterにも対応している。詳細は、下記リンクを参照のこと。

2013年3月18日月曜日

MarkdownでEPUB

MarkdownからEPUBを生成するには、Pandocを使うのがよさそう。


Pandocを使うと、EPUBだけでなくmobi, PDFなども生成可能な模様。実例としては、GitHubで公開されているDeveloping Backbone.js Applications(O’Reillyから出版予定)のEarty Release版の原稿が参考になる。


ここには、原稿のMarkdownファイルだけでなく、なんと生成後のEPUBまで公開されている。また、Pandocを使ってEPUBなどを生成するためのmakefileや、他に必要となるファイル一式が含まれており、大変参考になる。

関連リンク

2013年3月15日金曜日

Markdown記法

軽量マークアップ言語のひとつであるMarkdownの記法については、下記リンクを参照。

2013年3月11日月曜日

Gradleでソースコードやリソースが含まれるディレクトリを変更する

Gradleでソースコードやリソースが含まれるディレクトリを変更する方法は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
sourceSets {
main {
java { srcDir 'src' }
resources { srcDir 'src' }
}
}
task listSrcDir <<{
sourceSets.main{
it.java.srcDirs.each { println it}
it.resources.srcDirs.each {println it }
}
}
view raw build.gradle hosted with ❤ by GitHub

上記の例では、javaソースコードを格納するディレクトリ(デフォルトはsrc/main/java)とリソース(デフォルトはsrc/main/resources)を格納するディレクトリを、ともにsrcに変更している。

なお、上記のlistSrcDirタスクを実行すると、デフォルトのディレクトリは残ったままになっていることが確認できるが、実用上問題ないと思われる。

2013年2月25日月曜日

Gradleでファイルシステムをリポジトリとして利用する

ファイルシステム(Mavenなどで管理されていない通常のフォルダ)をリポジトリとして利用する例は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
repositories {
flatDir(dirs: file("lib"))
}
dependencies {
compile ":commons-lang:2.6"
}
view raw build.gradle hosted with ❤ by GitHub

この例では、プロジェクト内のlibフォルダ直下をリポジトリに指定している(5行目)。ファイルシステムをリポジトリとして使用する場合、依存関係の指定にはnameとversionを使用する(9行目)。groupの指定は必要ない。上記のように指定した場合はcommons-lang-2.6.jarが、versionを省略した場合はcommons-lang.jarが検索される。

関連リンク

2013年2月22日金曜日

Gradleでファイルシステム上にあるjarへの依存関係を定義する

Gradleを使ってファイルシステム上にある(Mavenなどで管理されていない)jarへの依存関係を定義する方法は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
dependencies {
compile fileTree(dir: 'lib', include: '*.jar')
}
view raw build.gradle hosted with ❤ by GitHub

この例では、プロジェクトのlibフォルダ直下に存在するjarファイルへの依存関係をflatDirを使って指定している(5行目)。jarファイルごとに依存関係を指定する必要がないので、gradleで管理されていない既存のプロジェクトで、依存関係のあるjarがすべてlibフォルダに含まれている場合は、この方法が手っ取り早そう。

関連リンク

2013年2月21日木曜日

GradleでEclipseのクラスパス変数を設定する

GradleでEclipseのクラスパス変数を設定する方法は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
eclipse {
pathVariables 'GRADLE_USER_HOME': gradle.gradleUserHomeDir
}
repositories {
mavenCentral()
}
dependencies {
compile 'commons-lang:commons-lang:2.6'
}
view raw build.gradle hosted with ❤ by GitHub

この例では、クラスパス変数GRADLE_USER_HOMEにgradleのユーザホームディレクトリを指定している(5行目)。

eclipseタスクを実行後に、Eclipse上でプロジェクトを更新すると、クラスパス変数がEclipseに反映される。Eclipseで作成したJavaプロジェクトでは、eclipseタスク実行後にJDKへの参照が重複して登録されることがあったので、事前にcleanEclipseタスクを実行しておくのが無難。

Mavenリポジトリなどを使って依存関係を解決している場合、上記のようにクラスパス変数を指定しておくと、Eclipseの.classpathファイルにユーザディレクトリの絶対パスが記述されるのを防ぐことができる。

関連リンク

2013年2月14日木曜日

GradleでGroovyアプリケーションを実行

Gradleでjarに固めていないGroovyアプリケーションを実行する方法は、以下の通り。

apply plugin: 'groovy'
apply plugin: 'eclipse'
dependencies {
groovy localGroovy()
}
task execGroovy (type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "example.Script"
}
view raw build.gradle hosted with ❤ by GitHub

GroovyのソースはJavaのクラスにコンパイルされるので、Javaアプリケーションを実行する際と同様、タスクのtypeにはJavaExceを指定する(8行目)。mainには明示的にmainメソッドを持つクラスだけでなく、Groovyスクリプトも指定可能(10行目)。

2013年2月13日水曜日

GradleでJavaアプリケーションを実行

Gradleでjarに固めていないJavaアプリケーションを実行する方法は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
task execJava (type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "example.Main"
}
view raw build.gradle hosted with ❤ by GitHub

タスクのtypeには、JavaExceを指定する(4行目)。classpathには実行時のクラスパスとしてsourceSets.main.runtimeClasspathを通すしておくのがミソ(5行目)。mainにはmainメソッドをもつクラスの完全修飾クラス名を指定する(6行目)。

2013年2月8日金曜日

GradleでJavaソースのエンコーディングを指定してコンパイル

Gradleで、Javaソースのエンコーディングを指定してコンパイルする方法は、以下の通り。

apply plugin: 'java'
apply plugin: 'eclipse'
compileJava.options.encoding = 'UTF-8'
view raw build.gradle hosted with ❤ by GitHub

2013年1月30日水曜日

Gradleで実行したコマンドの標準出力を文字列として取得する

Gradleで実行したコマンドラインのコマンドからの標準出力を、文字列として取得する方法は、以下の通り。

ant.condition(property: "os", value: "windows") { os(family: "windows") }
ant.condition(property: "os", value: "unix" ) { os(family: "unix") }
task execCommandLine(type:Exec) {
switch(ant.properties.os){
case 'windows':
commandLine 'cmd', '/c', 'echo', 'hello'
break
case 'unix':
commandLine 'echo', 'hello'
break
}
standardOutput = new ByteArrayOutputStream()
}
execCommandLine.doFirst {
println 'doFirst'
print standardOutput.toString()
}
execCommandLine << {
println 'doLast'
print standardOutput.toString()
}
view raw build.gradle hosted with ❤ by GitHub

標準出力をByteArrayOutputStreamに割り当て(13行目)、コマンド実行後にそのByteArrayOutputStreamから文字列を取得している(23行目)。

上記のタスクを実行した結果は以下の通り。
$ gradle -q execCommandLine
doFirst
doLast
hello

当たり前だが、コマンド実行時に出力される文字列は、コマンドの実行後でないと取得できない。

2013年1月8日火曜日

AmazonにKindle版書籍の領収証を発行してもらう方法

amazon.co.jpで購入したKindle版書籍の領収書が必要だったので、カスタマーサービスに問い合わせてみた。

急ぎだったので、電話での連絡を依頼。HPでこちらの電話番号を入力すると、ほどなくAmazonから電話がかかってくる。領収証の発行が必要なKindle版の書籍を口頭ですべて(4冊)確認したが、この担当者ではそれ以上対応できず、別の担当者から再度電話をかけさせるとのこと。

しばらくして別の担当者から電話があり、再度領収証の発行が必要な書籍を確認した後、領収書の宛名と送付先を伝える。領収書は郵送してくれるとのこと(実際、数日で送られてきた)。ここまでの所要時間は、待ち時間も含め、およそ30分。

電話で確認した時は、現状電話でのみ領収書発行を受け付けているとのことだったが、別途カスタマーサービスからEメールがあり、EメールやFaxでも領収書発行が可能とのこと。

Eメールで領収書の発行を依頼する場合は、下記の情報を連絡すればよい。なお、但し書きは指定できないとのこと。

・ 注文番号
・ 領収書の宛名
・ 領収書の送付先(郵便番号、住所、宛先)

また、急ぎの場合、Faxで領収書を送信してもらうことも可能。この場合、上記に加え、こちらのFax番号も伝える必要がある。

そもそも領収書発行を受け付けない(法的に許されるのだろうか?)電子書籍サービスがあることを考えると、Amazonの対応は十分良心的だが、いくらEメールでできるとはいえ、毎回領収書発行を依頼するのは面倒なので、注文時やアカウントの設定にて領収書発行を依頼できるようにして欲しい。

関連リンク

  • dev-xconnecting: Amazonの「納品書兼領収書」が「納品書」に変更されている件