レガシー環境から脱却したい

プログラミングや環境構築の話をまとめています。

Surface Pro 7からケーブル1本でトリプルディスプレイに挑戦

f:id:odaryo:20210427004910j:plain

最近、自宅の開発環境をトリプルディスプレイにしました。
(といっても半年ほど前ですが)

広い画面は良いですね。
いろんなウィンドウを表示したまま作業ができるので、仕事してる気になれますコーディングが捗ります。

また、現在メイン機として愛用している Surface Pro 7 にはUSB Type-Cポートが実装されています。
そこで、USB Type-Cケーブル1本でできるトリプルディスプレイ環境を構築しました。

はじめに

プログラミングを行うなら画面は(インチ数も解像度も)大きいほうが良いです。
(PC1台で、ワークスペースやウィンドウを切り替えながら作業できる方もいらっしゃいますが、私は脳が追いつきません。)

また、PCを持ち出したときなど、家に帰った際に「HDMI↔USB Type-Cケーブル」「電源ケーブル」「USB-HUB」などをつなぎ直すのも面倒です。

そこで、画面を広く使えて、ケーブル1本の抜き差しで接続できる環境を模索しました。

検討する条件

今回トリプルディスプレイを構築するにあたって、条件としたもの。

  1. ディスプレイ解像度は縦1200px以上(IDEで19pt、50行が無理なく目視できる大きさ)
  2. 横にウィンドウ3つは並べたい(IDE、ブラウザ、ターミナル)
  3. 机の大きさ的に24インチx2が限界
  4. 給電含めてケーブル1本で接続したい。←重要

その他

  • ディスプレイは1台持っている。(使わなくてもOK)

買ったもの

USB Type-C接続&デイジーチェーンなディスプレイを新規に購入しました。

japancatalog.dell.com

他の候補として、Surface Dockや

USB Type-C接続のウルトラワイドディスプレイ

も検討したのですが、予算的な問題で却下しました。

また、購入時にちょうどDELLがセールしていたのもポイントでした。

デイジーチェーンって?

ここで、今回選択したディスプレイに備わっているデイジーチェーンについて。

1台のディスプレイにPCを接続すると、下記の説明のように1台の入力で数珠つなぎ式に複数台に出力できます。

参考:デイジーチェーン対応モニターの導入ガイド | EIZO株式会社

今回購入したディスプレイは、 PC ↔ ディスプレイ間の接続にはUSB Type-Cを使い、ディスプレイ ↔ ディスプレイの接続にはディスプレイケーブルを利用します。

今回の構成

最終的に下記の構成となりました。

3枚のディスプレイをこんな感じで配置して作業しています。

ディスプレイの配置

画面配置

ウィンドウの配置例

ウィンドウ配置

①:確認用ブラウザ(Google Chrome
②:IDEIntelliJ IDEA)
③:ターミナル(Windows Terminal)
④:メール、チャットなど

②は、IDEを左右に分割した状態でディスプレイの真ん中に設置して、枠がちょうど真ん中に来るように配置しています。

おわりに

作業環境をトリプルディスプレイ化対応しました。
しかも、USB Type-C1本でPCとつなげるので、抜き差しも楽です。
机の上もスッキリします。

また、IDEを真ん中に置くと使い勝手がすごく良いので、 UWQHD(3,440 x 1,440)や DQHD(5,120 x 1,440)も試したいなという欲求がうまれました。

おまけ

今回の構成での懸念点は、Type-Cケーブルを指している間は常時給電中だということ。
バッテリーをフル充電状態で、更に充電しながら使うと劣化が早い(らしい)です。
もちろん、外すとディスプレイ出力が止まるので、満充電になったらケーブルを外すといった運用はできません。

ですので、SurfaceProをバッテーリー制限モードにしています。(「キオスクモード」とも呼ぶらしい)

下記のSurfacePro4と同じ設定でいけます。 docs.microsoft.com

バッテーリーの最大充電容量が50%までに制限されるので、バッテリーの寿命を延ばすことができます。
(未来のバッテリー消耗を危惧して今のバッテリー容量を半減させるのは本末転倒な気もする。)

サポート完全終了のCentOS6とPHP5.6の開発環境をDockerで作成する

f:id:odaryo:20200901175341p:plain

