# % Options Settings: https://orgmode.org/manual/Export-Settings.html
#+OPTIONS: timestamp:nil ^:nil <:nil p:t prop:t tags:t tasks:t todo:t
#+LATEX_CLASS: article
#+LaTeX_CLASS_OPTIONS: [a4paper,12pt]
#+LATEX_HEADER: \usepackage{booktabs}
# % to include pdf/eps/png files
#+LATEX_HEADER: \usepackage{indentfirst}
#+LATEX_HEADER: \usepackage{graphicx}
# % useful to add 'todo' markers
#+LaTeX_HEADER: \usepackage{todonotes}
#+LaTeX_HEADER: \setlength{\marginparwidth}{2cm} % fix todonotes warning
# % hyperrefs
#+LaTeX_HEADER: \usepackage{hyperref}
# % ----------------- Code blocks ----------------
# % Dependencies: pip install pygments
# % nice source code formatting
#+LaTeX_HEADER: \usepackage{xcolor}
#+LaTeX_HEADER: \definecolor{bg}{rgb}{0.98,0.98,0.98}
#+LaTeX_HEADER: \usepackage[cache=false]{minted}
#+LaTeX_HEADER: \setminted{
#+LaTeX_HEADER:   fontsize=\small,
#+LaTeX_HEADER:   baselinestretch=1,
#+LaTeX_HEADER:   xleftmargin=4em,
#+LaTeX_HEADER:   breaklines,
#+LaTeX_HEADER:   mathescape,
#+LaTeX_HEADER:   linenos,
#+LaTeX_HEADER:   numbersep=5pt,
#+LaTeX_HEADER:   frame=leftline,
#+LaTeX_HEADER:   framesep=2mm,
#+LaTeX_HEADER:   autogobble,
#+LaTeX_HEADER:   style=tango,
#+LaTeX_HEADER:   bgcolor=bg
#+LaTeX_HEADER: }
# % change style of section headings
#+LaTeX_HEADER: \usepackage{sectsty}
#+LaTeX_HEADER: \allsectionsfont{\sffamily}
# % only required for orgmode ticked TODO items, can remove
#+LaTeX_HEADER: \usepackage{amssymb}
# % only required for underlining text
#+LaTeX_HEADER: \usepackage[normalem]{ulem}
# % often use this in differential operators:
#+LaTeX_HEADER: \renewcommand{\d}{\ensuremath{\mathrm{d}}}
# % allow more reasonable text width for most documents than LaTeX default
#+LaTeX_HEADER: \setlength{\textheight}{21cm}
#+LaTeX_HEADER: \setlength{\textwidth}{16cm}
# % reduce left and right margins accordingly
#+LaTeX_HEADER: \setlength{\evensidemargin}{-0cm}
#+LaTeX_HEADER: \setlength{\oddsidemargin}{-0cm}
# % reduce top margin
#+LaTeX_HEADER: \setlength{\topmargin}{0cm}
# % references formats
#+LaTeX_HEADER: \usepackage[round]{natbib}
# % Chinese supported
#+LATEX_HEADER: \usepackage{ctex}
# % Increase default line spacing a little
#+LATEX_HEADER: \usepackage{setspace}
#+LATEX_HEADER: \renewcommand{\baselinestretch}{1.5}
#+LATEX_HEADER: \setlength{\parskip}{0.8em}
# % Line & paragraph space end
# % item list margin
#+LATEX_HEADER: \usepackage{enumitem}
# % Breaking Page Between Title and Toc
#+LATEX_HEADER: \makeatletter \def\@maketitle{\null \begin{center} {\vskip 5em \Huge \@title} \vskip 30em {\LARGE \@author} \vskip 3em {\LARGE \@date} \end{center} \newpage} \makeatother
# % End of Breaking Page Between Title and Toc
#+LATEX_HEADER: \renewcommand\contentsname{目录}
# Generate Tex File: C-c C-e l l; then replace verbatim with minted, and must special the code language
#+LATEX_HEADER: % Generate PDF: xelatex -shell-escape <tex file>
#+AUTHOR: jouyouyun
#+EMAIL: yanbowen717@gmail.com
#+TITLE: 构建远程 repo

#+latex: \newpage
** 前言
原子更新需要系统能够支持全量和增量更新，为了实现增量更新的功能，设计了类 =git repo= 的方案来管理 =rootfs= ，即采用 =ostree= 构建 =rootfs repo= 。

因此也要求 =rootfs= 需要满足以下要求：
+ =deb= 的构建必须支持可重复构建(=Reproducible=)

  相同源码构建出来的 =deb= 的内容应是一致的。
+ =rootfs= 的构建必须支持可重复构建(=Reproducible=)

  相同源码或相同 =deb= 构建出来的 =rootfs= 的内容应是一致的。

若 =Reproducible= 无法保证，则每次 =ostree commit= 操作时都将有大量的不必要的变更，使增量更新变得毫无意义。

