Corredor

ウェブ、プログラミングの勉強メモ。

Node.js スクリプトから外部コマンドを実行する

Node.js スクリプトから外部コマンドを実行してみる。child_process を使えば簡単にできる。

単純にコマンドを実行し、その結果を表示するだけ

まずは、nkf という文字コード解析コマンドを実行してみる。

const childProcess = require('child_process');
childProcess.exec('nkf --guess ./TEST.txt', (error, stdout, stderr) => {
  if(error) {
    // エラー時は標準エラー出力を表示して終了
    console.log(stderr);
    return;
  }
  else {
    // 成功時は標準出力を表示して終了
    console.log(stdout);
  }
});

コマンドの標準入力に値を流し込む

コマンドの標準入力に値を流し込む例。今回は cat コマンドを使って標準入力を標準出力を表示させてみる。

catコマンドは引数がないときに標準入力を標準出力にそのまま出力する。

普通にコマンドとして書くなら、

$ echo 'HOGE FUGA' | cat

という風に書いた時の状態を再現する。

const childProcess = require('child_process');

const exec = childProcess.exec('cat', (error, stdout, stderr) => {
  if(error) {
    // エラー時は標準エラー出力を表示して終了
    console.log(stderr);
    return;
  }
  else {
    // 成功時は標準出力を表示して終了
    console.log(stdout);
  }
});
// ↑ココまで同じ

// 標準入力に値を渡し、標準入力を閉じる (閉じないと終わりを待ち続けてしまう)
exec.stdin.write('HOGE FUGA');
exec.stdin.end();

childProcess.exec() の戻り値は ChildProcess。その stdin (標準入力) に値を write() して、最後に end() で閉じてやれば良い。

案外簡単に出来たのでよかった。

Node.js超入門

Node.js超入門

Jenkins Multibranch Pipeline でワークスペースのパスが長過ぎてエラーになるのを回避する

Windows Server 上で動作させている Jenkins にて。

Multibranch Pipeline を使うと、Git ブランチごとにワークスペースディレクトリが自動生成されるのだが、このディレクトリ名にユニーク ID と思われるランダムな文字列が付与される。これのせいで、Git チェックアウト時にファイルのフルパスが長くなり過ぎて、ビルドが失敗してしまった。

以下のような Filename too long といったコンソールログが表示される。

hudson.plugins.git.GitException: Command "git.exe checkout -f 2cea7d8eb9185899c01d2ffc86872f584da2e60c" returned status code 1:

stdout:
stderr: error: unable to create file edgemagic-nextgen-core/src/test/resources/dbunit_test_data/com/cybra/edgemagic/service/EmObjectServiceTest/data/testInstances_create_dataRequiresData.xml: Filename too long

そこで考えたのが、ワークスペースディレクトリの名前を短くできないか、ということで、調べてみるとやり方があった。

Declarative Pipeline の場合、ws() ステップでワークスペースディレクトリを変更できる他、agent {} ブロック内で customWorkspace オプションを指定すると任意のパス配下をワークスペースとして使えるようになるのだ。

早速書いてみるとこんな感じ。

pipeline {
  agent {
    label {
      label ""
      // ワークスペースディレクトリ配下のディレクトリ名を変える
      // ブランチ名に「feat/」が含まれていれば消す。それ以外の「/」は「-」にする
      // 「my-multi-job-【ブランチ名の省略形】-【ビルド番号】」にする
      customWorkspace "${JENKINS_HOME}/workspace/my-multi-job-${BRANCH_NAME.replaceAll("feat/", "").replaceAll("/", "-")}-${BUILD_NUMBER}"
    }
  }
  stages {
    steps {
      echo "${pwd()}"
    }
  }
}

Jenkins が設定する環境変数を用いて、元々のワークスペースディレクトリ ${WORKSPACE} と同階層に「my-multi-job-【ブランチ名の省略形】-【ビルド番号】」という名前のディレクトリを作り、通常よりも短いディレクトリ名で済ませられるようにした。

Jenkins が提供する環境変数の一例は以下のとおり。

環境変数 概要
${JENKINS_HOME} Jenkins のルートパス
${WORKSPACE} デフォルトのワークスペースのパス。デフォルトだと ${JENKINS_HOME}/workspace/${JOB_NAME} かな
${BUILD_NUMBER} ビルド番号 (1 からの連番になる)
${JOB_NAME} ジョブ名
${BRANCH_NAME} マルチブランチ・パイプラインの時だけ参照可能

