2020年のブログの執筆環境

ブログの環境について書いていた人がいたので、自分の環境も書いてみることにした。書いてみたがあまり書くことがなかった。

swfz.hatenablog.com yoshitaku-jp.hatenablog.com

エディタ

Emacsを惰性で使っている。特筆することはなくmarkdownを書いているだけ。

emacs

保存場所

これもテキトーなディレクトリに置いているだけ。~/up とかそのあたりに。 基本的に書き溜めなどはせず、その日書いてその場で投稿と言う感じ。例などもその場で考えて書くので、あまり練られていない例になっている部分はある。

投稿方法

自作のスクリプトはてなブログにアップロードしている。

github.com

# 新規投稿
$ shosai hatena push <file name> --publish

などとすると、はてなブログに投稿される。ファイル名をkeyに管理されているので、更新したい場合はもう一度実行し得たげれば良い。

また、自分は誤字脱字が多い。一度投稿したあとに数回程度記事を更新している気がする。更新の度にweb UIなどで操作はしたくはないので、CLIで更新ができるという要件は執筆環境として必須だった。

# 更新
$ shosai hatena push <file name> --publish

特筆する点があるとすると、画像アップロードに対応している点。ローカルの ![description](path) を見て、いい感じにはてなフォトライフにアップロードされる。指定したmarkdownファイル自体の該当箇所もアップロード後のURLに書き換わるので、次回の更新時には特に再アップロードされることはない(今回の記事のエディタの表示画面もそのようにしてアップロードされた)。

こういう箇所が
![emacs](~/Desktop/ScreenShots/20201230xxx.png)