** 构建 repo
=repo= 的构建关键在于 =rootfs= 的构建，首先需要确定构建 =rootfs= 所需的 =source list= ，然后根据 =source list= 构建 =rootfs= 。

主要的构建流程如下：
#+begin_src shell
      ------------------------------->|
      ^                               |
      |                               v
[source list] ---> [deb list] ---> [rootfs]     [upgrade desc] <--- admin
                                      |               |
                                      v               v
                                      -----------------
                                             |
                                             v
                                        [rootfs repo]
                                             |
                                             v
                                      ----------------
                                      |              |
                                      v              v
                                  [snapshot]    [snapshot desc]    [signature]
                                      |              |    |           ^  |
                                      v              v    |           |  |
                                      ----------------    |           |  |
                                      |       |           |           |  |
                                      |       v           |           |  |
                                      |       ------------------------>  |
                                      |                   |              |
                                      v                   v              v
                                      ------------------------------------
                                                        |
                                                        v
                                                      [ISO]
#+end_src

=rootfs= 可由 =source list= 直接构建，也可先将 =source= 构建为 =deb= ，然后再从 =deb list= 构建出 =rootfs= ，当前采用 =source -> deb -> rootfs= 的方式进行构建。

每次构建 =rootfs= 时，构建者需同时提供本次 =rootfs= 的描述信息，包括：版本、主题、描述、变更记录等，可参考 [[../misc/files/os_desc.xml][OS Description XML]] ，描述信息应存储于 =rootfs/META-INF/= 目录，文件名以版本号为名。

假定 =repo= 的路径为 =/data/os/v23/repo= ，构建得到的 =rootfs= 路径为 =/data/os/v23/rootfs= ，初始化 =repo= 的关键操作如下：
+ ~ostree --repo=/data/os/v23/repo init~
+ ~ostree --repo=/data/os/v23/repo commit -b <version> -s <subject> /data/os/v23/rootfs~

** 更新 repo
=repo= 的更新可有两种方式：重新构建 =rootfs= 和基于 =snapshot= 安装差异 =source list= 。

*** 重新构建 rootfs
此种方式就是基于最新的 =source list= 重新构建出 =rootfs= ，然后复制 =repo= 中的 =META-INF= 目录，并添加本次的描述信息文件，然后对此次的 =rootfs= 执行 =commit= 操作。

*** 基于 snapshot 安装差异 source list
此种方式的更新步骤如下：
1. 获取 =repo= 的最新版本，假定为 =last=

   使用 ~ostree --repo=/data/os/v23/repo refs~ 列出已有版本，然后找出最新版本。
2. 生成 =last= 版本的 =snapshot=

   使用 ~ostree --repo=/data/os/v23/repo checkout last /data/os/v23/snapshot/~ 生成。
3. =chroot= 到 =snapshot= 中，安装有更新的 =source list=
4. 添加本次的版本描述文件
5. 提交本次更新

   使用 ~ostree --repo=/data/os/v23/repo commit -s <version> -b <subject> /data/os/v23/snapshot/last~ 生成。

** 构建 rootfs
=rootfs= 的构建主要由以下步骤完成：
1. 根据 =base.list= 生成基础 =rootfs=
2. =chroot= 到 =rootfs=
3. 根据 =extra.list= 在 =chroot= 环境下安装扩展软件
4. 清理安装生成的缓存文件，需要考虑例外
   - =deb= 文件
   - =/var/cache=
     - =/var/cache/image-blur= 为例外
5. 合并文件到 =/usr= 目录
   - =/boot, /bin, /sbin, /lib, /lib<qual>, /etc, /var= 移入到 =/usr= ，并创建对应的 =symlink=
6. 生成需要强制覆盖的文件列表，主要是以下目录中的文件：
   - =/boot=
   - =/etc=
   - =/var=
7. 添加版本描述文件
   - 从 =rootfs repo= 中 =checkout META-INF= 到 =rootfs/usr=
   - 添加 =<version>.xml= 到 =rootfs/usr/META-INF=

** 生成 ISO
=ISO= 是基于 =snapshot= 生成的，因此在生成之前需确定要使用的 =repo version= 。
假定 =version= 为 =last= ， =ISO= 的数据目录为 =/data/os/v23/iso/last= ，生成步骤如下：
1. 生成 =last= 版本的 =snapshot=

   使用 ~ostree --repo=/data/os/v23/repo checkout last /data/os/v23/snapshot/~ 生成。
2. 移出 =META-INF=

   将 =last= 的描述文件复制到 =/data/os/v23/iso/last/description.xml= ，然后删除 =/data/os/v23/snapshot/META-INF= 。
3. 生成 =squashfs= ，文件名为 =rootfs.squashfs=

   使用 =mksquashfs /data/os/v23/snapshot/last /data/os/v23/iso/last/rootfs.squashfs -comp zstd=
4. 生成签名

   生成 =description.xml= 和 =rootfs.squashfs= 的签名，并保存到签名文件 =manifest.xml= 中。
5. 构建 =ISO=
