SonarQube on Docker with Windows 2

前回の続き

SonarQube on Docker with Windows - kntmr-blog

プロジェクト作成

Create new project で、Project key と Display name を入力して作成する。次に Token を作成する。Token を作成するときはプロジェクト名を使えばよいと思われる。

SonarScanner

ダウンロードして展開して PATH を通す。

https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

実行

解析したいプロジェクトフォルダでコマンドプロンプトを開く

> sonar-scanner -Dsonar.projectKey=<PROJECTKEY> -Dsonar.sources=src -Dsonar.java.binaries=classes -Dsonar.host.url=http://localhost:9000 -Dsonar.login=<TOKEN>

... ()

INFO: Analysis total time: 3:55.805 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 3:58.185s
INFO: Final Memory: 16M/60M
INFO: ------------------------------------------------------------------------

プロジェクトページの Overview を開くと解析結果が表示される。

今回はここまで。

SonarQube on Docker with Windows

SonarQube を試してみようかと。Docker イメージがあるようなので、まずは、Windows に Docker インストールするところから...。備忘録。

  • Windows 10 Enterprise 64bit
  • タスクマネージャー > パフォーマンス > CPU 仮想化: 有効
  • コントロールパネル > プログラムと機能 > Windows の機能の有効化または無効化 > Hyper-V にチェック (要再起動)

Hyper-V の設定は Docker Desktop をインストールすると勝手にやってくれるかも。ただし、再起動は必要。

Docker Desktop on Windows

Docker-docs-ja の Windows 導入ガイド には Docker Toolbox のインストール手順が書かれているが、Docker Toolbox のページに行くと「Docker Toolbox は Lagacy 向けです」と書かれている。今回は Docker Desktop をインストールする。

Docker Hub からインストーラをダウンロードしてインストール。(要アカウント作成)

Install Docker Desktop on Windows - Docker docs

2019/10/10 時点では、Docker Desktop 2.1.0.1 がインストールされる。

> docker -v
Docker version 19.03.1, build 74b1e89

SonarQube

Docker Hub の公式イメージを使う。無念にもプロキシ環境の場合は事前に Docker Desktop で設定する。

sonarqube - Docker Hub

> docker run -d --name sonarqube -p 9000:9000 sonarqube

localhost:9000 にアクセスして admin/admin でログイン。

f:id:knt_mr:20191010125023p:plain

今回はここまで。

参考)

古いバージョンのアプリケーションを Scoop で管理したい

前回の続き。

Scoop on Windows - kntmr-blog

Scoop に存在しないアプリケーションをインストールする場合は自分で Manifest を書いてインストールする。

普通にインストーラーを使ってインストールしてもいいけど、Scoop でインストールすると、管理が一元化できるし、バージョン切り替えが簡単にできるようになる。

例えば、プライベートでは最新の JDK を使っているけど、業務では 無念にも 古いバージョンの JDK を使っているとか。ということで、以降は jdk-7u45-windows-x64.exe でインストールした Java を Scoop に移行する手順。なぜこのバージョンを使っているのかはお察しいただきたい。

手順

Git リポジトリ作成する。このリポジトリbucket になる。

> mkdir sample-bucket
> cd sample-bucket
> git init

Manifest を作成する。Manifest のファイル名が scoop の中で使われるアプリケーションの名前になる。今回は legacy-jdk.json という名前で作成する。

{
  "version": "1.7.0_45",
  "architecture": {
    "64bit": {
      "url": "http://{web-server}/path/to/jdk1.7.0_45.zip", // zip ファイル
      "hash": "5c4c76711d19be11089a342181fb457f8799a19a7918745c53de87401a521748" // SHA256
    }
  },
  "env_add_path": "bin", // bin をユーザー環境変数に設定する
  "env_set": {
    "JAVA_HOME": "$dir" // JAVA_HOME をユーザー環境変数に設定する
  }
}

環境変数はデフォルトでユーザー環境変数に設定される。システム環境変数に設定する場合は --global を付ける。(未検証)

