Annieの部屋

ウィーンのホーフブルク宮殿の中にある非常口がアイコンの、きっとエンジニアな人。

asdfのバージョンが上がったときに.asdf/shims/{packages} が No such file or directory になる

自分用覚え書き

いつも何したら解決するか忘れてしまうので。

こんな感じのエラーが出てくる

asdfでインストールしたコマンドを実行しようとしたとき

/Users/{username}/.asdf/shims/kubectl: line 4: /opt/homebrew/Cellar/asdf/0.10.0/libexec/bin/asdf: No such file or directory
/Users/{username}/.asdf/shims/kubectl: line 4: exec: /opt/homebrew/Cellar/asdf/0.10.0/libexec/bin/asdf: cannot execute: No such file or directory

asdf reshim しても直らない

github.com

とりあえずどうにかしたいとき

~/.asdf/shimを消してからもう一回 asdf reshim を実行したら、とりあえずなおる

$ rm -rf ~/.asdf/shims && asdf reshim

Fitbit Web API + pixela で歩数を可視化するぞー (ローカル実行編)

最近、界隈でこのFitbit Web APIとpixela使ってみた記事をよく見かけるので、私もやってみたくなった。

といっても

やり方は↓こちらの記事をほぼそのままトレース。(これ以降、「もとの記事」と書いているところはすべてこちらの記事を指している)

bufferings.hatenablog.com

FitbitのAPIの呼び方やPixelaの使い方も詳しくまとめて書かれていて本当に読みやすい。

”やっていること”のうち

  1. Fitbit の API で歩数を取得
  2. Pixela に記録
  3. というスクリプトをつくって

のところまで。自動化は次のステップで頑張ってみる。

Rubyで書いた

Ruby 2.7.5。最近RubyのSilverを取得したので、こういうところで積極的に使っていきたいなぁと。

(業務レベルでは書いたことがないので、変な使い方をしているかもしれない。)

もとの記事ではTypeScriptで書かれている。

TOKEN系の管理はもとの記事を習って.envファイルで管理できるようにした。

もちろんpushしないように、.gitignoreに入れてある。

github.com

ローカルファイルで管理しているFitbitのRefresh Tokenの値を上書きするところは

↓こちらの記事のやり方を参考にして

Rubyでファイルの内容を書き換えるサンプル(置換する) - Qiita

  1. .envの中身を変数に展開して
  2. gsub()+正規表現を使って、変数の中のRefresh Tokenのところだけをうまいこと新しい値に置き換えて
  3. 元のファイルに書き戻す

とやることにした。

(とりあえず動いているけど、正規表現がイマイチなのでもうちょっとブラッシュアップしたい)

完成したもの

https://pixe.la/v1/users/anniewillescape/graphs/steps

2022年2月から3月中旬まで値が空白なのは、Fitbitが壊れてたから。 何ならこれがやりたいがためにFitbit買い替えたまである。

次はこれを自動化したい

まだ自分のローカルPCで手動で動かせるようにしかできていない。 勝手に更新し続けておいてほしいので、次はこのscriptの実行を自動化したいなぁと思っている。

おまけ(無駄な話)

rubygsubを使うときに、何を思ったのか正規表現'でくくってしまったので、当たり前だけど検索したい文字列が見つからなくて詰まった。

めちゃくちゃ恥ずかしいミスして時間が溶けた。

# 間違い
buffer.gsub!('/FITBIT_REFRESH_TOKEN=.+/', "FITBIT_REFRESH_TOKEN=#{new_refresh_token}")

# 正しくはこう
buffer.gsub!(/FITBIT_REFRESH_TOKEN=.+/, "FITBIT_REFRESH_TOKEN=#{new_refresh_token}")

MacBook Air (M1, 2020) にk8s勉強用の環境を整える

Udemyの「Kubernetes for the Absolute Beginners - Hands-on」を進めていて、

minikubeを使ったdemoを自分でもやってみようと思ったら想像以上に躓いたので自分用メモ。雑。

www.udemy.com

実行環境

2022/03/19 現在

※Udemyの講座ではLinux OS上で動かしている

Virtual BoxがM1 Macで使えない

$ brew install --cask virtualbox
==> Caveats
virtualbox requires a kernel extension to work.
If the installation fails, retry after you enable it in:
  System Preferences → Security & Privacy → General

For more information, refer to vendor documentation or this Apple Technical Note:
  https://developer.apple.com/library/content/technotes/tn2459/_index.html

==> Downloading https://download.virtualbox.org/virtualbox/6.1.32/VirtualBox-6.1.32-149290-OSX.dmg
######################################################################## 100.0%
Error: Cask virtualbox depends on hardware architecture being one of [{:type=>:intel, :bits=>64}], but you are running {:type=>:arm, :bits=>64}.

minikubeのdriverとしてvirtualboxを使う方法がdemoで使われているが、installできない。

