読者です 読者をやめる 読者になる 読者になる

eclipseの独自ant taskを触ってみる

自メモ)




eclipseで用意されてるAntTask)

task名 task class path task効果
eclipse.refreshLocal org.eclipse.core.resources.ant.RefreshLocalTask 指定プロジェクトの更新
eclipse.incrementalBuild org.eclipse.core.resources.ant.IncrementalBuild プロジェクトをビルド(incremental, full, clean )
eclipse.convertPath org.eclipse.core.resources.ant.ConvertPath 相対パスをリアルパスに変換
  • eclipse.refreshLocalの記述例
    • プロジェクト project1 をリフレッシュ(F5)する。





    • プロジェクト project1 をクリーンする。



eclipse-taskを含んだ build.xmlを実行する標準的な方法)



以前

な方法をググッて見つけてはいたんだけど、やっぱり重いので
antでどうにか出来ないか見てみる。

PS)
因みに上記は情報古すぎて動かないのが多いので

辺になるかも。。。(汗。でもコレでも古い。。。


自分がなんでコレ遣りたいか調べてたかというと

  1. library-projetを含めたapkを生成するためにant-build
  2. 本体プロジェクト側library-projetをXXXX.jarという形で本体が参照してる
    1. これがant-buildのタイミングで消えるのでプロジェクトが真っ赤になる

これをant-buildだけでなんとかしたい。
という形


ではantパスを通す方針で動かしてみます

android update project -p ./

と最新のADTで実行するとプロジェクト直下に

  • build.xml
  • custom_rules.xml
  • local.properties
  • project.properties(なければ)
  • proguard-project.txt(なければ)

が作成されます。

カスタムのタスクを追加するのは custom_rules.xml 追記が
がお作法になっているようなので下記のように記述します

  • custom_rules.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules">
	<loadproperties srcFile="local.properties" />

	<property name="out.final.file.change" location="${out.dir}/../${release.app.name}_${release.app.version}.apk" />
	<target name="aftert-copy">
		<copy file="${out.final.file}" tofile="${out.final.file.change}"/>
		<copy file="${out.dir}/proguard.txt" tofile="${out.dir}/../proguard.txt"/>
	</target>
	
	<target name="aftert-copy-install" depends="uninstall">
		<exec executable="${adb}" failonerror="true">
	        <arg line="${adb.device.arg}" />
	        <arg value="install" />
	        <arg value="-r" />
	        <arg path="${out.final.file.change}" />
	    </exec>
	</target>

	<property name="launch-package" value="com.irof.irof_history" />
	<property name="launch-activity" value=".IrofActivity" />
	
	<target name="apk-launch">
	    <echo message=" ==== apk-launch start ===="/>
		<exec executable="${adb}" failonerror="true">
		    <arg line="${adb.device.arg}" />
	        <arg line="shell am start -a android.intent.action.MAIN" />
	        <arg value="-n" />
	        <arg line="${launch-package}/${launch-activity}" />
	    </exec>
	    <echo message=" ==== apk-launch end ===="/>
	</target>


<!--eclipse4.4ベースで追加-->
	<property name="eclipse.home" value="/Users/XXXX/eclipse44" />
	<path id="classpath_eclipse_task">
		<pathelement location="factory/resources-ant.jar" />
		<fileset dir="${eclipse.home}/plugins">
			<include name="org.eclipse.equinox.common_*.jar" />
			<include name="org.eclipse.core.resources_*.jar" />
			<include name="org.eclipse.core.jobs_*.jar" />
			<include name="org.eclipse.core.runtime_*.jar" />
			<include name="org.eclipse.osgi_*.jar" />
		</fileset>
	</path>
	<target name="refresh">
	    <fail unless="eclipse.running" message="[refresh]need running on Eclipse"/>
	    <echo message=" ==== refresh start ===="/>
	    <taskdef name="eclipse.refreshLocal" classname="org.eclipse.core.resources.ant.RefreshLocalTask">
	    	<classpath refid="classpath_eclipse_task" />
	    </taskdef>
	    <eclipse.refreshLocal resource="${android.library.reference.1}" depth="infinite" />
	    <eclipse.refreshLocal resource="${android.library.reference.2}" depth="infinite" />
	    <eclipse.refreshLocal resource="${ant.project.name}" depth="infinite" />	    <echo message=" ==== refresh end ===="/>
   	</target>
</project>
  • local.properties
sdk.dir=/Users/XXXX/android-sdks
release.app.name=irof_history
release.app.version=v01g
  • project.propertie
target=android-19
android.library.reference.1=../QuickActionLib
android.library.reference.2=../NakamapSDK



eclipseのカスタムタスク自体は
ECLIPSE_HOME/plugin の中に格納されていて

  • org.eclipse.core.resources_3.9.0.v20130917-1718.jar
    • ant_tasks
      • resources-ant.jar

という形で格納されています。ただjarの内部のjarの指定が分からないので
とりあえず解凍して
プロジェクト直下の factoryフォルダに突っ込みます。

で実行していってエラーになるものの関連jarを芋づるで引っ張ってきた形が
上記のbuild.xmlとなります。

でここまで対応して実行すると

<groovy.util.AntBuilder@109ce4a3 log=java.util.logging.Logger@3152bdc7 project=org.apache.tools.ant.Project@48baa31b antXmlContext=org.apache.tools.ant.helper.AntXMLContext@552a66ea antElementHandler=org.apache.tools.ant.helper.ProjectHelper2$ElementHandler@52cab854 antTargetHandler=org.apache.tools.ant.helper.ProjectHelper2$TargetHandler@7b0bbd42 collectorTarget=null implicitTarget= lastCompletedNode=null insideTask=false saveStreams=true current=null nameMappingClosure=null proxyBuilder=groovy.util.AntBuilder@109ce4a3>
Caught: /Users/XXXX/Documents/workspace/irof_history/custom_rules.xml:47: java.lang.IllegalStateException: Workspace is closed.
/Users/XXXX/Documents/workspace/irof_history/custom_rules.xml:47: java.lang.IllegalStateException: Workspace is closed.
	at org.apache.tools.ant.IntrospectionHelper.extractBuildException(IntrospectionHelper.java:813)
	at org.apache.tools.ant.IntrospectionHelper.setAttribute(IntrospectionHelper.java:410)
	at org.apache.tools.ant.RuntimeConfigurable.maybeConfigure(RuntimeConfigurable.java:403)
	at org.apache.tools.ant.RuntimeConfigurable.maybeConfigure(RuntimeConfigurable.java:346)
	at org.apache.tools.ant.Task.maybeConfigure(Task.java:202)
	at org.apache.tools.ant.UnknownElement.configure(UnknownElement.java:196)
	at org.apache.tools.ant.UnknownElement.maybeConfigure(UnknownElement.java:163)
	at org.apache.tools.ant.Task.perform(Task.java:347)
	at org.apache.tools.ant.Target.execute(Target.java:392)
	at org.apache.tools.ant.Target.performTasks(Target.java:413)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
	at _apkinstall_builder.run(_apkinstall_builder.groovy:38)
Caused by: java.lang.IllegalStateException: Workspace is closed.
	at org.eclipse.core.resources.ResourcesPlugin.getWorkspace(ResourcesPlugin.java:407)
	at org.eclipse.core.resources.ant.RefreshLocalTask.setResource(RefreshLocalTask.java:106)
	at org.apache.tools.ant.IntrospectionHelper$AttributeSetter.setObject(IntrospectionHelper.java:1498)
	at org.apache.tools.ant.IntrospectionHelper.setAttribute(IntrospectionHelper.java:405)
	... 13 more

で メモリ上のworkspace情報を参照しようとしてコケる形のようです。
eclipseコマンドラインで なまじ -data でworkspaceを指定してるわけではありません(汗

備考)
resources-ant.jar の指定に関してはググる

の話が出てきますが*1
これは plugin taskの中の antTaskという属性がある なので使えません><

らへんの 話。

<!--OK case -->
<pathelement location="factory/resources-ant.jar" />
<!--NG case -->
<pathelement location="jar:${eclipse.home}/plugins/org.eclipse.core.resources_*.jar!/ant_tasks/resources-ant.jar" />

もダメポでしたorz

ここらへんのClassLoader的仕組みはjavaで書かないと面倒な話が書いてたりします
libraryタグも多分同じようなことしてるんだろうな。。。



 で、コンセプトを変えてeclipseを antでコマンドラインタスクで実行で遣る方法を
考えてみます。

 ただeclipse自体をコマンドライン実行した場合、
eclipseGUIをたちあげた状態だとworkspace-locがかかります。
 eclipseのexecLancherがどうも防いでいるようなので
lancher.jarの方を操作する方向が良さそうです

 で調べてみると

辺りの antRunner のmacrodefを上手く流用すれば出来そうです

  • custom_rules.xml (追記)
	<path id="equinox.launcher.path">
		<fileset dir="${eclipse.home}/plugins">
    	    <include name="org.eclipse.equinox.launcher_*.jar" />
	    </fileset>
	</path>
	
	<macrodef name="antRunner">
	    <!-- Ant script location -->
	    <attribute name="antFile" default="build.xml"/>
	    <!-- the arguments for the script that is executed -->
	    <attribute name="args" default=""/>
	    <sequential>
	        <available file="${eclipse.home}" property="eclipse.running" />
	        <java 
        	    fork="true" 
	            output="result_@{args}.txt"
	            outputproperty="cmdOut_@{args}"
    	        classname="org.eclipse.equinox.launcher.Main" 
        	    failonerror="true">
        	    <arg line="-verbose" />
        	    <arg line="-data ../" />
        	    <arg line="-application org.eclipse.ant.core.antRunner" />
        	    <arg line="-f @{antFile}" />
            	<arg line="@{args}"/>
        	    <classpath refid="equinox.launcher.path" />
        	</java> 
		    <echo message="[@{args}] ${cmdOut_@{args}}"/>
	    </sequential>
	</macrodef>

	<target name="refresh_exec">
		<antRunner args="refresh" />
   	</target>

で、[clean,debug,refresh_exec]
とタスク設定を実行すると eclipse上からの外部実行でも
task自体の実行は問題なくOKでした。


PS)

