Goalist Developers Blog

はじめてのAngular TODOアプリをつくる④ HTTP編

どうも、イイオです。
AngularでTODOアプリ的なものを作ってみようシリーズ、
チュートリアルでいうとこの辺りを見つつ、通信の部分やってきます。

https://angular.io/tutorial/toh-pt6

前回まで一体何をやっていたんだ?漢は過去に拘泥しない。

目標

今回のゴールは「HTTP通信してWebAPIを呼び出し、データのやり取りを行う」ことです。
でその際に
チュートリアルではObservableに包まれて来るレスポンスを.toPromise()でPromiseに変換してるけど
Observableをそのまま使うのがゴーリストではスタンダードっぽいのでそれに準じてます。

やること

  1. InMemoryWebApiModuleを使ってAPIサーバ風にふるまってもらう準備
  2. Observableを使ってHTTP通信する

1. InMemoryWebApiModuleを使ってAPIサーバ風にふるまってもらう準備

Webサーバのシミュレーションしてくれる機構が用意されています。

なぜか入ってなかったのでnpmで取ってきた

npm install angular-in-memory-web-api@latest

angular2の場合はangular2-in-memory-web-apiかもしれない

DBのふりするサービスを作成

ng g service in-memory-data

mock-tasks.tsからモックデータをコピってきて中身はこんなかんじに

in-memory-data.service.ts

import { Injectable } from '@angular/core';
import { InMemoryDbService } from 'angular-in-memory-web-api';

@Injectable()
export class InMemoryDataService implements InMemoryDbService {

  constructor() { }

  public createDb() {
    const tasks = [
      { id: 0, name: '', importance: 'high', isDone: false },
      { id: 11, name: '企画ロードマップ作成', importance: 'high', isDone: false },
      { id: 12, name: '山田さんにメール返信', importance: 'high', isDone: false },
      { id: 13, name: 'Angular2キャッチアップ', importance: 'mid', isDone: false },
      { id: 14, name: 'ブログ更新', importance: 'low', isDone: false },
      { id: 15, name: '新卒技術研修', importance: 'low', isDone: false }
    ];
    return tasks;
  }

}

http://localhost:4200/api/tasksをエンドポイントにGETすると
Response.json().dataでこの配列が返って来る。なんでか知らないけど返って来る。
わからなくても使えればいいんだなあ いいを

このサービスをapp.module.tsに登録して使えるようにする

import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';
・・・
@NgModule({
  imports: [
    ・・・
    InMemoryWebApiModule.forRoot(InMemoryDataService),
  ],
  ・・・
})

2. Observableを使ってhttp通信する

とりあえず全データ取得するやつをちゃんと動くようにしてみようかと。
前々回くらいに作ったTaskサービスを書き換えます。

task.service.ts