→ Driverにdockerを指定することでminikube start コマンド自体は実行できた

$ minikube start --driver=docker

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

Hello Minikubeで使われているimageがM1 Macで動かない

kubernetes.io

$ kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4
deployment.apps/hello-node created

$ kubectl get deployment
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
hello-node   0/1     1            0           79s

いつまで経ってもdeploymentがreadyにならない……。

k8s.gcr.io/echoserver:1.4 はM1 Macで動かないらしい。

M1 MacでMinikubeを使ってみる - Hacker Sheet

↑こちらを参考に、違うimageを使ってkubectl create deployment してみる

$ ubectl create deployment hello-minikube --image=arm64v8/nginx

$ kubectl get deployment
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
hello-minikube   1/1     1            1           107s

deplyomentがreadyになった!

Service URLにアクセスできない

そもそもURLが発行されない……

$ kubectl expose deployment hello-minikube --type=NodePort --port=80
service/hello-minikube expose

$ kubectl get service
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
hello-minikube   NodePort    10.108.178.165   <none>        80:31639/TCP   2m34s
kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP        26m

$ minikube service hello-minikube --url

🏃  Starting tunnel for service hello-minikube.
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.


$ minikube service list
|-------------|----------------|--------------|-----|
|  NAMESPACE  |      NAME      | TARGET PORT  | URL |
|-------------|----------------|--------------|-----|
| default     | hello-minikube |           80 |     |
| default     | kubernetes     | No node port |
| kube-system | kube-dns       | No node port |
|-------------|----------------|--------------|-----|

他にも問題に直面している人を見かけた

github.com

うーん、これはM1 Mac特有の問題ではなさそう。

そして「driverをdockerじゃなくてhyperkitにしたら動く」というのが解決策になっている……。

github.com

そしてM1 Macではhyperkitが動かない!詰んだ!

対応:microk8sを使う

今回は、minikubeを使うことを諦めてmicrok8sを使うことにした。

Canonicalの軽量Kubernetes「MicroK8s」がWindowsとMacに対応。インストーラーで簡単に導入可能に - Publickey

これで、いまのところdemo通りのコマンドが使える。

MicroK8sのパッケージインストール

$brew install ubuntu/microk8s/microk8s

MicroK8sのインストール

multipassが入っていないとinstallを促される

$microk8s install
Support for 'multipass' needs to be set up. Would you like to do that it now? [y/N]:

MicroK8sとSkaffoldで開発環境を構築した際のメモ(Mac) - Qiita

$ microk8s start
Started.

~/.kube/config に設定追加(任意)

追加しない場合はmicroku8s kubectlというコマンドを使えば良い。

私はこれ以外に切り替えるk8sクラスタはないので、以下のコマンドでconfigに設定を追加した。

$ microk8s config > ~/.kube/config

複数切り替える必要がある場合はmicrok8s configの結果をうまいこと切り取って~/.kube/configに追記する必要あり。

Hello Minikube をmicrok8sで再実行!

Hello Minikubeで使われていたコマンドをmicrok8s環境で使ってみる

$ kubectl create deployment hello-microk8s --image=arm64v8/nginx
deployment.apps/hello-microk8s created

$ kubectl get deployment
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
hello-microk8s   1/1     1            1           33s

$ kubectl expose deployment hello-microk8s --port=80
service/hello-microk8s exposed

これでhttp://localhostにアクセスすると馴染みのWelcome to nginx! が見れるはず!

あー、楽しかった。

おもうこと(2021年10月ver.)

2021年もあと2ヶ月になったのはあまり関係ないけれど、今の思いを綴りたくなったので書き残しておく。

先月まで一緒のチームで働いていた先輩エンジニアが今月から新たに素敵な挑戦をされていて、
その姿に勝手に刺激と影響を受けている自分がいるなぁと感じているけど
振り返れば、今までの人生も自分はこうやって周りの人の影響を受けまくって生きてきた気がするなぁと思った。

15歳のときに、偶然参加した「中学生Ruby教室」で出会った講師の先生に憧れて、
それまで選択肢に一切なかったその先生の出身校の高専に進学して情報工学を学び始めたし、
(プログラミングにも興味はあったけど、自分の誕生石がルビーなので何故か惹かれて参加しただけだった気がする)

バスケ部のマネージャをしているときに、他校のマネージャーさんがスポーツトレーナーもできる方でかっこよくて憧れて、
テーピングの資格を取ってみたり、コンディショニングコーチの資格を勉強したりして
エンジニアの道を捨ててスポーツトレーナーの道に進もうとした時期もあったし

結局色々あってスポーツトレーナーの道に進めなくて、半分惰性で工学を学び続けながら、
IT系に就職する気ないなぁと思いつつ参加したエンジニアの逆求人イベントで今の会社のマネージャーと出会って、
自分のことを「きみ面白いね」と言ってくれたその人と一緒に働きたくなって結果的に入社してるし。