また、処理部分で使用している ${pwd()} は、環境変数ではないが、カレントディレクトリを確認できる。

Jenkins の中身は Java なので、例のように replaceAll() という Java String のメソッドが使える。この replaceAll()\ 記号を扱う時は \\\\ と書かないと、PatternSyntaxException: Unexpected internal error near index 1 エラーが出るので注意。replaceAll("\\\\", "-") と書くことで、\ 記号を - に置換できる、というワケだ。

コレでワークスペースまでのパスを短くでき、チェックアウトするファイルの長さにも耐えられるようになった。一件落着。

[改訂第3版]Jenkins実践入門 ――ビルド・テスト・デプロイを自動化する技術 (WEB+DB PRESS plus)

[改訂第3版]Jenkins実践入門 ――ビルド・テスト・デプロイを自動化する技術 (WEB+DB PRESS plus)

  • 作者: 佐藤聖規,和田貴久,新井雄介,米沢弘樹,山岸啓,岩成祐樹,川口耕介
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/05/24
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

Angular の Router に関する書き方を整理する

Angular 4 以降の画面遷移、Router 周りの書き方を毎回忘れるので、自分用にまとめる。

通常のリンク

URL (ルーティング) 定義

AppModule ではなく、子の NgModule 単位でルーティングモジュールを作る方が、ディレクトリ構成と URL が対応付けやすくなる。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { ExampleComponent } from './example/example.component';

const routes: Routes = [
  { path: 'example', component: ExampleComponent }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ExampleRoutingModule { }

リンクする HTML

<!-- 以下は同義 -->
<a routerLink="/example">Link</a>
<a [routerLink]="['/example']">Link</a>

別の Component (TypeScript) から遷移する

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-index',
  templateUrl: './index.component.html',
  styleUrls: ['./index.component.scss']
})
export class IndexComponent {
  /**
   * コンストラクタ
   * 
   * router Router
   */
  constructor(private router: Router) { }
  
  /**
   * Example ページに遷移する
   */
  goToExamplePage() {
    this.router.navigate(['/example']);
  }
}

ルートパラメータ付きのリンク

クエリパラメータではなく、example/1 のように、ID などが URL にそのまま付くタイプのモノをルートパラメータという。

URL (ルーティング) 定義

const routes: Routes = [
  // 「id」を受け取る。「/example/」というパスではこのコンポーネントに到達しなくなるので注意
  { path: 'example/:id', component: ExampleComponent }
];

リンクする HTML

<!-- これで /example/1 とアクセスできる -->
<a [routerLink]="['/example', 1]">Link</a>

別の Component (TypeScript) から遷移する

// これで /example/1 とアクセスできる
this.router.navigate(['/example', 1]);

パラメータを受け取る

import { Component, OnInit } from '@angular/core';
import { Router, ParamMap } from '@angular/router';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss']
})
export class ExampleComponent implements OnInit {
  /**
   * コンストラクタ
   * 
   * router Router
   */
  constructor(private router: Router) { }
  
  /**
   * 初期表示時の処理
   */
  ngOnInit() {
    this.route.paramMap.subscribe((params: ParamMap) => {
      // ルーティングモジュールの「:id」部分の定義により、'id' で取得できる
      const id = params.get('id');
    });
  }
}

Matrix URI パラメータ付きのリンク

Matrix URI (マトリクス URI) とは、セミコロン ; を使ってパラメータを表記するモノ。?& によるクエリパラメータのようなモノだが、以下のような違い、メリットがある。

  • クエリは URI 中に1度しか書けないが、Matrix URI は複数書ける他、後ろに階層を続けて書ける
    • /user;id=123/friends といった URI が作れる
  • 参考:Matrix URIs - Ideas about Web Architecture … ティム・バーナーズ・リーが提唱してたみたい
  • セミコロン ; の場合はパラメータの順序が意味を持つモノ、カンマ , が順序に意味を持たないモノ、といった使い分けがされたりもする

