suguru.dev

バンクーバーで働くエンジニアの備忘録

Perforceのセットアップ for Mac

はじめに

PerforceSubversionのようなバージョン管理システムでbinaryの管理に向いているそうです。今回はp4vというツールとp4というコマンドラインツールを導入したのでそのセットアップ方法について書きます。

p4vのセットアップ

こちらのリンクからmac用のリンクをダウンロードします。

設定はこちらのリンク に沿ってやるだけですが、管理者からServerのアドレスとuser名をいただき入力するだけです。

https://www.perforce.com/perforce/doc.current/manuals/p4v-gs/images/p4v-gs001.png

以上で設定は完了です。

p4vの使い方

ログイン後、始めに差分を取得するためルートディレクトリで右クリックを押しGet Latest Revisionを取得します。 全てのファイルはRead Onlyになっており編集権限がありません。もし編集したい場合はファイルを右クリックでCheck outする必要があります。チェックアウトをすると編集が可能になり、その情報は他のユーザにシェアがされます。編集後、右クリックを押しsubmitすることで他のユーザに変更がシェアされます。 もし差分を見たい場合は、右クリックでDiff Against Have Revisionを押すとp4vdiffが起動し差分を見ることが可能です。

p4のセットアップ

p4vだとマウス操作が多いため、やはりCLIでどうにかしたいところです。そのためp4をインストールします。リンクはこちら

次にパスなどの情報をセットします。 私は.zshrcGithub上で管理しているため、secretな情報を隠すために別ファイルを用意しました。

# ~/.secret.sh
export P4PATH=<server-url>
export P4USER=<user-name>
export P4CLIENT=<workspace-name>
p4 login
# ~/.zshrc
if [ -f $HOME/.secret.sh ]; then
  source $HOME/.secret.sh
fi

上記の.secret.sh.zshrcで読み込み、terminal起動時にp4にログインをしています。これで準備は完了です。

編集したいときは、p4 editを使用することでチェックアウトが可能になります。また他にもいくつかコマンドがあるので試してください。

まとめ

私はgitばかり触っているゆとりですが、少しずつ慣れていこうかなと思っています。 次回はp4 + vimあたりについて書こうと思います。

リンク

Ruby on Railsのセットアップ

はじめに

Rubyデビューしたので初心に戻ってその勉強記録を記して行きたいと思います。

手順は

です。

rbenvのインストール

rbenvは最も有名なバージョン管理ツールらしいので、流行りに乗ってインストールしたいと思います。

…のつもりが、長いことmacを使っていると自ずとrbenvがインストールされていることもあるようで、gem installが通らなかったりしたのでuninstallから始めます。

手順はこちらです。

uninstall? · Issue #148 · rbenv/rbenv · GitHub

$ rm -rf ~/.rbenv
$ brew uninstall rbenv

と、.zshrcからrbenvなる記述を削除しました。

それでは気を取り直してインストールします。

$ brew install rbenv

後は.zshrcに追記します。

$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
$ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.zshrc

Rubyのセットアップ

次にrubyをインストールします。

$ rbenv install 2.4.1

最新版をインストールしたい方はrbenv install -lで最新版をチェックしてください。

rbenv rehash
rbenv global 2.4.1

以上で完了です。

nokogiriのインストール

ここで少しハマったのがmacではnokogiriのインストールをmacのインストレーションに沿ってやらないといけないようなので、別途インストールします。

$ gem update --system
$ xcode-select --install
$ gem install nokogiri

これはmac OS Xというところに記載されています。

Railsのインストール

$ gem install rails

コマンドはこちらだけですね、とても簡単。

アプリの起動

適当なディレクトリに行き、以下のコマンドを叩きます。 チュートリアルに沿って、

$ rails new hello_app
$ cd hello_app
$ rails server

これでhttp://localhost:3000/にアクセスすると以下の画面が表示されます。

f:id:suguru03:20170908081122p:plain

まとめ

とても簡単にRailsサーバが立ち上がりました。

Yay! I'm on Rails!

はい。せっかくなので何かサーバ建てたいですね。

リンク

classの継承についての考察

概要

ES6の継承が遅すぎると話題なので検証・最適化をしました。

どれくらい遅いのか

f:id:suguru03:20170428145927p:plain

こちらベンチマークによると、少しずつ改善は見られるものの、2.3-17倍程度遅い様子です。

実際に検証しました。

  • Node v6.10.1
  • benchmark.js v2.1.4

