s1r-Jの技術ブログ

とあるSEの技術ブログ

Jekyll TeXt Themeのアーカイブページにポスト以外のページとタグを表示する

JekyllとGitHub pagesを使って、個人的な技術メモサイトをつくりました(がんばって記事を書こう...)。

ページのテーマはTeXt themeを使っています。
シンプルな見た目のウェブサイトで、サイドバーや目次をページに追加できるなど見やすいメモサイトができると考えて使っています。

ちょっと改善したい所

Text themeにはアーカイブページというページが用意されています。デモサイトではこのようなページとなっています。

このアーカイブページは、ポスト記事(日付で整理される記事、_postフォルダ下のファイル)の一覧とポスト記事についているタグを集めて表示してくれます。また、タグが付いているページ数をカウントし、それも合わせて表示します。さらにタグを選択すると、そのタグが付いているページだけが表示されます。

しかしながら、アーカイブページは ポスト以外のページ の表示やタグの収集はおこないません。今回の私のサイトは日付で管理するブログ的なサイトというより、勉強したことを追記するメモサイトなので、ポスト以外のページも対象にしたいところです。

対応したこと・できていないこと

上記の困りごとのため、ソースコードを改変し、ざっくりと以下の内容に対応しました。

  • Text themeのアーカイブページにポスト以外のページを一覧表示させる
  • Text themeのアーカイブページにポスト以外のページに付いているタグを収集させる
      - 収集したタグを選択するとそのタグが付いているページのみ一覧表示される
    

できていないことは以下です。

  • タグがついているページ数をカウントする

改変後のアーカイブページはこちらです。

改変したこと

先に設定の変更とソースコードの改変部分を挙げておきます。

  • Jekyllのコレクションを使ってページを管理するように_config.xmlを変更
    • コレクションをまとめるディレクトリ(collection_dir)を利用する
  • archive.htmlでポスト以外のページも一覧にする
  • tags.htmlでポスト以外のページのタグを収集し、表示させる

_config.xmlの変更

Jekyllのコレクション(collections)とは、ページをまとめた配列を作成してくれるJekyll標準機能です。

<source>/_hogeという形式でフォルダを作成し、そのフォルダ以下にページを作成すると、site.collections.hogeという配列になります。

<source>はデフォルトではトップページとなりますが、_config.xmlcollection_dirというプロパティを使用することで別のフォルダにすることができます。collection_dirを使った場合には、ポスト記事のフォルダ(_post)や下書きのフォルダ(_draft)もcollection_dirで指定したフォルダ以下に配置する必要があります。

今回は_config.xmlに以下の設定のような設定を追加します。
articlesフォルダ以下にコレクションとなるフォルダを用意します。下のような場合、_java_nodejsというフォルダを用意することになります。

collections_dir: articles
collections:
  java:
    output: true
  nodejs:
    output: true

archive.htmlの改変

archive.htmlは、元々は全てのポスト記事を一覧にして表示してくれるページです。

ここでは、先述のように設定したコレクションを用い、ポスト記事以外のページもこのアーカイブページに表示させます。

具体的には、archive.htmlを以下のように変更します。

変更前

    {% assign my_list = site.posts | concat: site.nodejs | concat: site.oidc_oauth %}
    {%- include article-list.html articles=my_list type='brief' show_info=true reverse=true group_by='year' -%}

変更後

    {%- assign page_list = "" | split: ',' -%}
    {%- for coll in site.collections -%}
      {%- assign page_list = page_list | concat: coll.docs -%}
    {%- endfor -%}
    {%- include article-list.html articles=page_list type='brief' show_info=true reverse=true group_by='year' -%}

tags.htmlの改変

tags.htmlは元々アーカイブページ(archive.html)に読み込まれ、全てのポスト記事から収集したタグの一覧を表示します。タグをクリックすると、そのタグが付いているページのみ表示されるようになります。

今回は修正をおこない、ポスト記事以外の全てのページからタグを収集するように変更します。 最終的に_tagsという変数にタグ情報を格納することで、アーカイブページにタグ機能を利用できるようになります。もともと、変数_tagsにはJekyllに用意されているsite.tagsを格納しています。このsite.tagsはポスト記事についているタグだけが入っています。そこで、全てのページのタグを集め、site.tagsの代わりに同じ構造のオブジェクトを作成してそれを渡せばよいはずです。

site.tagsの構造を説明します。site.tagsは配列になっています。配列の各要素は、さらに配列となっています。この要素の配列の先頭はタグの名称です。配列の2番目はそのタグがつけられているページ情報の配列です。

全てのページのタグから作成したタグ情報のオブジェクトの配列(site.tagsの代替、以下では「タグ情報オブジェクト配列」と呼称)を作成するため、コレクションを使います。 全てのコレクションを取り出し、各コレクションからページを取り出し、ページに付いているタグを取り出します。これらはfor文によるループで実行します。取得したタグは、作成するタグ情報オブジェクト配列に同じ名称のタグがなければ新規に追加し、反対に既に存在すればページ情報の配列に追加します。