Matrix URI とクエリパラメータは、ルーティングモジュール側での設定は要らない。ルーティングモジュールは「通常のリンク」の例でも、「ルートパラメータ」を使った例でも、どちらの状態でも良い。

リンクする HTML

<!-- コレで /example;hogeParam=fugaValue とアクセスできる -->
<a [routerLink]="['/example', { hogeParam: 'fugaValue' }]">Link</a>

別の Component (TypeScript) から遷移する

// コレで /example;hogeParam=fugaValue とアクセスできる
this.router.navigate(['/example', { hogeParam: 'fugaValue' }]);

連想配列でパラメータを指定する部分は、後述するクエリパラメータと書く位置が違うので注意。Matrix URI は配列の2つ目の要素として書くが、クエリパラメータは配列の外、navigate() の第2引数で書く。

パラメータを受け取る

ルートパラメータと同じく、paramMap から取得する。

this.route.paramMap.subscribe((params: ParamMap) => {
  // ルートパラメータと同じ要領で Matrix URI パラメータが取得できる
  const hogeParamValue = params.get('hogeParam');
});

クエリパラメータ

よくある /example?foo=bar&spam=ham みたいなヤツ。Matrix URI と同じく、ルーティングモジュール側での設定は要らないので、「通常のリンク」の例でも、「ルートパラメータ」を使った例でも、どちらの状態でも良い。

リンクする HTML

<!-- コレで /example?foo=bar とアクセスできる -->
<a [routerLink]="['/example']" [queryParams]="{ foo: 'bar' }">Link</a>

別の Component (TypeScript) から遷移する

// コレで /example?foo=bar とアクセスできる
this.router.navigate(['/example'], { queryParams: { foo: 'bar' } });

パラメータを受け取る

ルートパラメータ、Matrix URI パラメータを受け取る paramMap ではなく、_queryParamMap で受け取る。

this.route.queryParamMap.subscribe((params: ParamMap) => {
  // ↑ が queryParamMap になる
  const fooValue = params.get('foo');
});

ハッシュリンク・フラグメントを付ける

ページ内リンクにも使う #anchor なヤツ。Fragment (フラグメント) と呼ぶ。

リンクする HTML

<!-- コレで /example#anchor とアクセスできる -->
<a [routerLink]="['/example']" fragment="anchor">Link</a>

別の Component (TypeScript) から遷移する

// コレで /example#anchor とアクセスできる
this.router.navigate(['/example'], { fragment: 'anchor' });

アクティブなリンクを示す CSS クラスを当てる

ナビゲーションバーとかでアクティブになっているリンクのスタイルを変えたりできる。

<!-- /example に居る時、.active クラスが付与される -->
<a routerLink="/example" routerLinkActive="active">Link</a>

併用するサンプル

users/:id なルーティングが定義されているとして、/users/1;viewType=hoge/friends;genres=fuga?foo=bar#friends-name という URL に遷移してみる。

<a [routerLink]="['/users', 1, { viewType: 'hoge' }, 'friends', { genres: 'fuga' }]" [queryParams]="{ foo: 'bar' }" fragment="friends-name">Link</a>
this.router.navigate(['/users', 1, { viewType: 'hoge' }, 'friends', { genres: 'fuga' }], { queryParams: { foo: 'bar' }, fragment: '' });

// インデントするとこうなる
this.router.navigate(
  [
    '/users',
    1,
    {
      viewType: 'hoge'
    },
    'friends',
    {
      genres: 'fuga'
    }
  ],
  {
    queryParams: {
      foo: 'bar'
    },
    fragment: ''
  }
);

以上。自分が使うのは、基本はルートパラメータとたまにクエリパラメータぐらいかな、とは思うが、記法を整理できたと思う。

Angular2によるモダンWeb開発 実践編~非同期通信やセキュリティなどの応用技法~

Angular2によるモダンWeb開発 実践編~非同期通信やセキュリティなどの応用技法~

React、Angular、Vue.js、React Nativeを使って学ぶ はじめてのフロントエンド開発

React、Angular、Vue.js、React Nativeを使って学ぶ はじめてのフロントエンド開発

  • 作者: 原一浩,taisa,小松大輔,永井孝,池内孝啓,新井正貴,橋本安司,日野洋一郎
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/05/09
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

Angular Webアプリ開発 スタートブック

Angular Webアプリ開発 スタートブック