継承

// classes
function ParentES5(value) {
  this._value = value;
}
function ES5(value) {
  ParentES5.call(this, value);
}
util.inherits(ES5, ParentES5);

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
}
class ES6 extends ParentES6 {
  constructor(value) {
    super(value);
  }
}

// functions
const funcs = {
  'es5': function() {
    return new ES5(1);
  },
  'es6': function() {
    return new ES6(1);
  }
};
**** benchmark.js ****
[1] "es5" 0.000029ms [1.00]
[2] "es6" 0.000045ms [1.56]

単純にclassを使うだけでも1.5倍遅いようです。

super classメソッドの呼び出し

function ParentES5(value) {
  this._value = value;
}
ParentES5.prototype.get = function() {
  return this._value;
};
function ES5(value) {
  ParentES5.call(this, value);
}
util.inherits(ES5, ParentES5);

ES5.prototype.get = function() {
  return ParentES5.prototype.get.call(this) * 2;
};

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
  get() {
    return this._value;
  }
}
class ES6 extends ParentES6 {
  constructor(value) {
    super(value);
  }
  get() {
    return super.get() * 2;
  }
}
const es5 = new ES5(1);
const es6 = new ES6(1);

// functions
const funcs = {
  'es5': function() {
    return es5.get();
  },
  'es6': function() {
    return es6.get();
  }
}
**** benchmark.js ****
[1] "es5" 0.000021ms [1.00]
[2] "es6" 0.000078ms [3.79]

super classメソッドの呼び出しは非常に遅いので避けたいところです。

考察

super classメソッドの呼び出し

function ParentES5(value) {
  this._value = value;
}
ParentES5.prototype.get = function() {
  return this._value;
};
function ES5(value) {
  ParentES5.call(this, value);
}
util.inherits(ES5, ParentES5);

ES5.prototype.get = function() {
  return ParentES5.prototype.get.call(this) * 2;
};

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
  get() {
    return this._value;
  }
}
class ES6 extends ParentES6 {
  constructor(value) {
    super(value);
  }
  get() {
    return ParentES6.prototype.get.call(this) * 2;
  }
}
const es5 = new ES5(1);
const es6 = new ES6(1);

// functions
const funcs = {
  'es5': function() {
    return es5.get();
  },
  'es6': function() {
    return es6.get();
  }
}
**** benchmark.js ****
[1] "es6" 0.000020ms [1.00]
[2] "es5" 0.000020ms [1.02]

super.get()の代わりにsuper classメソッドをcallすることでes5と同等のパフォーマンスが得られました。これは使えそうです。

こちらのパターンも同じような結果が得られます。

function ParentES5(value) {
  this._value = value;
}
function getES5() {
  return this._value;
};
function ES5(value) {
  ParentES5.call(this, value);
}
util.inherits(ES5, ParentES5);

ES5.prototype.get = function() {
  return getES5.call(this) * 2;
};

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
}
function getES6() {
  return this._value;
};
class ES6 extends ParentES6 {
  constructor(value) {
    super(value);
  }
  get() {
    return getES6.call(this) * 2;
  }
}
const es5 = new ES5(1);
const es6 = new ES6(1);

// functions
const funcs = {
  'es5': function() {
    return es5.get();
  },
  'es6': function() {
    return es6.get();
  }
}
**** benchmark.js ****
[1] "es5" 0.000023ms [1.00]
[2] "es6" 0.000023ms [1.00]

こちらもなかなか使いどころがありそうです。

継承

ParentES6.prototype.constructorへのアクセスは禁止されているため、classをextendsしsuperを呼び出す必要があります。

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
}

class ES6 extends ParentES6 {
  constructor(value) {
    super(value);
  }
}
// エラー
class ES6 {
  constructor(value) {
    ParentES6.prototype.constructor.call(this, value); 
  }
}
// TypeError: Class constructor ParentES6 cannot be invoked without 'new'

今のところたどり着いた最速の継承はこちらです。

function ParentES5(value) {
  this._value = value;
}
function ES5(value) {
  ParentES5.call(this, value);
}
util.inherits(ES5, ParentES5);

class ParentES6 {
  constructor(value) {
    this._value = value;
  }
  get() {
    return this._value;
  }
}
function ES6(value) {
  this._value = value;
}
ES6.prototype = ParentES6.prototype;

const es5 = new ES5(1);
const es6 = new ES6(1);
console.log(es6.get()); // 1
console.log(es6 instanceof ParentES6); // true