変更内容

tags.htmlの先頭に追加します。

{%- assign page_tags = "" | split: ',' -%}

{%- for coll in site.collections -%}
  {%- for page in coll.docs -%}
    {%- for tagname in page.tags -%}
      {%- assign found = false -%}
      {%- for target in page_tags -%}
        {%- if target[0] == tagname -%}
          {%- comment -%}
          下の行がうまく実行できていない
          {%- endcomment -%}
          {%- assign target[1] = target[1] | push: page -%}
          {%- assign found = true -%}
          {%- break -%}
        {%- endif -%}
      {%- endfor -%}
      {%- if found == false -%}
        {%- assign tagstruct = "" | split: ',' -%}
        {%- assign tagstruct = tagstruct | push: tagname -%}
        {%- assign page_list = "" | split: ',' -%}
        {%- assign page_list = page_list | push: page -%}
        {%- assign tagstruct = tagstruct | push: page_list -%}
        {%- assign page_tags = page_tags | push: tagstruct -%}
      {%- endif -%}
    {%- endfor -%}
  {%- endfor -%}
{%- endfor -%}

下のコードを、

{%- assign _tags = site.tags | sort -%}

以下のように変更します。

{%- assign _tags = page_tags | sort -%}

残っている課題

記事の先頭にも記載していますが、上のコードではできていないことがあります。

tags.htmlは元々タグが付いているページ数を表示するようになっていますが、今回の改修をおこなうとページ数が正しく表示できません。tags.htmlの実装コードにもコメントとして書いていますが、対象のタグが付いているページの配列に要素を追加することができていないです。 これは私がLiquid言語の配列の仕様を理解していないため、正しい実装をできていないことが原因のようです。

また、このページの配列が正しくセットされていなくとも、タグをクリックすることでページが絞り込まれる機能は動作しました。 アーカイブページはこちらです。

参考

JenkinsのPipeline Best Practicesを邦訳したので後で読み直す

最近Jenkinsを使うようになり、Jenkinsfileの書き方などをちょっと勉強するようになりました。

Pipeline Best Practicesという有用そうな記事を後で読み直したいので日本語訳して残します。もう少し勉強して記事の内容がわかるようになったら、もう一度読み直すつもりです。


Pipeline Best Practices

このガイドはいくつかのパイプラインのベストプラクティスを示し、最もありがちな間違いを指摘します。

ゴールは、パイプラインの作成者およびメンテナーがより良いパイプラインの実行となるパターンを目指し、知らず識らずに嵌ってしまう落とし穴を避けるようにすることです。このガイドは考えられるすべてのパイプラインのベストプラクティスを網羅したリストではなく、一般的な手法を見出すために有用ないくつかの具体的な事例を紹介します。一般的に「これをおこなう」ということを知るために利用し、驚くほど詳細な「ハウツー」としては利用しないでください。

一般

パイプラインの接着剤としてGroovyコードを使用する

パイプラインの主たる機能としてではなく、一連のアクションをつなげるためにGroovyコードを利用してください。言い換えると、ビルドプロセスを進めるためにパイプラインの機能性(Groovyやパイプラインステップ)に依存するのではなく、ビルドの複数のパートを完了させるためにシングルステップ(shのような)を使ってください。複雑性の増したパイプライン(Groovyコードの量、使用されるステップ数など)は、コントローラにより多くのコンピューターリソース(CPU、メモリ、ストレージ)を必要とします。ビルドのコアではなく、ビルドを完了させるためのツールとしてパイプラインを捉えてください。

例:単一のMavenビルドステップを使い、build/test/deployプロセスのビルドを進める

パイプラインで複雑なGroovyコードを避ける

パイプラインのため、Groovyコードは常にコントローラで実行され、コントローラのリソース(メモリおよびCPU)を使用します。それゆえ、パイプラインで実行されるGroovyコードの量(パイプラインにインポートされるクラスで呼び出されるメソッドを含む)を減らすことは非常に重要です。以下は、利用を避けるべき最も一般的なGroovyメソッドの例になります:

  1. JsonSlurper:この機能(およびXmlSlurperやreadFileのような類似した機能)はディスク上のファイルを読み取り、ファイルのデータをJSONオブジェクトに変換し、JsonSlurper().parseText(readFile("$LOCAL_FILE"))のようなコマンドを利用してパイプラインにオブジェクトを注入します。このコマンドはコントローラのメモリにローカルファイルを2回ロードします。ファイルが非常に大きい場合やコマンドが頻繁に実行される場合、大量のメモリが必要となります。
    1. ソリューション:JsonSlurperを使用する代わりに、シェルステップを使用して標準出力を返してください。このシェルは以下のようになります:def JsonReturn = sh label: '', returnStdout: true, script: 'echo "$LOCAL_FILE"| jq "$PARSING_QUERY"'。これはファイルの読み取りのためにエージェントのリソースを使い、$PARSING_QUERYはファイルをより小さいサイズに変換することに役立ちます。
  2. HttpRequest:このコマンドは外部ソースからデータを取得し、変数に格納するためによく利用されます。このプラクティスは理想的ではありません。コントローラから直接リクエストが発行される(コントローラに証明書が存在しない場合、HTTPリクエストに対して正しくない結果が返ってくる)だけでなく、リクエストに対するレスポンスが2回格納されます。
    1. ソリューション:エージェントからHTTPリクエストを実行させるためにシェルステップ、必要に応じてcurlwgetのようなツールを使用します。結果がパイプラインの後半で必要な場合、エージェント側で可能な限り結果をフィルダリングし、最小限の必須情報をJenkinsコントローラに返すべきです