ちなみに、今回は C:\Program Files\Java\jdk1.7.0_45 下のファイル群 (展開したときにファイルが配置されるように) を zip 圧縮して Scoop でダウンロードできるところに配置しているが、もっといい方法はないだろうか...。

> git add .
> git commit -m "add legacy-jdk"

Scoop で bucket を追加してインストールする。無念にもプロキシ環境の場合は事前に設定すること。

> scoop bucket add sample-bucket .
Checking repo... ok
The sample-bucket bucket was added successfully.

> scoop update
Updating Scoop...
Updating 'main' bucket...
Updating 'sample-bucket' bucket...
 * 73e7c0e add legacy-jdk                                                4 minutes ago
Scoop was updated successfully!

> scoop install legacy-jdk
Installing 'legacy-jdk' (1.7.0_45) [64bit]
jdk1.7.0_45.zip (131.7 MB) [======================================================================================] 100%
Checking hash of jdk1.7.0_45.zip ... ok.
Extracting jdk1.7.0_45.zip ... done.
Linking ~\scoop\apps\legacy-jdk\current => ~\scoop\apps\legacy-jdk\1.7.0_45
'legacy-jdk' (1.7.0_45) was installed successfully!

参考

Scoop on Windows

備忘録。

Cygwin 環境はないので Scoop を試してみる。Scoop は Mac で言うところの Homebrew みたいなもの。

scoop.sh

PowerShell 5 以上が必要。

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.18362.145
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.18362.145
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

実行ポリシーを変更してインストールする。

> Set-ExecutionPolicy RemoteSigned -scope CurrentUser

> Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
Initializing...
Downloading scoop...
Extracting...
Creating shim...
Downloading main bucket...
Extracting...
Adding ~\scoop\shims to your path.
'lastupdate' has been set to '2019-09-27T12:47:42.7720596+09:00'
Scoop was installed successfully!
Type 'scoop help' for instructions.

試してみる

無念にもプロキシ環境の場合は事前に設定すること。

今回は JDK をインストールしてみる。Scoop の JDKJava bucket というものに含まれる。

> scoop search jdk
Results from other known buckets...
(add them using 'scoop bucket add <name>')

'java' bucket:
    bucket/adoptopenjdk-hotspot-jre
    bucket/adoptopenjdk-hotspot
    bucket/adoptopenjdk-lts-hotspot-jre
    bucket/adoptopenjdk-lts-hotspot
    bucket/adoptopenjdk-lts-openj9-jre
    bucket/adoptopenjdk-lts-openj9
    bucket/adoptopenjdk-openj9-jre
    bucket/adoptopenjdk-openj9
    bucket/adoptopenjdk-upstream
    bucket/ojdkbuild-full
    bucket/ojdkbuild
    bucket/ojdkbuild10-full
    bucket/ojdkbuild10
    bucket/ojdkbuild11-full
    bucket/ojdkbuild11
    bucket/ojdkbuild12-full
    bucket/ojdkbuild12
    bucket/ojdkbuild8-full
    bucket/ojdkbuild8
    bucket/ojdkbuild9-full
    bucket/ojdkbuild9
    bucket/openjdk
    bucket/openjdk10
    bucket/openjdk11
    bucket/openjdk12
    bucket/openjdk13
    bucket/openjdk14
    bucket/openjdk7-unofficial
    bucket/openjdk9
    bucket/oraclejdk
    bucket/oraclejdk12

Java bucket を追加する。

> scoop bucket add java
Checking repo... ok
The java bucket was added successfully.

