Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Java→Kotlinの移行率を算出するコマンドラインツールをKotlinで実装してみた話...
Search
yu mitsuhori
December 20, 2018
Technology
1
300
Java→Kotlinの移行率を算出するコマンドラインツールをKotlinで実装してみた話.pdf
- コマンドラインツールをKotlinで実装してみた話です
- 2018.12.20 Kotlin愛好会で発表したスライドです
yu mitsuhori
December 20, 2018
Tweet
Share
More Decks by yu mitsuhori
See All by yu mitsuhori
【DroidKaigi版】ReactNativeとKotlinで叶える夢のリアルタイム音声配信
youmitsu
1
3.1k
ReactNativeとKotlinで叶える夢のリアルタイム音声配信
youmitsu
1
760
stand.fm(Android)におけるreact-native-track-playerの改善
youmitsu
1
2k
TargetSdkVersion29で BottomNavigationが点滅する件
youmitsu
1
1.5k
リリース前のリグレッションテストをUIテストで自動化、1年間運用した話
youmitsu
2
330
New features in RemoteConfig, Analytics at Google I/O 2019
youmitsu
1
610
FirebaseNotification,RemoteConfigでユーザセグメントごとにプッシュ通知を実装する
youmitsu
9
1.5k
Report from Google I/O 2019
youmitsu
1
69
OSSにコントリビュートした話
youmitsu
1
71
Other Decks in Technology
See All in Technology
スクラムチームを立ち上げる〜チーム開発で得られたもの・得られなかったもの〜
ohnoeight
2
350
SRE×AIOpsを始めよう!GuardDutyによるお手軽脅威検出
amixedcolor
0
110
マルチプロダクトな開発組織で 「開発生産性」に向き合うために試みたこと / Improving Multi-Product Dev Productivity
sugamasao
1
310
Making your applications cross-environment - OSCG 2024 NA
salaboy
0
190
社内で最大の技術的負債のリファクタリングに取り組んだお話し
kidooonn
1
550
組織成長を加速させるオンボーディングの取り組み
sudoakiy
2
150
信頼性に挑む中で拡張できる・得られる1人のスキルセットとは?
ken5scal
2
530
The Role of Developer Relations in AI Product Success.
giftojabu1
0
120
誰も全体を知らない ~ ロールの垣根を超えて引き上げる開発生産性 / Boosting Development Productivity Across Roles
kakehashi
1
230
Introduction to Works of ML Engineer in LY Corporation
lycorp_recruit_jp
0
120
OCI Security サービス 概要
oracle4engineer
PRO
0
6.5k
The Rise of LLMOps
asei
7
1.5k
Featured
See All Featured
Embracing the Ebb and Flow
colly
84
4.5k
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Statistics for Hackers
jakevdp
796
220k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
The Cult of Friendly URLs
andyhume
78
6k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
364
24k
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
Gamification - CAS2011
davidbonilla
80
5k
Typedesign – Prime Four
hannesfritz
40
2.4k
Code Review Best Practice
trishagee
64
17k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Being A Developer After 40
akosma
86
590k
Transcript
Java→Kotlinの移行率を算出する コマンドラインツールを Kotlinで実装してみた話 Yu Mitsuhori
自己紹介 三堀 裕 Android Developer 女性向けのヘルスケアアプリを担当してます。 Twitter: @1013Youmeee GitHub: https://github.com/youmitsu
Qiita: https://qiita.com/youmeee
Question 皆さんKotlinで何を作りますか?
None
None
None
コマンドラインツールも作れます
Java→Kotlinの移行率を算出する コマンドラインツール を Kotlin で 作ってみました
KotlinReplaceSupporter
作ったもの 計算対象となるファイ ル一覧を出力 Projectルートで、 コマンド叩く 移行率の表示
本日のアジェンダ 1. 経緯 2. デモ 3. 実装方法 a. 環境構築 b.
実装 c. jarの実行 4. まとめ
経緯 ・会社の評価の際にKotlin→Javaのリプレース率を出さなければいけな い時があった ・一つ一つ手で計算するのもあれだし、Kotlinで書けるなら勉強も兼ねて やってみよう!どうせならツール化もしてみよう! (シェルとか書けば一発な気もしますがそこはスルーでお願いしま す。。)
デモ
開発環境 ・Mac Book Pro Sierra 10.12.6 ・IntelliJ IDEA Community 2017.3
・Kotlin 1.2.10
環境準備 1. File > New > Projectを押下 2. 左メニューからGradleを選択後、Kotlinのチェックを入れる 3.
そのまま必要項目を入力してプロジェクトを作成する ↑2の選択画面 3の 作成されるプロジェクト →
おおまかな処理フロー 1. 言語情報を保持するクラスを定義し、初期化する 2. 計算対象に入れたくないファイルをignoreするための Readerクラスを定義し、ロードする 3. ディレクトリの探索 4. 移行率の計算、ログの出力
実装①:言語情報を保持するオブジェクトの作成 /** * 言語の情報を保持するクラス * */ data class Language( val
name: String, //言語名 val extension: String //拡張子 ){ override fun toString() = name }
各言語のファイルリスト、移行元/先情報のクラス /** * 言語のlistを保持するクラス */ class SourceList( val language: Language,
val isReplaceTarget: Boolean, val list: MutableList<File> = mutableListOf()) { fun add(file: File){ list.add(file) } }
Main.kt(SourceListの初期化) val javaList = SourceList(Language("Java", "java"), false) val kotlinList =
SourceList(Language("Kotlin", "kt"), true) SourceListを初期化する 移行元がfalse, 移行先がtrue
実装②:計算対象に入れたくないファイルを無視する ・Androidだと自動生成されたファイル (R, DataBindingのファイルなど)を無視したい時あると思います。 ・.krsignoreというファイル名でProjectルートからの相対パスで記述する ことで、計算対象から外すように実装する
ignoreファイルを読み取るためのReaderクラスの作成 class IgnoreFileReader(ignoreFilePath: String, private val cd: String) { private
var fileReader: FileReader? = null var files: List<File> = mutableListOf() init { try { fileReader = FileReader(ignoreFilePath) } catch(e: FileNotFoundException) { } } fun read() { fileReader?.let { val filesStr = it.readLines() files = filesStr.map { File("$cd/$it") } } } }
Main.kt(ignoreファイル読み込み) val homeDir = System.getProperty("user.home") ?: "" val cd =
File(".").absoluteFile.parent val ignoreFileReader = IgnoreFileReader("$homeDir/.krsignore", cd) ignoreFileReader.read() .krsignoreファイルを参照して、プロジェクトのルートディレクトリ から初期化したFileオブジェクトを渡す
実装③:ディレクトリ探索用のクラス class SearchHandler( private val path: String, private val langList:
Array<SourceList>, private val ignoreDirList: List<File>) { lateinit var result: Result fun execute() { var sizeAll = 0 val rootDir = File(path) rootDir.walkTopDown() .filter { isNotIgnoreFile(it) }.forEach { file -> langList.map { langList -> if(isTargetFile(file, langList.language.extension)){ langList.add(file) println(file) sizeAll++ } } } result = Result(langList, sizeAll) } private fun isTargetFile(file: File, extension: String): Boolean = file.extension == extension /** * 対象外ファイルを無視する */ private fun isNotIgnoreFile(file: File): Boolean = ignoreDirList.none { file.startsWith(it) } }
ファイルを再帰的に探索する File.walkTopDown() Fileクラスに拡張関数として実装されている。 FileTreeWalkというクラスが返却される。これがSequenceイン ターフェースを実装しているためforEachで各Fileオブジェクトを ループで取得できる https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-fil e/walk-top-down.html
Main.kt(探索処理及び結果表示) val handler = SearchHandler(cd, arrayOf(javaList, kotlinList), ignoreFileReader.files) handler.execute() val
logger = ResultLogger(handler.result) logger.log() 画面表示についての説明は割愛します
最終的なmain.kt fun main(args: Array<String>) { val homeDir = System.getProperty("user.home") ?:
"" val cd = File(".").absoluteFile.parent val javaList = SourceList(Language("Java", "java"), false) val kotlinList = SourceList(Language("Kotlin", "kt"), true) val ignoreFileReader = IgnoreFileReader("$homeDir/.krsignore", cd) ignoreFileReader.read() val handler = SearchHandler(cd, arrayOf(javaList, kotlinList), ignoreFileReader.files) handler.execute() val logger = ResultLogger(handler.result) logger.log() }
jarをビルド task packJar(type: Jar) { manifest { attributes 'Main-Class': 'jp.co.youmeee.app.MainKt'
} from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } with jar } $ ./gradlew packJar 1. jarファイル生成のtaskを書いてあげて、 2. gradlew wrapperでタスク実行 3. build/libs配下にjarができる
jarを叩きやすくする ・生成されたjarを実行するには`java -jar krs.jar`みたいな感じで打つのは面 倒。。 ・今回は、homebrewで配布する方法で簡単に叩けるようにしました。(方法は 割愛します) $ ./AndroidStudio/HogeApp> krs
完成! 計算対象となるファイ ル一覧を出力 Projectルートで、 コマンド叩く 移行率の表示
まだKotlinにできるものがありますね、、? せっかくなので、、 build.gradle→build.gradle.kts にしてみました
build.gradle.ktsへの移行 ・GradleのビルドスクリプトをKotlinのDSLで書ける! ・既存のbuild.gradleファイルを消して、新たにbuild.gradle.ktsファイルを作成 ・こちらのマイグレーションガイドが参考になりました。 https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/
build.gradle buildscript { ext.kotlin_version = '1.2.10' repositories { mavenCentral() }
dependencies { classpath "org.jetbrains.kotlin: kotlin-gradle-plugin:$kotlin_version" } } plugins { id 'org.jetbrains.kotlin.jvm' version '1.1.51' id 'com.github.johnrengelman.shadow' version '2.0.1' } apply plugin: 'application' apply plugin: 'java' group 'jp.co.youmeee' version '1.2' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" testCompile group: 'junit', name: 'junit', version: '4.12' compile 'org.slf4j:slf4j-api:1.7.25' compile 'org.slf4j:jcl-over-slf4j:1.7.25' compile 'org.slf4j:jul-to-slf4j:1.7.25' compile 'ch.qos.logback:logback-classic:1.2.3' } task packJar(type: Jar) { manifest { attributes 'Main-Class': 'jp.co.youmeee.app.MainKt' } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } with jar }
build.gradle.kts buildscript { val kotlinVersion = "1.2.10" repositories { mavenCentral()
} dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin: $kotlinVersion") } } group = "jp.co.youmeee" version = "1.2" plugins { java application `kotlin-dsl` id("org.jetbrains.kotlin.jvm") version "1.1.51" id("com.github.johnrengelman.shadow") version "2.0.1" } java { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } repositories { mavenCentral() } dependencies { val kotlinVersion = "1.2.10" compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") testCompile(group = "junit", name = "junit", version = "4.12") compile ("org.slf4j:slf4j-api:1.7.25") compile("org.slf4j:jcl-over-slf4j:1.7.25") compile("org.slf4j:jul-to-slf4j:1.7.25") compile("ch.qos.logback:logback-classic:1.2.3") } task("packJar", type = Jar::class) { archiveName = "krs.jar" manifest { attributes["Main-Class"] = "jp.co.youmeee.app.MainKt" } from(configurations.runtime.map({ if (it.isDirectory) it else zipTree(it) })) with(tasks["jar"] as CopySpec) }
全てKotlinで書くことができました!
まとめ、感想 ・Kotlinでもコマンドラインツールは作れる!! ・File系のクラスはAndroid書いてるとあまり触らないし、便利な拡張関数もあって、 勉強になりました。 ・エラーハンドリングとか甘い部分あるので、その辺りfixしていきたい。 ・もう少し汎用的にして、外からオプションで、言語の識別子を与えるようにすれば、 Java→Kotlinのようなこともできる(需要はない) https://github.com/youmitsu/KotlinReplaceSupport er
参考資料 ・Migrating build logic from Groovy to Kotlin https://guides.gradle.org/migrating-build-logic-from-groovy-to-kotlin/ ・JVMベースのコマンドラインツールをHomebrewで配布する
https://int128.hatenablog.com/entry/2015/02/27/220907