技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

Github の git アクセスを維持するために ssh 鍵認証

なぜ?

Github は公式に、Git アクセスのパスワード認証を停止していくと宣言したためです。

github.blog

曰く 2021/8/13 にパスワード認証を廃止するとの事です。

August 13, 2021 – Token (or SSH key) authentication will be required for all authenticated Git operations.

やり方

これは Windows/Mac/Linux 全部共通です。

git-scm.com

Windows に git をインストールした場合、「Git bash」がインストールされています。
Mac/Linux はターミナル開けば ok

f:id:white-azalea:20210113192456p:plain

起動したら $ ssh-keygen -o を叩けばやれます

azale@LAPTOP-T5MQIJ18 MINGW64 ~
$ ssh-keygen -o
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/azale/.ssh/id_rsa):
Created directory '/c/Users/azale/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/azale/.ssh/id_rsa
Your public key has been saved in /c/Users/azale/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:XhR0d0uB6se0C+n9YGJB4mJOktzVqlq74u/+wZg29Zk azale@LAPTOP-T5MQIJ18
The key's randomart image is:
+---[RSA 3072]----+
|         .o . ooo|
|          .o o...|
|         o.o.  . |
|    . o o.+. .   |
|     + =S+o.+ .  |
|      =.B..+++   |
|       O.o.E+o.  |
|     .+ o o.oo.  |
|    .o=*o.    .. |
+----[SHA256]-----+

すると、~/.ssh/id_rsa.pub が生成されます。これが ssh 公開鍵です。
そしたらこの中身を開いてコピーします。

$ cat .ssh/id_rsa.pub
~省略(見せられないよ~)~

Windows だと必要ないかもだけど、chmod 600 ~/.ssh/id_rsa もやっておいて、ほかのユーザから参照できないようにしませう。

github に登録

次のリンクから、「New SSH Key」を指定します。

https://github.com/settings/keys

f:id:white-azalea:20210113201907p:plain

f:id:white-azalea:20210113202103p:plain

コピった内容を貼り付けで OK です。

ssh config の生成

そしてホームディレクトリに .ssh ディレクトリができているので、.ssh/config を追加しましょう。
個人的には vi 使いますが、まぁお好きに。

Host github
    HostName     github.com
    IdentityFile ~/.ssh/id_rsa
    User         git

ここまで書いたら保存。

接続確認でござる

$ ssh github
The authenticity of host 'github.com (52.192.72.89)' can't be established.
RSA key fingerprint is SHA256:...

中略

Hi Sunao-Yoshii! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

successfully authenticated, と出ていれば設定は成功です。

Laravel 開発環境をDockerで

久々にPHP 使うお仕事になったついで。
PHP で非常に人気のある Laravel の開発環境を用意したいと思った。(※注意:リリース環境ではありません)

XAMPP とかクソくらえ!

ちょっと暴論ではあるのだけど、自分は XMPP が気に入らない。

理由は非常に明白で

  • 常駐アプリ入れすぎ
  • 何でもかんでも入りすぎ
  • しかも重い

という事で、既存の環境を汚さずに開発環境を手に入れるのが自分の中でジャスティス。
そこで、Docker でその対応を行ってみようという企画です。

Laravel のインストール方法を見てみる

ちょっと調べてみると、Homestead や LaravelValet とかいうものがあるらしい。
で、LaravelValet は Windows ではつけあないとかなんとか…

www.hypertextcandy.com

Docker で構築する以上どうでもいい気がする…。
で、更に調べると、Composer で構築するっぽいことがわかった

github.com

ここまで判ればまずは手を動かしてみるか

ごめん、公式見た方がかなりマシ

laravel.com

composer だとコマンド一発だわ。
長時間無駄した…

PHP と Composer インストール済み環境を作る

といっても、Docker 系ファイル作成するだけ

基本的な Docker イメージは Docker Hub ここから取ってくる。
ちょうど、PHPComposer があるので、これで環境作っちゃえ

docker-compose.yml

version: '2'
services:
  host:
    restart: always
    build: ./data/main
    environment: 
      TZ: 'Asia/Tokyo'
    volumes:
      - './sources:/root/codes'

volumes 設定で、ローカルディスク(./sources)を仮想 OS 上のディレクトリ、 /root/codes に紐づける

で、./data/main/Dockerfile はこんな感じ