類似したパイプラインステップの繰り返しを減らす

パイプラインの複数のステップを単一のステップに結合することは、パイプラインの実行エンジン自体のオーバーヘッドを減らすためにしばしば利用されます。例えば、連続して3つのシェルステップを実行する場合、ステップごとに開始と停止をしなければならず、作成と片付けのためにはエージェントとコントローラのコネクションとリソースが必要となります。しかし、すべてのコマンドを単一のシェルステップに入れる場合、たった1つのステップを開始および停止することが必要です。

例:echoshステップの作成を避け、それらを1つのステップまたはスクリプトに結合する。

Jenkins.getInstanceの呼び出しを避ける

パイプラインや共有ライブラリでJenkins.instanceやそのアクセッサメソッドを利用することは、パイプラインや共有ライブラリ内でのコードの誤用を表します。サンドボックス化されていない共有ライブラリからのJenkins APIの呼び出しは、その共有ライブラリが共有ライブラリであると同時にある種のJenkinsプラグインであることを意味します。パイプラインでのJenkins APIの呼び出しは重大なセキュリティ問題およびパフォーマンス問題を避けるため、非常に注意深くなる必要があります。ビルド時にJenkins APIを利用しなければならない場合、推奨アプローチはパイプラインのステップAPIを利用し、アクセスしたいJenkins APIを安全なラッパーでくるむように実装したJavaの小さいプラグインを作成することです。サンドボックス化されたJenkinsfileからJenkins APIを直接使用するということは、パイプラインを編集できる人によってサンドボックス保護をバイパスできるようなメソッドをホワイトリストに登録する必要があることを意味します。これは重大なセキュリティリスクです。ホワイトリストに登録されたメソッドは管理者権限を持つシステムユーザによって実行され、開発者が意図しているよりも大きな権限で実行されることになります。

ソリューション:ベストソリューションは呼び出しをおこなわないことですが、実行する必要がある場合には必要なデータを収集できるJenkinsプラグインを実装することを推奨します。

共有ライブラリを利用する

組み込みパイプラインステップをオーバーライドしない

可能な限り、カスタマイズ/上書きされたパイプラインステップを避けるべきです。組み込みパイプラインステップのオーバーライドは、shtimeoutのような標準パイプラインAPIを上書きするような共有ライブラリを利用する処理を指します。パイプラインAPIはいつでも変更できるため、この処理は危険です。カスタムコードが壊れたり、期待と異なる結果をもたらしたりします。パイプラインAPIの変更によってカスタムコードが破壊されたとき、カスタムコードが変更されてなくともAPIの変更後に同じように動作するわけではないため、トラブルシューティングが難しくなります。カスタムコードが変更されなかった場合でさえ、API更新後に同じように動作するわけではありません。最後に、パイプライン全体でこれらのステップが広く使われているため、何かが正しく実装されていない/非効率に実装されている場合にJenkinsに壊滅的な結果をもたらします。

巨大なグローバル変数宣言ファイルを避ける

巨大な変数宣言ファイルを持つことは、メリットがわずかもしくは全くない代わりに変数の必要有無に関わらずすべてのパイプラインにファイルがロードされるため膨大なメモリを必要とします。現在のジョブに関連する変数だけを含んだ小さな変数ファイルを作成することを推奨します。

非常に巨大な共有ライブラリを避ける

パイプラインで巨大な共有ライブラリを利用することは、パイプラインを開始する前に非常に巨大なファイルをチェックアウトし、実行中のジョブごとに同じ共有ライブラリをロードすることを必要とします。これはメモリオーバーヘッドを増やし、実行時間を遅くすることになります。

追加のFAQへの回答

パイプラインでの並列処理

複数のパイプライン実行または複数の異なるパイプライン同士でワークスペースを共有しないようにしてください。このプラクティスは、各パイプラインまたはワークスペースでの改名を含む予期しないファイル変更を引き起こす可能性があります。

理想的には、共有ボリュームやディスクは別の場所にマウントされ、その場所から現在のワークスペースにファイルがコピーされます。そして、ビルドが完了すると、更新があった場合にファイルをコピーして戻すことができます。