はじめに

2020年11月30日をもちまして、延長サポートを含めたCentOS 6系のすべてのサポートが終了しました。

しかしながら、社内システムなどまだまだ現役の環境はあると思いますし、
リプレース案件の確認作業のために同バージョンの開発環境が欲しいといった要望もあるかと思います。

今回、CentOS6.9で動いているシステムを保守する必要があり、過去に作った開発環境をDockerで動かそうとしたところ「yum install」でこけました。
yumリポジトリなどがすべてアーカイブに移動しているため、デフォルトのままだとリポジトリが見つからずにエラーとなるようです。

そこで、本日はDockerを使ってCentOS6.9環境を構築する方法をまとめます。

Dockerfileについて

実行環境

Dockerで構築する環境

  • CentOS6.9
  • PHP5.6
  • Apache2.2

動いたときのDockerfileはこちらになります。

FROM centos:6.9

ENV PHP_VERSION 5.6.40

RUN sed -i "s|#baseurl=|baseurl=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|http://mirror\.centos\.org/centos/\$releasever|http://vault\.centos\.org/centos/6.9|g" /etc/yum.repos.d/CentOS-Base.repo

RUN rpm -Uvh https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && \
    rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

RUN yum install -y --enablerepo=remi --enablerepo=remi-php56 \
        php \
        php-devel \
        php-mbstring \
        php-pdo \
        php-gd \
        php-xml \
        php-mcrypt \
        php-mysql \
        php-pear \
        php-xdebug \
        php-pecl-xdebug \
    && yum install -y \
        zip \
        unzip \
        httpd \
        gcc

RUN yum clean all

CMD ["/usr/sbin/apachectl","-DFOREGROUND"]

CentOS6.9環境用に作ったものなので、ほかのバージョンにする場合は6.9の記述を変更してください。
PHPモジュールの記述は環境に合わせて修正してください。

変更点

CentOS-Base.repoを修正

yumリポジトリアーカイブされているので、参照先を書き換えます。

RUN sed -i "s|#baseurl=|baseurl=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|mirrorlist=|#mirrorlist=|g" /etc/yum.repos.d/CentOS-Base.repo \
  && sed -i "s|http://mirror\.centos\.org/centos/\$releasever|http://vault\.centos\.org/centos/6.9|g" /etc/yum.repos.d/CentOS-Base.repo

② PHP5.6をインストールするためのEPELリポジトリを修正

CentOSに標準搭載以外のバージョンのPHPをインストールする場合は、EPEL、REMIリポジトリの設定が必要になります。

EPELリポジトリアーカイブされているため、URLをアーカイブ先に設定します。
REMIレポジトリはそのままで良いみたいです。

RUN rpm -Uvh https://archives.fedoraproject.org/pub/archive/epel/6/x86_64/epel-release-6-8.noarch.rpm && \
    rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

デフォルト設定の場合のエラーについて

Yumリポジトリが見つからない場合のエラー

CentOS-Base.repoを修正すると直ります。

Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again
YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
 Eg. Invalid release/repo/arch combination/
removing mirrorlist with no valid mirrors: /var/cache/yum/x86_64/6/base/mirrorlist.txt

② EPELリポジトリの設定を変えていなかった場合のエラー(アーカイブ前のURLを指定した場合)

curl: (22) The requested URL returned error: 403 Forbidden
error: skipping https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm - transfer failed
Retrieving https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm

EC-CUBE4のSQLで特定のIDの商品を先頭に表示したい場合の書き方

はじめに

EC-CUBEのカスタマイズ案件の中で、「商品一覧の先頭に指定した商品を指定した順に表示させる」という要望がありました。

MySQLだと慣れているので問題ないのですが、
EC-CUBE4ではSQLではなくDoctrineのDQLのため、作法が違う部分がいくつかあります。

そこで、EC-CUBEでうまくいった方法をまとめます。

対象環境

  • MySQL8
  • EC-CUBE4

やりたいこと

仕様

  • IDを指定した場合、その商品を先頭に持ってくる
    • IDは複数指定可能
  • IDを指定していない商品は、指定した商品の後にID順に並べる

次のようなデータがあった場合

id name
1 いちご
2 りんご
3 バナナ
4 メロン
5 すいか