> scoop search jdk
'java' bucket:
    adoptopenjdk-hotspot-jre (12.0.2-10)
    adoptopenjdk-hotspot (12.0.2-10)
    adoptopenjdk-lts-hotspot-jre (11.0.4-11)
    adoptopenjdk-lts-hotspot (11.0.4-11)
    adoptopenjdk-lts-openj9-jre (11.0.4-11-0.15.1)
    adoptopenjdk-lts-openj9 (11.0.4-11-0.15.1)
    adoptopenjdk-openj9-jre (12.0.2-10-0.15.1)
    adoptopenjdk-openj9 (12.0.2-10-0.15.1)
    adoptopenjdk-upstream (11.0.3-7)
    ojdkbuild-full (12.0.1.12-1)
    ojdkbuild (12.0.1.12-1)
    ojdkbuild10-full (10.0.2-1.b13)
    ojdkbuild10 (10.0.2-1.b13)
    ojdkbuild11-full (11.0.3.7-1)
    ojdkbuild11 (11.0.3.7-1)
    ojdkbuild12-full (12.0.1.12-1)
    ojdkbuild12 (12.0.1.12-1)
    ojdkbuild8-full (1.8.0.212-1.b04)
    ojdkbuild8 (1.8.0.212-1.b04)
    ojdkbuild9-full (9.0.4-1.b11)
    ojdkbuild9 (9.0.4-1.b11)
    openjdk (12.0.2-10)
    openjdk10 (10.0.2-13)
    openjdk11 (11.0.2-9)
    openjdk12 (12.0.2-10)
    openjdk13 (13-33)
    openjdk14 (14-16-ea)
    openjdk7-unofficial (7u80-b32)
    openjdk9 (9.0.4-12)
    oraclejdk (12.0.2-10)
    oraclejdk12 (12.0.2-10)

OpenJDK をインストールする。現時点では OpenJDK 12 がインストールされて、ユーザー環境変数JAVA_HOME=~\scoop\apps\openjdk\current が設定される。

> scoop install openjdk
Installing 'openjdk' (12.0.2-10) [64bit]
openjdk-12.0.2_windows-x64_bin.zip (187.4 MB) [===============================================================] 100%
Checking hash of openjdk-12.0.2_windows-x64_bin.zip ... ok.
Extracting openjdk-12.0.2_windows-x64_bin.zip ... done.
Linking ~\scoop\apps\openjdk\current => ~\scoop\apps\openjdk\12.0.2-10
'openjdk' (12.0.2-10) was installed successfully!

> java -version
openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)

OpenJDK 13 をインストールしてみる。

> scoop install openjdk13
Installing 'openjdk13' (13-33) [64bit]
openjdk-13_windows-x64_bin.zip (186.8 MB) [===================================================================] 100%
Checking hash of openjdk-13_windows-x64_bin.zip ... ok.
Extracting openjdk-13_windows-x64_bin.zip ... done.
Linking ~\scoop\apps\openjdk13\current => ~\scoop\apps\openjdk13\13-33
'openjdk13' (13-33) was installed successfully!

> java -version
openjdk version "13" 2019-09-17
OpenJDK Runtime Environment (build 13+33)
OpenJDK 64-Bit Server VM (build 13+33, mixed mode, sharing)

バージョンを切り替える。

> scoop reset openjdk@12.0.2-10 # @ でバージョンを指定する場合
Resetting openjdk (12.0.2-10).
Linking ~\scoop\apps\openjdk\current => ~\scoop\apps\openjdk\12.0.2-10

> scoop reset openjdk13 # 名前で指定する場合
Resetting openjdk13 (13-33).
Linking ~\scoop\apps\openjdk13\current => ~\scoop\apps\openjdk13\13-33

その他

仕組み的に PATH が汚れないしバージョンの切り替えが簡単でいいかもしれない。ローカルの開発環境を構築するのに便利そう。というかその目的で作られたツールっぽい。

参考)

ツリー構造の Java 実装サンプル

以前の続き。

動的にデータを取得する Vue.js のツリーコンポーネント - kntmr-blog

これに関連して、フォルダ階層のようなツリー構造を Java で実装したサンプル。

kntmr/playground/folder-tree-examples - GitHub


子階層の要素を同じ型の List<T> で持つことでツリー構造を表現する。

public class FolderTree {
    private long id;
    private String name;
    private List<FolderTree> children;
    public FolderTree(long id, String name) {
        this.id = id;
        this.name = name;
    }
    public long getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public List<FolderTree> getChildren() {
        return children;
    }
    public void setChildren(List<FolderTree> children) {
        this.children = children;
    }
}