必要なリソースをスクラッチで作成する個別のコンテナでビルドすべきです(クラウドタイプのエージェントはこれに最適です)。これらのコンテナをビルドすることは、いつでもビルド処理を開始し、簡単に繰り返せることを保証します。コンテナのビルドが機能しない場合、パイプラインで同時実行を無効にするか、Lockable Resourcesプラグインを使用し、実行時にワークスペースをロックし、ロック中は他のビルドがワークスペースを利用できないようにしてください。注意:同時実行を無効にしたり、実行中にワークスペースをロックしたりすることは任意のリソースがロックされている場合、リソースの待機中にパイプラインがロックされます。

また、これらの両方の手法はジョブごとに一意のリソースを利用するよりもビルド結果が出るまでに時間がかかることになります。

NotSerializableExceptionを避ける

パイプラインコードはCPS変換されるため、パイプラインはJenkins再起動後に再開することができます。パイプラインがスクリプトを実行している間、Jenkinsをシャットダウンしたり、エージェントとの接続を切断したりすることができます。再開したとき、Jenkinsは何を実行していたのかを覚えており、パイプラインのスクリプトは中断されなかったかのように処理を再開できます。「continuation-passing style(CPS)」実行として知られるテクニックはパイプラインの再開で重要な役割を果たします。しかし、いくつかのGroovy表現はCPS変換の結果として正しく動作しません。

内部的には、CPSはパイプラインの現在の状態とともに実行予定のパイプラインの残りがシリアライズ化可能であることに依存します。これはシリアライズ化できないオブジェクトをパイプラインで利用することは、パイプラインが状態を永続化しようとするとき、NotSerializableExceptionをスローさせることに意味します。

詳細な情報と問題となりうるいくつかの例は、Pipeline CPS method mismatchesを御覧ください。

以下では期待するようにパイプラインが機能することを保証するテクニックを紹介します。

永続変数がシリアライズ可能であることを保証する

ローカル変数は、シリアライズ化中にパイプラインの状態の一部としてキャプチャされます。これは、パイプライン実行に変数内のシリアライズ化できないオブジェクトを保存する際にNotSerializableExceptionがスローされることを意味します。

変数にシリアライズ不可オブジェクトを割り当てない

シリアライズ化できないオブジェクトを使う手法の1つは、値を計算して変数に格納する代わりに常に「ジャストインタイム」で値を推測させることです。

@NonCPSを利用する

必要であれば、CPS変換されると正しく実行できなくなる特定のメソッドのために@NonCPSアノテーションを利用してCPS変換を無効化できます。これは、Groovy関数が変換されていないため、完全に再実行させる必要があることに注意してください。

非同期なパイプラインステップ(shsleepのような)は常にCSP変換され、@NonCPSアノテーションがついたメソッドの内部で利用することができません。一般的に@NonCPSアノテーション付きメソッドの内部でパイプラインステップを利用することを避けるべきです。

パイプラインの耐久性

パイプラインの耐久性を変更することは、スローされるはずの箇所でNotSerializableExceptionがスローされないことは注目に値します。PERFORMANCE_OPTIMIZEDによってパイプラインの耐久性を低下させることはパイプラインの現在の状態を永続化させる頻度を大幅に低下させることを意味するからです。つまり、パイプラインはシリアライズ化できない値をシリアライズ化しようとしなくなり、結果として例外がスローされなくなります。

このメモは、この操作の根本的な原因についてユーザに。パイプラインの耐久性の設定はパフォーマンス最適化のためだけに操作し、シリアライズ化問題を避けるためにおこなうことは推奨されません。

さよならBrackets

先日Bracketsがサポート終了となり、VS Codeへの移行が推奨と発表されました。 少し前まで愛用していたエディタだったので、ここでは追悼的な記事を書き残します。Adobeのサポートが終わるだけなので、もしかすると今後さらに発展するかもしれないですし。。。

2021 年 9 月 1 日、AdobeBrackets のサポートを終了します。 Brackets の使用、保守、改善を継続する場合は、GitHub でプロジェクトをフォークできます。 Visual Studio Code は、オープンソース上に構築された Microsoft の無料コードエディターです。AdobeMicrosoft とパートナー関係にあり、このエディターへの移行をお勧めします。

写真はHOTEL EDITというホテルのマグカップです。
Bracketsっぽくておしゃれ。

ホテル エディットのマグ

Bracketsとは

Brackets - Web デザインを認識する最新のオープンソースコードエディター

Bracketsとはオープンソーステキストエディタです。ちょっとリッチなエディタで、IDEのように重くないといったエディタです。