// functions
const funcs = {
  'es5': function() {
    return es5.get();
  },
  'es6': function() {
    return es6.get();
  }
}
[1] "es6" 0.000020ms [1.00]
[2] "es5" 0.000026ms [1.33]

es5の継承よりも高速な継承が可能となりました。もう少し検証が必要ですが、instanceofがtrueとみなされるのでこちらは意外と使えるかもしれません。 こちらの案はthamminさんがベースを提供してくれました。

まとめ

superクラスの呼び出しを避ける考察でした。ns,μsレベルのチューニングなので普通にsuperを呼んでいただければと思います。

JavaScriptっておもしろい。

リンク

Powerlineの導入

概要

Powerlineとはshell・vimにちょっとした情報をカッコよく表示してくれるツールです。何よりカッコいい。導入手順はこちらです。

Powerline for Shell

まずはshellからカッコよくしていきます。はじめにpowerline-shellをクローンします。

$ cd ~
$ git clone https://github.com/milkbikis/powerline-shell

このディレクトリは削除できないのでお好みなところにクローンしてきてください。 次にインストールします。設定を変えたい場合はconfig.pyを変更することでお好みの設定に変更できます。設定変更後は再度install.shを実行する必要があります。

$ ./install.sh

これでpowerline-shell.pyが生成されるので、Symlinkを貼ります。

$ ln -s ~/powerline-shell/powerline-shell.py ~/powerline-shell.py

私はzshを使用しているので、zshrcに設定を以下のように追加します。bash, fishの設定はこちらを参照してください。

# power-shell
function powerline_precmd() {
    PS1="$(~/powerline-shell.py --cwd-max-depth 1 $? --shell zsh 2> /dev/null)"
}

function install_powerline_precmd() {
  for s in "${precmd_functions[@]}"; do
    if [ "$s" = "powerline_precmd" ]; then
      return
    fi
  done
  precmd_functions+=(powerline_precmd)
}

if [ "$TERM" != "linux" ]; then
    install_powerline_precmd
fi

次にフォントのインストールをします。こちらはREADMEのスクリプトをそのまま実行するだけです。

# clone
git clone https://github.com/powerline/fonts.git
# install
cd fonts
./install.sh
# clean-up a bit
cd ..
rm -rf fonts

こんな感じになりました、カッコいいだけでなく意外に便利です。

f:id:suguru03:20170403130056p:plain

Powerline for Vim

次にvimのpowerlineの設定をしていきます。はじめにお使いのvimの環境を確認してください。こちらから条件を確認できます。

私はvim-plugを使っているので.vimrcに以下のように追加します。

Plug 'powerline/powerline', {'rtp': 'powerline/bindings/vim/'}

フォントもインストール済みなので、以上で設定は終了です。 別のプラグインを使っている方はこちらから確認してみてください。

こんな感じになります。

f:id:suguru03:20170403125852p:plain

まとめ

デメリットはshellが少し重くなりますが、カッコいいだけでなく意外にも便利だったので導入してもいいかなと思いました。

リンク

AnyenvでGoのバージョン管理

概要

Anyenvとはこれ一つで色々なパッケージ管理ができるスグレモノのようです。今回はGolangまわりだけ整理していたので、Golangのセットアップ手順について書きます。

インストール

まずはリポジトリをクローン。

$ git clone https://github.com/riywo/anyenv ~/.anyenv

.zshrcに以下を追記。

# anyenv
export PATH="$HOME/.anyenv/bin:$PATH"
eval "$(anyenv init -)"

goenvをインストールします。

$ anyenv install goenv

次にGolangをインストールします。

$ goenv install 1.8

.zshrcにGOPATHを設定します。(goenv rehashで解決してくれると思ったらそうでもない)

# Go
export GO_VERSION=1.8
export GOROOT=$HOME/.anyenv/envs/goenv/versions/$GO_VERSION
export GOPATH=$HOME/dev
export PATH=$HOME/.anyenv/envs/goenv/shims/bin:$PATH
export PATH=$GOROOT/bin:$PATH
export PATH=$GOPATH/bin:$PATH
echo Now using golang v$GO_VERSION

なんとなくnvmと同じechoを追加します。

Now using node v6.10.1 (npm v3.10.10)
Now using golang v1.8

$ go version
go version go1.8 darwin/amd64

良い感じになりました。

まとめ

