GitHubのソースコードをSourceTreeでcloneしようとしたらエラーが出た話

何をしたか

GitHub用の秘密鍵を別PCに持ってきてSourceTreeでcloneしようとしたら、リポジトリが認識されなかった。

 

こういう感じのエラーが出る

The server's host key is not cached. You have no guarantee that the server is the computer you think it is.

 

If you trust this host, enter "y" to add the key to PuTTY's cache and carry on connecting. If you want to carry on connecting just once, without adding the key to the cache, enter "n". If you do not trust this host, press Return to abandon the connection. Store key in cache? (y/n, Return cancels connection, i for more info) fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.

SSHでknown_hostsに記録を残すように、PuTTYも同様のしくみを持っているそうで。

当然SourceTreeでyを押せるわけではないので、そこでエラーになるらしい。

 

解決法

初めてGitHub秘密鍵を使って接続する場合は、SourceTree内蔵PuTTYplink.exeを使ってyを押すと解決する。

plinkの正確な場所は、スタートメニューなどからSourceTreeを右クリックして「ファイルの場所を開く」で開いて、ショートカットのプロパティを開いた時の「作業フォルダー」から探した方がよい

"作業フォルダーのパス\tools\putty\plink.exe" -ssh -C -i "秘密鍵のパス" git@github.com

ここでyを押して、GitHubからHi!って挨拶されればOK。

もう一度SourceTreeを操作すれば、リポジトリタイプがGitとして認識されるはず。

 

参考:

サーバが移転した場合は下記が参考になりそう。

Flutter環境構築

環境構築

Flutter本体をダウンロード

https://docs.flutter.dev/get-started/install/windows

 

ZIPを解凍し、適当なところに置く。

環境変数PATHにflutter/binのファイルパスを指定。

flutter doctorをコマンドラインで実行して開発環境が整っているかチェック。

 

Android Studioとかが入ってない場合は↓

noitalog.tokyo

Android Studioをインストール

Android StudioからSDK Managerを選択するか、プロジェクトを作成したのならTools > SDK Manager

SDK ToolsからAndroid SDK Command-line Toolsにチェックを入れてApply。ダウンロードが完了すればOK

flutter doctorを実行してエラーが解消されればOK

 

 

パッケージの導入

プロジェクトまでcdで移動して

flutter pub add パッケージ名

pubspec.yamlにインストールしたパッケージ名とかが入る。composerのcomposer.jsonみたいなやつ。

 

 

アプリ用アイコン

 

 

Play Consoleに出せるアプリを作る

keytoolで鍵を作るが、Flutter単独だと面倒なので、Android Studioの機能を使って鍵を作る。

  • FlutterプロジェクトのandroidディレクトリをAndroid Studioで開く。
  • Build > Generate Signed Bundle or APK
  • Android App Bundleを選択 > Next
  • Create new
  • Key store pathにキーの保存先、PasswordとConfirmに鍵のパスワードを入力。
  • Key項目ではPasswordとConfirm、First and Last Nameを入力。パスワードは一つ前の手順で入力したパスワードと同じにしないといけない。
  • OK
  • Next
  • releaseを選択 > Finish

これで鍵が作成される。

  • flutterプロジェクト/android にkey.propertiesファイルを作成
  • ファイルに以下を追記
    storePassword=鍵のパスワード
    keyPassword=鍵のパスワード
    keyAlias=鍵のエイリアス
    storeFile=鍵のパス
  • flutterプロジェクト/android/app/build.gradleに追記
    android {の前に以下を追加
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
  • buildTypes {の上に以下を追加
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
  • buildTypes.release.signingConfigの設定をdebugからreleaseに変更
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.release
}
}
  • Terminalからflutter build appbundleを実行するとaabファイルが生成される
    生成されたファイルパスはコマンドの結果に出力される
  • aabファイルのバージョンを上げる場合は、pubspec.yamlのversionの+から右を変更する

 

参考:

Laravel JSONB型について

前提

ドキュメントを横断的に見ないとLaravelでDBのJSON/JSONB型に関するまとまった情報はない。なので、この記事を書いている。

DBに保存するならちゃんとカラムを設定するのが王道だが、ちょっとした小さなデータならJSON/JSONB型を検討しても良いとは思う。

PostgreSQLのドキュメントは、JSON/JSONB型について以下のように述べている。

8.14.2. JSONドキュメントの設計

JSONデータは従来のリレーショナルデータモデルよりもかなり柔軟に表現することができます。そのため、要件が変わりやすい環境では説得力があります。 そして、それは同じアプリケーション内で、両方のアプローチが共存し相互に補完することが可能です。 しかし、最大の柔軟性が要求されるアプリケーションのためでもJSONドキュメントには、まだいくらかの固定構造を持つことを推奨します。 構造は(いくつかのビジネスルールを強制することは宣言的に可能であるが)、一般的に強制されないですが、テーブル内の「ドキュメント」(データ)セットをまとめて予測可能な構造にすることで、簡単に問い合わせを記述することができます。

