sashimi4’s diary

日々の雑多なメモを書きます

MacOS で zsh を使うことを想定して .zprofile / .zshrc を取り急ぎ書いてみた

スーパー雑だけど取り急ぎ。

# Ctrl+U でカーソル以降を削除しない
bindkey \^U backward-kill-line

# Home/End/Delキーを意図した動作に変更
bindkey "^[[3~" delete-char
bindkey "^[[1~" beginning-of-line
bindkey "^[[4~" end-of-line

GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUNTRACKEDFILES=true
GIT_PS1_SHOWSTASHSTATE=true
GIT_PS1_SHOWUPSTREAM=auto

# PS1~n
# https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh
source ~/.git-prompt.sh
autoload -Uz colors

if [ $UID -eq 0 ];then
  # root(git-ps1無し + 色を変える)
  setopt PROMPT_SUBST ; PS1='%F{yellow}[%*%f %F{green}%n@%m%f%F{red}:%!%f %F{blue}%.%f%F{yellow}]%B%#%b%f '
else
  # other
  setopt PROMPT_SUBST ; PS1='%F{red}[%*%f %F{green}%n@%m%f%F{red}:%!%f %F{blue}%.%f%F{cyan}$(__git_ps1 "(%s)")%f%F{red}]%B%#%b%f '
fi

# 補完機能
autoload -Uz compinit && compinit
# Case-insensitiveな補完(zshで.inputrcは効かない)
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'

# コマンド履歴
HISTFILE=~/.zsh_history
HISTSIZE=6000000
SAVEHIST=6000000
setopt hist_ignore_dups     # ignore duplication command history list
setopt share_history        # share command history data

# コマンド履歴検索
autoload history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^P" history-beginning-search-backward-end
bindkey "^N" history-beginning-search-forward-end

# Screen session
export SCREENDIR=$HOME/.screen

# Get the aliases and functions
if [ -f ~/.zshrc ]; then
  . ~/.zshrc
fi

# bash履歴即時反映
# export PROMPT_COMMAND="history -a"
export PROMPT_COMMAND='history -a; history -r'

# (以下省略)

.bashrc / .zshrc には alias くらいしか書かない派なので省略。

f:id:sashimi4:20190628141216p:plain

ちなみに昔からPS1にはこだわりがあって、その見た目はこんな感じ。

Macがスリープ復帰後にRealforceを認識しない件

とりあえずの解決策

USBケーブルの抜き差しはコネクタに傷がつくので避けたいので、取り急ぎこれを買いました(妥協😇)。

www.amazon.co.jp

f:id:sashimi4:20190627200615j:plain

今の所良好です。はい。😇

途中まで調べたんだけど…

キー入力ができない状態のMacSSHしてとりあえずioregを覗いてみた。

$ ioreg -p IOUSB
+-o Root  <class IORegistryEntry, id 0x100000100, retain 20>
  +-o AppleUSBVHCIBCE Root Hub Simulation@80000000  <class AppleUSBRootHubDevice, id 0x1000004d7, registered, matched, active, busy 0 (0 ms), retain 13>
  | +-o iBridge@80100000  <class AppleUSBDevice, id 0x1000004d9, registered, matched, active, busy 0 (130614 ms), retain 13>
  | +-o Headset@80200000  <class AppleUSBDevice, id 0x1000004dd, registered, matched, active, busy 0 (89043 ms), retain 14>
  +-o AppleUSBXHCI Root Hub Simulation@14000000  <class AppleUSBRootHubDevice, id 0x1000004f7, registered, matched, active, busy 0 (0 ms), retain 10>
    +-o USB3.0 Hub             @14700000  <class AppleUSBDevice, id 0x1000004f9, registered, matched, active, busy 0 (2 ms), retain 14>
    +-o USB2.0 Hub             @14600000  <class AppleUSBDevice, id 0x1001f7a21, registered, matched, active, busy 0 (2 ms), retain 15>
      +-o Realforce 87@14640000  <class AppleUSBDevice, id 0x1002a7914, registered, matched, active, busy 0 (2894 ms), retain 14>