import { Http, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';

@Injectable()
export class TaskService {
  private headers: Headers = new Headers({'Content-Type': 'application/json'});

  constructor(private http: Http) { }

  public getTasks(): Observable<Task[]> {
    const url = 'api/tasks';
    return this.http.get(url, {headers: this.headers})
      .switchMap((response: Response) => {
        return Task.toTasks(response.json().data); // チュートリアルみたいに as Task[] ではキャストできなかった
      })
      .catch((error) => {
        throw new Error(error); // なんかエラー出たら呼び出し元の方でで受け取ってもらう
      });
  }
  
}

そうしてObservableにくるんだオブジェクトを呼び出し元に返してあげる。
呼び出し元ではObservableで返ってきたオブジェクトをsubscribeしたら使える状態になります。

export class TasksComponent implements OnInit {
  private tasks: Task[];

  constructor(private taskService: TaskService) { }

  ngOnInit() {
    this.getTasks();
  }

  private getTasks(): void {
    this.taskService.getTasks()
      .subscribe(
        (retTasks: Task[]) => {
          console.log(retTasks);
          this.tasks = retTasks;
        },
        (error: any) => {
          console.log(error);
        }
      );
  }

}

よし!!!!目標達成!!!!!
同様にしてデータ作成・更新・削除のメソッドを作れば完成!!!
大胆にも割愛する勇気ッ!!!ソイヤッソイヤッ

はい

というわけで、Observableからのsubscribeする流れの一例として見ていただければと思います。

Q. TODOアプリ完成させないんですか?
A. 完全性は地獄に置いて来た

誰の役にも立たないものを作るのはつらい。自分のためか。
とはいえ新卒も加入してどんどこ更新してくれるらしいのでエンジニアブログの未来は明るい。
明るい!

はい

最近業務でWebアプリをリリースしました。
チュートリアルを完走する前に本番の締切が来た。
フロントはAngularによって書かれています。できたてホカホカです。

map.hrog.net

企画とかからやらしてもらってます。

イベント告知

2017年7月21日(金) 19:30〜21:30、ゴーリスト東京本社にて
AWS Lambdaを中心に、サーバレスアーキテクチャを勉強する会
が開催されます!

connpass.com

このブログでもシチメンロッピの活躍中の盛次さんが登壇します。
すでに席はかなり埋まってしまっていますが、ご興味あればぜひ٩( ‘ω’ )و

はい

そんなかんじです

StoryboardのPreview機能の使い方

こんちは。渡部です。
初めて健康診断でバリウム飲みました。
お腹が痛いなうです。

f:id:watabe1028:20170629112824p:plain

今回はXcodeのPreview機能について紹介します。

なぜこの機能かというと
恥ずかしながら未だにAutoLayoutが苦手です。
きっとAutoLayoutが苦手な人はたくさんいるはず。。。

そんな人のための機能?とも言えるPreview機能、
知らない人もたくさんいるのでは?と思い書こうと思いました。

Preview機能とは

簡単に言うと
「複数端末のレイアウトをリアルタイムで一度に確認できる」
機能です。
ビルドの必要なし。
すぐに反映されます。

起動手順

1.XcodeでStoryboardを起動します。

f:id:watabe1028:20170629113250p:plain

2.右上のボタン押して二画面表示にします。

f:id:watabe1028:20170629113436p:plain f:id:watabe1028:20170629113523p:plain

3.Previewを選択します。

f:id:watabe1028:20170629113641p:plain

左画面がStoryboard、右画面がPreview画面です。 f:id:watabe1028:20170629113710p:plain

使用方法

とりあえずStoryboardに以下のUIKitを配置します。

UILabel、UIImageView、UIButtonを配置。

f:id:watabe1028:20170629113910p:plain

表示したい端末を複数選択します。

Preview画面左下の「+」ボタンから端末を選択します。

f:id:watabe1028:20170629114139p:plain

選択順に並びます。

f:id:watabe1028:20170629114207p:plain

すでに画面が崩れてますね。。。

あとはStoryboardをいじいじするだけです。
いじいじするとリアルタイムで各端末毎に反映されます。

では軽くAutoLayoutを設定してみます。

中央揃えしてみて、、、

f:id:watabe1028:20170629114256p:plain f:id:watabe1028:20170629114313p:plain

こう!

f:id:watabe1028:20170629115638p:plain

全端末がいい感じになりました。

まとめ

もっと早くこの機能を知っていれば。。。
この機能知らないと、シュミレータで毎回ビルドしていた人もいると思います。
Storyboardによってフロントの開発効率は上がりましたが
複数端末対応にかなり手間取っていました。 このPreview機能を使ってより効率的に開発できるようになります。

Xcodeの隠された便利機能、引き続き紹介していけたらと思います。
ちなみに使用している画像は弊社新サービスの「HRogマップ」です。

map.hrog.net

Lambda & PhantomJS & Selenium WebDriver for Java

f:id:t-moritsugu:20170623103856p:plain
こんにちわ、 ゴーリスト開発のモリツグです。
EC2インスタンス100台で毎日クローリングしてたら請求額が洒落にならなくなったので必要にせまられてLambdaでクローラを作ることにしました。
あっさりできるかと思ったのですが、思いのほか手こずったので同じ経験をする人が居なくなることを願ってブログに残しておこうと思います。

今回の課題を列挙してみます
1.Lambda & PhantomJSで複数のフォントを見れるようにする(日本、中国、韓国、タイ、アラビア、ヘブライ)
2.PhantomJSはSelenium WebDriverを使ってJavaから操作する
3.クローリング結果の一時保存以外では/tmp領域は使わない

Lambda & PhantomJSで複数のフォントを見れるようにする 前半

とりあえずリクルートさんのブログが参考になります。
LinuxのPhantomJSはfontconfigに依存しています。
Lambdaにはデフォルトでfontconfigは入ってないので日本語などは文字化けします。
Lambdaでユーザが一時的に自由に扱える領域は/tmpだけです。とりあえず/tmp以下にfontconfigをぶち込めば動くのですが、/tmp以下に同じ名前のディレクトリを作ると衝突することがあるので乱数をつけたり衝突を回避する手段が必要です。
ここで制限つきですが、もう1ヶ所それなりに好き放題できる場所があります。
それが/var/task以下です。Lambdaでとりあえずpwdすると/var/taskが返ってきます。
jarやzipが展開されるディレクトリもここになります。書き込みはできません。(これが制限になります)
したがってここにfontconfigをつっこみます。 私の環境はWindows7だったので、とりあえずVagrantでVirtualBoxにCentOSをインストールしました。
https://github.com/2creatives/vagrant-centos/releases/tag/v6.4.2

せっかくminimalなのに無理やりGUIを入れたせいでちょっと大変でしたが、みなさんはminimalのままで良いと思います。
では先ほどのブログを丸ぱくり参考にして設定をしていきます。

#無心で以下のコマンドを打ちます。  
yum install epel-release  
  
#PhantomJSをインストール
rpm -ivh http://repo.okay.com.mx/centos/6/x86_64/release/okay-release-1-1.noarch.rpm  
yum search all phantomjs  
yum install phantomjs.x86_64  

# 一旦アップデート
yum update

# GUIとかいれてるせいで怒られる
yum update --skip-broken

# 依存ライブラリをインストール
yum install gperf freetype-devel libxml2-devel python-lxml

# ソースを落としてディレクトリ移動
git clone http://anongit.freedesktop.org/git/fontconfig
cd fontconfig

# configure
./autogen.sh --sysconfdir=/var/task/fontconfig/etc --prefix=/var/task/fontconfig/usr --mandir=/var/task/fontconfig/usr/share/man --enable-libxml2

# make & install
make
make install

# 上手くいけばいいが、以下のエラーで怒られた
# ImportError: No module named six.moves
# とりあえずpipを落としてきてインストール
cd ..
curl -kL -O https://bootstrap.pypa.io/get-pip.py
python get-pip.py

# pipをアップデート python2.6早くアップデートしろ!と出てるが一旦無視
# pip install -U pip

# なんかエラーでるけどとりあえず入る
pip install six

# とりあえずmakeしてみたら通った
cd fontconfig
make
make install

Lambda & PhantomJSで複数のフォントを見れるようにする 後半

引き続き、最初に紹介したブログを丸パクリ参考に設定を進めていきます。
/var/task/fontconfig/etc/fonts/local.confというファイルを以下の内容で作成します。

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/var/task/fontconfig/usr/share/fonts</dir>
</fontconfig>

続いて、/var/task/fontconfig/usr/share/fontsというディレクトリを作成し、 IPAフォントとかを突っ込んでおきます。

mkdir /var/task/fontconfig/usr/share/fonts/
curl http://dl.ipafont.ipa.go.jp/IPAexfont/ipaexg00301.zip > ipaexg00301.zip
unzip ipaexg00301.zip
cp ipaexg00301/ipaexg.ttf /var/task/fontconfig/usr/share/fonts/

ここまででPhantomJSで無事に日本語が表示できるかを確認します。
以下のようなファイルを作成しcap.jsという名前で保存してください。

var page = require('webpage').create();
page.open('http://developers.goalist.co.jp/entry/2017/06/23/120000', function () {
    window.setTimeout(function () {
        page.render('debug.png');
        phantom.exit();
    }, 5000);
});

フォントキャッシュを再構築して実行

/var/task/fontconfig/usr/bin/fc-cache -fs
LD_LIBRARY_PATH=/var/task/fontconfig/usr/lib/ phantomjs cap.js

日本語以外のフォントも見れるようにする

基本は yum search thai font とかして出てきたなかで一番それっぽいフォントを入れます。 あんまり色々なフォントを入れるとLambdaのデプロイ上限の250Mを超えます。
yum installすると/usr/share/fonts/にインストールされるので/var/task/fontconfig/usr/share/fontsにコピーしましょう。
私は本当に大丈夫か確認するためにコピー後にyum removeし、消えないことがあるので/usr/share/fonts/以下の該当フォントをrmで削除しました。
以下は今回入れたフォント一覧です。

韓国 baekmuk-ttf-gulim-fonts.noarch
タイ thai-scalable-kinnari-fonts.noarch
中国(繁体) cjkuni-ukai-fonts.noarch
中国(簡体) wqy-microhei-fonts.noarch
アラビア amiri-fonts.noarch
ヘブライ culmus-aharoni-clm-fonts.noarch

LambdaでPhantomJSをSelenium WebDriverを使ってJavaから操作する

以下は主にJava向けの内容になります。
どの言語にも共通する重要なポイントは「/var/task/libはデフォルトでLD_LIBRARY_PATHに含まれる」という所だと思います。AWSの中のイケメンがやってくれたようです。

今回はeclipseにawsのプラグインを入れてLambdaプロジェクトを作りました。
このあたりは詳しくは説明しませんが、S3とかを扱う目的でaws-java-sdkを入れるとそれだけでLambdaに乗らなくなる可能性があるので、aws-java-sdk-coreとaws-java-sdk-s3だけ入れるみたいな努力が必要です。
Seleniumライブラリ、fontconfigと各言語のフォント、PhantomJSのバイナリを入れるので結構カツカツになります。
適当なフォルダ(今回はdriverという名前)を作ってビルドパスのソースに含めます。

f:id:t-moritsugu:20170623022716p:plain

画像のようにdriverには以下の3つを配置します。
・/var/taskにあるfontconfigディレクトリ
・PhantomJSバイナリ
・LD_LIBRARY_PATHで指定していた/var/task/fontconfig/usr/lib/をlibとして配置

/var/task/libがLD_LIBRARY_PATHにデフォルトで含まれることを利用して/var/task/fontconfig/usr/lib/以下のファイルをそこに配置する目的で置いています。
/var/task/fontconfig/usr/lib/pkgconfig/fontconfig.pcの中とかを見ると絶対パスで色々書かれてるので大丈夫ぽいです。
あとはeclipseの機能でエクスポートから実行可能JARファイルを作成すればいいのですが、ライブラリ形式は一番上の「生成されるJARに必須ライブラリーを抽出」を選んでください。

あとはこれをLambdaにデプロイすればすべて上手く。。。行きません。

以下の2つの問題をクリアしないといけません。
1.PhantomJSや/var/task/fontconfig/usr/bin/fc-cacheに実行権限が無いため怒られる、さらにJARにした段階(antによるjar作成)でパーミッションが引き継がれず事前に実行権限を付与していても実行権限が無くなってしまう。
2.デフォルトでphantomjsdriver.logがカレントディレクトリに作成されるが/var/taskには書き込めないので怒られる。

1については私の環境がWindowsでそもそも実行権限を付与できなかったため、VirtualBoxにCentOSとeclipseをいれました。しかし何故かKDEデスクトップとの相性が悪いせいかJAR作成画面が固まって作れなかったため、Windowsで実行可能JARをつくるときにantファイルを保存してそれを利用するというちょっと特殊なことを行ったので、もしかしたら不正確かもしれません。 ただ、Windowsユーザは事前に実行権限を付与する術がないためLinux環境は必須です。
以下のようなスクリプトを作成し、antファイルを一部書き換えることで無理やり実行権限を引継げるようにしました。肝はfilesetは実行権限を設定できないけれど、zipfilesetはfilemodeで設定できる所だとおもいます。期待通りに固められているかは拡張子をzipとかにして中身を見れば良いと思います。

antの前にゴニョゴニョするスクリプト

#!/usr/bin/bash
cd /work/workspace/Hoge/bin
zip -r bin.zip *
cd /work
ant -buildfile hoge.xml

antファイル hoge.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar" name="Create Runnable Jar for Project Hoge">
    <!--this file was created by Eclipse Runnable JAR Export Wizard-->
    <!--ANT 1.7 is required                                        -->
    <target name="create_run_jar">
        <jar destfile="/work/dest/Hoge.jar" filesetmanifest="mergewithoutmain">
            <manifest>
                <attribute name="Main-Class" value="com.goalist.hoge.LambdaFunctionHandler"/>
                <attribute name="Class-Path" value="."/>
            </manifest>
        <!-- 権限を引き継ぐために一旦事前のスクリプトでzipにしてそっちを使う
            <fileset dir="/work/workspace/Hoge/bin"/>
        -->
        <zipfileset filemode="755" src="/work/workspace/Hoge/bin/bin.zip"/>
            (.....libraryのjar系の記述なので省略.....)
        </jar>
    </target>
</project>

2については–webdriver-logfileパラメータがどうやってもPhantomJSに渡らない(実行時にコンソールでパラメータを確認できる)ので以下のような方法しかなさそうです。

Runtime.getRuntime().exec(new String[]{"/var/task/fontconfig/usr/bin/fc-cache", "-fs"})

String phantomJsBinaryPath = "/var/task/phantomjs"; 
String userAgent = "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.41 Safari/535.1";

DesiredCapabilities capabilities = DesiredCapabilities.phantomjs();  
capabilities.setJavascriptEnabled(true);  
capabilities.setCapability(  
  PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
  phantomJsBinaryPath
);

capabilities.setCapability(
  PhantomJSDriverService.PHANTOMJS_PAGE_SETTINGS_PREFIX + "userAgent", userAgent);

File logfile = new File("/dev/null");
PhantomJSDriverService pjsds = new PhantomJSDriverService.Builder()
  .usingPhantomJSExecutable(new File(phantomJsBinaryPath))
  .usingAnyFreePort()
  //.withProxy(proxy)                       
  //.usingCommandLineArguments(commandLineArguments)
  .withLogFile(logfile)
  .build();

return new PhantomJSDriver(pjsds, capabilities);

やっとLambda上で快適にクローリングできます!

まとめ

Javaじゃなかったら最後の方の問題は関係ないと思います。
この作業中に仮想環境が2回ぐらい壊れて再インストールしたので物凄く疲れました。
Lambdaは夢が広がるので面白いなぁと思います。

バックエンドエンジニアがフロントエンドを書く① 〜React、storybookのセットアップ〜

現プロジェクトでバックエンドを実装しているJPです。 ですが、フロントエンドのReactとstorybookを使った開発に興味を惹かれたため、自分でReactプロジェクトを作成してみたいと思います。

筆者の経験:CLIツールなどもあまり触ったことがない、フロントエンドの初心者
環境   :macOS Sierra

目次

Reactとは

facebook が開発した素晴らしい描画ライブラリだということしか知りません。
申し訳ありませんが、説明は端折らせていただきます。

storybookとは

簡単に言うと、React で作成したコンポーネントを1つづつ見ることができるカタログのようなもののようです。
github.com

各種ツールをインストールする

homebrew

インストール手順:Homebrew — macOS 用パッケージマネージャー

npm

ホームディレクトリで以下のコマンドを実行

brew install node
node -v
npm -v

yarn

特に理由はありませんが、フロントチームが使っていたので、yarnを使ってみます。
npmみたいなツールのようです。
GitHub - yarnpkg/yarn: 📦🐈 Fast, reliable, and secure dependency management.

npm i -g yarn@0.19.1

storybook

npm i -g @storybook/cli

create-react-app

Reactプロジェクトを自動で作成してくれるCLIツールです。
eslintやbabelなどの推奨されるライブラリも自動で落としてくれるようです。

npm install -g create-react-app 

これで準備は完了です。

React プロジェクトの作成

作業ディレクトリへ移動

cd プロジェクトを作成するディレクトリ

新規プロジェクトの作成

create-react-app my-app

こんな感じのフォルダができました。
依存ライブラリは my-app/node_modules 以下にあります。
f:id:j-itoh:20170615192836p:plain

プロジェクトの起動

cd my-app
yarn start

こんな画面が表示されます。これだけでアプリケーションとして動くようです。 f:id:j-itoh:20170615193839p:plain

storybookのセットアップ・起動

my-app直下で以下のコマンドを実行

getstorybook
yarn run storybook

http://localhost:9009/にアクセスすると、以下のページが表示されます。 f:id:j-itoh:20170615200240p:plain

以上で storybook が起動するところまで完了です。
最初に React プロジェクトを作成しなければならないこと以外は割りとスムーズにできました。
ここまで自動化されているとありがたいです。

次回

次回は以下の内容について書きたいと思います。

  • KNOBSアドオンを追加する
  • Material-Uiのコンポーネントを追加する
  • コンポーネントを中央に配置する

iOS11からNFCが解放か!?

こんちは。渡部です。

みなさん、コイキング育ててますか?
渡部は育ててます。

f:id:watabe1028:20170608164110p:plain

ブリーダスキルMAX、コイキングの種類全コンプリート、
リーグ全制覇しました。
早くアップデートしてほしいです。

今日はそんなコイキングに全く関係ないネタを書きます。
ノンコーディングネタです。

先日のWWDCで発表された機能についてです。
タイトル通りNFCなど。

「Core NFC」

先日のWWDCにて「Core NFC」なるものが発表されました。
https://developer.apple.com/documentation/corenfc

NFCとは?

news.mynavi.jp

今まではApplePay専用だったNFCですが
ようやく開発者に解放されるっぽいです。

何ができるようになるのか?

ではNFCを使って何ができるようになるのか?

まず1つめはカード決済などです。
もうAndroidでは当然の機能ですが、日本で言うところのおサイフケータイです。

実際ドキュメントをまだ読んでいないのでできるかどうかは定かではありませんが
割り勘アプリなどは今頃実装に入っているのではないでしょうか?

2つめは証明書がわりです。
もはや社員証はいらなくなります。

勤怠管理もiPhoneをかざすだけで出勤、退勤を記録できるようになるでしょう。
(今までもBLEを使えばできたけど)

ドキュメントを軽くみた感じだとタグやメッセージ的なものが使えそう。
あとは規約がどうなるかAppleの発表待ちですね。

他にも・・・

スパコンばりの「iMac Pro」、
送金が可能になるiMessages、
使ってないアプリの自動アンインストール、
コントロールセンターの自由なカスタマイズ、
Siriに知能がつく?、
自分が使ってるWifiをワンタップで招待できる「Wifiシェア機能」など
年々盛り上がりに欠けると言われているWWDCでも
こんなに多くの発表がありました。

iPad10.5インチが出るみたいですね。
開発者としてはサイズ違いの端末が出るのは嬉しくありません。
勘弁してください。
AutoLayout苦手なんす。

まとめ

前々回のWWDCではBLEが結構変わりました。
今回はNFCの解放(規約未定だけど)です。
個人的にはこれからは近接センサー的なもの、
iPhoneとIoTの端末での連携が流行ってくるのかなと予想しています。

現在ゴーリストではiOSアプリ開発をやっているのはごく少数ですが、
来年あたり開発チームでWWDCに参戦したいなーと思う今日この頃です。

AmazonS3に社内用Mavenリポジトリを作成し、Gradleから使う

こんにちは、毛虫にさされて赤いポツポツ持ちの鈴木です。

タイトルの通り、AmazonS3 で Mavenリポジトリ を作成しGradleから使う手順をかきました。

社内のモジュールに依存するモジュールを開発する際に、サーバー上で依存関係を解決しビルドするために使ったりします。

Qiitaにも同様の内容を投稿済みなので、最新情報はこちらを参照してください。

qiita.com

前提

  • Gradleをインストールしている
  • S3のバケットにファイルをアップロードできるAWS IAMユーザーを作成している
  • 上記IAMユーザーのアクセスキーIDとシークレットアクセスキーを持っている

本記事のゴール

S3上にアップロードしたライブラリを別のGradleプロジェクトからダウンロードできるようにします。

具体的には以下のようなbuild.gradleの設定で「gradle build」コマンドを実行した際にダウンロードできるようにします。

build.gradle

dependencies {
    compile 'jp.co.goalist:library:1.0.0'
}

以下の内容については本記事では扱いません。いつかまた。

  • Jenkinsなどビルドサーバー側での設定
  • S3上のリポジトリへのアクセス管理

Mavenリポジトリへのアップロード

Gradleプロジェクト作成

以下のコマンドを実行します。

mkdir gradle-upload-s3repo
cd gradle-upload-s3repo/
gradle init --type=java-library

生成されたファイルはこんな感じです。

.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   └── java
    │       └── Library.java
    └── test
        └── java
            └── LibraryTest.java

この時点で build.gradle の内容は以下の通りです。(不要なコメントと依存ライブラリの設定は削除しています)

build.gradle

apply plugin: 'java'

//依存ライブラリが未定義のため、
//現時点ではrepositoriesとdependenciesは不要ですが、
//後ほど使うので残しておきます。
repositories {
    jcenter()
}

dependencies {
}

確認のため、プロジェクトルートで「gradle build」と打ってあげると、build/libsに「gradle-upload-s3repo.jar 」が生成されます。ここまではjavaプラグインのデフォルト機能です。
確認後、「gradle clean」してビルド結果を削除してあげましょう。

groupId、artifactId、version を決める

Mavenでは、groupIdとartifactIdとversionの組み合わせでライブラリを一意に定義します。

慣習にならい、

キー
groupId jp.co.goalist
artifactId library
version 1.0.0

にしましょう。

build.gradleに以下の設定を追加します。

group = "jp.co.goalist"
version = "1.0.0" 

settings.gradleを以下のように設定します。

settings.gradle

rootProject.name = 'library'

S3上にリポジトリ用のバケットを作成する

手順は省略しますが、リポジトリとして使用するバケットを作成します。

今回は「s3://repository.hoge/maven/」を作成します。

開発環境の設定

~/.gradle/gradle.propertiesにリポジトリのURLとIAMユーザーのアクセスキーIDとシークレットアクセスキーを設定します。
これをプロジェクト側が参照することで、プロジェクトに含めないですむのでセキュリティ的に安全になります。(普通のこと言ってます) あと個々のプロジェクトでアクセスキーIDとか設定したりとかしないですみます。

gradle.properties

goalistRepoUrl=s3://repository.hoge/maven/
awsAccessKeyId = AKIAJWORQEXXXXXXXXXX
awsSecretAccessKey = waTa0aakgK2e5hXXXXXXXXXXXXXXXXXXXXXXXXXX

mavenプラグインのuploadArchives設定

MavenリポジトリへのアップロードにはmavenプラグインのuploadArchivesを使います。
先程設定したリポジトリのURL、IAMユーザーのアクセスキーID、シークレットアクセスキーを参照するように設定します。

build.gradle

apply plugin: 'maven'
uploadArchives {
    repositories {
        mavenDeployer {
            configuration = configurations.deployerJars
            repository(url: goalistRepoUrl) {
              authentication(userName: awsAccessKeyId, password: awsSecretAccessKey)
            }
        }
    }
}

S3へのアクセスには org.springframework.build:aws-maven を使いますので、dependenciesに追加します。
今回は最新版の5.0.0.RELEASEを使います。

The Central Repository Search Engine

build.gradle

configurations {
    deployerJars
}

dependencies {
    deployerJars 'org.springframework.build:aws-maven:5.0.0.RELEASE'//追加
}

これで設定は完了。最終的には以下のようになります。

build.gradle

apply plugin: 'java'
apply plugin: 'maven'

group = "jp.co.goalist"
version = "1.0.0" 

repositories {
    jcenter()
}

configurations {
    deployerJars
}

uploadArchives {
    repositories {
        mavenDeployer {
            configuration = configurations.deployerJars
            repository(url: goalistRepoUrl) {
              authentication(userName: awsAccessKeyId, password: awsSecretAccessKey)
            }
        }
    }
}

dependencies {
    deployerJars 'org.springframework.build:aws-maven:5.0.0.RELEASE'
}

settings.gradle

rootProject.name = 'library'

uploadArchivesタスクを実行

以下のコマンドを実行し、BUILD SUCCESSFULL したら成功です。

gradle uploadArchives

S3を確認すると

s3://repository.hoge/maven/以下にライブラリがアップロードされていると思います。

Mavenリポジトリからダウンロード

今回アップロードしたライブラリに依存するGradleプロジェクトを作成します。

mkdir gradle-upload-s3repo-child
cd gradle-upload-s3repo-child/
gradle init --type=java-library

build.gradleを変更し、S3のリポジトリを参照するための設定と、依存関係の設定をします。

build.gradle

apply plugin: 'java'

repositories {
    jcenter()
    maven {
        url goalistRepoUrl
        credentials(AwsCredentials) {
            accessKey awsAccessKeyId
            secretKey awsSecretAccessKey
        }
    }
}

dependencies {
    compile 'jp.co.goalist:library:1.0.0'
}

以下のコマンドを実行し、BUILD SUCCESSFULなことを確認できたら完了です。

gradle build

さいごに

実運用ではビルドサーバーからしかアップロードできないようにして、開発者は参照のみ出来るようにすればいい感じに運用できると思います。 モジュールを再利用していきましょう。

Swiftの型変換一覧@備忘録

こんちは。渡部です。
ちょいちょい型変換でつまずくので備忘録がてらまとめておきます。

f:id:watabe1028:20170531180439p:plain

Int

Int → String

let int : Int = 23
let string : String = String(int)
print(string)
// 23

Int → Double

let int : Int = 23
let double: Double = Double(int)
print(double)
// 23.0

Int → Float

let int : Int = 23
let float: Float = Float(int)
print(float)
// 23.0

Float

Float → String

let float : Float = 23.5
let string : String = String(float)
print(string)
// 23.5

Float → Int (切り捨て)

let float : Float = 23.5
let int : Int = Int(float)
print(int)
// 23

Float → Double

let float : Float = 23.5
let double : Double = Double(float)
print(double)
// 23.5

Double

Double → String

let double: Double = 23.5
let string : String = String(double)
print(string)
// 23.5

Double → Int (切り捨て)

let double : Double = 23.5
let int : Int = Int(double)
print(int)
// 23

Double → Float

let double : Double = 23.5
let float : Float = Float(double)
print(float)
// 23.5

Bool

Bool → String

let bool : Bool = true
let string : String = String(bool)
print(string)
// true

Bool → Int

let bool : Bool = true
let int : Int = Int(bool)
print(int)
// 1

Bool → Float

let bool : Bool = true
let float : Float = Float(bool)
print(float)
// 1.0

Bool → Double

let bool : Bool = true
let double : Double = Double(bool)
print(double)
// 1.0

まとめ

超個人的な備忘録です。
型変換を忘れがちな人の役に立てればいいなと思います。 決して手抜き記事ではありません。