JSONデータはテーブルに格納するとき、他のデータ型と同一の同時実行制御の対象となります。大きな文章を保存することは実行可能ですが、すべての更新が行レベルロックを取得することに留意してください。 更新トランザクション間のロックの競合を減少させるために、管理可能なサイズにJSONドキュメントを制限することを検討してください。 理想的には、JSONドキュメントはビジネス・ルール上、独立して変更することができない単位までデータを分割すべきです。

8.14. JSONデータ型

要約すると巨大なJSONをカラムに格納するより、意味が紐づいている小さなカラムに小分けにした方が効率が良いという事。

小規模でマシンリソースが豊富な環境なら多分気にならないだろうが、大規模であったりリソースが制限されている環境では気をつけたい。

この記事では、特記がない限りテストコードを書いて外部的に挙動を確認している。また、JSONB型で試しているので、JSON型の場合は挙動が違う場合がありうる。

 

基本

'カラム名->キー名'でアクセスする。

キー名はネスト可能。

$users = DB::table('users')
                ->whereJsonContains('options->languages', 'en')
                ->get();

更新も同様。

$affected = DB::table('users')
              ->where('id', 1)
              ->update(['options->enabled' => true]);

 

モデルの設定

$casts

Eloquent:ミューテタ/キャスト 9.x (翻訳中)Laravel

キャストなしだとモデルを新規登録する時とかにPHPの配列/連想配列ではなく、json_encodeでJSONに変換した文字列としてデータを入れる必要がある。

キャストを事前に設定しておくと配列/連想配列を格納可能。

use Illuminate\Database\Eloquent\Casts\AsArrayObject;

protected $casts = [
    'options' => AsArrayObject::class,
];

'options' => 'array'でも大体の場合は問題がないが、

AsArrayObjectにすると以下のような部分的な更新が行える。

$user = User::find(1);
$user->options['key'] = $value;

 

$fillable

Eloquentの準備 9.x (翻訳中)Laravel

/**
 * 複数代入可能な属性
 *
 * @var array
 */
protected $fillable = [
    'options->enabled',
];

上記のように指定した場合、キーは以下のように書かないといけない。

Model::create([

    'options->enabled' =>

]);

下記のような書き方は反映されない

Model::create([

    'options' => [

        'enabled' =>

    ]

]);

下記のように書くとJSONを格納出来るが特定の構造を持つ事は出来ない。

protected $fillable = [
    'options',
];

下記の場合は、カラムの方が優先っぽい。ここら辺の挙動は詳しく調べてないと怖い目にあいそう。

protected $fillable = [
    'options',
  'options->enabled',
];

Model::create([

    'options->enabled' => ['enabled'],

    'options' => ['options'] //こちらが格納される

]);

 

whereによる検索

データベース:クエリビルダ 9.x (翻訳中)Laravel

'options->enabled'でキー名を指定出来るし、ネストも出来るが、メソッドによって挙動が変わる。

EloquentやQueryBuilderでのカラムとキー名の指定は->のみ有効で、SQL演算子として->を使うかどうかはメソッドによって異なる

メソッド名 機能
where

数値、文字列、真偽値を検索可能。

nullは明示的にnullを付けた場合とキーが存在しない場合のnullを区別しない。

'options->enabled'SQL変換時に'options->>enabled'として扱う。キー名は->でネスト可能だが、最後のキーが自動的に->>になる。

通常のwhereと同じでLIKE等使えるが、キーの中身がオブジェクトだった場合JSONに対してLIKEを使う事になるので注意。

例)

以下のJSONを格納している状態で、where('column->key1', 'LIKE', 'key%')を使うと'{ 'key2' : false }'という文字列で曖昧検索を行う

{

    'key1' : { 'key2' : false }

}

whereJsonContains

数値、文字列、真偽値、配列の中身を検索可能。

nullは明示的にnullと指定したものだけを検索できる。

whereとは違い、SQL変換時は最後まで->になる。また、値の存在チェックには専用の演算子(@>)が使用される。

ソースコードを読む限り、PostgreSQLの場合は第二引数をjson_encode()で変換するので、キー名と値の完全一致を取得する場合はPHPの配列を使う必要がある。

また、キー名の存在を確認する?演算子はこのメソッドでは使えない(JSONのWHEREは@>でハードコーディングされている)

例)

以下のJSONを格納している状態で、キーと値の完全一致を検索する場合はwhereJsonContains('column->key1', ['key2'=>false])とするとヒットする。'{"key2":false}'はオブジェクトではなく文字列扱いになるので(そういう文字列を検索したい場合でなければ)意図通りには動かない

