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
770
stand.fm(Android)におけるreact-native-track-playerの改善
youmitsu
1
2k
TargetSdkVersion29で BottomNavigationが点滅する件
youmitsu
1
1.5k
リリース前のリグレッションテストをUIテストで自動化、1年間運用した話
youmitsu
2
340
New features in RemoteConfig, Analytics at Google I/O 2019
youmitsu
1
610
FirebaseNotification,RemoteConfigでユーザセグメントごとにプッシュ通知を実装する
youmitsu
8
1.5k
Report from Google I/O 2019
youmitsu
1
75
OSSにコントリビュートした話
youmitsu
1
75
Other Decks in Technology
See All in Technology
サーバレスアプリ開発者向けアップデートをキャッチアップしてきた #AWSreInvent #regrowth_fuk
drumnistnakano
0
190
Microsoft Azure全冠になってみた ~アレを使い倒した者が試験を制す!?~/Obtained all Microsoft Azure certifications Those who use "that" to the full will win the exam! ?
yuj1osm
2
110
プロダクト開発を加速させるためのQA文化の築き方 / How to build QA culture to accelerate product development
mii3king
1
260
UI State設計とテスト方針
rmakiyama
2
540
NW-JAWS #14 re:Invent 2024(予選落ち含)で 発表された推しアップデートについて
nagisa53
0
260
大幅アップデートされたRagas v0.2をキャッチアップ
os1ma
2
530
生成AIをより賢く エンジニアのための RAG入門 - Oracle AI Jam Session #20
kutsushitaneko
4
220
C++26 エラー性動作
faithandbrave
2
730
株式会社ログラス − エンジニア向け会社説明資料 / Loglass Comapany Deck for Engineer
loglass2019
3
32k
10分で学ぶKubernetesコンテナセキュリティ/10min-k8s-container-sec
mochizuki875
3
330
Snowflake女子会#3 Snowpipeの良さを5分で語るよ
lana2548
0
230
Wvlet: A New Flow-Style Query Language For Functional Data Modeling and Interactive Data Analysis - Trino Summit 2024
xerial
1
110
Featured
See All Featured
Art, The Web, and Tiny UX
lynnandtonic
298
20k
For a Future-Friendly Web
brad_frost
175
9.4k
Typedesign – Prime Four
hannesfritz
40
2.4k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
Become a Pro
speakerdeck
PRO
26
5k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
26
1.5k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.4k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
0
97
The World Runs on Bad Software
bkeepers
PRO
65
11k
Done Done
chrislema
181
16k
Docker and Python
trallard
42
3.1k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
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