このように
![emacs](https://cdn-ak.f.st-hatena.com/images/fotolife/p/podhmo/20201230/20201230192204.png)

あとはタグはタイトル部分の記述を見ている。以下の様に書いたうちの先頭の[]で囲まれた部分がタグになる。

#[<tag1>][<tag2>]... <title>

内容

昔に記事を書いていたらしい。

pvとかのモニタリング

はてなブログgoogle analyticsを埋め込める機能がある。一応設定はしているがあまり見ていない。 元々備忘録というような体で始めていたので。

追記

書き忘れていたので追記。 記事中に現れるコードのファイルが複数になったときには、なるべくgistにあげるようにしている。これには自作のgoのコマンドを使っている。一番良く使っているのにも関わらず、goを学び始めたときに習作で作ってからあまり手を入れていない。世の中そういうものかもしれない。

github.com

こちらも例によって、新規作成のあとの更新が手軽にできるようになっている。

Githubで今年作ったリポジトリの一覧を出力する

毎年この方法を調べている気がするが、今年はGithub CLIGraphQL APIの呼び出しをサポートしたようなので、コレを使って出力してみることにする1。GraphQL自体を試したい場合には、 https://docs.github.com/en/free-pro-team@latest/graphql/overview/explorer のあたりを参考にして試行錯誤してみれば良い。

利用例は以下のような形。 --paginate をつけると、いい感じに100件以上になったときもページネーションして取ってきてくれる。必要なら引数を渡せる。

$ gh api graphql --paginate -f query='
  query($endCursor: String) {
    viewer {
      repositories(first: 100, after: $endCursor) {
        nodes { nameWithOwner }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
  }
'

このサンプルの例をベースに作ってみる。

createdAtが2020以降のもの

個人的には以下の様なものが欲しい

以下の様なMakefileを作る。フィルタリングは自作のコマンドでやっているが、慣れている人はjqなどでやっても良い。

# query
00:
  gh api graphql --paginate -f query='$(shell cat list-repository.query)' | jq . | tee repositories.json

# filtered
01:
  jqfpy --squash -c '[h.pick("nameWithOwner", "createdAt", d=row) for row in get("data/viewer/repositories/nodes") if not row["isFork"] and not row["isPrivate"] and row["createdAt"].startswith("2020-")]' repositories.json | tee 2020-repositories.json

# setup
setup:
  port install gh # or https://github.com/cli/cli
  pip install jqfpy

list-repositories.queryは以下のようなもの。

query($endCursor: String) {
  viewer {
    repositories(first: 100, after: $endCursor) {
      nodes { nameWithOwner createdAt updatedAt isPrivate isFork }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

ちなみに、これはMakefile故の問題ではあるのだけれど、オプションに渡すqueryを'ではなく"でクォートしようとしてしまうと$endCursorなどが展開されてしまいParseErrorになってしまう。コレでしばらくハマってしまっていた2

今年作られたリポジトリ

そんなわけで今年作ったリポジトリは以下の様なものらしい。それぞれの雑感については別の記事で触れるかもしれない。この記事では触れない。

{"nameWithOwner": "podhmo/cliauth", "createdAt": "2020-01-08T14:08:56Z"}
{"nameWithOwner": "podhmo/minitask", "createdAt": "2020-01-26T08:09:01Z"}
{"nameWithOwner": "podhmo/snatch", "createdAt": "2020-02-01T06:28:14Z"}
{"nameWithOwner": "podhmo/scoop-buckets", "createdAt": "2020-03-13T14:50:54Z"}
{"nameWithOwner": "podhmo/baku", "createdAt": "2020-03-23T16:19:22Z"}
{"nameWithOwner": "podhmo/egoist", "createdAt": "2020-04-21T20:34:34Z"}
{"nameWithOwner": "podhmo/maperr", "createdAt": "2020-05-03T06:47:54Z"}
{"nameWithOwner": "podhmo/typoless", "createdAt": "2020-05-29T21:48:10Z"}
{"nameWithOwner": "podhmo/sheetconf", "createdAt": "2020-07-04T08:22:49Z"}
{"nameWithOwner": "podhmo/startevent", "createdAt": "2020-09-22T14:11:50Z"}
{"nameWithOwner": "podhmo/tenuki", "createdAt": "2020-09-26T23:12:42Z"}
{"nameWithOwner": "podhmo/reflect-openapi", "createdAt": "2020-10-03T05:50:01Z"}
{"nameWithOwner": "podhmo/starlette-dataframe-response", "createdAt": "2020-10-30T16:17:07Z"}
{"nameWithOwner": "podhmo/inflexible", "createdAt": "2020-11-28T21:09:31Z"}

createdAtの他にupdatedAtもあるので、更新日でみたい人はそちらを使えば良い。更新日だとさすがに長くなる。

{"nameWithOwner": "podhmo/emacs-sandbox", "updatedAt": "2020-12-09T07:26:20Z"}
{"nameWithOwner": "podhmo/alchemyjsonschema", "updatedAt": "2020-08-17T13:42:55Z"}
{"nameWithOwner": "podhmo/python-semver", "updatedAt": "2020-11-05T17:19:18Z"}
{"nameWithOwner": "podhmo/miniconfig", "updatedAt": "2020-07-09T19:24:53Z"}
{"nameWithOwner": "podhmo/prestring", "updatedAt": "2020-11-29T20:08:08Z"}
{"nameWithOwner": "podhmo/handofcats", "updatedAt": "2020-07-09T19:18:58Z"}
{"nameWithOwner": "podhmo/individual-sandbox", "updatedAt": "2020-12-26T16:55:55Z"}
{"nameWithOwner": "podhmo/selfish", "updatedAt": "2020-05-30T10:46:06Z"}
{"nameWithOwner": "podhmo/magicalimport", "updatedAt": "2020-02-06T00:48:25Z"}
{"nameWithOwner": "podhmo/dictknife", "updatedAt": "2020-10-05T01:57:29Z"}
{"nameWithOwner": "podhmo/swagger-marshmallow-codegen", "updatedAt": "2020-12-20T21:46:40Z"}
{"nameWithOwner": "podhmo/kamidana", "updatedAt": "2020-03-17T12:41:41Z"}
{"nameWithOwner": "podhmo/moduleknife", "updatedAt": "2020-05-23T15:22:48Z"}
{"nameWithOwner": "podhmo/jqfpy", "updatedAt": "2020-12-29T22:36:40Z"}
{"nameWithOwner": "podhmo/commithistory", "updatedAt": "2020-04-29T09:35:17Z"}
{"nameWithOwner": "podhmo/go-twitter-notififer", "updatedAt": "2020-04-29T08:59:35Z"}
{"nameWithOwner": "podhmo/go-traceable", "updatedAt": "2020-08-27T03:23:49Z"}
{"nameWithOwner": "podhmo/pyinspect", "updatedAt": "2020-02-06T06:29:52Z"}
{"nameWithOwner": "podhmo/shosai", "updatedAt": "2020-01-17T13:15:27Z"}
{"nameWithOwner": "podhmo/pycomment", "updatedAt": "2020-07-04T16:54:44Z"}
{"nameWithOwner": "podhmo/go-webtest", "updatedAt": "2020-12-12T04:06:44Z"}
{"nameWithOwner": "podhmo/lsp-spec-to-openapi-doc", "updatedAt": "2020-08-12T05:03:04Z"}
{"nameWithOwner": "podhmo/pypackage", "updatedAt": "2020-10-31T14:20:45Z"}
{"nameWithOwner": "podhmo/metashape", "updatedAt": "2020-12-26T12:21:52Z"}
{"nameWithOwner": "podhmo/monogusa", "updatedAt": "2020-02-29T15:17:08Z"}
{"nameWithOwner": "podhmo/cliauth", "updatedAt": "2020-01-08T14:09:11Z"}
{"nameWithOwner": "podhmo/minitask", "updatedAt": "2020-02-26T15:26:11Z"}
{"nameWithOwner": "podhmo/snatch", "updatedAt": "2020-02-01T07:07:36Z"}
{"nameWithOwner": "podhmo/scoop-buckets", "updatedAt": "2020-03-13T15:07:18Z"}
{"nameWithOwner": "podhmo/baku", "updatedAt": "2020-03-23T17:07:24Z"}
{"nameWithOwner": "podhmo/egoist", "updatedAt": "2020-10-31T14:44:25Z"}
{"nameWithOwner": "podhmo/maperr", "updatedAt": "2020-05-09T10:11:39Z"}
{"nameWithOwner": "podhmo/typoless", "updatedAt": "2020-05-30T08:34:52Z"}
{"nameWithOwner": "podhmo/sheetconf", "updatedAt": "2020-07-05T20:49:17Z"}
{"nameWithOwner": "podhmo/startevent", "updatedAt": "2020-09-22T15:57:50Z"}
{"nameWithOwner": "podhmo/tenuki", "updatedAt": "2020-09-29T19:24:23Z"}
{"nameWithOwner": "podhmo/reflect-openapi", "updatedAt": "2020-12-26T14:57:03Z"}
{"nameWithOwner": "podhmo/starlette-dataframe-response", "updatedAt": "2020-10-31T14:19:26Z"}
{"nameWithOwner": "podhmo/inflexible", "updatedAt": "2020-12-12T15:03:52Z"}

雑感

こういう取得・整形(フィルタリング)の処理を1ファイルでまとめてしまいたいと言う気持ちもあるし、収集と整形は処理を分けたいと言う気持ちもある。Makefile1つでやってやれないことはないのだけれど、ちょっと複雑になるので結局分けた。

gist


  1. それ以外にもいつの間にかいろいろ機能が増えて便利になっていた

  2. gh: Parse error on ":" (COLON) at [1, 7] というようなエラー。