{

    'key1' : { 'key2' : false }

}

 

 

Laravelでxdebug + VS Codeを実行出来るようにする

Laravel8でも途中からDockerに関する扱いが変わっているっぽい(要出典)

古い環境の場合、最新のLaravelのソースコードの変更点を見ると解決への道筋がある

  1. (古い環境向け)Dockerfileにphp8.0-xdebugを追加
  2. (古い環境向け)docker-compose.ymlにextra_hostsとXDEBUG_MODE、XDEBUG_CONFIGを追加
  3. (git clone時に実施).envにSAIL_XDEBUG_MODEを追加
    ドキュメントにはSAIL_XDEBUG_CONFIGでIPアドレスを書き換えろと書いてあったり、検索するとhost.docker.internalがWSL2で使えないという記事があるが、Docker Desktopがアップデートされ追加する必要がなくなった
  4. sail up -dでコンテナを立ち上げ
  5. (プロジェクト初回のみ実行)sail artisan sail:publishでdockerディレクトリを生成

(プロジェクト初回のみ実行)docker/バージョン名 のディレクトリにあるphp.iniに以下を追加

[xdebug]
xdebug.mode=debug
xdebug.start_with_request = yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9013
xdebug.discover_client_host = 1

(プロジェクト初回のみ実行)sail build --no-cacheを実行してphp.iniを反映する

VS Codeの左側にある実行とデバッグでlaunch.jsonを生成し、以下を追加

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "hostname": "0.0.0.0",
            "port": 9013,
            "pathMappings": {
                "/var/www/html": "${workspaceRoot}"
            },
            "log": true
        },
    ]
}

VS Codeの実行とデバッグの再生ボタンを押すとデバッグが行える。

うまくいかない時はタブの下に出来るデバッガの操作ボタンの再起動を押す。

 

 

参考:

qiita.com

qiita.com

Docker ComposeでTCP/UDPサーバを立てる

PHPTCPサーバを実装した場合

 

PHP

コードは割愛

以下注意点

  • socket_bindに指定するIPアドレスを0.0.0.0にしないとコンテナ外と通信できない
  • docker compose up用にechoを書いておくと分かりやすい

 

Dockerfile

FROM php:latest

EXPOSE ポート番号

CMD ["php", "スクリプト名.php"]

 

docker-compose.yml

services:

    好きな名前:
        build:
            context: Dockerfileのパス
            dockerfile: Dockerfile
        ports:
            - '23:23' #ポートを指定した場合はここも設定しとく

 

 

 

 

 

 

シェルスクリプトの場合

もっと良い方法はあるかもしれない

基本的にLaravel Sailを参考に以下を書いた

シェルスクリプトとDockerfileを用意し、docker-compose.ymlに設定を追加する

 

コンテナ内部に送って起動時に実行されるシェルスクリプト

必要に応じて-pでポート番号を指定したり、-uでUDPにしたりする

UDPは接続が切れると再接続は出来ないような気がする

#!/bin/sh

while true; do echo "クライアントに返す文字列" | nc -l -k; done

 

Dockerfile

FROM alpine:latest

COPY スクリプト名 /usr/local/bin/スクリプト
RUN chmod +x /usr/local/bin/スクリプト

EXPOSE ポート番号

ENTRYPOINT ["スクリプト名"]

 

docker-compose.yml

services:

    好きな名前:
        build:
            context: Dockerfileのパス
            dockerfile: Dockerfile
        ports:
            - '23:23' #ポートを指定した場合はここも設定しとく

 

TCP/UDPサーバのコンテナにデータが送信できたか確認する

docker exec -it コンテナ名 sh

ps aux #ENTRYPOINTで指定したスクリプトのPIDを確認する

cat /proc/PIDの番号/fd/1

 

Chrome拡張APIメモ(v3)

chrome.alarms.onAlarm.addListener

DevTools起動時は正しく動くが、非起動時に途中から動かない場合がある。

Service Worker起動中は正しく動くが、Service Workerが落ちてイベントリスナー内に拘束された変数があるとエラーになって動かなくなると推測される。

デバッグ

拡張一覧のService WorkerからDevToolsを開き、コンソールで以下を叩くと即座にタイマーのイベントが走る。

chrome.alarms.create('test', {when : Date.now()})

 

chrome.storage.local

基本的な概念

一つのオブジェクトを操作するような感じ。

なので最上位のキーは分割して取得出来る。

ただし{"a":1}を取得しても1が取れるわけではなく、hoge.aという形でアクセスする必要がある。

最上位のキー以下を部分更新は出来ない?

 

参考

chrome extension StorageArea の仕様

なんか落ちる

Promiseを使って非同期で更新中に参照すると落ちるっぽい?

更新が終わった後に次の処理をすれば問題なく動作する。