<java 
    fork="true" 

としていると eclipse上だとコンソールには処理結果がでない形です。

外すとコンソールにはでますが
outputproperty あたりの出力は出力されない感じ*2
なんか痛し痒しですね。。。


ただ、refreshかけるだけで本リビルドまではかからないようです。

  1. eclipse上から JREを一致させて build.xml で実行でも
    1. △(期待した動きではない。workspaceは赤いまま)

だったので 外部実行経由がコケてる? という話だけではないようです。

ここらへんは実は eclipse.incrementalBuild の方が正しいのかもしれない。
で下記に追加してみる

  • custom_rules.xml (追記)
	<property name="android.library.reference.project.1" value="/NakamapSDK" />
	<property name="android.library.reference.project.2" value="/QuickActionLib" />

	<target name="incremental">
	    <fail unless="eclipse.running" message="[incremental]need running on Eclipse"/>
	    <echo message=" ==== incremental start ===="/>
<!--  
	    <antTask  library="ant_tasks/resources-ant.jar" name="eclipse.incrementalBuild" classname="org.eclipse.core.resources.ant.IncrementalBuild" loaderref="hmant">
	        	<classpath refid="classpath_eclipse_task" />
	    </antTask>
-->	    
	    <taskdef name="eclipse.incrementalBuild" classname="org.eclipse.core.resources.ant.IncrementalBuild" loaderref="hmant">
	        	<classpath refid="classpath_eclipse_task" />
	    </taskdef>
	    <eclipse.incrementalBuild project="${android.library.reference.project.1}" kind="clean" />
	    <eclipse.incrementalBuild project="${android.library.reference.project.2}" kind="clean" />
	    <eclipse.incrementalBuild project="${ant.project.name}" kind="clean" />
	    <echo message=" ==== incremental end ===="/>
   	</target>

なタスクを追加してみましたが

  1. eclipse上から JREを一致させてant-buildで実行
    1. OK(期待した動き)
  2. 外部ツール経由でant-buildで実行
    1. NG (IResource辺りのロードで失敗)

な感じでした。UI依存部分がなんか引っかかってしまっているのかも。。(汗


Ant書くのに参考にした資料)

なんか世の中は gradleマンセーになってるけど
antもマダマダ奥が深いな〜とか思ってたりもしてます*3

gradle前提のASって
あれ「初心者向け開発ツール」ってやたら喧伝されてるけど
大丈夫なんだろうか?って思っちゃったりもしますね(苦笑

*1:library属性で指定すればい

*2:ココはant task既存の動き

*3:mavenのほうがもっと闇が深いですが<汗