ツリー全体のデータを取得するときは最上位から順番に子階層の要素を取得する。

public FolderTree folderTree() {
    FolderTree tree = new FolderTree(0, "Root"); // 最上位から
    return getFolderTreeRecursive(tree, tree);
}
FolderTree getFolderTreeRecursive(FolderTree tree, FolderTree currentNode) {
    List<FolderTree> children = getChildren(currentNode.getId()); // 子階層を取得
    currentNode.setChildren(children);
    for (FolderTree nextNode : children) {
        getFolderTreeRecursive(tree, nextNode); // 子階層の要素に対して再帰的に処理する
    }
    return tree;
}

これはグラフデータの探索で言うところの 深さ優先探索 になっている。深さ優先探索の場合、縦方向 (深い階層) の探索を優先する。ちなみに、幅優先探索の場合は横方向 (隣接する要素) の探索を優先する。

@RequestMapping で正規表現を使って @PathVariable を宣言する

普段、こういう使い方をしないので、URI のパスの宣言に正規表現が使えることを初めて知りました...。

URI patterns - Web on Servlet Stack


@GetMapping("/users/{id:[0-9]{5}}") // 数字5桁
public String get(@PathVariable long id) {
    //
}

また、1つのパスの中身は分解して変数に抽出できる。

@GetMapping("/users/{prefix:[a-z]{1}}{id:[0-9]{5}}") // 英小文字1桁 + 数字5桁
public String get(@PathVariable String prefix, @PathVariable long id) {
    //
}

固定の prefix の場合はこういう書き方も可。例えば、内部では数字で扱うけど、外部からは prefix 付きでアクセスされるような要件があるときに便利かもしれない。

@GetMapping("/users/user{id:[0-9]{5}}") // `user` + 数字5桁
public String get(@PathVariable long id) {
    //
}

あと、同階層の URI のパスに応じて Controller のメソッド呼び出しが分けられる。

@GetMapping("/users/user{id:[0-9]{5}}")
public String get1(@PathVariable long id) {
    // /users/user12345 はこっちに入る
}
@GetMapping("/users/admin{id:[0-9]{5}}")
public String get2(@PathVariable long id) {
    // /users/admin12345 はこっちに入る
}

今までは1つのメソッドで受けて、パラメータを判定して処理を分岐したりしてたかもしれないけど、Controller のメソッドで分岐できるならその方がアプリケーションコードはシンプルになりそう。

アルゴリズム体操

Javaアルゴリズムの復習。久しぶりに書くとすっかり忘れてますね...。こういうのを呼吸するように書けるようになりたいものです。

バブルソート

配列の先頭から隣り合う要素を比較して入れ替える。これを配列の最後の要素まで繰り返してソートする。

gist.github.com

クイックソート

ここでは配列の真ん中の要素をピボットとする。ピボットの左右で要素を比較し、ピボットより小さい要素が左に、ピボットより大きい要素が右に来るように入れ替える。ピボット未満の要素の配列とピボット以上の要素の配列で同様のソートを再帰的に繰り返してソートする。ピボットを境界にして再帰するには入れ替え処理で使ったインデックスをそのまま返す。最初のピボットの位置ではない。(入れ替えでピボットの位置が変わるため)

gist.github.com

マージソート

配列を単一要素になるまで分割する。ソートする要素を作業配列に入れておいて、比較しながら元の配列に書き戻すことでソートする。

gist.github.com

二分探索

ソート済みの配列を前提とする。真ん中の要素と対象の要素を比較して左か右の配列を再帰的に探索する。

gist.github.com

(番外編) フィボナッチ数

これはアルゴリズムではないかもしれないが、みんなが大好きなフィボナッチ数。通常バージョンとメモ化バージョン。

gist.github.com

(番外編) 素数判定

これもアルゴリズムではないかもしれないが、みんなが大好きな素数。判定は平方根以下の値までとする。(対象の値が合成数の場合、平方根より小さい素因数が存在するため)

gist.github.com