一応Realforceは認識してるみたい…。

次にキーイベントをフックして見たかったんだけど...時間がなくて止めました 😇😇😇

暇な時に引き続き調べて、原因がわかり次第追記したいと思います。

私のMacOSの初期セットアップ項目リスト

Mac miniを購入したので、備忘の為にも自分がMacOSを新たにセットアップする際の項目を公開してみる。
「他にもこんな設定をすると便利だぞ」というのがある人はこの記事を無断でパクってもらって構いませんので、添削しつつ別所で公開してもらって大丈夫です。

取り急ぎインストール系

システム/OS設定

ターミナルのcase-insensitiveな補完

ドットファイルは流石にバックアップ&リストアしてるんだけど、コレくらいは紹介しておこうと。

$ echo 'set completion-ignore-case on' >> ~/.inputrc

これでファイルシステムに限らず補完できるようになるはずっ!

# e.g.
$ ls ~/des (Tabキー打鍵)
↓
$ ls ~/Desktop/

Finder系

  • ショートカットで随時トグルできるけど、 Cmd + Shift + . で隠しファイルは常時表示しておきたい気持ち。

拡張子を表示

f:id:sashimi4:20190414001657p:plain

ちなみにこのダイアログの別タブで他にもいろいろ弄れるので必見!

 キーボード系

  • (Windows向けのRealfoceを使っているので) Cmd と Opt を入れ替え
  • Caps は使わないので Ctrl に変更
    • Ctrlキーはコマンドラインを使うときは A の横にあってほしいし GUI 操作してるときは Opt の横にもあってほしいので非常に便利

f:id:sashimi4:20190413215832p:plain

  • Key Repeat と Delay Until Repeat を最短にする(ストレスフリー!!!) ※ Key Repeat は OFF ではなくて Fast にする f:id:sashimi4:20190417005010p:plain

  • Input source の切り替えショートカットを Cmd + Space に設定

    • Spootlight search 表示ショートカットを昔ながらの Ctrl + Space に設定(尚、私はエディタでの補完と被るので Ctrl + Shift + Space に設定しています)

f:id:sashimi4:20190413215441p:plain f:id:sashimi4:20190413215540p:plain

  • Tabキーでウィンドウやダイアログ内のボタンフォーカスを移動できるようにする

    • System Preferences => Shortcuts => All controls にチェック f:id:sashimi4:20190413233147p:plain
  • コマンドをコピペするとき等にクォートが化けないようにする

    • System Preferences => Text => Use smart quote and dashes からチェックを外す f:id:sashimi4:20190705130341p:plain

Trackpad

  • 主な設定は↓ f:id:sashimi4:20190415132328p:plain f:id:sashimi4:20190415132354p:plain f:id:sashimi4:20190415132414p:plain

  • 3本指ドラッグを有効化(超便利) f:id:sashimi4:20190415132522p:plain

省電力系

  • Turn display off after をお好みで設定
  • (ワークステーション的に使うマシンであれば) System Preferences => Energy Saver => Prevent computer from sleeping automatically when the display is off にチェック

スクリーンセーバー

  • System Preferences => Desktop & Screen Saver => Start after をお好みで設定
  • System Preferences => Security & Privacy => Require password **** after sleeping or screen saver begins の時間を適宜設定

リモートログイン設定

  • SSHでログインするために Remote Login にチェック f:id:sashimi4:20190415135020p:plain (個人的にApple Remote Desktop を使ったりするので Remote Management もON)