標準でライブプレビュー機能を持っているということが売りのひとつだと思います。ライブプレビューとは、Bracketsと連携させたGoogle ChromeブラウザでBracketsで編集したHTML・CSSファイルの内容が即座に反映されるという機能です。
HTML・CSS・JSの勉強をするときに非常に便利でした。というか、もともとEclipseしか使ったことがなかったとき、Webフロント周りの勉強をするために便利なエディタを探していて見つけたのがBracketsでした。

初めて使ったときには以下のQiitaの記事を参考にセットアップしました。

Bracketsの機能紹介、使い方解説 - Qiita

記事の内容はさらにまとめられて、書籍になっています。
Webのための次世代エディタ Bracketsの教科書 | 半田 惇志 | 工学 | Kindleストア | Amazon

プラグイン(エクステンション)

Bracketsではプラグインをインストールし、組み合わせることでエディタをカスタマイズするようになっていました。

ユーザからも様々なプラグインが提供されており、例えば、エディタの表示を変えたり、ファイルツリーのアイコンを変えたり、特にマークダウンのライブプレビューにはお世話になりました。

使っていたプラグインについて書き残します。とは言っても、Brackets おすすめエクステンション集・解説 - Qiitaで紹介されているプラグインがほとんどですが。。。

記事で紹介されているエクステンション

asgerf/bracket-rename: Rename refactoring for bracket

記事中では「Refactoring Tools for JavaScript」と紹介されていました。変数名や関数名を一括で変更できるエクステンションです。リファクタリングのときに便利です。

brackets-beautify/brackets-beautify: Beautify HTML, CSS, and Javascript in Adobe Brackets

ソースコードの整形をおこなうBeautifyのエクステンションです。

cmgddd/Brackets-css-color-preview: css color preview extension for Brackets

CSSファイルで色を指定している行の左端に、実際の色を表示してくれます。

assialiholic/brackets-highlight-multibyte-symbols: Highlight multibyte symbols and alphabets.(including Show Whitespace by DennisKehrig)

マルチバイト文字(全角文字)の英数字および記号をハイライトしてくれます。なぜか動かないJSにありがちな打ち間違いを探すときに便利です。

lkcampbell/brackets-indent-guides: A Brackets extension to show indent guides in the code editor

インデントを見やすく表示してくれます。なぜか動かないJSにありがちなカッコの過不足を探すときに便利です。

brackets-key-remapper

ショートカットキーのカスタマイズをBracketsデフォルトを含めて変更できるようにするエクステンション。エクステンションを追加していくと重複したり、そもそもBrackets以外のショートカットキーと重複したりするので、その解消に使うそうです。個人的にはあまり利用しませんでした。

Bitbucketで公開されていたリポジトリが削除されたかなにかでソースコードが見られなくなっている。

gruehle/MarkdownPreview: Brackets extension for previewing markdown files

Markdownファイルのプレビューをできるようにするエクステンション。とても利用しました。

abagshaw/brackets-minifier: Minifies and Concatenates JS and CSS in Brackets using UglifyJS3 and CleanCSS

JS、CSSのminifyするためのエクステンション。正直あまり使わなかった。

konstantinkobs/brackets-colorHints: Get all used hex colors in the current CSS file as code hints

CSSファイル内で同じ色を指定するときにサジェストをしてくれます。

alessandrio/custom-work-for-brackets

複数ファイルをタブで開けるようにしたり、分割表示できるようにしたりするエクステンションです。

この手のエクステンションを複数入れると、表示がおかしくなったりBracketsが起動しなくなったりするので注意です。

dnbard/brackets-extension-rating: Brackets extension used to display other extensions rating

Bracketsに標準搭載されているエクステンション検索のソート機能を強化するエクステンションです。

yasinkuyu/brackets-tools: Brackets developer tools extension

プログラミングでよくおこなう大文字・小文字の変換など諸々を解消してくれる便利エクステンションです。

機能が多いので、インストールしてから「これはできるっけ?」みたいな感じで機能を探すとよいです。

ivogabe/Brackets-Icons: File icons in Brackets' file tree

サイドバーなどに表示されるファイルのアイコンをいい感じにします。

似ているエクステンションは多くあるので、好みで選ぶとよいでしょう。

JeffryBooher/brackets-bookmarks-extension: Brackets Editor Bookmarks Extension

ソースコード内にブックマークをつけることができます。// TODOのようなコメントを残さずに済むようになります。

Wikunia/brackets-QuickDocsJS: Inline short documentation for JavaScript functions, including a summary,syntax and parameters.

クイックドキュメント(ショートカットキーで表示される説明)に、JSのドキュメントを追加してくれる。

sathyamoorthi/brackets-sidebar-plus: adding auto show/hide to sidebar

サイドバーの挙動を改善。

sprintr/brackets-color-palette: An extension for Brackets that lets you pick colors from images.

画像から色を抽出できるエクステンション。

ペイントを開いたり、インターネット上のツールを使ったりすることなく、Bracketsで完結できるようになります。

記事で紹介されていないエクステンション

AlanHohn/markdown-toolbar: Brackets extension that adds Markdown editing support via a toolbar