ID [4, 2] を指定して、こう表示させたい

id name
4 メロン
2 りんご
1 いちご
3 バナナ
5 すいか

MySQLでのやり方

① order by句で直接指定

SELECT *
FROM table
ORDER BY id = '4' DESC, id = '2' DESC, id;

② FIELD関数を利用する

FIELD関数は知らなかったのですが、このやり方でもできるようです。
(本仕様を満たすにはIDを逆順に指定する必要があるので気持ち悪いですが)

SELECT *
FROM table
ORDER BY FIELD(id, '2', '4') DESC, id;

EC-CUBE(Doctrine)での問題

EC-CUBEのクエリビルダで上記のSQLを書こうとしたら、うまくいきませんでした。

① order by句で直接指定

orderBy関数にはカラム名しか指定できないためエラーとなる

例:

...
  ->orderBy('id = 4', 'DESC')    // <- error!
  ->addOrderBy('id = 2', 'DESC')  // <- error!
  ->addOrderBy('id')

(※変数のエスケープ処理はひとまず無視)

② FIELD関数を利用する方法

DoctrineにMySQL関数が実装されていないため使えません。

DoctrineExtensionsというものを入れると使えるようです。

参考

ですが、今回はデフォルトの機能で再現する方法を紹介します。

解決方法

CASE文を使って、条件に合致する要素を先頭に持ってくるように設定しました。

sort専用のパラメータを新しく作って、それを基準に並べ替えています。

$qb = $this->createQueryBuilder('p')
  ->addSelect('CASE WHEN p.id = 4 THEN 1 ELSE 0 END as HIDDEN sort_id1')
  ->addSelect('CASE WHEN p.id = 2 THEN 1 ELSE 0 END as HIDDEN sort_id2')
  ->orderBy('sort_id1', 'DESC')
  ->addOrderBy('sort_id2', 'DESC')
  ->addOrderBy('p.id');

$result = $qb->getQuery()->getResult();

結果

id name
4 メロン
2 りんご
1 いちご
3 バナナ
5 すいか

また、HIDDENキーワードを使った要素は取得結果に含まれないので、ソートの為に作った要素が取得オブジェクトには入らずすっきりします。

終わりに

素のSQLなら簡単にできることでもORMをかますと工夫が必要なことがあります。 複雑になってくるとSQLを直接書いたほうが早いこともありますが、可能ならORMの機能を生かすほうが良いですね。

EC-CUBE4(というかDoctrine)にまだ慣れていないので他に良い方法があるかもしれません。

Nuxt.jsで「Cannot read property '_normalized' of undefined」エラーが出た

f:id:odaryo:20200901175501p:plain

Nuxt.jsで静的サイトを作っていたときに、下記エラーが出るようになりました。

[error]  /blog

TypeError: Cannot read property '_normalized' of undefined
    at normalizeLocation (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:971:12)
    at VueRouter.resolve (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:3015:18)
    at a.render (/opt/build/repo/front/node_modules/vue-router/dist/vue-router.common.js:1062:22)
    at a.t._render (/opt/build/repo/front/node_modules/vue/dist/vue.runtime.common.prod.js:6:35273)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70637
    at Yi (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:67201)
    at io (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70613)
    at ro (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:70244)
    at _t.eo [as renderNode] (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:67491)
    at _t.next (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:20507)
    at n (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:18719)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68602
    at _t.eo [as renderNode] (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68610)
    at _t.next (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:20507)
    at n (/opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:18719)
    at /opt/build/repo/front/node_modules/vue-server-renderer/build.prod.js:1:68602

開発環境のyarn devでは出ず、本番用ビルドのyarn generateで発生。

原因

nuxt-linkの内容がundefinedだったため。

例:

<nuxt-link :to='link'>リンク</nuxt-link>

↑のようなコードでlink変数がundefinedとなっていました。

開発環境でSSRで動いているときはデータを都度取得していたのに対し、 静的ビルドのときはpayloadで予めデータを取得していました。 そのpayloadの書き方がまずく、データが取れていなかったのが原因でした。

分かってみれば簡単なことですが、
1行目のTypeError: Cannot read property '_normalized' of undefinedだけ読んでも意味不明。 内容にvue-routerの記載があるのでルーティング周りかなと思ったものの、場所がわからずなかなか特定できませんでした。