FROM php:7-fpm-buster
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y unzip curl wget git gcc
COPY --from=composer /usr/bin/composer /usr/bin/composer
WORKDIR /root
  • php7-fpm-buster というタグ(設定のバージョン)をベースにする。(これ自体は debian ベース)
  • とりあえず apt-get で必要そうなソフトを入れておく
  • composer の Docker イメージから、/usr/bin/composer だけつまみ食い的に取ってくる
  • ログイン時の作業ディレクトリを /root 指定

てな感じ。

では早速ビルド

PS C:\Workspace\PHP\lalabel> docker-compose build
Building host
Step 1/4 : FROM php:7-fpm-buster
 ---> f5460fa2369d
Step 2/4 : RUN apt-get update &&     apt-get upgrade -y
 ---> Running in a714759d79bb
Get:1 http://deb.debian.org/debian buster InRelease [121 kB]
Get:2 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:3 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:4 http://deb.debian.org/debian buster/main amd64 Packages [7907 kB]
Get:5 http://security.debian.org/debian-security buster/updates/main amd64 Packages [260 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7860 B]
Fetched 8414 kB in 1s (6516 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following package was automatically installed and is no longer required:
  lsb-base
Use 'apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Removing intermediate container a714759d79bb
 ---> bc4b7370dc31
Step 3/4 : COPY --from=composer /usr/bin/composer /usr/bin/composer
latest: Pulling from library/composer
801bfaa63ef2: Already exists
30e209609427: Pull complete
320f26ee9b1c: Pull complete
4612e05a72cf: Pull complete
9b2beae78beb: Pull complete
79c03e12047a: Pull complete
51393fef6543: Pull complete
5571c1cd7f43: Pull complete
65564f077fec: Pull complete
d65380960587: Pull complete
925a16b14f98: Pull complete
b5b77b9b221e: Pull complete
5f53c0c9d3ed: Pull complete
555ce7422600: Pull complete
312d42e4a2ef: Pull complete
Digest: sha256:dd50f470e49d0b3ab9efe556dec5a8485703629ba7128e0f56c196d166f734f0
Status: Downloaded newer image for composer:latest
 ---> 8a9435afb5dd
Step 4/4 : WORKDIR /var/www/html
 ---> Running in 466504abae53
Removing intermediate container 466504abae53
 ---> 764db2ea70ec

Successfully built 764db2ea70ec
Successfully tagged lalabel_host:latest

では起動

PS C:\Workspace\PHP\lalabel> docker-compose up -d
Creating lalabel_host_1 ... donedoc
PS C:\Workspace\PHP\laravel> docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS      NAMES
bda1c00994e0   laravel_host   "docker-php-entrypoi…"   14 seconds ago   Up 13 seconds   9000/tcp   laravel_host_1
PS C:\Workspace\PHP\laravel> 

ではログインしてプロジェクト立ち上げますか

root@2743ff93f2f3:~/codes# composer create-project laravel/laravel example-app
Creating a "laravel/laravel" project at "./example-app"
Installing laravel/laravel (v8.5.7)
  - Downloading laravel/laravel (v8.5.7)
  - Installing laravel/laravel (v8.5.7): Extracting archive
Created project in /root/codes/example-app
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies
Lock file operations: 105 installs, 0 updates, 0 removals
  - Locking asm89/stack-cors (v2.0.2)
  - Locking brick/math (0.9.1)
  - Locking dnoegel/php-xdg-base-dir (v0.1.1)
  - Locking doctrine/inflector (2.0.3)
  - Locking doctrine/instantiator (1.4.0)
  - Locking doctrine/lexer (1.2.1)

...中略...

  - Installing phar-io/version (3.0.4): Extracting archive
  - Installing phar-io/manifest (2.0.1): Extracting archive
  - Installing myclabs/deep-copy (1.10.2): Extracting archive
  - Installing phpunit/phpunit (9.5.0): Extracting archive
77 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
73 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan key:generate --ansi
Application key set successfully.

するとローカルディレクトリは f:id:white-azalea:20210113094637p:plain

よっしこれで開発が始められる…

Raspberry Pi 4 で LED + スイッチ点灯

基本から行くべきだよねってことでやってみた。
作ったのはこいつ

f:id:white-azalea:20210106201344j:plainf:id:white-azalea:20210106201333j:plain

スイッチで LED の On/Off するだけの実装です。

ラズパイの IO

これは公式に落ちているものを拝借する。

gpiozero.readthedocs.io

f:id:white-azalea:20210106202109p:plain

使用しているライブラリはこれなので、まずはこのレイアウトを印刷して横に置いときながら組み立てます。
実装は大きく分けて2つ。

  1. スイッチの入力を受け付ける実装
  2. LED のOnOff通電する実装

という2つを考えます。

スイッチ入力を受け付ける実装

回路図をきれいに書くツールとか持ってないので、そこんとこ宜しく

f:id:white-azalea:20210106204137p:plain

ということで、3.3V 出力(ピン番号1)から出力して、スイッチ→抵抗を挟んで GND に帰ります。
スイッチを入れたときに抵抗を挟むのは、ショート(短絡)するとラブパイぶっ壊れるかもしれんので…

で、途中から GPIO 27 に分岐してますが、これをプログラムで拾います。

LED の On/Off する実装

こっちはもっと楽

f:id:white-azalea:20210106205231p:plain

こっちは IO ポートから電流を流すか Off るかだけの制御なので、楽勝。
LED はコレ。

akizukidenshi.com

GPIO はデフォ 3.3V で、330Ω 抵抗なら 0.01A = 10mA 以下になると思われ。

コード実装: スイッチ押してる間だけ光る

といってもさして難しい事はしていません。

# GPIO と sleep 関数の読み込み
import RPi.GPIO as GPIO
from time import sleep

SWITCH_INPUT = 27  # スイッチ入力で使用するポート番号の指定
LED_OUT = 25             # LED 向け出力で利用するポート番号の指定

# GPIO の初期化
# GPIO.BOARD: 物理ピン番号(左上からの連番)
# GPIO.BCM: 役割ピン番号(broadcomが命名しているもの)今回はこっち採用
GPIO.setmode(GPIO.BCM)

# LED_OUT はあくまでアウトプット利用
GPIO.setup(LED_OUT, GPIO.OUT)

# Switch_input は入力用に IN 指定
GPIO.setup(SWITCH_INPUT, GPIO.IN)

try:
    # 無限ループ
    while True:

        # スイッチが High になったらLEDに給電
        if GPIO.input(SWITCH_INPUT) == GPIO.HIGH:
            GPIO.output(LED_OUT, GPIO.HIGH)

        # スイッチ押してない場合は、LED に給電しない
        else:
            GPIO.output(LED_OUT, GPIO.LOW)

        sleep(0.01)  # ループに休憩入れる(入れないとCPUがビジー状態になりえる)

except KeyboardInterrupt:
    # Ctrl+C で終了したときの処理。要するに終了命令やね
    pass

# 終了前にデバイス開放(しないと色々問題になる)
GPIO.cleanup()

コードよりコメント書くほうが疲れたわ(汗
わかりやすい感じですね

コード実装: スイッチの Toggle 実装

今度は、スイッチを押されたタイミングをイベントで拾う方法。
写真はこれで撮った

import RPi.GPIO as GPIO
from time import sleep

SWITCH_INPUT = 27
LED_OUT = 25


# LED の状態設定
isLedStateOn = False

# イベントコールバック
def switch_callback(channel):
    global ledState
    if channel == SWITCH_INPUT:
        isLedStateOn = not isLedStateOn
        if isLedStateOn:
            GPIO.output(LED_OUT, GPIO.HIGH)
        else:
            GPIO.output(LED_OUT, GPIO.LOW)


GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_OUT, GPIO.OUT, initial = GPIO.LOW)

# プルアップダウンの組み込み抵抗を設定できる。
# これを入れると、スイッチ側の抵抗と GND が不要になる(別に取らなくても良いといえば良い)
GPIO.setup(SWITCH_INPUT, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

# SWITCH_INPUT の入力が入った(GPIO.RISING Low -> High となった)ら、switch_callback を呼ぶべし。
# なお、物理的にはスイッチ変動の瞬間に On/Off が前後するので、一度イベントを検出したら、200ms は待機する
GPIO.add_event_detect(SWITCH_INPUT, GPIO.RISING, callback=switch_callback, bouncetime = 200) 

# イベント式に変わったので、ループ処理はあくまで終了まで待機する扱い
try:
    while True:
        sleep(0.01)
except KeyboardInterrupt:
    pass

GPIO.cleanup()

Raspberry pi 4 をSSID隠蔽した無線 LAN に接続する

うん、自宅の設定がそもそも SSID 隠蔽だからねぇ(汗

ということでやってみた記録。

接続設定を作成する

pi@raspberrypi:~ $ wpa_passphrase "ssid_name" "password"
network={
    ssid="ssid_name"
    #psk="password"
    psk=16c384515e2eb5bad36a7bd4057ffd7987f9ee248c2a9c44c16bcf74077abc51
}

設定にハッシュ化もしてない値を保存できないので、こんなコマンドでパスフレーズを生成します。
実にわかりやすいこって

設定を記載

無線LAN設定はここに記載されてます

pi@raspberrypi:~ $ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf 

ここを開くと色々出てくるので、こんなふうに記述しましょう

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
    ssid="ssid_name"
    #psk="password"
    psk=16c384515e2eb5bad36a7bd4057ffd7987f9ee248c2a9c44c16bcf74077abc51
        scan_ssid=1
}
~

scan_ssid=1 を記述することで、隠れた SSID でも接続を試行してくれます。

ここまで書いたら reboot で再起動して OK

プログラム入門書で毎回「足りないなぁ」と思った事

脳トレパズル本 プログラマを育てる脳トレパズル 遊んでおぼえるPythonプログラミング&アルゴリズム を読んで、最初の課題が三目並べなのだけど、毎回入門書に足りないものがあるんじゃまいかと思うことがあったので、じゃぁ「職業エンジニアとして考えるならどういう開発スキルが要るのか?」をコンセプトに考えてみた。

テストの観点

この点は若干の本には記載がある。おそらく第二言語として学ぶ人を前提にしてる場合は書いてある。
しかし多くの入門書ではテストを書くこと自体が扱われていない。

しかし、プログラマーを目指す人のための入門書には是非ほしい。

本のコンセプト上入れるべきでないケースもあるだろう。
あくまで自動化をさせる目的の 退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング や、 プログラマを育てる脳トレパズル 遊んでおぼえるPythonプログラミング&アルゴリズムITエンジニアがときめく自動化の魔法~仕事を効率化したくなる自動化テクニック~ なんかでやる必要はないかもしれない。

とはいえ、実際問題テストというのは作りの確認作業なので、問題の早期発見には必須項目だ。

まずは作れるようになることが先決というのはわかる。
しかし実務の観点で見れば、保守の過程で修正し、変更が入る。既存の処理に影響を与えないためにもテストは必要だ。

ならテストコードは処理の仕様が変化していないことを確認(リグレッションテスト)できる最も簡単な手段でもある。

可読性の観点

この項目も欠けがちだ。
むしろ、実装系技術書全般で足りていない。

別に言語仕様と直接的に結びつく問題ではない。ならばコラム的に説明を入れることは可能なハズだと思う。

強いて書籍時の問題を挙げるなら、変数名が長くなる。尺や改行を踏まえると問題になることはわかるが…むしろ初心者にこそ叩き込んでおきたいと思うのは私だけだろうか?

可読性の観点はいくつもあるので、すべてを説明することは不可能だろう。感性の問題もあるので、深くは立ち入れないかもしれない。
しかし、名称の付け方、説明変数などのテクニックはどの言語においてもほぼ共通する内容のハズだ。

実務上では、常にコードを読む。なぜならここを修正したらどこに影響するのか?これは何をするものなのか?その速度はすなわちコードの修正、変更時間に直結する。
読みやすさに対する最小限の記述はすべきだ。

というかアルゴリズム系の本は、数学者的なセンスで書かれてることが多いので、変数名が数学的記号に合わせがちになる。
すると、説明もなく変数が名数学してると、数学してる人にしか読みにくい実装となっていて、本来知りたいと思っている層のエンジニアには読みにくいものではなかろうか?
エンジニア脳なら 「数式<=コード」で実装を理解する人が多いので、その点は本当に困る。

メソッド分離、クラス分離の考え方

これも実装系技術書全般で足りていない様に思う。

SOLID 原則まで紹介しろとは思いません。
役割、目的ごとに分割する考え方はやはり必要な気がします。

アプリケーション実装系、複雑なアルゴリズム(AIとか)の実装系本でこれが全くされてないと発狂しそうになる…。
1メソッドで 50 行とか書いてある入門書を見ると正直レビューに☆1(むしろマイナス)をつけたくなります。
「動けばいい」じゃねーんだよ! …すまない、ヒートアップした。

だが、思うことはそういう事だ…特に入門書である場合、初心者が学ぶ過程で、クッソ汚いコードを書く癖を残してほしくはないものである。

確かに!下手な入門書より面白い「プログラマを育てる脳トレパズル」

最近読んだのでレビューを。
入門書じみてるのにワクテカがとまらんw

この入門書のポイント

  • Good
    • 発想をコードに落とす実装力が身につく : あくまでゲームとパズルを解くのが中心
    • 課題に対して解決を考える基礎力がつく : プログラミングの考え方を中心に据えているので、「入門書やったけど、これで何ができるかわからない」がない
  • Weak
    • 逆に言語仕様の深い話はしない : GUI とか 3D とかやりたくなったら、ライブラリは別途調べる必要がある

という、非常にアルゴリズム寄りな内容。
むしろ小学校でのプログラミング教育に突っ込みたい内容だ。

ただし文章などを含むと、独力で読むには最低中学生、高校生以上が望ましい文章だと思う。
逆を言えば家庭であれば親が一緒になってやるには丁度いい難易度。

ターゲット層

多分この本が狙ってるターゲット層はこんな感じだろう。

  • 何らかのプログラミングの入門書やったけど「これで何ができるんだろう?」という人
  • 言語仕様説明系の入門書読んで混乱した人。写経系入門書読んで意味不明とブチ切れた人
  • プログラミング初心者(年齢的には、高校生以上。頑張れば中学生でも読めないことはない)可能。
  • プログラマー就職してからプログラム言語を触ったけど、自分で実装設計できない人

所感

続きを読む

Chrome は実は裏で色々できる

Google Chrome は実はコマンドラインから色々できるという話です。
事の起こりは、Selenium でブラウザ起動もせずスクショが取れたことから。

で、調べて見たら出るわ出るわ…

ブラウザ表示せずスクショを取るあれこれ

ということで早速やってみる。
--headless --print-to-pdf (URL) を指定すると、

 % /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --headless --print-to-pdf https://white-azalea.hatenablog.jp/
[1223/205258.121603:ERROR:xattr.cc(63)] setxattr org.chromium.crashpad.database.initialized on file /var/folders/c6/_s3qbf0x5qg5fxfdhm__hp_40000gn/T/: Operation not permitted (1)
[1223/205258.122462:ERROR:file_io.cc(90)] ReadExactly: expected 8, observed 0
[1223/205258.123082:ERROR:xattr.cc(63)] setxattr org.chromium.crashpad.database.initialized on file /var/folders/c6/_s3qbf0x5qg5fxfdhm__hp_40000gn/T/: Operation not permitted (1)
[1223/205258.476157:ERROR:command_buffer_proxy_impl.cc(122)] ContextResult::kTransientFailure: Failed to send GpuChannelMsg_CreateCommandBuffer.
[1223/205305.595811:INFO:headless_shell.cc(616)] Written to file output.pdf.

こんなログが流れるが

% ls -l
total 16224
-rw-------@ 1 armeria  staff  8305469 12 23 20:53 output.pdf

マジか!?

% /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --headless --screenshot https://white-azalea.hatenablog.jp/
[1223/205945.105995:ERROR:xattr.cc(63)] setxattr org.chromium.crashpad.database.initialized on file /var/folders/c6/_s3qbf0x5qg5fxfdhm__hp_40000gn/T/: Operation not permitted (1)
[1223/205945.107835:ERROR:file_io.cc(90)] ReadExactly: expected 8, observed 0
[1223/205945.109470:ERROR:xattr.cc(63)] setxattr org.chromium.crashpad.database.initialized on file /var/folders/c6/_s3qbf0x5qg5fxfdhm__hp_40000gn/T/: Operation not permitted (1)
[1223/205945.475913:ERROR:command_buffer_proxy_impl.cc(122)] ContextResult::kTransientFailure: Failed to send GpuChannelMsg_CreateCommandBuffer.
[1223/205949.235907:INFO:headless_shell.cc(616)] Written to file screenshot.png.

f:id:white-azalea:20201223210042p:plain

参考

developers.google.com