Anaconda カスタマイズガイド
インストーラーの表示の変更とカスタムアドオンの作成
概要
サポートステートメント
Red Hat は、Red Hat Enterprise Linux インストールメディアの変更またはカスタマイズをサポートしていませ ん。システムテンプレートやライブ CD などの OS イメージをカスタマイズするには、キックスタート を使用してインフラストラクチャー内に一貫したシステムを構築するか、Red Hat Enterprise Linux Image Builder を使用してカスタム OS イメージを作成します。
1. Anaconda のカスタマイズの概要
- ブートメニュー: 事前設定されたオプション、色スキーム、および背景
- グラフィカルインターフェイスの外観: ロゴ、背景、製品名
- インストーラーの機能: グラフィカルユーザーインターフェイスおよびテキストユーザーインターフェイスに新しいキックスタートコマンドと新しい画面を追加して、インストーラーを強化できるアドオン
2. ISO イメージを使った作業
2.1. Red Hat Enterprise Linux Boot イメージの抽出
手順1 ISO イメージの抽出
- ダウンロードしたイメージをマウントします。
#
mount -t iso9660 -o loop path/to/image.iso /mnt/isopath/to/image.iso をダウンロードした ISO へのパスで置き換えます。ターゲットとするディレクトリー (/mnt/iso
) が存在し、そこに他のものがマウントされていないことを確認します。 - ISO イメージのコンテンツを配置する作業ディレクトリーを作成します。
$
mkdir /tmp/ISO - マウントされたイメージのすべてのコンテンツを新しい作業ディレクトリーにコピーします。
-p
オプションを使用して、ファイルおよびディレクトリーのパーミッションと所有権を保持するようにしてください。#
cp -pRf /mnt/iso /tmp/ISO - イメージをアンマウントします。
#
umount /mnt/iso
/tmp/ISO
に抽出され、ここでコンテンツの修正ができます。続ける「ブートメニューのカスタマイズ」また「インストーラーアドオンの開発」.変更が完了したら、の手順を使用して、変更された新しい ISO イメージを作成します。「カスタムブートイメージの作成」 .
2.2. product.img ファイルの作成
product.img
イメージファイルは、インストーラーのランタイムに既存ファイルを置き換える、または新たなファイルを追加する、ファイルを含むアーカイブです。起動中の Anaconda はブートメディアの images/
ディレクトリーからこのファイルを読み込みます。そしてこのファイル内にあるファイルを使用してインストーラーのファイルシステム内にある同一名のファイルを置換します。インストーラーのカスタマイズにはこれが必要になります (例えば、デフォルトのイメージをカスタムのもので置き換える場合)。product.img
イメージに含まれるディレクトリーは、インストーラーと同じディレクトリー構造である必要があります。
カスタムコンテンツのタイプ | ファイルシステムの場所 |
---|---|
Pixmaps (ロゴ、サイドバー、トップバー、など) | /usr/share/anaconda/pixmaps/ |
インストール進捗画面のバナー | /usr/share/anaconda/pixmaps/rnotes/en/ |
GUI スタイルシート | /usr/share/anaconda/anaconda-gtk.css |
Installclasses (製品名変更用) | /run/install/product/pyanaconda/installclasses/ |
Anaconda アドオン | /usr/share/anaconda/addons/ |
product.img
ファイルを作成します。
手順2 product.img の作成
/tmp
などの作業ディレクトリーに移動し、product/
という名前のサブディレクトリーを作成します。$
cd /tmp$
mkdir product/- 置換するファイルの場所と同じディレクトリー構造を作成します。例えば、アドオンをテストする場合、これがインストールシステムの
/usr/share/anaconda/addons
に配置されているとすると、作業ディレクトリー内で同じ構造を作成します。$
mkdir -p product/usr/share/anaconda/addons注記インストーラーのランタイムファイルシステムをブラウズするには、インストールを起動し、仮想コンソール 1 に切り替え (Ctrl+Alt+F1) その後に 2 つ目の tmux ウィンドウに切り替えます (Ctrl+b 2)。これでファイルシステムをブラウズするためのシェルプロンプトが開きます。 - カスタマイズしたファイル (この例では、Anaconda 用のカスタムアドオン) を新規作成したディレクトリーに配置します。
$
cp -r ~/path/to/custom/addon/ product/usr/share/anaconda/addons/ - インストーラーに追加するすべてのファイルについて、上記の 2 つのステップを繰り返します (ディレクトリー構造の作成および変更済みファイルの移動)。
- このディレクトリーの root に
.buildstamp
ファイルを作成します。これは、product.img
ファイルになります。このファイルは、product.img
ファイルになります。以下は、Red Hat Enterprise Linux 7.4 からの.buildstamp
ファイルの例です。[Main] Product=Red Hat Enterprise Linux Version=7.4 BugURL=https://bugzilla.redhat.com/ IsFinal=True UUID=201707110057.x86_64 [Compose] Lorax=19.6.92-1
IsFinal
パラメーター。そのイメージが製品のリリース (一般公開) バージョンである (True
) か、アルファ、ベータ、内部マイルストーンなどのプレリリース版である (False
) かを指定します。 product/
ディレクトリーに移動し、product.img
アーカイブを作成します。$
cd product$
find . | cpio -c -o | gzip -9cv > ../product.imgこれでproduct.img
ファイルがproduct/
ディレクトリーの 1 つ上のレベルに作成されます。product.img
ファイルを抽出した ISO イメージのimages/
ディレクトリーに移動します。
product.img
ファイルはインストーラーの起動時に自動的に読み込まれます。
product.img
ファイルを追加する代わりに、別の場所にこのファイルを追加し、ブートメニューで inst.updates=
ブートオプションを使用して読み込むことができます。この場合、イメージファイルは任意の名前を指定することができ、インストールシステムからこの場所にアクセス可能な限り、任意の場所 (USB フラッシュドライブ、ハードディスク、HTTP、FTP、または NFS サーバー) に配置できます。
2.3. カスタムブートイメージの作成
手順3 ISO イメージの作成
- すべての変更が作業ディレクトリーに含まれていることを確認してください。例えば、アドオンをテストする場合は、
product.img
をimages/
ディレクトリーに配置します。 - 作業ディレクトリーが抽出した ISO イメージのトップレベルのディレクトリーであることを確認します。例えば、
/tmp/ISO/iso
。 - genisoimage を使用して、新規 ISO イメージを作成します。
#
genisoimage -U -r -v -T -J -joliet-long -V "RHEL-7.1 Server.x86_64" -volset "RHEL-7.1 Server.x86_64" -A "RHEL-7.1 Server.x86_64" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -e images/efiboot.img -no-emul-boot -o ../NEWISO.iso .上記の例では、以下のようになります。- 同じディスクにファイルを読み込む場所を必要とするオプションに
LABEL=
ディレクティブを使用している場合は、-V
、-volset
、-A
のオプションの値がイメージのブートローダー設定と一致することを確認してください。ブートローダーの設定 (BIOS の場合はisolinux/isolinux.cfg
、UEFI の場合はEFI/BOOT/grub.cfg
) がinst.stage2=LABEL=disk_label
スタンザを使用して同じディスクからインストーラーの 2 番目のステージを読み込む場合は、ディスクラベルが一致する必要があります。重要ブートローダー設定ファイルで、ディスクラベルのすべてのスペースを\x20
に置き換えます。例えば、RHEL 7.1
というラベルの ISO イメージを作成する場合、ブートローダー設定ではRHEL\x207.1
を使用してこのラベルを参照します。 -o
オプションの値 (-o ../NEWISO.iso
) を、新しいイメージのファイル名に置き換えます。この例の値は、現在のディレクトリーの上にNEWISO.iso
ファイルを作成します。
このコマンドに関する詳細は、genisoimage(1)
man ページを参照してください。 - MD5 チェックサムをイメージに埋め込みます。このステップを実行しないと、イメージ検証チェック (ブートローダー設定の
rd.live.check
オプション) に失敗し、インストールを続行できなくなります。#
implantisomd5 ../NEWISO.isoこの例では、../NEWISO.iso をこの前のステップで作成した ISO イメージのファイル名と場所で置き換えます。
4. グラフィカルユーザーインターフェイスのブランド化と色調節
product.img
ファイルを作成し、これに installclass (インストーラーで表示される製品名を変更する) と独自のブランド化資料を格納します。この product.img
ファイルはインストールイメージではありません。これは完全インストール ISO イメージを補完するもので、カスタマイズを読み込んで使用することで、デフォルトでブートイメージに含まれているファイルを上書きします。
product.img
ファイルの作成、およびこのファイルを ISO イメージに追加する方法については、を参照してください。
4.1. グラフィカル要素のカスタマイズ
/usr/share/anaconda/pixmaps/
ディレクトリーに保存されています。このディレクトリーには以下のファイルが格納されています。
pixmaps ├─ anaconda-selected-icon.svg ├─ dialog-warning-symbolic.svg ├─ right-arrow-icon.png ├─ rnotes │ └─ en │ ├─ RHEL_7_InstallerBanner_Andreas_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_Blog_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_CPAccess_CommandLine_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_CPAccess_Desktop_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_CPAccess_Help_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_Middleware_750x120_11649367_1213jw.png │ ├─ RHEL_7_InstallerBanner_OPSEN_750x120_11649367_1213cd.png │ ├─ RHEL_7_InstallerBanner_RHDev_Program_750x120_11649367_1213cd.png │ ├─ RHEL_7_InstallerBanner_RHELStandardize_750x120_11649367_1213jw.png │ └─ RHEL_7_InstallerBanner_Satellite_750x120_11649367_1213cd.png ├─ sidebar-bg.png ├─ sidebar-logo.png └─ topbar-bg.png
/usr/share/anaconda/
ディレクトリーには anaconda-gtk.css
という名前の CSS スタイルシートが格納されており、これがファイル名や、ロゴおよびサイドバー/トップバーの背景といったメインの UI 要素のパラメーターを決定します。このファイルには以下のコンテンツが含まれます。
/* vendor-specific colors/images */ @define-color redhat #021519; /* logo and sidebar classes for RHEL */ .logo-sidebar { background-image: url('/usr/share/anaconda/pixmaps/sidebar-bg.png'); background-color: @redhat; background-repeat: no-repeat; } .logo { background-image: url('/usr/share/anaconda/pixmaps/sidebar-logo.png'); background-position: 50% 20px; background-repeat: no-repeat; background-color: transparent; } AnacondaSpokeWindow #nav-box { background-color: @redhat; background-image: url('/usr/share/anaconda/pixmaps/topbar-bg.png'); background-repeat: no-repeat; color: white; } AnacondaSpokeWindow #layout-indicator { color: black; }
@define-color
の行で一致する背景色を定義します。そのため、バックグラウンド イメージ は背景の 色 にフェードします。これは、イメージのスケーリングを必要とせずに、すべての解像度でバックグラウンドが機能することを意味します。
background-repeat
パラメーターをバックグラウンドのタイル配置に変更することもできます。インストールするすべてのシステムが同じディスプレイの解像度を持つことを保証している場合は、バー全体を埋めるバックグラウンドイメージを使用できます。
rnotes/
ディレクトリーにはバナーのセットを格納します。インストール中は、ほぼ 1 分ごとにバナーイメージが画面下部で循環します。
product.img
を作成し、「カスタムブートイメージの作成」変更を含む新しいブータブル ISO イメージを作成します。
4.2. 製品名のカスタマイズ
custom.py
という名前の新規ファイルを作成します。
例1 カスタム Installclass の作成
from pyanaconda.installclass import BaseInstallClass from pyanaconda.product import productName from pyanaconda import network from pyanaconda import nm class CustomBaseInstallClass(BaseInstallClass): name = "My Distribution" sortPriority = 30000 if not productName.startswith("My Distribution"): hidden = True defaultFS = "xfs" bootloaderTimeoutDefault = 5 bootloaderExtraArgs = [] ignoredPackages = ["ntfsprogs"] installUpdates = False _l10n_domain = "comps" efi_dir = "redhat" help_placeholder = "RHEL7Placeholder.html" help_placeholder_with_links = "RHEL7PlaceholderWithLinks.html" def configure(self, anaconda): BaseInstallClass.configure(self, anaconda) BaseInstallClass.setDefaultPartitioning(self, anaconda.storage) def setNetworkOnbootDefault(self, ksdata): if ksdata.method.method not in ("url", "nfs"): return if network.has_some_wired_autoconnect_device(): return dev = network.default_route_device() if not dev: return if nm.nm_device_type_is_wifi(dev): return network.update_onboot_value(dev, "yes", ksdata) def __init__(self): BaseInstallClass.__init__(self)
class CustomBaseInstallClass(BaseInstallClass): name = "My Distribution" sortPriority = 30000 if not productName.startswith("My Distribution"): hidden = True
sortPriority
属性が 20000
を超えていることを確認します。これにより、新規インストールクラスが最初に読み込まれるようになります。
product.img
ファイルを作成し、「カスタムブートイメージの作成」変更を含む新しいブータブル ISO ファイルを作成します。
5. インストーラーアドオンの開発
5.1. Anaconda とアドオンについて
5.1.1. Anaconda の概要
Gtk
ウィジェット (C で作成)、systemd
ユニット、および dracut
ライブラリーといったファイルも含まれています。これらが一体となることで、このツールを使用するとターゲットとなるシステムのパラメーターを設定でき、そのシステムをマシンにセットアップします。インストールプロセスには、主に 4 つのステップがあります。
- インストール先の準備 (通常はディスクのパーティション設定)
- パッケージおよびデータのインストール
- ブートローダーのインストールと設定
- 新規にインストールされたシステムの設定
VNC
を使ったリモートアクセスもサポートしており、これを使用するとグラフィックスカードやモニターのないシステムでも GUI の使用が可能になります。ただし、この方法が望ましくない場合もあり、また対話式インストールを希望する場合もあるでしょう。そのようなケースでは、テキストモード (TUI) が使用できます。TUI はモノクロのラインプリンターのように動作し、カーソルやカラー、他の高度な機能に対応していないシリアルコンソールでも機能します。テキストモードは、ネットワーク設定や言語オプション、インストール (パッケージ) ソースなどの非常に一般的なオプションしかカスタマイズできないという制限があります。手動によるパーティション設定といったような高度な機能はこのインターフェイスでは利用できません。
5.1.2. 初回起動と初期設定
Gtk2
や pygtk2
などのメンテナーンスされていないツールに依存しています。[1] このため、Initial Setup と呼ばれる新しいツールが開発され、Anaconda のコードを再利用します。これにより、Anaconda 向けに開発されたアドオンを Initial Setup で簡単に再利用できます。このトピックについては、「Anaconda アドオンの作成」 .
5.1.3. Anaconda と初期設定アドオン
5.1.4. 追加情報
- Fedora Project Wiki の Anaconda ページ にはインストーラーについての詳細情報があります。
- Anaconda の、現行バージョンへの開発に関する情報は、Anaconda/NewInstaller の Wiki ページ にあります。
- 『Red Hat Enterprise Linux 7 インストールガイド』のキックスタートを使ったインストールの章では、対応しているコマンドとオプションの一覧など、キックスタートの全ドキュメントを紹介します。
- 『Red Hat Enterprise Linux 7 インストールガイド』のAnaconda を使用したインストールの章では、グラフィカルユーザーインターフェイスのインストールプロセスが説明されています。
- インストール後の設定に使用するツールの情報は、初期設定を参照してください。
5.2. Anaconda のアーキテクチャー
pykickstart
- Kickstart ファイルを解析、検証するとともに、インストールを実行する値を保存するデータ構造も提供します。yum
- パッケージのインストールと依存関係の解決を処理するパッケージマネージャーです。blivet
- もともと anaconda パッケージから pyanaconda.storage として分割されました。ストレージ管理に関連するすべてのアクティビティーを処理するために使用されますpyanaconda
- キーボードとタイムゾーンの選択、ネットワーク設定、ユーザー作成、さらには多数のユーティリティーやシステム指向の機能など、Anaconda 固有の機能向けのユーザーインターフェイスやモジュールを含むパッケージです。python-meh
- クラッシュ時に追加のシステム情報を収集、保存し、この情報をlibreport
ライブラリーに渡す例外ハンドラーを含みます。このライブラリー自体は ABRT プロジェクト に含まれます。
pykickstart
モジュールがこれを処理してツリー構造としてメモリーにインポートします。Kickstart ファイルが提供されない場合は、代わりに空のツリー構造が作成されます。インストールが対話式の場合 (必須の Kickstart コマンドの一部しか使用されなかった場合)、この構造は対話式インターフェイスでユーザーが選択したもので更新されます。
/root/
ディレクトリーに保存されます。このため、この自動生成の Kickstart ファイルを再使用することで、このインストールを自動複製することが可能になります。
pyanaconda.kickstart
モジュールの修正版によってオーバーライドできます。この動作を決定する重要なルールは、選択データの保存場所がなく、インストールプロセスはデータ駆動型であり、最大限この処理に依存しているということです。このため、以下の点が確保されます。
- インストーラーの全機能が Kickstart でサポートされる 必要がある
- インストールプロセスで、変更がターゲットシステムに書き込まれる単一の明確な時点がある。この時点の前では、永続的な変更 (例: ストレージのフォーマット) はなされません
- ユーザーインターフェイスでなされた手動での変更は作成される Kickstart ファイルに反映され、複製が可能
setup
メソッド)、それを実行することで (execute
メソッド) ターゲットシステム上で変更がなされます。これらの方法については、「Anaconda アドオンの作成」 .
5.3. ハブ & スポークモデル
- ユーザーは画面上でインストールを進める際に決まった順序に従う必要がない。
- 設定するオプションについて理解しているかどうかに関わらず全画面を開く必要がない。
- 特定のボタンがクリックされるまで、希望する値を設定してもマシンには実際には何もされないというトランザクションモードが機能する。
- 設定された値の概要を表示する方法がある。
- 並び替えや複雑な並び順の依存関係を解決せずに新たなスポークをハブに追加できるので、拡張性が高い。
- インストーラーのグラフィカルとテキストと両方のモードに使用可能。
図2 ハブ & スポークモデルの図
- インストールの概要 ハブ。インストール前に設定したオプションの概要を表示します。
- 設定および進捗状況 ハブ。インストールの概要 で インストールの開始 をクリックすると表示され、インストールプロセスの進捗状況が確認できるほか、追加オプションの設定ができます (root パスワードの設定やユーザーアカウントの作成など)。
- ready: スポークが開けるかどうかを指定します。例えば、あるパッケージソースをインストーラーが設定している場合、そのスポークは準備ができておらずグレー表示され、設定が完了するまでアクセスできません。
- completed: スポークが完了 (必須の値がすべて設定済み) か未完了かをマークします。
- mandatory: インストールの続行にそのスポークを開いてユーザーが確認する 必要がある かどうかを決定します。例えば、自動ディスクパーティション設定を使用する場合でも、インストール先 スポークは開く必要があります。
- status: (ハブのスポーク名で表示される) 内で設定された値の短いサマリーを提供します。
5.4. スレッドと連絡
GLib.idle_add
を使うことですが、これは必ずしも容易ではなく、推奨されません。この問題を軽減するために、いくつかのヘルパー関数とデコレーターが pyanaconda.ui.gui.utils モジュールで定義されています。
@gtk_action_wait
および @gtk_action_nowait
デコレーターです。これらは、装飾された関数やメソッドを変更し、これらが呼び出されると自動的に Gtk のメインループにキュー登録され、戻り値が発信者に返されるか切断されるようにします。
hubQ
というメッセージキューによって処理され、メインイベントループで定期的にチェックされています。スポークがアクセス可能になると、その旨とブロックされないべきであるとのメッセージをこのキューに送信します。
progressQ
と呼ばれる別のキューがあり、インストールの進捗状況更新を送信するロールを果たします。
5.5. Anaconda アドオンの構造
__init__.py
と他のソースディレクトリー (サブパッケージ) を格納しているディレクトリーが含まれています。Python は各パッケージ名のインポートを 1 回しか許可しないので、パッケージのトップレベルのディレクトリー名は一意のものである必要があります。同時に、アドオンは名前に関係なく読み込まれるため、任意の名前を指定できます。必須要件は、特定のディレクトリーに配置する必要があることです。
_
) で組織に予約されているドメイン名を持つアドオン名に接頭辞を付けます。これにより、ディレクトリー名が Python パッケージの有効な識別子となります。つまり、アドオン名の前に自分の組織のリバースドメイン名を追加します (com_example_hello_world
)。この規則は、Python パッケージおよびモジュール名の recommended naming scheme (推奨命名スキーム) に準拠しています。
__init__.py
ファイルを作成することを忘れないでください。このファイルがないディレクトリーは、有効な Python パッケージとはみなされません。
ks
、グラフィカルインターフェイスには gui
、テキストベースのインターフェイスには tui
という名前を指定する必要があります。gui
と tui
パッケージには、spokes
サブパッケージが含まれる必要があります。[3]
ks/
、gui/
および tui/
のディレクトリー内の Python モジュール名はどんなものでも構いません。
例2 アドオン構造の例
com_example_hello_world ├─ ks │ └─ __init__.py ├─ gui │ ├─ __init__.py │ └─ spokes │ └─ __init__.py └─ tui ├─ __init__.py └─ spokes └─ __init__.py
5.6. Anaconda アドオンの作成
5.6.1. キックスタートのサポート
com_example_hello_world/ks/
ディレクトリーに移動し、__init__.py
ファイルがあることを確認して、さらに hello_world.py
という名前の Python スクリプトを追加します。
例3 Kickstart ファイルでのアドオンの使用
%addon ADDON_NAME [arguments] first line second line ... %end
AddonData
と呼ばれます。このクラスは pyanaconda.addons で定義され、キックスタートファイルからのデータを解析および保存するためのオブジェクトを表します。
AddonData
クラスから継承されたアドオンクラスのインスタンスに、リストとして渡されます。最初の行と最後の行の間にあるものはすべて、一度に一行ずつアドオンのクラスに渡されます。Hello World のアドオンサンプルをシンプルにするために、このブロック内のすべての行を単一行にまとめ、元の行を空白で区切ります。
AddonData
から継承する必要があります。pyanaconda/addons.py
モジュールにはこれに使用可能な以下の 2 つのメソッドが含まれています。
handle_header
: %addon 行のリスト (およびエラー報告用の行番号) を取ります。handle_line
: %addon と %end のステートメント間のコンテンツの単一行を取ります。
例4 handle_header と handle_line の使用
from pyanaconda.addons import AddonData from pykickstart.options import KSOptionParser # export HelloWorldData class to prevent Anaconda's collect method from taking # AddonData class instead of the HelloWorldData class # :see: pyanaconda.kickstart.AnacondaKSHandler.__init__ __all__ = ["HelloWorldData"] HELLO_FILE_PATH = "/root/hello_world_addon_output.txt" class HelloWorldData(AddonData): """ Class parsing and storing data for the Hello world addon. :see: pyanaconda.addons.AddonData """ def __init__(self, name): """ :param name: name of the addon :type name: str """ AddonData.__init__(self, name) self.text = "" self.reverse = False def handle_header(self, lineno, args): """ The handle_header method is called to parse additional arguments in the %addon section line. :param lineno: the current linenumber in the kickstart file :type lineno: int :param args: any additional arguments after %addon <name> :type args: list """ op = KSOptionParser() op.add_option("--reverse", action="store_true", default=False, dest="reverse", help="Reverse the display of the addon text") (opts, extra) = op.parse_args(args=args, lineno=lineno) # Reject any additoinal arguments. Since AddonData.handle_header # rejects any arguments, we can use it to create an error message # and raise an exception. if extra: AddonData.handle_header(self, lineno, extra) # Store the result of the option parsing self.reverse = opts.reverse def handle_line(self, line): """ The handle_line method that is called with every line from this addon's %addon section of the kickstart file. :param line: a single line from the %addon section :type line: str """ # simple example, we just append lines to the text attribute if self.text is "": self.text = line.strip() else: self.text += " " + line.strip()
__all__
変数の定義から始めます。これは、Anaconda の collect メソッドがアドオン固有の HelloWorldData
ではなく AddonData
クラスを取得しないようにするのに必要な変数を定義します。
__init__
を呼び出して、self.text
と self.reverse
属性を False
に初期化する __init__
メソッドで、AddonData
から継承したクラス HelloWorldData
の定義を示しています。
self.reverse
属性が handle_header
メソッドに反映され、self.text
が handle_line
に反映されます。handle_header
メソッドは pykickstart
が提供する KSOptionParser
のインスタンスを使用して、%addon 行で使用される追加オプションを解析し、handle_line
は各行の最初と終了時に空白のコンテンツ行を取り除き、self.text
に追加します。
setup
: インストール処理の開始前に呼び出され、インストールランタイム環境の変更に使用されます。execute
: 処理の最後に呼び出され、ターゲットシステムの変更に使用されます。
例5 setup および execute メソッドのインポート
import os.path from pyanaconda.addons import AddonData from pyanaconda.constants import ROOT_PATH HELLO_FILE_PATH = "/root/hello_world_addon_output.txt"
setup
および execute
メソッドを含む Hello World アドオンの更新例を以下に示します。
例6 setup および execute メソッドの使用
def setup(self, storage, ksdata, instclass, payload): """ The setup method that should make changes to the runtime environment according to the data stored in this object. :param storage: object storing storage-related information (disks, partitioning, bootloader, etc.) :type storage: blivet.Blivet instance :param ksdata: data parsed from the kickstart file and set in the installation process :type ksdata: pykickstart.base.BaseHandler instance :param instclass: distribution-specific information :type instclass: pyanaconda.installclass.BaseInstallClass :param payload: object managing packages and environment groups for the installation :type payload: any class inherited from the pyanaconda.packaging.Payload class """ # no actions needed in this addon pass def execute(self, storage, ksdata, instclass, users, payload): """ The execute method that should make changes to the installed system. It is called only once in the post-install setup phase. :see: setup :param users: information about created users :type users: pyanaconda.users.Users instance """ hello_file_path = os.path.normpath(ROOT_PATH + HELLO_FILE_PATH) with open(hello_file_path, "w") as fobj: fobj.write("%s\n" % self.text)
setup
メソッドは何もせず、Hello World アドオンはインストールランタイム環境に変化を加えません。execute
メソッドは、保存したテキストを、ターゲットシステムのルート (/
) ディレクトリーで作成したファイルに書き込みます。
__str__
メソッドを呼び出すことで実行されます。つまり、AddonData
から継承されたクラスは、有効なキックスタート構文で保存されたデータを返す独自の __str__
メソッドを定義する必要があります。この返されるデータは、pykickstart
を使用して再度解析する必要があります。
__str__
メソッドを以下の例のようになります。
例7 __str__ メソッドの定義
def __str__(self): """ What should end up in the resulting kickstart file, i.e. the %addon section containing string representation of the stored data. """ addon_str = "%%addon %s" % self.name if self.reverse: addon_str += "--reverse" addon_str += "\n%s\n%%end" % self.text return addon_str
handle_header
、handle_line
、setup
、execute
、および __str__
) が含まれると、有効な Anaconda アドオンになります。次のセクションに進み、グラフィカルおよびテキストベースのユーザーインターフェイスのサポートを追加するか、次のセクションに進むことができます。「Anaconda アドオンのデプロイおよびテスト」アドオンをテストします。
5.6.2. グラフィカルユーザーインターフェイス
SpokeWindow
などの Anaconda 固有の Gtk ウィジェットを含む anaconda-widgets および anaconda-widgets-devel パッケージを必ずインストールしてください。
5.6.2.1. 基本的機能
NormalSpoke
で、これは pyanaconda.ui.gui.spokes
で定義されます。クラス名の通り、ノーマルスポーク タイプのスクリーン用のクラスです。「ハブ & スポークモデル」 .
NormalSpoke
から継承した新たなクラスを実装するには、API が必要とする以下のクラス属性を定義する必要があります。
builderObjects
: スポークの.glade
ファイルからすべてのトップレベルオブジェクトを一覧表示します。これらのオブジェクトは、その子オブジェクトとともに (反復的に) スポークに公開されるべきものです。ただし、すべてをスポークに公開する場合 (非推奨) は、空のリストにします。uiFile
:.glade
ファイルの名前が含まれます。category
: スポークが属するカテゴリーのクラスが含まれます。icon
: ハブ上のスポークに使用するアイコンの識別子が含まれます。title
: ハブ上のスポークに使用するタイトルを定義します。
例8 Normalspoke クラスに必須の属性の定義
# will never be translated _ = lambda x: x N_ = lambda x: x # the path to addons is in sys.path so we can import things from org_fedora_hello_world from org_fedora_hello_world.gui.categories.hello_world import HelloWorldCategory from pyanaconda.ui.gui.spokes import NormalSpoke # export only the spoke, no helper functions, classes or constants __all__ = ["HelloWorldSpoke"] class HelloWorldSpoke(NormalSpoke): """ Class for the Hello world spoke. This spoke will be in the Hello world category and thus on the Summary hub. It is a very simple example of a unit for the Anaconda's graphical user interface. :see: pyanaconda.ui.common.UIObject :see: pyanaconda.ui.common.Spoke :see: pyanaconda.ui.gui.GUIObject """ ### class attributes defined by API ### # list all top-level objects from the .glade file that should be exposed # to the spoke or leave empty to extract everything builderObjects = ["helloWorldSpokeWindow", "buttonImage"] # the name of the main window widget mainWidgetName = "helloWorldSpokeWindow" # name of the .glade file in the same directory as this source uiFile = "hello_world.glade" # category this spoke belongs to category = HelloWorldCategory # spoke icon (will be displayed on the hub) # preferred are the -symbolic icons as these are used in Anaconda's spokes icon = "face-cool-symbolic" # title of the spoke (will be displayed on the hub) title = N_("_HELLO WORLD")
__all__
属性はスポーククラスのエクスポートに使用され、これまでに説明した属性の定義を含む定義の最初の行がその後に続きます。これらの属性値は、com_example_hello_world/gui/spokes/hello.glade
ファイルで定義されるウィジェットを参照します。
category
で、com_example_hello_world.gui.categories
モジュールの HelloWorldCategory
クラスからインポートされます。のHelloWorldCategory
class については後で説明しますが、ここでは、com_example_hello_world パッケージからインポートできるように、アドオンへのパスが sys.path にあることに注意してください。
title
で、定義に 2 つのアンダースコアが含まれています。最初の 1 つは、翻訳の文字列のマークをマークする N_
関数名の一部ですが、変換されていないバージョンの文字列を返します (変換は後で行われます)。2 つ目のアンダースコアはタイトル自体の始まりをマークし、Alt+H キーボードのショートカットを使用してスポークに移動できるようにします。
__init__
メソッドと initialize
メソッドという 2 つの方法があります。
__init__
メソッドは親の __init__
メソッドのみを呼び出してから、GUI 以外の属性を初期化します。一方、インストーラーのグラフィカルユーザーインターフェイスの初期化時に呼び出される initialize
メソッドは、スポークの完全な初期化を完了する必要があります。
__init__
メソッドに渡される属性の数と記述に注意):
例9 __init__ および initialize メソッドの定義
def __init__(self, data, storage, payload, instclass): """ :see: pyanaconda.ui.common.Spoke.__init__ :param data: data object passed to every spoke to load/store data from/to it :type data: pykickstart.base.BaseHandler :param storage: object storing storage-related information (disks, partitioning, bootloader, etc.) :type storage: blivet.Blivet :param payload: object storing packaging-related information :type payload: pyanaconda.packaging.Payload :param instclass: distribution-specific information :type instclass: pyanaconda.installclass.BaseInstallClass """ NormalSpoke.__init__(self, data, storage, payload, instclass) def initialize(self): """ The initialize method that is called after the instance is created. The difference between __init__ and this method is that this may take a long time and thus could be called in a separated thread. :see: pyanaconda.ui.common.UIObject.initialize """ NormalSpoke.initialize(self) self._entry = self.builder.get_object("textEntry")
data
パラメーターが __init__
メソッドに渡されていることに留意してください。これは、すべてのデータが保存されている Kickstart ファイルのインメモリーのツリー構造を表します。ancestor の __init__
メソッドのいずれかで、self.data
属性に格納されます。これにより、クラス内の他のすべてのメソッドで構造の読み取りおよび修正が可能になります。
HelloWorldData
クラスはすでに定義されています「キックスタートのサポート」、すでにサブツリーがありますself.data
このアドオンのルート (クラスのインスタンス) は次のように利用できます。self.data.addons.com_example_hello_world
.
__init__
は他にも、スポークの .glade
ファイルがある GtkBuilder
のインスタンスを初期化し、これを self.builder
として保存します。これは、kickstart ファイルの %addon セクションからのテキストの表示およびその修正に使用される GtkTextEntry
の取得に initialize
で使用されます。
__init__
および initialize
メソッドは両方とも、スポークの作成時に重要となります。ただし、スポークの主要なロールは、ユーザーがこのスポークで表示、設定される値を変更または見直すことです。これを有効にするには、その他の 3 つの方法を使用できます。
refresh
: スポークをユーザーが表示する際に呼び出されます。このメソッドはスポークの状態を更新し (主に UI 要素)、self.data
構造に保存されている現行値を表示します。apply
: スポークが残っている場合に呼び出され、UI 要素の値をself.data
構造に戻す際に使用されます。execute
: スポークが残され、スポークの新しい状態に基づいてランタイム変更を実行する場合に呼び出されます。
例10 更新、適用、および実行メソッドの定義
def refresh(self): """ The refresh method that is called every time the spoke is displayed. It should update the UI elements according to the contents of self.data. :see: pyanaconda.ui.common.UIObject.refresh """ self._entry.set_text(self.data.addons.org_fedora_hello_world.text) def apply(self): """ The apply method that is called when the spoke is left. It should update the contents of self.data with values set in the GUI elements. """ self.data.addons.org_fedora_hello_world.text = self._entry.get_text() def execute(self): """ The excecute method that is called when the spoke is left. It is supposed to do all changes to the runtime environment according to the values set in the GUI elements. """ # nothing to do here pass
ready
: スポークを表示する準備ができているかどうかを判断します。値が false の場合は、スポークにアクセスできません (例: パッケージソース設定前の Package Selection スポークなど)。completed
: スポークが完了しているかどうかを確認します。mandatory
: スポークが必須かどうかを判断します (例: 自動パーティション設定を使用する場合でも、インストール先 スポークは表示する必要があります)。
HelloWorldData
クラスの text
属性で設定する必要があるものもあります。
例11 準備完了、完了、および必須メソッドの定義
@property def ready(self): """ The ready property that tells whether the spoke is ready (can be visited) or not. The spoke is made (in)sensitive based on the returned value. :rtype: bool """ # this spoke is always ready return True @property def completed(self): """ The completed property that tells whether all mandatory items on the spoke are set, or not. The spoke will be marked on the hub as completed or uncompleted acording to the returned value. :rtype: bool """ return bool(self.data.addons.org_fedora_hello_world.text) @property def mandatory(self): """ The mandatory property that tells whether the spoke is mandatory to be completed to continue in the installation process. :rtype: bool """ # this is an optional spoke that is not mandatory to be completed return False
status
と呼ばれる別のプロパティーがあり、これには設定した値の簡潔な概要がテキスト 1 行で含まれています。これはハブ内のスポークタイトルの下で表示できます。
status
プロパティーは、以下のように Hello World の例のアドオンで定義されます。
例12 status プロパティーの定義
@property def status(self): """ The status property that is a brief string describing the state of the spoke. It should describe whether all values are set and if possible also the values themselves. The returned value will appear on the hub below the spoke's title. :rtype: str """ text = self.data.addons.org_fedora_hello_world.text # If --reverse was specified in the kickstart, reverse the text if self.data.addons.org_fedora_hello_world.reverse: text = text[::-1] if text: return _("Text set: %s") % text else: return _("Text not set")
SpokeWindow
ウィジェットのインスタンスのメインウィンドウが必要になるという点です。このウィジェットは、Anaconda に固有の他のウィジェットとともに、anaconda-widgets パッケージにあります。GUI をサポートするアドオンの開発に必要なその他のファイル (Glade 定義など) は、anaconda-widgets-devel パッケージにあります。
5.6.2.2. 高度な機能
pyanaconda
にはスポークやハブが使用するヘルパーやユーティリティー関数、コンストラクトが含まれており、これらはここまでのセクションで説明されていません。ほとんどのものは、pyanaconda.ui.gui.utils
にあります。
englightbox
で使用する englightbox コンテンツマネージャーの使用方法が説明されています。このマネージャーはウィンドウをライトボックスにおいて視認性を高めてフォーカスし、ユーザーが下層のウィンドウと対話しないようにします。この機能を示すために、サンプルアドオンには新しいダイアログウィンドウを開くボタンが含まれています。ダイアログ自体は、pyanaconda.ui.gui.__init__
で定義される GUIObject
クラスから継承される特別な HelloWorldDialog
です。
dialog
クラスは、self.window
属性を介してアクセス可能な内部 Gtk ダイアログを実行および破棄する run
メソッドを定義します。この属性は、同じ意味の mainWidgetName
クラス属性を使用して設定されます。そのため、以下の例のようにダイアログを定義するコードは非常にシンプルです。
例13 englightbox Dialog の定義
# every GUIObject gets ksdata in __init__ dialog = HelloWorldDialog(self.data) # show dialog above the lightbox with enlightbox(self.window, dialog.window): dialog.run()
enlightbox
コンテキストマネージャーを使用してライトボックス内でそのダイアログを実行します。コンテキストマネージャーは、スポークのウィンドウとダイアログのウィンドウのライトボックスをインスタンス化するためにこれらのウィンドウへの参照を必要とします。
FirstbootSpokeMixIn
(より正確には mixin) を、pyanaconda.ui.common
モジュールで定義されている最初の継承クラスとして継承する必要があります。
FirstbootOnlySpokeMixIn
クラスを継承します。
@gtk_action_wait
と@gtk_action_nowait
デコレータ) ですが、このガイドの範囲外です。例については インストーラーのソース を参照してください。
5.6.3. テキスト形式のユーザーインターフェイス
tui
ディレクトリーの下に一連の新しいサブパッケージを作成します。「Anaconda アドオンの構造」 .
simpleline
ユーティリティーをベースとしており、これは非常にシンプルなユーザーの対話のみを可能にするものです。これはカーソルの操作はできず (ラインプリンターのような動作になります)、色およびフォントのカスタマイズといった視覚的拡張機能もありません。
simpleline
ツールキットには、App
、UIScreen
、Widget
の 3 つの主要クラスがあります。画面に表示 (プリント) する情報を格納しているユニットである Widget は、App
クラスの単一インスタンスで切り替えられる UIScreens に配置されます。基本的な要素のほかには hubs、spokes および dialogs があり、これらはすべてグラフィカルインターフェイスと同様の各種ウィジェットを格納しています。
NormalTUISpoke
と pyanaconda.ui.tui.spokes
パッケージで定義される他の各種クラスです。これらのクラスはすべて TUIObject
クラスに基づいています。それ自体は、前の章で説明した GUIObject
クラスと同等です。各 TUI スポークは、NormalTUISpoke
クラスを継承する Python クラスであり、API で定義される特別な引数とメソッドをオーバーライドします。テキストインターフェイスは GUI よりも簡単なため、引数は以下の 2 つのみになります。
title
: GUI のtitle
引数の場合と同様に、スポークのタイトルを指定します。category
: スポークのカテゴリーを文字列として判別します。カテゴリー名はどこにも表示されず、グループ化にのみ使用されます。注記カテゴリーは GUI とは異なる処理です。[5] 既存のカテゴリーを新しいスポークに割り当てることが推奨されます。新しいカテゴリーを作成するには、Anaconda にパッチを適用する必要があり、ほとんどメリットがありません。
__init__
、initialize
、refresh
、refresh
、apply
、execute
、input
、prompt
、および プロパティー (ready
、completed
、mandatory
、および status
) をオーバーライドすることが期待されています。これらはすべて、「グラフィカルユーザーインターフェイス」 .
例14 シンプルな TUI Spoke の定義
def __init__(self, app, data, storage, payload, instclass): """ :see: pyanaconda.ui.tui.base.UIScreen :see: pyanaconda.ui.tui.base.App :param app: reference to application which is a main class for TUI screen handling, it is responsible for mainloop control and keeping track of the stack where all TUI screens are scheduled :type app: instance of pyanaconda.ui.tui.base.App :param data: data object passed to every spoke to load/store data from/to it :type data: pykickstart.base.BaseHandler :param storage: object storing storage-related information (disks, partitioning, bootloader, etc.) :type storage: blivet.Blivet :param payload: object storing packaging-related information :type payload: pyanaconda.packaging.Payload :param instclass: distribution-specific information :type instclass: pyanaconda.installclass.BaseInstallClass """ NormalTUISpoke.__init__(self, app, data, storage, payload, instclass) self._entered_text = "" def initialize(self): """ The initialize method that is called after the instance is created. The difference between __init__ and this method is that this may take a long time and thus could be called in a separated thread. :see: pyanaconda.ui.common.UIObject.initialize """ NormalTUISpoke.initialize(self) def refresh(self, args=None): """ The refresh method that is called every time the spoke is displayed. It should update the UI elements according to the contents of self.data. :see: pyanaconda.ui.common.UIObject.refresh :see: pyanaconda.ui.tui.base.UIScreen.refresh :param args: optional argument that may be used when the screen is scheduled (passed to App.switch_screen* methods) :type args: anything :return: whether this screen requests input or not :rtype: bool """ self._entered_text = self.data.addons.org_fedora_hello_world.text return True def apply(self): """ The apply method that is called when the spoke is left. It should update the contents of self.data with values set in the spoke. """ self.data.addons.org_fedora_hello_world.text = self._entered_text def execute(self): """ The excecute method that is called when the spoke is left. It is supposed to do all changes to the runtime environment according to the values set in the spoke. """ # nothing to do here pass def input(self, args, key): """ The input method that is called by the main loop on user's input. :param args: optional argument that may be used when the screen is scheduled (passed to App.switch_screen* methods) :type args: anything :param key: user's input :type key: unicode :return: if the input should not be handled here, return it, otherwise return True or False if the input was processed succesfully or not respectively :rtype: bool|unicode """ if key: self._entered_text = key # no other actions scheduled, apply changes self.apply() # close the current screen (remove it from the stack) self.close() return True def prompt(self, args=None): """ The prompt method that is called by the main loop to get the prompt for this screen. :param args: optional argument that can be passed to App.switch_screen* methods :type args: anything :return: text that should be used in the prompt for the input :rtype: unicode|None """ return _("Enter a new text or leave empty to use the old one: ")
__init__
のみを呼び出す場合は __init__
メソッドを上書きする必要はありませんが、この例のコメントでは、一般的な方法でスポーククラスのコンストラクターへ渡された引数を記述します。
initialize
メソッドはスポークの内部引数のデフォルト値を設定し、これは refresh
メソッドで更新され、 Kickstart データの更新に apply
メソッドが使用します。この 2 つのメソッドが GUI のものと違う点は、refresh
メソッドの戻り値のタイプ (None ではなく bool) と、それらが取る追加の args
引数のみです。返された値の意味はコメントで説明されています。このスポークにユーザー入力が必要かどうかに関係なく、アプリケーション (App
クラスインスタンス) に指示します。追加の args
引数は、スポークに追加情報を渡す予定の場合に使用されます。
execute
メソッドは、GUI の同等のメソッドと同じ目的で、この場合はメソッドは何もしません。
input
と prompt
メソッドはテキストインターフェイスに固有のものです。キックスタートまたは GUI には同等のものはありません。この 2 つのメソッドはユーザーの対話に使用されます。
prompt
メソッドは、スポークのコンテンツがプリントされた後に表示されるプロンプトを返します。このプロンプトに文字列を入力すると、これが input
メソッドに渡されて処理されます。input
メソッドはこの文字列のタイプと値に応じてアクションを実行します。上記の例は任意の値を要求してから、それを内部属性 (key
) として保存します。より複雑なアドオンでは通常、c
を "continue" または r
を "refresh" として解析する、数字を整数に変換する、新たな画面を表示するもしくはブール値を切り替えるなど、簡単ではないアクションを実行する必要があります。
input
クラスの戻り値は、INPUT_PROCESSED
か INPUT_DISCARDED
の定数 (これらは両方とも pyanaconda.constants_text
モジュールで定義) となるか、もしくは 入力文字列そのもの (この入力が別の画面で処理される場合) である必要があります。
apply
メソッドは自動的に呼び出されません。input
メソッドから明示的に呼び出す必要があります。同じことがスポークの画面閉鎖 (非表示) にも該当し、これは close
メソッドの呼び出しで実行します。
TUIObject
をインスタンス化し、self.app.switch_screen*
の App
メソッドの 1 つを呼び出します。
pyanaconda.ui.tui.spokes
パッケージから EditTUISpoke
クラスを使用し、これを実行する別の方法があります。このクラスを継承すると、設定するフィールドと属性を指定するだけで通常の TUI スポークを実装できます。以下の例ではこの方法を示しています。
例15 EditTUISpoke を使ったテキストインターフェイスのスポークの定義
class _EditData(object): """Auxiliary class for storing data from the example EditSpoke""" def __init__(self): """Trivial constructor just defining the fields that will store data""" self.checked = False self.shown_input = "" self.hidden_input = "" class HelloWorldEditSpoke(EditTUISpoke): """Example class demonstrating usage of EditTUISpoke inheritance""" title = _("Hello World Edit") category = "localization" # simple RE used to specify we only accept a single word as a valid input _valid_input = re.compile(r'\w+') # special class attribute defining spoke's entries as: # Entry(TITLE, ATTRIBUTE, CHECKING_RE or TYPE, SHOW_FUNC or SHOW) # where: # TITLE specifies descriptive title of the entry # ATTRIBUTE specifies attribute of self.args that should be set to the # value entered by the user (may contain dots, i.e. may specify # a deep attribute) # CHECKING_RE specifies compiled RE used for deciding about # accepting/rejecting user's input # TYPE may be one of EditTUISpoke.CHECK or EditTUISpoke.PASSWORD used # instead of CHECKING_RE for simple checkboxes or password entries, # respectively # SHOW_FUNC is a function taking self and self.args and returning True or # False indicating whether the entry should be shown or not # SHOW is a boolean value that may be used instead of the SHOW_FUNC # # :see: pyanaconda.ui.tui.spokes.EditTUISpoke edit_fields = [ Entry("Simple checkbox", "checked", EditTUISpoke.CHECK, True), Entry("Always shown input", "shown_input", _valid_input, True), Entry("Conditioned input", "hidden_input", _valid_input, lambda self, args: bool(args.shown_input)), ] def __init__(self, app, data, storage, payload, instclass): EditTUISpoke.__init__(self, app, data, storage, payload, instclass) # just populate the self.args attribute to have a store for data # typically self.data or a subtree of self.data is used as self.args self.args = _EditData() @property def completed(self): # completed if user entered something non-empty to the Conditioned input return bool(self.args.hidden_input) @property def status(self): return "Hidden input %s" % ("entered" if self.args.hidden_input else "not entered") def apply(self): # nothing needed here, values are set in the self.args tree pass
_EditData
は、ユーザーが入力した値を保存するデータコンテナーとして機能します。HelloWorldEditSpoke
クラスはチェックボックス 1 つとエントリー 2 つの簡単なスポークを定義し、これらはすべて Entry
クラスとしてインポートされる EditTUISpokeEntry
のインスタンスになります。最初のインスタンスはスポークが表示されるたびに表示され、2 つ目のインスタンスは 1 つ目に空以外の値が含まれる場合にのみ表示されます。
EditTUISpoke
クラスについての詳細は、上記の例にあるコメントを参照してください。
5.7. Anaconda アドオンのデプロイおよびテスト
/usr/share/anaconda/addons/
ディレクトリーから収集します。独自のアドオンをこのディレクトリーに追加するには、同じディレクトリー構造で product.img
ファイルを作成し、ブートメディアに配置する必要があります。
product.img
ファイルの作成、およびイメージの再パッケージ化に関する具体的な手順については、次を参照してください。「ISO イメージを使った作業」 .
inst.kdump_addon=on
オプションを使用して有効にできます。
A. 更新履歴
改訂履歴 | ||||||
---|---|---|---|---|---|---|
改訂 2-11 | Mon Aug 19 2019 | |||||
| ||||||
改訂 2-10 | Wed May 29 2019 | |||||
| ||||||
改訂 2-9 | Tue Oct 30 2018 | |||||
| ||||||
改訂 2-8 | Tue Aug 21 2018 | |||||
| ||||||
改訂 2-7 | Fri Apr 6 2018 | |||||
| ||||||
改訂 2-6 | Fri Dec 15 2017 | |||||
| ||||||
改訂 2-5 | Tue Aug 1 2017 | |||||
| ||||||
改訂 2-4 | Tue May 16 2017 | |||||
| ||||||
改訂 2-3 | Mon May 15 2017 | |||||
| ||||||
改訂 2-2 | Mon Nov 16 2015 | |||||
| ||||||
改訂 2-1 | Mon Jun 22 2015 | |||||
| ||||||
改訂 2-0 | Fri Jun 19 2015 | |||||
| ||||||
改訂 1-0 | Wed Jan 15 2014 | |||||
| ||||||
改訂 0-0 | Fri Dec 28 2012 | |||||
|
索引
シンボル
- 起動メニュー
- BIOS システムのカスタマイズ, BIOS ファームウェアのシステム
- UEFI システムのカスタマイズ, UEFI ファームウェアのシステム
G
- grub2
- カスタム設定, UEFI ファームウェアのシステム
I
- ISO イメージ
- ISO イメージの作成, カスタムブートイメージの作成
- isolinux
- カスタム設定, BIOS ファームウェアのシステム
M
- MD5sum
- ISO イメージへの埋め込み, カスタムブートイメージの作成
P
- product.img
- ホストの, product.img ファイルの作成