UbuntuへIntellij IDEAをインストールする

はじめに

Ubuntuへインストールする方法のメモ

ほかにスマートなやり方はあると思いますが、とりあえずできた方法をメモします。
Intellij IDEA以外のJetbrain製品も手順は同じだと思いますので、参考になるかと思います。

①ダウンロード

ダウンロードページからtar.gzファイルをダウンロードします。

www.jetbrains.com

②インストール

/opt/ideaにインストールして、コマンドで実行できるように/usr/local/binシンボリックリンクを張ります。

$ sudo mkdir /opt/idea && sudo tar xfz ideaIU-*.tar.gz -C /opt/idea --strip-components 1
$ sudo ln -s /opt/idea/bin/idea.sh /usr/local/bin/idea

下記のように起動できます。

$ idea

ちなみに、tarの-C--strip-componentsオプションの意味はこちらが参考になります。

kakakakakku.hatenablog.com

Dockerでファイルのパーミッションをホストユーザと合わせる方法

f:id:odaryo:20200901175341p:plain

はじめに

最近WSL2にDockerをインストールして、WSL2内でコーディングをするような環境を構築しました。
その環境でDocker経由でファイルを作成するとパーミッションエラーが起こったためその解決方法をまとめます。

※WSL2にインストールしたDockerにて動作確認はしておりますが、Docker for WSL2では未検証です。

原因

Linux系のホストからDockerにボリュームをマウントするとホスト側から編集できなくなることがあります。
これはホストのユーザとDockerコンテナ内のユーザIDが異なるためパーミッションエラーとなるためです。

対処方法は、ホストとコンテナ内のユーザIDを合わせることです。

解決策

/etc/passwdと/etc/groupをDockerコンテナにマウントする

やり方は下記の記事を参考にしています。

qiita.com

docker-compose.ymlで/etc/passwdと/etc/groupをマウント
コンテナ内で勝手に書き換えないようにro(read only)オプションをつけています。

version: '3'

services:
  nginx:
    build:
      context: ./
      dockerfile: ./docker/nginx/Dockerfile
    ports:
      - 8080:80
    volumes:
      - ./app/public:/app/public:cached

  php-fpm:
    build:
      context: ./
      dockerfile: ./docker/php-fpm/Dockerfile
    volumes:
      - ./app:/app:cached
      - /etc/passwd:/etc/passwd:ro
      - /etc/group:/etc/group:ro

※Dockerfileの詳細は割愛します。

起動コマンド

コンテナを実行するときにユーザIDを指定してやることで、そのユーザと同じUIDでコンテナを操作できます。

# コンテナ起動済みの場合の例
$ docker-compose exec -u $(id -u $USER) nginx /bin/bash

# コンテナ未起動の場合
$ docker-compose run --rm -u $(id -u $USER) nginx /bin/bash

コマンドが長いので、.bashrcなどでエイリアスを設定しておくと良いかも。

$ cat .bashrc

...
alias doce='docker-compose exec -u $(id -u $USER)'
alias docr='docker-compose run --rm -u $(id -u $USER)'
...

まとめ

Windows側のエディタでファイルを編集する場合はWSL側のパーミッションは無視できますが、
WSL2側でファイル操作しようと思うとパーミッションも考慮する必要が出てきます。

気を付けよう。

UbuntuへHugoをインストール

f:id:odaryo:20200901174711p:plain

はじめに

公式のページに情報はありますが、Linux版はHomuBrewでの方法しか書かれていなかったため、バイナリからインストールしました。

gohugo.io

インストール手順

下記リンク先より、Hugoの最新バイナリを取得します。

github.com

scssのコンパイルもしたかったので、extendedバージョンをダウンロードします。(2020/07/24更新)

$ wget https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_extended_0.74.3_Linux-64bit.deb

Ubuntuではdebパッケージもaptでインストールできるので、管理しやすいようにaptで行います。

$ sudo apt install hugo_extended_0.73.0_Linux-64bit.deb

インストールされたことを確認する

$ hugo version
Hugo Static Site Generator v0.73.0-428907CC/extended linux/amd64 BuildDate: 2020-06-23T16:40:09Z

以上