2017年9月23日土曜日

python3インストール(pyenvは使わない)

以前書いた記事ではpyenvを使用してPython3をインストールしました。
Pythonインストール

後日、下記の記事を拝見し、
確かにpyenvいらないかもと思ったので、別のインストール方法をメモしておこうと思います。
pyenvが必要かどうかフローチャート

# python3のインストール
$ mkdir ~/DL
$ cd ~/DL
$ wget https://www.python.org/ftp/python/3.6.2/Python-3.6.2.tgz
$ sudo tar -zxvf Python-3.6.2.tgz -C /usr/local/src/
$ cd /usr/local/src/Python-3.6.2/
$ ./configure
$ make
$ sudo make install

# python3がインストールされていることを確認
$ python3 -V
Python 3.6.2

#現在のpythonコマンドを確認
$ python -V
Python 2.7.5
$ which python
/usr/bin/python
$ ls -l /usr/bin/python
lrwxrwxrwx. 1 root root 7 Aug  1 22:19 /usr/bin/python -> python2

# pythonコマンドをpython2からpython3にする
$ which python3
/usr/local/bin/python3
$ ln -si /usr/local/bin/python3 /usr/bin/python

# 変更後のpythonコマンドの確認
$ python -V
Python 3.6.2
※既存の機能で使用している可能性があるため、pythonコマンドのリンク先は変更しないほうが良いようです。

以上です。

2017年9月12日火曜日

JavaによるAWS S3へのファイルアップロード注意点

S3へファイルをアップロード(TransferManagerを使用)するコードを書く機会がありました。その際に困った点について共有したいと思います。
実際はコードを書いている際に困ったわけではなく、運用している際に困った話です。
(つまりテストなどで逃しやすい)
さっそく結論から
1.TransferManagerは必ずtransferManager.shutdownNow()でシャットダウンする。
2.amazonS3Client.getCachedResponseMetadata()でS3ResponseMetadataを取得しログに出力しておく。
3.マルチパートアップロードされないように閾値を変更しておく。(アップロードサイズとの兼ね合い)
コード例
private void fileUploadToS3(String s3UploadFilePath, MultipartFile multipartFile) throws Exception {
    String s3BucketName = "test_bucket";

    AmazonS3Client amazonS3Client = new AmazonS3Client();
    PutObjectRequest putObjectRequest = null;
    try (
        InputStream multipartFileInStream = multipartFile.getInputStream()) {

        TransferManager transferManager = new TransferManager(amazonS3Client);
        TransferManagerConfiguration config = new TransferManagerConfiguration();

        // ResponseMetadataを取得するために閾値変更
        Long multipartUploadThreshold = 50L * 1000L * 1000L
        transferManagerConfiguration.setMultipartUploadThreshold(multipartUploadThreshold);
        transferManager.setConfiguration(transferManagerConfiguration);

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(multipartFile.getSize());

        putObjectRequest = new PutObjectRequest(s3BucketName, s3UploadFilePath, multipartFileInStream, objectMetadata);
        Upload upload = transferManager.upload(putObjectRequest);
        upload.waitForUploadResult();

    } finally {
        S3ResponseMetadata s3ResponseMetadata = amazonS3Client.getCachedResponseMetadata(putObjectRequest);
        if (s3ResponseMetadata != null) {
            // AWSサポートへの問い合わせに使用する。(SLF4Jとか使ってオブジェクトごと出したほうがいいかも)
            System.out.println("RequestId : "+ s3ResponseMetadata.getRequestId() + ", HostId : " + s3ResponseMetadata.getHostId());
        } else {
            System.out.println("ResponseMetadata :null");
        }
        // シャットダウンしないとExceptionの素
        transferManager.shutdownNow(false);
    }
}
簡単にですが説明
1.について
シャットダウンしない場合、アップロードが頻繁に起きた際にException発生の原因になる。ドキュメントの例をよく見るとこっそり必ず入ってました。
2.について
S3アップロードの失敗など、調査でAWSサポートへ問い合わせる場合に必要になる。
3.について
閾値を超えてマルチパートアップロードになった場合2.で取得予定のS3ResponseMetadataが取得できません。
TransferManagerでのアップロードではアップロードファイルサイズによって単体アップロードかマルチパートアップロードかを切り替えているため、必ず取得したい場合、閾値を上げる必要があります。(デフォルト16MB)
ただし、サイズが大きい場合マルチパートアップロードの恩恵を受けるために致し方なし?
今気づきましたが、S3ResponseMetadata、ResponseMetadataのドキュメントにAWSサポートで使用するっぽいことって書いてますね。
Returns the Amazon S3 host ID, providing additional debugging information about how a request was handled.
Returns the AWS request ID contained in this response metadata object. AWS request IDs can be used in the event a service call isn't working as expected and you need to work with AWS support to debug an issue.