Markdown記法のツールバーです。ヘッダの挿入、リストの挿入、文字表現のON/OFF、リンクの作成などを簡便にしてくれます。

ranjandatta/brackets-open-in-linux-terminal: Open current location in terminal

Bracketsで開いているワークスペース内でターミナルを開くエクステンションです。

Nodejsの実行など、いちいちファイルエクスプローラをたどってターミナル・コマンドプロンプトを開くのが面倒くさかったので、Bracketsからすぐに開くために導入しました。

yasinkuyu/brackets-newdoc: Brackets new html5 document extension

HTML5ファイルの新規作成に利用するエクステンションです。

brackets-userland/brackets-git: brackets-git — git extension for adobe/brackets

BracketsにGitクライアントの機能を追加します。

差分の確認、ステージング、コミット・プッシュをGUIで実行できるようになります。ただし、差分の表示ではマルチバイト文字が文字化けします。

Bracketsの残念なところ

Bracketsの使いにくかったところ、残念だったところを上げていきます。

UTF-8以外の文字コードに対応していない

まずはこれですね。S-JISとかのファイルがあると別のエディタで開いて、変換してというようなことをしていました。これについてはエクステンション(Hiromi-Ayase/brackets-shizimily-multiencoding)を入れることで対応できるため、そこまで大きな問題ではないかもしれません。
ですが、エクステンションがマルチバイト文字に対応していないことがあり、これは時折問題になりました。Brackets-Gitは特に面倒くさく、差分を見てもマルチバイト文字が文字化けしてしまい、ろくに確認ができませんでした。

ファイル数が3万を超えるとフリーズする

プロジェクトとしてフォルダを開くとき、ファイルが3万を超えるとフリーズします。こちらもエクステンション(brackets-userland/brackets-file-tree-exclude)で対応できるそうですが、ちょっと不親切な感じもしました。

似たエクステンションを複数インストールするとクラッシュする

サイドバーの挙動を変更するエクステンションを複数インストールするとBracketsが起動しなくなったり、表示がおかしくなったりします。
当然といえば当然ですが、こっちのエクステンションのこの機能とあっちのエクステンションのこの機能がほしいというとき、諦めざるを得なかったのは残念です。

たぶんちょっと流行っていない

難癖っぽいですが、ちょっと流行っていなかったと思います。
エクステンションはあまり管理されていないものがあり、機能の追加やバグの修正が長く行なわれていないことがありました。

プラグインのインストールがプロキシに妨害される

会社で働くSEあるあるのプロキシ大嫌い問題です。 BracketsのエクステンションはAWSのS3からファイルをダウンロードし、PCに保存して利用するようになっているようです。社内プロキシは大抵の場合、このアクセスを許可してくれておらず、エクステンションを入れることができませんでした。(プロキシ設定をちゃんとすればできた??) やるとすればGitHubからzipファイルをダウンロード・解凍し、フォルダに配置でしょうか。

ちなみにVS Codeは利用者が多いから許可しているのか、プロキシ設定がちゃんと通るのか、実際にはわかりませんが。プラグインを入れられました。

Bracketsイチオシのライブビュー機能だが、VS CodeにもLive Serverという拡張機能が存在する

上記のようなことがあってVS Codeを使おうかなー、と思っていたところ、VS Codeにもライブビュー機能があることを知り、乗り換えることになりました。

ritwickdey/vscode-live-server: Launch a development local Server with live reload feature for static & dynamic pages.

おわりに

私自身、BracketsからVS Codeに乗り換えたため、今のPCにはBracketsのインストールすらしていないです。

HTML、CSSJavaScriptやNodejsを学び始めたときに、Bracketsを使っていたのは良い出会いだったとおもます。BracketsのエクステンションにGitHubでプルリクを出したこともありますし、思い入れのあるエディタです。
Bracketsの開発が別のサポートされるようになったり、後継となるエディタができたりしたら、また使ってみたいと思います。

サンキュー、Brackets

Amazon CloudFrontで「Operation would result in exceeding resource limits.」が発生した

Amazon CloudFrontを利用しているときに、「Operation would result in exceeding resource limits.」が発生したので、その原因について調べました。

最初に断っておくと、きちんとした解決はできずに諦めてしまいました。

原因

以下に同じエラーメッセージが発生したひとがおり、また原因についても参考先を示してくれていました。 https://github.com/aws-samples/aws-waf-sample/issues/8#issuecomment-298635439

内容をみるとCloudFront自体ではなく、CloudFrontに付与しているAWS WAFのせいということでした。

AWS WAFとは、Webアプリを保護するためのAWSが提供しているウェブアプリケーションファイアウォールのこと。SQLインジェクションXSS、また特定のIPアドレスからのアクセスを防ぐことができます。

さて、エラーの原因はWAFに設定されている制限(正式には「クォータ」)にひっかかっていることでした。下記のリンク先のいずれかのクォータのようですが、タイトルのようなエラーメッセージでは内容まではわかりませんでした。

