Gradle:プロジェクト間の共通処理パターンを実現する
複数のプロジェクトがあり、それぞれにbuild.gradleを作成するわけだが、ほとんど同じことを毎度毎度書かなくてはいけないのは辛い。なんとか簡単に済ませる方法は無いものか。
処理の例
例えば、eclipseプラグインでecipseの.project、.classpathをgradleに作成させるものとする。さらにその制御を細かくしたいのだが、複数プロジェクトでほとんど同じだ。例えば、以下のように記述する。
apply plugin: 'eclipse'
....
eclipse {
  project {
    ....
    file {
      whenMerged {
        ....
      }
    }
  }
  classpath {
    defaultOutputDir = file('output')
    downloadSources = true   
    file {
      whenMerged { cp->
        ....
      }
    }
  }      
}
結論から言えば、以下のようにしたいのである。新たなメソッドeclipseExを導入し、そのクロージャの中でプロジェクトごとに異なる部分だけを記述したい。
さらにこれをcommon.gradleといった共通ファイルを通して行いたい。
apply from: 'common.gradle'
....
eclipseEx {
  output = file('output2')
  extraSources = [ 'src_test' ]
  ....
}
これをどうするか?
実際のコード
以下のようになる。
build.gradle
apply from: 'common.gradle'
apply plugin: 'java'
apply plugin: EclipseExPlugin
repositories {
  mavenCentral()
}
sourceSets {
  main {
    java {
      srcDir 'src'
    }
    resources {
      srcDir 'src'
    }    
  }
}
dependencies {
  compile('javax.inject:javax.inject:1')
  compile('com.google.inject:guice:4.0')
}
eclipseEx {
  output = file('output')
  extraProjects = ['/gwtcenter_bwidget']
  extraSources = ['src_test'];
}
common.gradle
ext.EclipseExPlugin = EclipseExPlugin
class EclipseExPlugin implements Plugin<Project> {
  def void apply(Project project) {
    project.apply(plugin:'eclipse')
    project.convention.plugins.eclipseExConvention = new EclipseExConvension(project)
  }
}
/* EclipseExのコンベンション */
class EclipseExConvension {
  /* プロジェクト */
  Project project
  /* 出力先 */
  File output;
  /* 追加プロジェクトリスト */
  List extraProjects;
  /* 追加ソースフォルダリスト */
  List extraSources;
  /* GWT用natureを追加 */
  boolean gwtNature;  
  EclipseExConvension(project) {
    this.project = project
  }
  def eclipseEx(Closure closure) {
    closure.delegate = this
    closure()    
    project.eclipse {
      project {
        gwtNatureBuildCommand(delegate)        
        file {
          whenMerged {
            addCommonGradle(delegate)
          }
        }
      }
      classpath {
        defaultOutputDir = output
        downloadSources = true   
        file {
          whenMerged { cp->
            removeOutputFoldersForSourceFolders(cp)
            removeDuplicatedSources(cp)      
            removeAllExcludes(cp)        
            appendExtraSources(cp)
            appendExtraProjects(cp)
            sortProjectEntries(cp)
          }
        }
      }      
    }
  } // eclipseEx
  /* GWT用のNature、ビルドコマンドを追加 */  
  def gwtNatureBuildCommand(p) {
    if (!gwtNature) return;
    p.natures 'org.eclipse.wst.common.project.facet.core.nature'
    p.buildCommand 'org.eclipse.wst.common.project.facet.core.builder'
    p.buildCommand 'com.gwtplugins.gdt.eclipse.core.webAppProjectValidator'
  }
  /* common.gradleへの参照を追加 */
  def addCommonGradle(proj) {
    proj.linkedResources.add(new org.gradle.plugins.ide.eclipse.model.Link(
    'common.gradle', '1', 'J:/OwnCloud/CryptoFiles/gradle/common.gradle', null));
  }
  /* ソースフォルダの出力指定を削除する。こうしないと、フォースフォルダごとに別のフォルダに出力されてしまう */
  def removeOutputFoldersForSourceFolders(cp) {
    cp.entries.findAll{ it.kind == 'src' }.each{
      it.output = null
    }
  }
  /* ソースフォルダが重複してしまうことがあるので重複分を削除する */
  def removeDuplicatedSources(cp) {
    def newList = new ArrayList()
    def duplicated = new HashSet()
    cp.entries.each { e-> 
      if (e.kind != 'src') {
        newList.add(e);
        return
      }
      if (duplicated.contains(e.path))
        return;
      newList.add(e);
      duplicated.add(e.path);          
    }
    cp.entries = newList;
  }
  /* 追加のソースフォルダ */
  def appendExtraSources(cp) {
    if (extraSources == null) return;
    extraSources.each {
      cp.entries.add(new org.gradle.plugins.ide.eclipse.model.SourceFolder(it, null))
    }
  }
  /* 追加のプロジェクト */
  def appendExtraProjects(cp) {
    if (extraProjects == null) return;
    extraProjects.each {
      cp.entries.add(
        new org.gradle.plugins.ide.eclipse.model.SourceFolder(it, null)
      )
    }
  }
  // srcDir 'src'; exclude '**/*Test.java';のexcludeを削除する。
  //   IDE上ではテストユニットが見えていて欲しい
  def removeAllExcludes(cp) {
    cp.entries.findAll{ it.kind == 'src' }.each{
      it.setExcludes(new ArrayList())  
    }
  }
  /* 
       ライブラリ他をアルファベット順にソートする。アルファベット順でないと非常に見つけにくい
       これは単純にEclipseの.projectファイルの内容をソートするもの。追加・削除等は行わない。
  */
  def sortProjectEntries(cp) {
    Map srcMap = new HashMap();
    Map libMap = new HashMap();
    List others = new ArrayList();
    cp.entries.each {
      if (it.kind == 'lib') {
        String path = it.path;
        int index = path.lastIndexOf('/')
        libMap.put(path.substring(index + 1), it);
      } else if (it.kind == 'src') {
        srcMap.put(it.path, it);
      } else {
        others.add(it);
      }     
    }
    def newList = new ArrayList();
    // ソースフォルダをソートして入れる
    srcMap.keySet().sort({ a, b -> a.compareToIgnoreCase b }).each{
      newList.add(srcMap.get(it))
    }
    // ライブラリ以外を入れる
    newList.addAll(others);
    // ライブラリをソートして入れる
    libMap.keySet().sort({ a, b -> a.compareToIgnoreCase b }).each{
      newList.add(libMap.get(it))
    }  
    cp.entries = newList
  }
}




ディスカッション
コメント一覧
まだ、コメントがありません