余談:Qiita投稿用に書いてたものをコピペしたら、Qiitaでの書式がそのままコピーされた。

2017年8月31日木曜日

historyの設定変更

コマンド履歴はちょくちょく見たりするので残しておきたい。
なので設定を変更します。

今回は全ユーザ共通のhistory設定にしたいので
”/etc/profile”の末尾に追加してみようと思います。

この設定方法はあまり良くない方法な気もしますが、
ローカル環境なので気にしなーい。
 【設定する内容】
  サイズを50000に変更、
  historyコマンド実行時のフォーマット変更、
  連続して同じコマンドを実行時、重複記録しない。

$ sudo vi /etc/profile
 以下を末尾に追加
   # Add
    HISTSIZE=50000
    HISTTIMEFORMAT='%Y/%m/%d %H:%M:%S '
    export HISTCONTROL=ignoredups

ちなみにHISTSIZEはすでにあるので、それを変更してもいいかも。
(念のためコピーして元の設定はコメントアウトとかするのがベスト?)

これでほぼコマンド履歴が消えずに残ってかついつ実行したかがわかって便利!

そんな感じで以上です。

参考
・historyの設定
  bash を自分好みに設定する

2017年8月11日金曜日

「git status」で変更していないファイルが表示される

「git status」で変更したファイルを確認した際に、
変更していないはずのファイルも表示された。

「git diff」で変更内容を確認してみると以下の内容が。
old mode 100644
new mode 100755

よくわからないのでそのまんま検索してみた。

ファイルのパーミッションが変更されたのが原因らしい。
Linuxで作成してpushしたリポジトリをWindowsとの共有ディレクトリに移動した影響っぽい?

とりあえず以下のコマンドで無視する設定を入れたら解消されるみたい。
$ git config core.filemode false

LinuxとWindowsでファイルを共有したいので変更内容をpushすることにした。
あまりよろしくない気がする・・。もうちょっと調べよう。

追記:
Linuxにログインして共有したディレクトリからだと「old mode~~」が出る。
windowsからだと出ない。
git_bashで「ls -l」してみるとパーミッションも644のままっぽい。
git操作はLinux上からじゃなくてgit_bashから(windowsで)行うことにしよっかな。
そもそも共有ディレクトリ上に置いているのが問題だよねー。

参考
msysgit でファイルを変更していないはずなのに merge できない場合の対処



2017年8月4日金曜日

Erlangでfizzbuzzっぽいの書いてみた。

Erlangを勉強しだしてまだちょっとですが、
fizzbuzzっぽいの書いてみました。

今回書いたfizzbuzzのルール。
・3で割り切れる。
・5で割り切れる。
・3と5両方で割り切れる。
・数のリストを受け取りfizzbuzzした結果リストを返す。

ーコードーーーーーーーーーーーーーーーーーーーーーーー
fizzbuzz(L) -> fizzbuzz(L, []).
fizzbuzz([H|T], Result) -> 
    case {H rem 3, H rem 5} of
        {0,0} -> fizzbuzz(T, [fizzbuzz|Result]);
        {0,_} -> fizzbuzz(T, [fizz|Result]);
        {_,0} -> fizzbuzz(T, [buzz|Result]);
        {_,_} -> fizzbuzz(T, [H|Result])
    end; 
fizzbuzz([], Result) -> lists:reverse(Result).

ー実行結果ーーーーーーーーーーーーーーーーーーーーーー
1> c(test).
{ok,test}
2> test:fizzbuzz([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]).
[1,2,fizz,4,buzz,fizz,7,8,fizz,buzz,11,fizz,13,14,fizzbuzz,16]
ーーーーーーーーーーーーーーーーーーーーーーーーーーー

こんな簡単な処理を書くのにも数時間かかった・・。
ちゃんと実践せずに本を読んでるだけじゃだめってことですね。
早く並列分散をガシガシ書きたい!

こんな感じで、今回は以上です。


追記:
出力バージョンも作ってみました。
ーコードーーーーーーーーーーーーーーーーー
%% 受け取ったリストに対して以下の処理を行う
%% 3で割り切れる場合は「Hello」を出力。
%% 5で割り切れる場合は「World」を出力。
%% 3,5どちらでも割り切れる場合は「Hello World」を出力。
%% すべてのリスト要素を処理したら「End」を出力。
fizzbuzz([H|T]) ->
    case {H rem 3, H rem 5} of
        {0,0} -> io:format("~p:Hello World~n", [H]),fizzbuzz(T);
        {0,_} -> io:format("~p:Hello~n", [H]),fizzbuzz(T);
        {_,0} -> io:format("~p:World~n", [H]),fizzbuzz(T);
        {_,_} -> io:format("~p~n", [H]),fizzbuzz(T)
    end;