なんかいろいろなことを真剣に考えずに直感で選んで生きてしまった感はあってちょっと不安だけど、
でもそれはきっと今まで素敵な人との出会いがあったからだから私ってツイてるなって思うし
おかげで今が楽しいからいいかなって27歳の自分は思ってると記しておこう。

どんぶらこと「Chrome Extension作りたい欲」が流れてきた(1)

学生時代、履修した授業の5段階評価アンケートにWEBで回答するという儀式が毎学期末にあったのですが、
技術に尖っていた先輩が「いちいち手で選ぶの面倒くさい」ということでChrome拡張機能を自作し 、各評価項目のラジオボタンをランダムに選択して提出できるものを作っておられて感動したのを覚えています。(実際に使用されていたのかまでは把握していませんが。)

あの感動から約10年、突然川上の方からどんぶらこと「Chrome Extension作りたい欲」が流れてきたのでやってみた記録です。

(n番煎じ感はありますが・・・)

たどり着きたいところ

スケジュールの話をするときにいちいちカレンダーアプリを開くのが面倒なので、
Chrome Extensionで簡単なカレンダーを開けるようになる!

  • Nice to have: やれたらいいけど今は優先度低めなこと

    • ReactやVueを使って書いてみる?
    • そのカレンダー上で予定を登録できるようにする??
    • そのほかリッチな機能の実装
    • 実際にweb storeで公開する($5かかるらしい)

今回のゴール

公式にGetting startedがあるのでやってみる!

developer.chrome.com

とりあえずはじめてみる

Extensionをつくるのに必要なものは、以下の4つでした

  • jsファイル
  • css ファイル
  • html ファイル
  • manifest.json: 「どんな拡張機能か」を記載しておく定義書のようなもの

※ 執筆時点ではmanifest v3の形式でmanifest.jsonを記述しています。

もちろん、実装する機能によってサイズ感や難しさは変わると思いますが
Extensionはとてつもなく特殊な方法で作られているのかなと勝手に思い込んでいたので、普通にwebページを作る感覚で作り上げることができるんだなーというのが最初の印象です。

できた!

ということで、Getting startedに載っているコードをそのままコピペするだけで、こんな感じのOptionメニュー付き Extensionを作ることができました!

chrome-extension-sample gif

特に詰まってしまうところはなくて、ゆっくりやっていましたが所要時間は1時間程度で形にすることができました。

「あれ、書いてあるとおりに動かないぞ・・・?」となるときは、だいたい拡張機能管理画面の更新ボタンを押し忘れているときでした。

chrome-extension-management-screen img

次回は・・・

popup.htmlの要領で、カレンダーを表示するものを作ってみようと思います!

今回実際に書いたコード。フォルダ構成を若干変えていますが、ほぼ公式ページに載っているコードそのままです。

github.com

Hammerspoonでmacの画面分割を快適(?)にしてみた

windowsを使っている場合、「win」+「方向キー←↓↑→」で簡単に画面分割することができます。
macの画面分割は「Split View」というデフォルトの機能があります

support.apple.com

が、対象の画面を長押しないといけなかったり、全画面表示になっちゃったり、ショートカットキーでサクッと分割することができないので、ずっと有料のMagnet.appを使っていました。

そんな中、「実はこの画面分割って自分で実装できたりしないかな」という考えに至り、やってみたらできたので紹介したいと思います。

無料アプリ ShiftIt を使うという選択肢

無料アプリで同じようなことを実現しているものがないか探してみたところ、ShiftItというものがありました。

github.com

このままこれを使ってもいいかなと思ったのですが

Looking for a new maintainer #296.
This project is looking for a new maintainer. Until that transition is completed, there will likely not be further development on this project.
Alternatives
A highly recommended alternative to ShiftIt that can be implemented using Hammerspoon.

ということで、代替アプリとしてHammerspoonを使うことが推奨されていたのでHammerspoonにしてみることにしました。

ちなみに、最初アプリ名を「しふと えるてぃー」と読んでいましたが、Repositoryの文字列を ASCIIコード変換機 にかけてみたところ、6文字目は0x49だったので小文字のLではなく大文字のI(アイ)でした。

(個人的にはマニュアル車のシフトレバーのようなアイコンが素敵で惹かれました。)

Hammerspoon とは?

Hammerspoonとは、Macにホットキーなどを設定できるユーティリティだそうです。

www.hammerspoon.org

Getting Started

実行環境

Hammerspoon をインストール

インストール手順は公式のRepositoryにも記載されていますが、

  • 最新のアプリ(zip)をダウンロードしてApplicationsフォルダに配置する
  • brew installコマンドを使う

の2択です。とても簡単。

私はbrew installの方を実施しました。