よく使う設定へのショートカット配置

  • System Preferences => Bluetooth => Show Bluetooth in menu bar にチェック
  • System Preferences => Sound => Show volume in menu bar にチェック
  • Finder で Cmd + Shift + G で /System/Library/PreferencePanes/ へ移動。Displays.prefPane をドラッグしてDockに追加。その他お好みで追加すると良し。
    f:id:sashimi4:20190413222852p:plain
    システム設定項目に簡単にアクセスできて良い!

時計

  • System Preferences => Date &Time => Show date にチェック

画面のズーム機能

  • 何かと便利。 Windows の Magnify より断然便利。 f:id:sashimi4:20190417005213p:plain

一旦こんな感じかしら。思い出したら随時追記します。

Minecraftの入退室をWebhookで通知する

概要

ゲームサーバーのログをポーリングして入退室等々の通知を行います。 追加インストール不要(OS同梱のもの)で設定します。

環境

  • Ubuntu 14.x or later
    • ディストリビューションによっては curl が同梱されていない場合があるようなので sudo apt install -y curl でインストールしましょう。

設定手順

sudo su - 等々で root に昇格した上で、下記コマンドをコピー&ペーストで実行します。

cat << 'EOF' > /opt/minecraft/notify_log.sh
#!/bin/bash

HOST_NAME=$(hostname)
CHANNEL=#minecraft-notice
USERNAME=Minecraft
ICON_EMOJI=:minecraft:
# NOTE: DiscordはWebhook URL末尾に /slack とつけるとSlack互換のpayloadを扱えます
#       See: https://discordapp.com/developers/docs/resources/webhook#execute-slackcompatible-webhook
WEBHOOK_URL=https://hooks.slack.com/services/****/****/********

post_webhook() {
  while read i
  do
    echo $i | grep -iq -e "joined the game" -e "left the game"
    if [ $? = "0" ];then
      echo $i
      curl -X POST --data-urlencode "payload=\
      {\
        \"channel\": \"$CHANNEL\", \
        \"username\": \"$USERNAME\", \
        \"icon_emoji\": \"$ICON_EMOJI\", \
        \"text\": \"[HOST_NAME: $HOST_NAME]$i\" \
      }" \
      $WEBHOOK_URL
    fi
  done
}

tail -n 0 -F $1 | post_webhook
EOF
chmod +x /opt/minecraft/notify_log.sh
chown ubuntu /opt/minecraft/notify_log.sh
cat << EOF > /etc/systemd/system/minecraft_notifier.service
# /etc/systemd/system/minecraft_notifier.service
[Unit]
Description=Server daemon for Minecraft notifier

[Service]
Type=forking
User=ubuntu
KillMode=none
Restart=on-failure
ExecStart=/usr/bin/screen -dmS minecraft_notifier /bin/bash -c "/opt/minecraft/notify_log.sh /opt/minecraft/logs/latest.log"
ExecStop=/usr/bin/screen -S minecraft_notifier -X quit

[Install]
WantedBy=multi-user.target
EOF
systemctl enable minecraft_notifier
systemctl start minecraft_notifier

ポイント

HOST_NAME

HOST_NAME=$(hostname) の部分は、愛称やドメイン・アドレス等々を直書きしても良いと思います。特に複数サーバーの運用をしている方などは。 HOST_NAME=example.com といった感じに。

WEBHOOK_URL

スクリプト中にもコメントを挿しましたが、なんと Discord は Slack の Incoming Webhook に互換があります!

Discord に通知したい場合は Webhook URL の末尾に /slack を付加すると Slack 互換になります。(イケてますよね、さすが Discord)

なお、本スクリプトでは payload で送っているので channel icon_emoji 等は指定しても Discord では効きません。

echo $i | grep -iq -e "joined the game" -e "left the game"

ここで joined / left のログを検知して通知処理に飛ばしています。 サーバーの警告等も合わせて通知したい場合は、ここで追加で grep すると良いと思います。

操作方法

状態確認

  • sudo systemctl status minecraft_notifier

停止

  • sudo systemctl stop minecraft_notifier