fizzbuzz([]) -> io:format("End~n").

% 引数の数値nから1~nのリスト作成
make_list(MaxNum) -> make_list(1, MaxNum, []).
make_list(MinNum,MaxNum) -> make_list(MinNum, MaxNum, []).
make_list(I, Max, List) when Max >= I-> make_list(I + 1, Max, [I|List]);
make_list(I, Max, List) when Max =< I -> lists:reverse(List).

ー実行結果ーーーーーーーーーーーーーーーーーーーーーー
1> c(hello).
{ok,hello}
2> L = hello:make_list(30).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
 23,24,25,26,27,28,29|...]
3> hello:fizzbuzz(L).
1
2
3:Hello
4
5:World
6:Hello
7
8
9:Hello
10:World
11
12:Hello
13
14
15:Hello World
16
17
18:Hello
19
20:World
21:Hello
22
23
24:Hello
25:World
26
27:Hello
28
29
30:Hello World
End
ok
4>
ーーーーーーーーーーーーーーーーーーーーーーーーーーー

「;」と「,」の使いどころがまだ理解できてないため、毎回コンパイラに怒られる。
あと、 io:formatとかもうちょいドキュメント(Erlang -- io)読まなきゃなぁ。

追記は以上です。

2017年7月21日金曜日

Java Calendarクラスのモック化(mock)

Javaの単体テストでCalendarクラスをモック化。
調べても目的のものが見つからなかったのでメモ。

Calendarのインスタンス生成時に指定時刻に設定したい。
JMockitとか使って無理やりやっちゃってます。
モック自体が無理やりな感じだしこれでいっかなぁ。

------------------------------------------------------------------------------------
// Calendarクラスのインスタンスを生成するメソッドを取得(getInstanceの中身)
Method method = Calendar.class.getDeclaredMethod("createCalendar", TimeZone.class, Locale.class);
method.setAccessible(true);

// Calendar.getInstance()を実行した際に指定した時刻を返すようにモック化
Calendar expected = (Calendar) method.invoke(Calendar.class, TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
expected.setTime(new Date(1498835040000L)); // Unixミリ秒で時刻を設定
new MockUp<Calendar>() {
@Mock
public Calendar getInstance() {
return expected;
}
};
------------------------------------------------------------------------------------

// テスト対象の例(現在時刻に対して時刻調整をする)
------------------------------------------------------------------------------------
Calendar cal = Calendar.getInstance();
log.info("初期値:" + cal.toString());

// 時刻を調整
cal.add(Calendar.MINUTE, Integer.parseInt(adjustedTime));

log.info("変更値:" + cal.toString());

------------------------------------------------------------------------------------

2017年6月24日土曜日

Erlangインストールメモ

$ gcc -v
$ perl -v
$ sed --version
$ java -version

$ sudo yum -y install ncurses ncurses-devel openssl openssl-devel orber gcc gcc-c++ unixODBC unixODBC-devel fop

$ mkdir DL
$ cd DL

※下記JDKのURLは最新版以外は取得できないため都度最新URLに変更する。
$ curl -OL --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u144-b01/090f390dda5b47b9b721c7dfaa008135/jdk-8u144-linux-x64.rpm
$ sudo rpm -ivh jdk-8u144-linux-x64.rpm

メモ:OpenJDKでも大丈夫な気がする。
   $ sudo yum install java-1.8.0-openjdk java-1.8.0-openjdk-devel

$ wget http://www.erlang.org/download/otp_src_20.0.tar.gz
$ sudo tar -zxvf otp_src_20.0.tar.gz -C /usr/local/src/
$ cd /usr/local/src/otp_src_20.0

$ sudo ./configure
$ sudo make
$ sudo make
$ sudo make install

インストール後の確認。(Erlangのコンソールに入れることを確認)
$ erl
1>
1> q().

$ cd ~/DL
$ wget http://erlang.org/download/otp_doc_man_20.0.tar.gz
$ sudo tar xvzf otp_doc_man_20.0.tar.gz -C /usr/local/lib/erlang/

ドキュメントの確認
$ erl -man lists
lists(3)                           Erlang Module Definition                          lists(3)

NAME
       lists - List processing functions.

DESCRIPTION
       This module contains functions for list processing.

       Unless  otherwise  stated,  all  functions assume that position numbering starts at 1.
       That is, the first element of a list is at position 1.

       Two terms T1 and T2 compare equal if T1 == T2 evaluates to true. They match if T1  =:=
       T2 evaluates to true.