今回は利用時ではなく、設定時に発生したので「ウェブ ACLs の最大数」かなと考えましたが、確認を取る方法は不明でした。

AWS WAF のクォータ

クォータは引き上げリクエストをおこない、承認されることで緩和されますが、若干時間がかかりそうですね。

(おわり...)

参考

AWS WAF を使用してコンテンツへのアクセスを管理する - Amazon CloudFront

Oracle OpenJDK15でOWASP ZAPが起動しない

『体系的に学ぶ 安全なWebアプリケーションの作り方 第2版』では、OWASP ZAPというアプリを使って学習を進めていきます。
インストールしたあと、ZAP.exeをダブルクリックしても起動しないことがありました。

原因と対処方法をまとめておきます。

OWASP ZAP

OWASP ZAPとは、フリー(Apache 2.0)のWebアプリケーション脆弱性診断ツールのこと。
Javaで作成されており、実行するにはJREが必要となります。

下記サイトからダウンロードできます。

HTTPリクエスト・レスポンスを取得して確認したり、セッションを操作したり、諸々おこなうことができます。

ZAP.exeから起動できない

本題です。

実行環境

先に実施した環境について記載しておきます。

コマンドプロンプトjava --verisonを実行すると以下のように出力結果が得られました。

openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9-18)
OpenJDK 64-Bit Server VM (build 15.0.1+9-18, mixed mode, sharing)

エラー発生

OWASP ZAPをインストールすると、デスクトップにZAP.exeのショートカットが作成されるのでダブルクリックします。
すると、以下のようなエラーが発生しました。

起動エラー

バージョン1.8.0のJREが必要とのことですが、使っているPCにはJDK15を入れてあるため問題ないはずです。

原因

調べたところそこそこ知られている問題らしく、GitHubのissueや記事を見つけることができました。

内容としては、ZAPを起動するにはJavaSoft(Oracle) registry keysを設定しないといけないようです。

JavaSoft(Oracle) registry keys

Oracle JDKで使用しているレジストリ・キーのことらしい。

Microsoft WindowsプラットフォームでのJDKおよびJREのインストール によると以下のレジストリ・キーのことのようです。

HKEY_LOCAL_MACHINE\Software\JavaSoft\JRE HKEY_LOCAL_MACHINE\Software\JavaSoft\JRE\<version> HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Web Start\

Oracle OpenJDKでは設定されないようです。

レジストリエディタを開いて(Win + Rでregeditを入力)、確認したところ私の環境では設定されていませんでした。

exeから起動するときはWindowsの機能を利用するため、レジストリ・キーが設定されていないとダメということかもしれません。

解決策

AdoptOpenJDKをインストールする

OpenJDKにはいくつかのディストリビューションがあります。AdoptOpenJDKはその中のひとつになります。

AdoptOpenJDKではインストール時にJavaSoft(Oracle) registry keysを書き換えることができるようです。

以下のような記事を見つけました。

この方法ではせっかくインストールしたOracle OpenJDKをやめて、AdoptOpenJDKをインストールすることになります。もったいなかったので、次の方法を実行しました。

batファイルを作成する

ZAP.exeをダブルクリックで起動するのではなく、jarから起動するbatファイルを作成して起動します。

ZAPをインストールしたフォルダ(例: C:\Program Files\OWASP\Zed Attack Proxy)に以下のようなbatファイルを作成します。

このbatファイルをダブルクリックすることで、ZAPを起動することができるようになりました。

batファイルのショートカットをデスクトップに配置してあげれば使いやすいでしょう。


WSL2にDocker Desktopをインストールする

今回はWSL2にDocker Desktopをインストールして、actをインストールする準備を完了させます。

Docker公式サイトのガイド通りで問題なかったです。いくつかスクショを貼っておきます。

WSL2のインストールは、こちらを参照してください。

参考

手順

事前準備

先にWSL2をインストールしておきましょう。

ダウンロード

Windows用のインストールをダウンロードします。

インストール

ダウンロードが完了したら、インストーラを起動します。

とりあえず両方ともチェックをつけて、進めます。

インストーラ

どんどんインストールが進んでいきます。

インストール中1

インストール中2

インストールが完了しました。

インストール完了

ここまで進んだら、PCを再起動します。

Dockerの起動確認

デスクトップ上にDocker Desktopのアイコンがあるので、ダブルクリックで起動します。

docker run -d -p 80:80 docker/getting-startedを実行するように、と指示されているのでWSLを起動してコマンドを入力します。

$ docker run -d -p 80:80 docker/getting-started
Unable to find image 'docker/getting-started:latest' locally
latest: Pulling from docker/getting-started
188c0c94c7c5: Pull complete
617561f33ec6: Pull complete
7d856acdaa9c: Pull complete
a0d3c6e28e6d: Pull complete
af69a9b963c8: Pull complete
0739f3815ad8: Pull complete
7c7b75d0baf8: Pull complete
Digest: sha256:b821569034e3b5fae03b40e64a866017067f3bf17effe185b782bdbf02179528
Status: Downloaded newer image for docker/getting-started:latest