起動/再起動

  • sudo systemctl start minecraft_notifier
  • sudo systemctl restart minecraft_notifier

自動起動設定(OS起動時に自動で起動させる/させない)

  • sudo systemctl enable minecraft_notifier
  • sudo systemctl disable minecraft_notifier

ご一緒にサーバーはいかがでしょうか←

「ご一緒にポテトは」的な()

さくらインターネット からも Minecraftサーバ の スタートアップスクリプト が出ましたね。 vps-news.sakura.ad.jp

私は早速移行し、ここで個人のサーバーを運用しています。

さくらから提供されているスクリプトで鯖立てしつつ、↑で紹介したような通知設定を行っています。快適です。

同様に screen + systemd でスッキリ収まっていて良い感じです。

おまけ

Minecraft とタイトルに入れましたが、ポーリングするログファイルと grep パターン、通知テキストを少し修正すれば、他のゲームやツール等々でも普通に使えますよね。 直近でいうと Factorio でも使えそうですね。はい。

以上、良いゲームライフを :wave:

よくある Press back again to exit なToastを再現してみる

現在携わっている業務アプリでは原則 onBackPressed をフックしてダイアログでの終了確認を行うようにしています。 が、終了確認ダイアログのNegativeButtonを毎度毎度押したくないので、よくある(?)あの「終了するにはもう一度押してください」というToastを再現してみました。

コード

package com.example.finishingconfirmsoftly;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    static final long SHORT_DURATION_TIMEOUT = 4000;
    static final long LONG_DURATION_TIMEOUT = 7000;
    boolean doubleBackToExitPressedOnce = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Toast doubleBackToExit
            = Toast.makeText(this, "Press back again to exit", Toast.LENGTH_SHORT);
        doubleBackToExit.show();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, (doubleBackToExit.getDuration()
            == Toast.LENGTH_SHORT ? SHORT_DURATION_TIMEOUT : LONG_DURATION_TIMEOUT) / 2);
    }
}

まだ汎用化してないので絶妙に汚いですが :bow:

見た目

f:id:sashimi4:20181128184448g:plain

その他

参考: stackoverflow.com

参考: android.widget.Toastソースコード

Notify Gradle's build completion to Slack.

Gradleのビルド終了をSlackに通知する

今関わってるプロジェクトのビルドが諸事情により酷く長く、Instant Runが使えないこともしばしばあり、ビルド終了の通知を受けたくなったのでやってみたメモ。

How to

Slack通知を専門に行うtaskを追加する。

[project dir]/gradle/build_notifier.gradle

task pushToSlack << {
  Properties localProperties = new Properties()
  localProperties.load(project.rootProject.file('local.properties').newDataInputStream())
  (["${project.rootDir}/gradle/notify_build_finish.sh", localProperties.getProperty('slackToken')].execute().text)
}

tasks.whenTaskAdded { task ->
  if (task.name ==~ /assemble.*/) {
    task.doLast {
      project.tasks.getByName("pushToSlack").execute()
    }
  }
}

NOTE: task名が assemble で始まるタスクの終了を通知します

通知を行うシェルスクリプトを追加する。 [project dir]/gradle/notify_build_finish.sh

#!/bin/bash
curl -X POST --data-urlencode 'payload={"channel": "#チャンネル名 または @ユーザ名", "username": "Gradle", "text": "Build has just finished.", "icon_emoji": ":gradle:"}' https://hooks.slack.com/services/$1

NOTE: chmod +x notify_build_finish.sh で実行権限の付与を忘れないこと。

SlackのIncomingWebhookのTokenを設定。 [project dir]/local.properties

slackToken=*********/*********/***********************

追加したtaskを読み込む。

[project dir]/app/build.gradle

...
apply from: file('../gradle/build_notifier.gradle')
...

android {...}
...