$ brew install hammerspoon --cask

ちなみに2021年9月18日現在、Hammerspoonの最新versionは0.9.90です。

$ brew info hammerspoon
hammerspoon: 0.9.90 (auto_updates)
https://www.hammerspoon.org/
/usr/local/Caskroom/hammerspoon/0.9.90 (125B)
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/hammerspoon.rb

画面分割の設定を書く

アプリを立ち上げて、メニューバーのOpen Configを押すと~/.hammerspoon/init.luaというファイルが開かれます。
ここに自分が設定したい内容を書いていけば良いのですが、拡張子からわかるように言語はLuaです。
Luaは初挑戦ですが、公式のRepositoryのWikiにサンプルがたくさん載っていたので、それを参考にしてなんとか実装できました。

今回設定する内容は、Magnet.appの画面分割の中でも個人的に使用頻度の高かった、画面を二分割するためのショートカットキーにしました。

  • Control (⌃) + Option (⌥) + ← : フォーカスしているwindowを左半分に寄せる
  • Control (⌃) + Option (⌥) + → : フォーカスしているwindowを右半分に寄せる
  • Control (⌃) + Option (⌥) + ↑ : フォーカスしているwindowを上半分に寄せる
  • Control (⌃) + Option (⌥) + ↓ : フォーカスしているwindowを下半分に寄せる

出来上がった設定ファイルはこんな感じです。

hs.window.animationDuration = 0
units = {
  right50       = { x = 0.50, y = 0.00, w = 0.50, h = 1.00 },
  left50        = { x = 0.00, y = 0.00, w = 0.50, h = 1.00 },
  top50         = { x = 0.00, y = 0.00, w = 1.00, h = 0.50 },
  bot50         = { x = 0.00, y = 0.50, w = 1.00, h = 0.50 }
}

mash = { 'ctrl', 'option' }
hs.hotkey.bind(mash, 'right', function() hs.window.focusedWindow():move(units.right50, nil, true) end)
hs.hotkey.bind(mash, 'left', function() hs.window.focusedWindow():move(units.left50, nil, true) end)
hs.hotkey.bind(mash, 'up', function() hs.window.focusedWindow():move(units.top50, nil, true) end)
hs.hotkey.bind(mash, 'down', function() hs.window.focusedWindow():move(units.bot50, nil, true) end)

Luaの構文だけでなく、Hammerspoon独自の関数なども確認する必要がありますが、思ったよりも直感的にかける印象を受けました。(たくさん登場しているhsはHammerspoonのfunctionを指している感じですね)

この設定をinit.luaに上書きしたら、メニューバーのReload Configを押すことで設定が反映されます!

完了!!

コードを見ていく

今回実装したコードを(理解できている範囲で)少しだけ見ていこうと思います。(間違っていたらこっそり教えて下さい・・・。)

windowの動かし方を決める

units = {
  right50       = { x = 0.50, y = 0.00, w = 0.50, h = 1.00 },
  left50        = { x = 0.00, y = 0.00, w = 0.50, h = 1.00 },
  top50         = { x = 0.00, y = 0.00, w = 1.00, h = 0.50 },
  bot50         = { x = 0.00, y = 0.50, w = 1.00, h = 0.50 }
}

こちらは、windowを右半分・左半分にするときに、windowの左上をスクリーンのどこ(x,y)にどんな幅&高さで配置するかというルールを記述しています。
C言語で言う構造体のように見えますが、これはLuaTable型で、keyとvalueで構成される連想配列らしいです。

各keyにはその後の画面分割の処理で使いやすいように、Hammerspoonの構文に従って{x=X, y=Y, w=W, h=H}という形式でtable型のvalueとして指定しています。

ショートカットキーとwindowの動かし方を組み合わせる

hs.hotkey.bind(mash, 'right', function() hs.window.focusedWindow():move(units.right50, nil, true) end)

hs.hotkey.bind の引数には、以下のような値を指定していきます。

  1. Command (⌘), Control (⌃), Option (⌥), Shift (⇧)キー名を0個以上指定
    • ここでは'ctrl''option'のtableを指定している
  2. キーボードのキー名またはキーボードの番号を指定
    • ここではのキー名の'right'を指定している
  3. キーが押されたときに呼び出す関数を指定
    • Luaの関数はfunction()で始まりendで終わる
    • ここでフォーカスしているwindowを移動させるHammerspoonの機能 hs.window.focusedWindow():move()を実行して、画面分割させる!

まとめ & 感想

画面分割のショートカットキーをHammerspoon + Luaで簡単に実装することができました!

Hammerspoonにkey bindingや画面を動かすための関数が用意されていて、そこに引数を渡すだけで済んだので、予想以上に短いコードで実現することができて驚いています。

そして楽しかったです!

今回のサンプルコード(+α)はこちらに載せています。 github.com