上記のような出力があって、Dockder Desktopでは起動させたコンテナが表示されます。

Docker Desktop

Docker Desktop上からコンテナの起動・停止、コマンドの発行等をおこなえるようです。

WSL2へのバージョンアップ

参考になる記事はたくさんあるけれど、いちおう書き残しておきます。

背景

個人的な事情

GitHub Actionsをローカル環境でテストできるactには、 Docker(Docker Desktop)が必要だったので入れようとしたら、WSL2が必要だったという話。

WSL2と1の比較

WSL 2 と WSL 1 の比較 | Microsoft Docs

うーん、わからない。わざわざWSL1を使う理由はなさそうなのでバージョンアップします。
Linux版のDockerをきちんとインストールできるようになる、のようなメリットを聞いたことがあります。 上述のactのインストールには必要なのでインストールします。

参考文献

以下の2つの記事を読めば全て書いてあります。
(今書いているこの記事は要らないのでは???)

  1. Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs
  2. WSL2導入|WinアップデートからWSL2を既定にするまでのスクショ - Qiita

手順

参考文献の1のほうを基本的には見ていきます。
スクショが見たくなったら2を確認します。前提条件が揃っていなくて、準備が必要な場合も2に記載されています。

Windows Insiderではないので、Manual Installation Stepsの方で実施します。

前提条件

WSLのバージョン

そもそも今使っているWSLのバージョンを確認するには以下のコマンドを実行します。

PS C:\Windows\system32> wsl --list --verbose
  NAME      STATE           VERSION
* Ubuntu    Running         2

入っているディストリビューションとそのWSLのバージョンが書いてあります。 この場合はUbuntuが入っており、そのWSLのバージョンは2であることがわかります。

Windowsのバージョン

WSL2にはWindowsのバージョンが2004である必要があります。

バージョンの確認方法は以下の通り。

Win + Rで「ファイル名を指定して実行」を開き、winverと入力。
バージョンが表示されます。

バージョンがこれ以前の場合には、Windows Updateをおこないます。

Windows Subsystem for Linuxの有効化

日本語だと「LinuxWindowsサブシステム」となっているWindowsの機能の有効化をおこないます。 以下のコマンドではなくとも コントロールパネル > プログラムと機能 > Windowsの機能の有効化または無効化 から変更することもできます。

Linux用Windowsサブシステムの有効化

コマンドを実行するときにはPowerShellを管理者権限で実行する必要があります。

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

コントロールパネルで変更した場合でもコマンドで変更した場合でも、PCを再起動します。

仮想マシン プラットフォームの有効化

さらにWindowsの機能の「仮想マシン プラットフォーム」を有効化します。「LinuxWindowsサブシステム」と同じくコントロールパネルから変更することもできます。

仮想マシン プラットフォームの有効化

また、同じくコマンドを実行することもでき、PowerShellを管理者権限で実行する必要があります。

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Linuxカーネルの更新

Linuxカーネルを更新します。
下記のMicrosoft公式サイト(「手順 4 - Linux カーネル更新プログラム パッケージをダウンロードする」)からmsiファイルをダウンロードして実行します。

Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs

WSL2を既定にする

PowerShellを起動して下記のコマンドを実行します。

wsl --set-default-version 2

Linuxディストリビューションをインストールする

WSL1のさいに何かしらのディストリビューションを入れていればこの部分は飛ばします。

ここまでの手順をおこなって新規にインストールした場合には、WSL2で動くことになります。

Microsoft Storeを開いて、好みのディストリビューションをインストールします。
とりあえず、Ubuntuあたりがよさそう。

インストールしたディストリビューションのバージョンが気になれば、以下のコマンドをPowerShellで実行して確認できます。

PS C:\Windows\system32> wsl --list --verbose
  NAME      STATE           VERSION
* Ubuntu    Running         2

既にインストールしているディストリビューションをWSL2にする

既に何かしらのディストリビューションをインストールしている場合には、以下のコマンドをPowerShellで実行してバージョンをWSL2にします。

wsl --set-version <distribution name> <versionNumber>

<distribution name>にはディストリビューションの名称にします。例:Ubuntu
<versionNumber>は今回WSL2を使うようにしたいので2にします。

ディストリビューションの名称ですが、下記のコマンドの出力結果NAMEにあたります。

PS C:\Windows\system32> wsl --list --verbose
  NAME      STATE           VERSION
* Ubuntu    Running         2

終わりに

今回私が実行したときには上述の流れで問題は発生しませんでした。
よくあるトラブルシューティングMicrosoft公式サイトに記載されています。

やはり公式サイトが最強ですね。