めも

  • 共同開発には微妙。なにかしらオプトアウトできる手段を提供すべき。
  • Unix/Linux系OSでしか動作しない。WSLで動くだろうか?

おまけ

単純にMac内で通知が見れればいい場合は、 .bashrcalias notify='osascript -e '"'"'display notification "めっせーじ" with title "たいとる" subtitle "さぶたいとる" sound name "Purr"'"'"'' と入れておいて、

$ ./gradlew check ; notify

なんてすると終了時に通知を受け取れますね。

gradlew自体にaliasを張って、

alias gradle='echo $@ ; osascript -e '"'"'display notification "めっせーじ" with title "たいとる" subtitle "さぶたいとる" sound name "Purr"'"'"''

こんな感じにしたかったんだけどうまくいきませんでした。:thinking_face:

以上。

現存するFindBugsErrorを全て除外設定してみる

いろいろな理由から、
「今あるFindBugsのエラーを一旦無視したい!」「だけどFindBugs自体は有効化させたままでいたい…!」
という時があるかもしれません。
(私は既存プロジェクトにFindBugsを途中から導入しようとしてこうなりました…。既に数百件のエラーがあります…。)
(「とりあえず今あるエラーは一旦無視して、これから発生する分は随時対応しようね」ということにしました。)

除外ルールを自動生成してしまおう!

FindBugsのレポートを生成

パースしやすいように、一時的にXMLにします。

task findbugs(type: FindBugs) {
  ...
  ignoreFailures = false
  effort = "max"
  reportLevel = "low"
  excludeFilter = new File("${project.rootDir}/config/findbugs/findbugs_filter.xml")
  classes = files("$project.buildDir/intermediates/javac/")

  source 'src/main'
  include '**/*.java'

  reports {
//    xml.enabled = false
//    html.enabled = !xml.isEnabled()
//    html {
//      destination(new File("${project.rootDir}/build/reports/findbugs_report.html"))
//    }
    // 一時的に形式をXMLに変更
    xml.enabled = true
    html.enabled = !xml.isEnabled()
    html {
      destination(new File("${project.rootDir}/build/reports/findbugs_report.xml"))
    }
  }
  classpath = files()
  ...
}

Findbugsを実行

$ ./gradlew build # FindBugsは成果物を静的解析するので、まだであればbuildする
$ ./gradlew findbugs

除外ルール自動生成

$ cat fb-filter-generator.rb
#! /usr/bin/ruby
require 'active_support'
require 'active_support/core_ext'
require 'open-uri'

def create_match(classname:, abbrev:)
  <<~EOS
  <Match>
      <Class name="#{classname}"/>
      <Bug code="#{abbrev}"/>
  </Match>
  EOS
end
hash = Hash.from_xml open('./build/reports/findbugs_report.xml').read

filter_xml = ""
hash["BugCollection"]["BugInstance"].each do |bi|
  if bi["Class"].is_a?(Array)
    bi["Class"].each do |bc|
      filter_xml << create_match(classname: bc["classname"], abbrev: bi["abbrev"])
    end
  else
    filter_xml << create_match(classname: bi["Class"]["classname"], abbrev: bi["abbrev"])
  end
end

File.open('./findbugs_filter.xml','w') do |file|
    file.puts <<~EOS
    <?xml version="1.0" encoding="UTF-8"?>
    <FindBugsFilter>
      #{filter_xml}
    </FindBugsFilter>
  EOS
end

↑のスクリプトをプロジェクト直下で実行します。

$ ruby ./fb-filter-generator.rb

実行したディレクトリに findbugs_filter.xml という除外ルールのファイルができるはずです。

私はFindBugsの除外ファイルを

excludeFilter = new File("${project.rootDir}/config/findbugs/findbugs_filter.xml")

と設定していますので、

$ mv ./findbugs_filter.xml ./config/findbugs/findbugs_filter.xml

と実行して設置しました。

これで、いま存在するFindBugsのエラーが全て除外できます!!!