Version Managerにこだわりが無いようでしたら、新しい言語をインストールするときにあちこちVersion Managerを探しに行くよりサクッとインストールできるのでいいかなぁと思います。

リンク

GitHub - riywo/anyenv: all in one for **env

GitHub - ingtk/dotfiles

Dockerのお掃除

概要

MBPの容量が圧迫しておりどうやら犯人はDocker for Macのようなのでお掃除していきます。

不要なコンテナの削除

Docker – Clean Up After Yourself! | Yohan Liyanage

こちらのブログより。

exited containersは自動削除されないとのことで、こちらを実行してくださいとの。

$ docker rm -v $(docker ps -a -q -f status=exited)

rmコマンドは少なくとも1つ以上の引数を必要とするので、

"docker rm" requires at least 1 argument(s).
See 'docker rm --help'.

Usage:  docker rm [OPTIONS] CONTAINER [CONTAINER...]

Remove one or more containers

このエラーが出た場合は削除できるexited containersが存在しないとのことなので気にせず進みます。

不要なイメージの削除

macos - How to clean up Docker for Mac containers - Ask Different

続いてこちら。 ポイポイしていきます。

$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /etc:/etc spotify/docker-gc

不要なコンテナ・イメージの削除【追記】

Christinaさんよりアドバイスいただき、以下のコマンドで上記2つは解決できるそうです、ありがとうございます。

$ docker system prune

Docker.qcow2の削除

Where does Docker keep images/containers so i can better track my disk usage - Docker for Mac - Docker Forums

最後のこちらが一番大物で、私の場合は30GBほど占領していました。 キャッシュのようですが容量をこんなに占拠されては困りますのでポイポイしていきます。

$ rm ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/Docker.qcow2

ソース

Node.jsで内部変数・関数の取得

概要

テストやちょっとしたツールを作りたいときに内部変数・関数にアクセスしたい時がありますが、 そんなときに便利なのがvmモジュールです。しかしvmではvarの変数は取得できるものの、letconstの変数は取得できません。 そこで色々試行錯誤して作ったツールについて書きます。

vmを用いた内部関数の取得

vm.runInNewContextではコードを実行時にglobalオブジェクトをセットすることができます。vm.runInThisContextは自動的に現在のglobalオブジェクトが使われます。

この関数は実行時にglobalスコープ上のvarをglobalオブジェクトに代入することで外からのアクセスを可能にしてくれますが、letconstは変換されません。

sample.js

const test1 = 'test1';
let test2 = 'test2';
var test3 = 'test3';

function test(arg1, arg2, arg3) {
  const sum = arg1 + arg2 + arg3;
  let num1 = 1;
  var num2 = 2;
  num3 = 3;
  return sum + num1 + num2 + num3;
}

exec.js

const vm = require('vm');
const fs = require('fs');
const path = require('path');

const filepath = path.resolve(__dirname, 'sample.js');
const file = fs.readFileSync(filepath, 'utf8');

const context = {};
vm.runInNewContext(file, context);
console.log(context);
/* 
 * { test3: 'test3', 
 *   test: [Function: test] } // let, constが取得できない
 */

vm-agent

今回作ったツールはlet, constが取得できるのと、関数を自動実行して値を取得できるツールを作りました。 また関数の実行も可能です。

const fs = require('fs');
const path = require('path');
const { Agent } = require('vm-agent');

const filepath = path.resolve(__dirname, ''sample.js');
const file = fs.readFileSync(filepath, 'utf8');

const result1 = new Agent(file)
  .run()
  .getInnerVariable();

console.log(result1);
/* 
 * { test1: 'test1',
 *   test2: 'test2',
 *   test3: 'test3',
 *   test: [Function: test] }
 */

const result2 = new Agent(result1.test)
  .setArguments(4, 5, 6)
  .run()
  .getInnerVariable();

console.log(result2);
/*
 * { arg1: 4, 
 *   arg2: 5, 
 *   arg3: 6, 
 *   sum: 15, 
 *   num1: 1, 
 *   num2: 2, 
 *   num3: 3 }
 */

vm-agent/example at master · suguru03/vm-agent · GitHub

実装内容

実装内容はesprimaを用いてlet, constvarに変換し、escodegenを用いてコードを再構築し実行するというものです。constが上書きできてしまったりパフォーマンスが低下したりしますが、テスト用なのでいったん良しとします。

また関数の実行については、関数の引数を解析し変数に変換することでvmモジュールでのアクセスを可能にしています。

ソース